# PayPal v2 Checkout This document will cover the flow of the PayPal checkout option in the consumer apps and storefront. There are two different types of payment mechanisms PayPal provide us: **Single Payment** - We use this whenever a user doesn't have a Slice account and is going through the guest checkout. This allows us to authorise a single payment made against the users PayPal account. Every time a guest user checks out they will need to log into their PayPal account. **Billing Agreement** - We use this whenever the user has a Slice account and is logged in on the app. This allows us to create a Billing Agreement which we only need to authorise once, then on reorders we can reuse without the user having to log into PayPal each time. ### PayPal Api Requests Both payment flows have requirements for the user to authorise them by logging into their PayPal account. This is done by the apps displaying a webpage with a specific url, which presents them with PayPals login page. This url is returned from the initial request to either create a single payment or a billing agreement token, under the links key in the response. For the billing agreement token flow, the rel stays the same, "approval_url", but for the sinle payment method **is changed to "approve"**. Whenever the user successfully authenticates, the PayPal website will redirect to a url we provide, allowing the apps to deep link back into the Slice application and continue the checkout process. I think storefront does not use the sinle payment method core api endpoint, it uses the PayPal smart buttons, and should look here: https://developer.paypal.com/docs/checkout/# about how to update The following Core Api endpoints are used by the apps to communicate with payPal (They are all POST requests): `v1/paypal/billing_agreement_tokens` - (**No changes done**) This creates a billing agreement token for a user who hasn't already set up a billing agreement. This token must then be authorised as mentioned above before it can be used. This endpoint can take return/cancel urls, but has defaults if you don't send any. ``` { "redirect_urls": { "return_url": "https://www.slicelife.com/checkout/app/paypal?success=true", "cancel_url": "https://www.slicelife.com/checkout/app/paypal?success=false" } } ``` ``` { "links": [{ "href": "https://www.sandbox.paypal.com/agreements/approve?ba_token=BA-2J7808419E191762K", "rel": "approval_url", "method": "POST" }, { "href": "https://api.sandbox.paypal.com/v1/billing-agreements/BA-2J7808419E191762K/agreements", "rel": "self", "method": "POST" }], "payer": { "payment_method": "paypal" }, "plan": { "type": "MERCHANT_INITIATED_BILLING_SINGLE_AGREEMENT", "merchant_preferences": { "cancel_url": "https://www.slicelife.com/checkout/app/paypal?success=false", "return_url": "https://www.slicelife.com/checkout/app/paypal?success=true" } }, "token_id": "BA-2J7808419E191762K" } ``` `v1/paypal/billing_agreements` - (**No changes done**) This creates a billing agreement from the authorised token generated in the billing_agreement_token request. This billing agreement will have a unique id which can be used for future orders.  ``` { "token_id": "BillingAgreementToken" } ``` ``` { "id": "B-20C92195W3842605U", "token_id": "BA-2J7808419E191762K", "state": "ACTIVE", "payer": { "payer_info": { "email": "accounting-buyer@slicelife.com", "first_name": "test", "last_name": "buyer", "payer_id": "UE4QHP58NCSYA", "phone": "408-264-2531", "billing_address": { "line1": "143 Varick Street", "city": "New York", "country_code": "US", "postal_code": "10013", "state": "NY" } } }, "plan": { "type": "MERCHANT_INITIATED_BILLING", "merchant_preferences": { "notify_url": "https://example.com/notify" } }, "create_time": "2018-10-19T08:34:21.000Z", "update_time": "2019-02-28T15:00:12.000Z", "links": [{ "href": "https://api.sandbox.paypal.com/v1/billing-agreements/agreements/B-20C92195W3842605U/cancel", "rel": "cancel", "method": "POST" }, { "href": "https://api.sandbox.paypal.com/v1/billing-agreements/agreements/B-20C92195W3842605U", "rel": "self", "method": "GET" }] } ``` ### **The changes** `v2/paypal/payments` - This creates a single PayPal payment using Paypal's v2 of their API, which must be authorised by the user before it can be completed. The parameters it accepts are listed below, but they are the same as for `v1/paypal/payments`. The thing that is changed is the response If our order is a pickup, the delivery address will be the address of the pizza shop and the recipient name will be the shop's name. If the order is a delivery, it will be the customers delivery address and the customers name. ``` { "payment": { "shipping_type": "delivery", "delivery_address": { "phone": "(359) 384-65346", "state": "NY", "recipient_name": "Aidan Malone", "line1": "50 MacDougal St", "city": "New York", "postal_code": "10012" }, "order_total": 17.25, "redirect_urls": { "return_url": "https:\/\/www.slicelife.com\/checkout\/app\/paypal?success=true", "cancel_url": "https:\/\/www.slicelife.com\/checkout\/app\/paypal?success=false" }, "shop_id": 23173 } } ``` ``` { "id": "397067788K125313R", "intent": "AUTHORIZE", "status": "CREATED", "purchase_units": [ { "reference_id": "default", "amount": { "currency_code": "USD", "value": "17.25" }, "payee": { "email_address": "accounting-facilitator@slicelife.com", "merchant_id": "WD6ZRVVHX9Z96" }, "soft_descriptor": "Billy's Pizza & Pasta" } ], "create_time": "2020-08-18T13:38:00Z", "links": [ { "href": "https://api.sandbox.paypal.com/v2/checkout/orders/397067788K125313R", "rel": "self", "method": "GET" }, { "href": "https://www.sandbox.paypal.com/checkoutnow?token=397067788K125313R", "rel": "approve", "method": "GET" }, { "href": "https://api.sandbox.paypal.com/v2/checkout/orders/397067788K125313R", "rel": "update", "method": "PATCH" }, { "href": "https://api.sandbox.paypal.com/v2/checkout/orders/397067788K125313R/authorize", "rel": "authorize", "method": "POST" } ] } ``` `Create Order Api Request` The Create Order endpoint `/v1/orders` does not require any changes. The Core API itself has the logic based on the `payment_id` received whether it should use Paypal's v1 or v2 of their API to authorize the request. The v1 payment ids start with `PAY` whereas the v2 do not have prefixes. For the billing agreement payments, the logic is based on a flipper `enable_paypal_v2`, if that is on, the v2 will be used to generate the whole flow, otherwise v1. ``` "paypal": { "metadata_id": "41fc446e1f884dc29228782db2cc5960", "payer_id": "UE4QHP58NCSYA", "payment_id": "PAY-9AT30021YW054862YLR4P3QI" } ``` ``` "paypal": { "metadata_id": "15de62f9378c427d929ad62ffd7e7baa", "payer_id": "UE4QHP58NCSYA", "billing_agreement_id": "B-20C92195W3842605U" } ``` ``` "paypal": { "metadata_id": "a8d4eea1438044b2a65259f13b60f67b", "payer_id": "accounting-buyer@slicelife.com", "billing_agreement_id": "B-20C92195W3842605U" } ``` `metadata_id` - This is used as a part of PayPals anti fraud system. The clients need to install a third party library which will gather device info and return this meta data id to be included in the create order request. `payer_id` - For single payments and new billing agreements, this is an id which represents the payer, which we get back as a query parameter in our deep link back to the app. For a repeat billing agreement, this is the email address of the PayPal account holder who set up the billing agreement. We save this as the remote_cutomer_id on our Slice payment methods. `payment_id` - Used to identify the single payment we create, returned from the api request to create a single payment `billing_agreement_id` - Used to identify the billing agreement, this is returned from the create billing agreement endpoint on a new billing agreement, or saved as the payment_token on our Slice payment method for a repeat billing agreement. Response: ``` { "order": { "id": 33136525, "uuid": "22b35917-07bd-43d9-9567-1d9160a82cd9", "shipping_type": "pickup", "date_purchased": "2020-08-18T10:25:48.000-04:00", "delivery_telephone": "5555555555", "delivery_first_name": "Emilija", "delivery_last_name": "Talevska", "delivery_name": "Emilija Talevska", "payment_method": "credit", "email": "emilija.t@slicelife.com", "confirmed_at": null, "voided_at": null, "payment_status": "authorized", "progress_step": null, "promo_code_discount_amount": "0", "service_fee_amount": "0.0", "slice_credit_discount": 0.0, "total_coupon_discount_amount": 0, "total": "22.44", "subtotal": "18.95", "tax": "1.6", "tip": "2.84", "shop_id": 103, "shop_name": "Billy's Pizza & Pasta", "shop_web_slug": "ny/brooklyn/11225/billy-s-pizza-pasta", "shop_address": "1626 Bedford Ave", "shop_city": "Brooklyn", "shop_state": "NY", "shop_zipcode": "11225", "shop_phone": "9175550101", "shop_latitude": "40.6671391", "shop_longitude": "-73.956571", "shop_discount_percentage": 5, "invalid_selections": false, "min_eta_timestamp": "2020-08-18T10:40:48.000-04:00", "max_eta_timestamp": "2020-08-18T10:45:48.000-04:00", "coupons": [], "order_items": [ { "products_final_price": "18.95", "products_quantity": 1, "products_id": 9885326, "product_name": "Veggie Thick Crust Pan Pie", "product_type_name": "14\" (6 Slices)", "product_type_price": "18.95", "products_type_id": 12841246, "order_item_selections": [] } ], "user_facing_line_items": [ { "name": "Tax", "value": "$1.60" }, { "name": "Tip", "value": "$2.84" }, { "name": "% Discount", "value": "-$0.95" } ], "adjustments": [ { "order_id": 33136525, "amount": "2.84", "category": "tip", "tag": "tip", "description": "Tip" }, { "order_id": 33136525, "amount": "1.6", "category": "tax", "tag": "tax", "description": "Tax" }, { "order_id": 33136525, "amount": "-0.95", "category": "discount_percent", "tag": "discount_percent", "description": "5% discount" } ], "transactions": [ {} ] } } ``` PayPals documentation for the api requests we use can be found here: https://developer.paypal.com/docs/api/payments.billing-agreements/v1/ https://developer.paypal.com/docs/api/payments/v2/ https://developer.paypal.com/docs/checkout