New PayPal-Braintree moduleBraintree client SDK + PayPal JS v6 in the web SDKClient token in method configconsume it to boot the stackNonce + multi-use token in OTTcarried like any credentialPrice-update mechanismnet-new merchant communication on address changecreateClientToken serviceproven in the sandbox prototypeNonce → multi-use exchangeexact mutation TBC — need vault without charge for $0 flowsbraintree-webhookvalidate PayPal event mappingNonce from OTT → chargepass it in the charge callvault_on_successsupport on payment creationWallet persistence modelcurrent model is card-centric — define wallets as customer payment methodsThe merchant opens a checkout session with Yuno. Yuno's server calls the Braintree GraphQL API to mint a short-lived client token that authorizes the browser SDK — the merchant never touches Braintree credentials.
The merchant mounts the Yuno SDK, which renders the PayPal button and initializes Braintree JS under the hood. It calls createCheckoutWithVaultSession, wiring up onShippingAddressChange / onShippingOptionsChange so the merchant page can re-price live. The PayPal window opens.
After the customer approves in the PayPal window, the Yuno SDK tokenizes the approval into a single-use token and surfaces the customer details to the merchant's front end.
The merchant creates the payment with Yuno (POST /payments). Yuno's server calls chargePayPalAccount: consumes the nonce, creates the transaction, and receives a multi-use payment method token that Yuno vaults for future charges.
amountorder total at session startcurrencye.g. USD, BRL, MXNcountrydrives available payment methodscustomer_idYuno customer referencemerchant_order_idSpaceX order referenceshipping_addressoptional — only if SpaceX already collected itamountfrom the Yuno sessioncurrencyfrom the Yuno sessioncommit: true“Pay Now” button (vs. “Continue”)enableShippingAddressPayPal collects + returns an addressshippingAddressOverridepre-fill with SpaceX's address (name, line1, city, state, zip, country, phone)shippingAddressEditablefalse = locked, callbacks never fire · true = customer can change itcontactPreferencecontrols email / phone collectiononShippingAddressChangecallback → SpaceX re-pricesonShippingOptionsChangecallback → SpaceX re-pricesmerchantAccountIdroutes to the right Braintree account / currencyclientToken← returned; authorizes the browser SDKshippingAddressOverride + editable: false; priced upfront, no callbacks needed.
| # | From → To | Call | Returns / purpose |
|---|---|---|---|
| Setup | |||
| 1 | Merchant → Yuno | POST /checkout/sessions | Session + method config; “PayPal via Braintree” listed as its own method |
| 2 | Checkout → Integrations (internal) | createClientToken (new service) | Requests the provider client token |
| 3 | Integrations → Braintree | GQL mutation createClientToken | Short-lived clientToken, delivered in the method config |
| 4 | Yuno SDK (browser) | loads Braintree JS + PayPal v6 | Renders the PayPal button — script load, not an API call |
| In the PayPal window — all client-side | |||
| 5 | Yuno SDK → PayPal | createCheckoutWithVaultSession | Opens the window; checkout + vault session |
| 6 | PayPal → SDK → merchant page | onShippingAddressChange / onShippingOptionsChange | Candidate address (city/state/zip/country); buyer is waiting |
| 7 | Merchant page → SDK → PayPal | updatePayment (new amount) or reject | Buyer sees the new total — or an inline “doesn’t ship here” error |
| 8 | Yuno SDK | tokenizePayment → wrap into OTT | Single-use nonce + payer name, email, phone, address. No server call. |
| Completion — server-side | |||
| 9 | Merchant → Yuno | POST /payments { ott, amount, vault_on_success: true } | Creates the payment with the approved total |
| 10 | Payments → Integrations (internal) | charge with nonce from the OTT | Payments unwraps the OTT; Integrations owns the provider call |
| 11 | Integrations → Braintree | GQL mutation chargePayPalAccount { nonce, amount, vault-on-success } | Transaction (PayPal txn ID) + multi-use payment method token — nonce consumed, single use |
| 12 | Core | persist multi-use token | Stored as the customer’s vaulted payment method (wallet model — open item) |
| 13 | Braintree → Yuno | braintree-webhook events | Statuses, refunds, disputes — existing infra; PayPal event mapping to validate |
| Renewals — no shopper present | |||
| 14 | Merchant → Yuno | POST /payments { vaulted_token } | Monthly renewal / one-click purchase |
| 15 | Integrations → Braintree | GQL chargePayPalAccount { vault token } | Charges the billing agreement — no PayPal window, buyer absent |
Topologydirect PSP connection to PayPal — 3 partiesComponent modelcheckout.create('paypal') — merchant picks the method, mounts one componentRe-pricingserver round-trip: /paypal/updateOrder with rotating paymentData on every changeApprovalonAdditionalDetails → /payments/details to finalizeVaultstorePaymentMethod → stored method for lightbox-free chargesTopologyorchestrated through Braintree — 4 parties, Yuno is Braintree's merchant of recordComponent modeltoday: full SDK owns the selector — the gap; the ask is Adyen-style mount-per-methodRe-pricingclient-side: callback patches the amount in the Braintree JS session — no server round-tripApprovaltokenize → nonce + customer details → POST /paymentsVaultchargePayPalAccount vault:true → multi-use token held by Yuno