--- title: "Pay Monthly Messaging" slug: "pay-monthly-messaging-ios" updated: 2026-05-22T16:10:50Z published: 2026-05-22T16:10:50Z canonical: "developer.upgrade.com/pay-monthly-messaging-ios" --- > ## Documentation Index > Fetch the complete documentation index at: https://developer.upgrade.com/llms.txt > Use this file to discover all available pages before exploring further. # Pay Monthly Messaging For legal and regulatory purposes, it is important that all pricing calculations be handled by Flex Pay only. Flex Pay typically returns a "from" price, which is an estimated monthly payment amount for the current shopping cart. Because the final monthly payment amount varies by the outcome of the underwriting process, the pricing is estimated, hence the word "from". The iOS SDK offers a variety of options to handle both base and incremental prices (such as ancillaries or upgrades) and "per person" and total prices, as follows: ### Price Type | Price Type | Description | | --- | --- | | Total | Type when the price represents the total price of the product. | | Addon | Type when the price represents only an addon above the standard price of the product. | ### Price Model | Price Model | Description | | --- | --- | | Total | Use this value when the price represents the total price. | | PerNight | Use this value when the price represents the per night price. | | PerDay | Use this value when the price represents the per day price. | | AvgPerNight | Use this value when the price represents the average per night price. | | PerPerson | Use this value when the price represents the per person price. | | PerNightPerPerson | Use this value when the price represents the per night per person price. | | PerDayPerPerson | Use this value when the price represents the per day per person price. | | AvgPerNightPerPerson | Use this value when the price represents the average per night per person price. | ### From Pricing Flex Pay's **iOS SDK** provides a method to annotate any price with Pay Monthly Messaging using the `ULPMMessage` object. It contains a built-in information modal which will display the details of the offer when it is selected. More detail about the information modal is provided below. ``` /** * From Price * priceId: Unique id to identify the price object * value: 30000, Total value of the reservation in USD cents * type: .total, Price type of the price. It means the price represents the price of the reservation and it's not an additional service price. * model: .total, Price model of the price. It means the price represents the total value of the reservation */ let hotelReservationPrice = ULPMPrice(priceId: UUID().uuidString, value: 30000, type: .total, model: .total) /** * Per Person Price * priceId: Unique id to identify the price object * value: 15000, Value of the reservation in USD cents per person * type: .total, Price type of the price. It means the price represents the price of the reservation and it's not an additional service price. * model: .perPerson, Price model of the price. It means the price represents the per person price of the reservation */ let pmPrice = ULPMPrice(priceId: UUID().uuidString, value: 15000, type: .total, model: .perPerson) ``` ### Upgrade Pricing An upgrade price represents the extra cost of adding ancillaries such as priority boarding or baggage fees. Since an upgrade price must be combined with a base price on Flex Pay's back end, a total price or total per person price is required along with an upgrade price. To represent an upgrade item, the `value` has to be the sum of the base price and the upgrade price and the `type` has to be `addon`. All prices are in USD cents. For example $300 is 30000. ``` /** * From Price * priceId: Unique id to identify the price object * value: 35000, Value of the reservation in USD cents where 30000 is the base price and 5000 is the upgrade price * type: .addon, Price type of the price. It means the price represents the upgraded reservation and not just the base price * model: .total, Price model of the price. It means the price represents the total price of the reservation */ let basePrice = 30000 let upgradePrice = 5000 let ancillaryPrice = ULPMPrice(priceId: UUID().uuidString, value: basePrice + upgradePrice, type: .addon, model: .total) /** * Per Person Price * priceId: Unique id to identify the price object * value: 17500, Value of the reservation in USD cents per person, where 15000 is the base price and 2500 is the upgrade price * type: .addon, Price type of the price. It means the price represents the upgraded reservation and not just the base price * model: .perPerson, Price model of the price. It means the price represents the per person price of the reservation */ let basePrice = 15000 let upgradePrice = 2500 let ancillaryPrice = ULPMPrice(priceId: UUID().uuidString, value: basePrice + upgradePrice, type: .addon, model: .perPerson) ``` ## Configuring a PM Messaging A `ULPMMessage` button can be created for each `ULPMPrice`. To configure a `ULPMMessage`, a `ULPMTripInfo` will need to be created. It is important to be as detailed as possible when constructing the `ULPMTripInfo` and include all available information in this object. Please consult the test application to see an implementation. More detail about the `ULPMTripInfo` below. A `ULPMMessage` can be set up to display the monthly price amounts as a Pay Monthly Message. You can configure this button with 3 different methods, each defining the way the info modal will appear. ``` let trip: ULPMTripInfo = your_trip_info let hotelReservationPrice: ULPMPrice = ulpmprice_for_the_hotel // Create the button for hotelReservation let hotelReservationButton = ULPMMessage(type: .custom) // The button can notify its delegate if an error happens or the detail page // is dismissing. For more info check the ULPMMessageDelegate protocol. hotelReservationButton.delegate = self hotelReservationButton.setTitleColor(.blue, for: .normal) self.view.addSubview(hotelReservationButton) // Configure it with the ULPMPrice // Case 1: The info modal will be presented in full screen above the given view controller hotelReservationButton.configurePMMessage(with: hotelReservationPrice, tripInfo: trip, presenterViewController: self) { result in switch result { case .success(let hasOffer): if hasOffer { // Uplift has a valid offer for the configured ULPMPrice } else { // Uplift doesn't have any offer for the configured ULPMPrice } case .failure(let error): // An error has happened during the configuration } } // Case 2: The info modal will be pushed into the given navigation controller hotelReservationButton.configurePMMessage(with: hotelReservationPrice, tripInfo: trip, presenterNavigationController: self.navigationController) { result in switch result { case .success(let hasOffer): if hasOffer { // Uplift has a valid offer for the configured ULPMPrice } else { // Uplift doesn't have any offer for the configured ULPMPrice } case .failure(let error): // An error has happened during the configuration } } // Case 3: Present the info modal manually hotelReservationButton.configurePMMessage(with: hotelReservationPrice, tripInfo: trip) { presentableViewController in // present the screen manually } dismissBlock: { dismissedViewController in // The info modal has been dismissed } completionBlock: { result in switch result { case .success(let hasOffer): if hasOffer { // Uplift has a valid offer for the configured ULPMPrice } else { // Uplift doesn't have any offer for the configured ULPMPrice } case .failure(let error): // An error has happened during the configuration } } ``` ### Updating a PM Messaging To update the displayed value of a `PMMessage`, simply configure it again with a new `ULPMPrice` object. ### Customizing the title of a PM Messaging Flex Pay provides the possibility to fully customize the title of a PM Messaging. To do that, set your `titleFormatString` and create the `attributedTitleBuilder` block which has to return with an `NSAttributedString`. With these changes, the title of the Messaging will be the returned attributed string. Consult the test app for an implementation. ``` message.titleFormatString = "From\n$%.0f/mo" message.attributedTitleBuilder = { title, price in let attirbutedString = NSMutableAttributedString(string: title) //Underlined part let underlinedString = String(format: "$%.0f/mo", price) if let range = title.range(of: underlinedString) { attirbutedString.addAttributes([.underlineStyle: [NSUnderlineStyle.single, NSUnderlineStyle.patternDot]], range: NSRange(range, in: title)) } //Bigger, Bold pard let boldString = String(format: "$%.0f", price) if let range = title.range(of: boldString) { attirbutedString.addAttributes([.font: UIFont.boldSystemFont(ofSize: 20.0)], range: NSRange(range, in: title)) } return attirbutedString } ```