# Mobile Integration Story (Server Side Order Creation) These stories outline the mobile integration experience and what the customer journey will look like. These stories assume that the order will be created on the merchant server. An [example code snippet](##Snippet-E) is provided to showcase the client side order creation integration. - [How it Works](##How-it-Works) - [Initial Setup](##Setup) - [Card Integration](##Card-Integration) - [PayPal Integration](##PayPal-Integration) - [Venmo Integration](##Venmo-Integration) - [Button Integrations](##Button-Integrations) - [Vault with Purchase](##Vault-with-Purchase) ## How it Works ![](https://i.imgur.com/LEeeN6I.png) New integration flow: ***In review*** ![](https://i.imgur.com/N4gQQJZ.png) ## Setup #### Add the Payments SDK to your app (All Modules) ##### Swift Package Manager In Xcode, add the [package dependency](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) and enter https://github.com/paypal/iOS-SDK as the repository URL. Tick the checkboxes for the specific PayPal libraries you wish to include. In your app's source code files, use the following import syntax to include PayPal's Card, Venmo and PayPal libraries: ```swift import Card // Card module (includes 3DS) import PayPal // PayPal module import Venmo // Venmo module ``` ##### CocoaPods Include the PayPal pod in your `Podfile`. ```ruby pod 'PayPal' ``` In your app's source code files, use the following import syntax to include PayPal's Card, Venmo and PayPal libraries: ```swift import Card // Card module import PayPal // PayPal module import Venmo // Venmo module ``` ## Card Integration #### Merchant/Client Journey (with 3DS challenge) 1. Customer: Checking out in the merchant's app 1. Merchant: Call `SDK Eligibility` method to determine if credit card processing is available [[See Code]](###Snippet-A) 1. Merchant: Renders card input UI 1. Customer: types in card PAN, expiry date, billing address, CVV etc. and taps submit 1. Merchant: Call `SDK approveOrder` on `SDK Card` module using the data input by the customer [[See Code]](###Snippet-B) 1. `SDK sets the payment source using the data passed in` 1. `API response indicates that a 3DS challenge is required` 1. An `In App Browser` is displayed in the merchant app by the SDK 1. Customer: Authenticates the challenge and the `In App Browser` is dismissed and the control is returned to the merchant app 1. Merchant: Receives order in APPROVED state via SDK #### Merchant/Client Journey (no 3DS challenge) 1. Customer: Checking out in the merchant's app 1. Merchant: Call `SDK Eligibility` method to determine if credit card processing is available [[See Code]](###Snippet-A) 1. Merchant: Renders card input UI 1. Customer: types in card PAN, expiry date, billing address, CVV etc. and taps submit 1. Merchant: Call `SDK approveOrder` on `SDK Card` module using the data input by the customer [[See Code]](###Snippet-B) 1. `SDK sets the payment source using the data passed in` 1. `API response indicates NO 3DS challenge is required` 1. Merchant: Receives order in APPROVED state via SDK ## PayPal Integration #### Merchant/Client Journey 1. Customer: Checking out in the merchant's app 1. Merchant: Call `SDK Eligibility` method to determine if PayPal processing is available [[See Code]](###Snippet-A) 1. Merchant: Renders PayPal button 1. Customer: Taps PayPal button 1. Merchant: Call `SDK approveOrder` on `SDK PayPal` module passing in all relevant params [[See Code]](###Snippet-C) 1. `SDK sets the payment source using the data passed in` 1. `API response contains URL for approval` 1. An `In App Browser` is displayed in the merchant app by the SDK showing the approval URL 1. Customer: Authenticates the PayPal payment and the `In App Browser` is dismissed and the control is returned to the merchant app 1. Merchant: Receives order in APPROVED state via SDK ## Venmo Integration #### Merchant/Client Journey 1. Customer: Checking out in the merchant's app 1. Merchant: Call `SDK Eligibility` method to determine if Venmo processing is available and that the Venmo app is installed [[See Code]](###Snippet-A) 1. Merchant: Renders Venmo button 1. Customer: Taps Venmo button 1. Merchant: Call `SDK approveOrder` on `SDK Venmo` module passing in all relevant params [[See Code]](###Snippet-D) 1. `SDK sets the payment source using the data passed in` 1. `API response contains order information` 1. The SDK composes the Universal Link URL with all required params that will open the Venmo app and `invokes the app switch` 1. Customer: Is switched to the Venmo app for authorization/approval 1. Customer: Approves in the Venmo app and is returned to the merchant app 1. `SDK does a GET on the Order` 1. Merchant: Receives order in APPROVED state via SDK # Code Snippets ### Snippet A Check eligibility for current and future payment methods: ```swift= // Setup config let config = CoreConfig(clientID: "<CLIENT_ID>", environment: .sandbox) let apiClient = APIClient(config: config) // Merchant calls eligibility API apiClient.checkEligibility { result in switch result { case .success(let result): // `result.eligibility.acdc` // `result.eligibility.venmo` // `result.eligibility.paypal` // `result.eligibility.applepay` // `result.eligibility.googlepay` // `result.eligibility.sepa` // `result.eligibility.ach` case .failure(let error): // handle the error by accessing `result.localizedDescription` } } ``` ### Snippet B Card integration. ```swift= class MyViewController: ASWebAuthenticationPresentationContextProviding, CardDelegate { ... func checkoutWithCard() { let config = CoreConfig(clientID: "<CLIENT_ID>", environment: .sandbox) let apiClient = APIClient(config: config) let cardClient = CardClient(apiClient: apiClient) // This data comes from the merchant UI let card = Card( number: "4111111111111111", expirationMonth: "01", expirationYear: "25", securityCode: "123", cardholderName: "Jane Smith", billingAddress: Address( addressLine1: "123 Main St.", addressLine2: "Apt. 1A", locality: "city", region: "IL", postalCode: "12345", countryCode: "US" ) ) let cardRequest = CardRequest(card: card) cardClient.delegate = self cardClient.approveOrder(cardRequest: cardRequest, orderId: "<ORDER_ID_FROM_SERVER>") } func cardClient(_ cardClient: CardClient, didFinishWithResult result: CardResult) { // Order was APPROVED: `result.order.id` } func cardClient(_ cardClient: CardClient, didFinishWithError error: CoreSDKError) { // handle the error by accessing `error.localizedDescription` } func cardClientDidCancel(_ cardClient: CardClient) { // the user canceled } func cardClientWillPresentChallenge(_ cardClient: CardClient) { // In App Browser is about to be shown } func cardClientChallengeDismissed(_ cardClient: CardClient) { // In App Browser dismissed } // Required OS method to display In App Browser func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { UIApplication .shared .connectedScenes .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } .first { $0.isKeyWindow } ?? ASPresentationAnchor() } } ``` ### Snippet C PayPal integration. ```swift= class MyViewController: ASWebAuthenticationPresentationContextProviding, PayPalWebCheckoutDelegate { ... func checkoutWithPayPal() { let config = CoreConfig(clientID: "<CLIENT_ID>", environment: .sandbox) let apiClient = APIClient(config: config) let payPalClient = PayPalWebCheckoutClient(apiClient: apiClient) let payPalRequest = PayPalWebCheckoutRequest() payPalClient.delegate = self payPalClient.approveOrder(payPalRequest: payPalRequest, orderId: "<ORDER_ID_FROM_SERVER>") } func payPal(_ payPalClient: PayPalWebCheckoutClient, didFinishWithResult result: PayPalWebCheckoutResult) { // Order was APPROVED: `result.order.id` } func payPal(_ payPalClient: PayPalWebCheckoutClient, didFinishWithError error: CoreSDKError) { // handle the error by accessing `error.localizedDescription` } func payPalDidCancel(_ payPalClient: PayPalWebCheckoutClient) { // the user canceled } func payPalClientWillPresentAuthentication(_ payPalClient: PayPalWebCheckoutClient) { // In App Browser is about to be shown } func payPalClientAuthenticationDismissed(_ payPalClient: PayPalWebCheckoutClient) { // In App Browser dismissed } // Required OS method to display In App Browser func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { UIApplication .shared .connectedScenes .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } .first { $0.isKeyWindow } ?? ASPresentationAnchor() } } ``` ### Snippet D Venmo integration. ```swift= class MyViewController: ASWebAuthenticationPresentationContextProviding, VenmoDelegate { ... func checkoutWithVenmo() { let config = CoreConfig(clientID: "<CLIENT_ID>", environment: .sandbox) let apiClient = APIClient(config: config) let venmoClient = VenmoClient(apiClient: apiClient) let venmoRequest = VenmoRequest() venmoRequest.requireBillingAddress = true venmoClient.delegate = self venmoClient.approveOrder(venmoRequest: venmoRequest, orderId: "<ORDER_ID_FROM_SERVER>") } func venmoClient(_ venmoClient: VenmoClient, didFinishWithResult result: VenmoResult) { // Order was APPROVED: `result.order.id` } func venmoClient(_ venmoClient: VenmoClient, didFinishWithError error: CoreSDKError) { // handle the error by accessing `error.localizedDescription` } func venmoClientDidCancel(_ venmoClient: VenmoClient) { // the user canceled } func venmoClientWillAppSwitch(_ venmoClient: VenmoClient) { // Customer is about to be app switched to the Venmo app } func venmoClientAppSwitchReturned(_ venmoClient: VenmoClient) { // Customer returned from app switch } } ``` ### Snippet E Example Venmo integration setup when order is created on the client rather than the server. ***NOTE: This integration pattern for client side order creation applies to all current and future payment methods: Venmo, Card, PayPal...*** ```swift= func checkoutWithVenmo() { let config = CoreConfig(clientID: "<CLIENT_ID>", environment: .sandbox) let apiClient = APIClient(config: config) let venmoClient = VenmoClient(apiClient: apiClient) let venmoRequest = VenmoRequest() venmoRequest.requireBillingAddress = true let orderRequest = OrderRequest() var purchaseUnit = PurchaseUnit() orderRequest.intent = .capture orderRequest.purchaseUnits = [purchaseUnit] orderRequest.amount = "20.99" venmoClient.delegate = self venmoClient.createAndApproveOrder(venmoRequest: venmoRequest, orderRequest: orderRequest) } ``` ## Button Integrations Each payment module will include an optional and customizable button. ```swift= // PayPalButton will be a UI button in the PayPal module lazy var payPalButton: PayPalButton = { let payPalButton = PayPalButton(...) payPalButton.addTarget(self, action: #selector(paypalButtonTapped), for: .touchUpInside) return payPalButton }() @objc func paypalButtonTapped() { // Merchant starts the PayPal flow here... } ``` ## Vault with Purchase By using the Orders V2 API, the Native SDK can provide the merchant with vaulting capabilities during a purchase for Cards and PayPal Wallet ### Vault with Purchase Flow The flow for each of the payment methods is similar. The OrdersAPI v2 allows PayPal Wallet, Cards and Venmo to vault any of these payment methods with a purchase. Look at the changes in the payment_source section of this Create Order request for each payment method: #### Cards Request Sequence: ***payment_source.card.attributes.vault*** `"confirm_payment_token":"ON_ORDER_COMPLETION"`: Defines that the payer's payment-source should be vaulted only when at least one payment (authorization/capture) using that payment-source is successful. ```json= curl -v -k -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders/' \ -H 'PayPal-Request-Id: 7b92603e-77ed-4896-8e78-5dea2050476a' \ -H 'Authorization: Bearer 6V7rbVwmlM1gFZKW_8QtzWXqpcwQ6T5vhEGYNJDAAdn3paCgRpdeMdVYmWzgbKSsECednupJ3Zx5Xd-g' \ -H 'Content-Type: application/json' \ -d '{ "intent": "AUTHORIZE", "purchase_units": [ { "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b", "amount": { "currency_code": "USD", "value": "100.00" } } ], "payment_source": { "card": { "number": "4111111111111111", "expiry": "2020-02", "name": "John Doe", "billing_address": { "address_line_1": "2211 N First Street", "address_line_2": "17.3.160", "admin_area_1": "CA", "admin_area_2": "San Jose", "postal_code": "95131", "country_code": "US" }, "attributes": { "customer": { "id": "wxj1234" }, "vault": { "confirm_payment_token": "ON_ORDER_COMPLETION" } } } } }' ``` #### PayPal Request Sequence: ***payment_source.card.attributes.vault*** `"confirm_payment_token":"ON_ORDER_COMPLETION"`: Defines that the payer's payment-source should be vaulted only when at least one payment (authorization/capture) using that payment-source is successful. ```json= curl -v -k -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders/id/authorize' \ -H 'PayPal-Request-Id: 7b92603e-77ed-4896-8e78-5dea2050476a' \ -H 'Authorization: Bearer 6V7rbVwmlM1gFZKW_8QtzWXqpcwQ6T5vhEGYNJDAAdn3paCgRpdeMdVYmWzgbKSsECednupJ3Zx5Xd-g' \ -H 'Content-Type: application/json' \ -d '{ "intent": "AUTHORIZE", "purchase_units": [ { "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b", "amount": { "currency_code": "USD", "value": "100.00" } } ], "payment_source": { "paypal": { "attributes": { "customer": { "id": "wxj1234" }, "vault": { "confirm_payment_token": "ON_ORDER_COMPLETION", "usage_type": "PLATFORM" } } } } }' ``` #### Venmo Request Sequence: ***payment_source.card.attributes.vault*** `"confirm_payment_token":"ON_ORDER_COMPLETION"`: Defines that the payer's payment-source should be vaulted only when at least one payment (authorization/capture) using that payment-source is successful. `"usage_type":"MERCHANT"`: TBC: *Defines that the merchant performing the vaulting* ```javascript= curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer Access-Token" \ -d '{ "intent": "CAPTURE", "purchase_units": [ { "amount": { "currency_code": "USD", "value": "100.00" } } ], "payment_source": { "venmo": { "email_address": "customer@example.com", "experience_context": { "shipping_preference": "SET_PROVIDED_ADDRESS", "brand_name":"EXAMPLE INC" }, "attributes": { "customer": { "id": "wxj1234" }, //The vault parameter is added to allow vaulting with a purchase "vault": { "store_in_vault": "ON_ORDER_COMPLETION", "usage_type": "MERCHANT" } } } } }' ``` ## Retrieve a Vaulted Payment Method Now that a payment method has been vaulted via the Orders API, a merchant can retrieve a customer's vaulted payment method(s) by using the Vault API. Retrieving vaulted payment methods via the customer ID returns all the payment methods that the specified `customerID` have vaulted in the past. This allows the merchant-developer to retrieve them and be able provide the buyer with a better experience at checkout. ### Vault Retrieval Request ```json= curl -v -k -X GET 'https://msmaster.qa.paypal.com:18582/v3/vault/payment-tokens?customer_id=customer_4029352050' \ -H 'Authorization: Bearer FULL_scoped_access_token' \ -H 'Content-Type: application/json' ``` ### Vault Retrieval Response ```json= //Response HTTP status code: 200 HTTP Headers: "Content-Type": "application/json" Response payload: { "customer_id": "customer_4029352050", "payment_tokens": [ { "id": "8kk845", "status": "CREATED", "source": { "card": { "brand": "VISA", "last_digits": "1111", "verification_status": "NOT_VERIFIED" } }, "links": [ { "rel": "self", "href": "https://api-m.paypal.com/v2/vault/payment-tokens/8kk845", "method": "GET" }, { "rel": "delete", "href": "https://api-m.paypal.com/v2/vault/payment-tokens/8kk845", "method": "DELETE" } ] }, { "id": "6km842", "status": "CREATED", "source": { "card": { "brand": "VISA", "last_digits": "1234", "verification_status": "NOT_VERIFIED" } }, "links": [ { "rel": "self", "href": "https://api-m.paypal.com/v2/vault/payment-tokens/6km842", "method": "GET" }, { "rel": "delete", "href": "https://api-m.paypal.com/v2/vault/payment-tokens/6km842", "method": "DELETE" } ] } ], "links": [ { "rel": "self", "href": "https://api-m.paypal.com/v2/vault/payment-tokens?customer_id=customer_4029352050&page=1&page_size=5&total_required=false", "method": "GET" }, { "rel": "first", "href": "https://api-m.paypal.com/v2/vault/payment-tokens?customer_id=customer_4029352050&page=1&page_size=5&total_required=false", "method": "GET" }, { "rel": "last", "href": "https://api-m.paypal.com/v2/vault/payment-tokens?customer_id=customer_4029352050&page=1&page_size=5&total_required=false", "method": "GET" } ] } ``` ## Future Integration Offerings From the building blocks of the various payment modules, larger orchestrations can be offered: * Smart Payment Button UI * Card Forms * Payment Sheets ## Appendix