mount, the same callbacks and webhooks. The provider only changes what you set up once and what the customer needs before the order.
Providers
Eligibility tells you what a provider still needs for a given customer, so you don’t have to hardcode the column above.
Stripe
- Credentials. In production, Stripe orders run on your own Stripe account. Stripe onboards it for its embedded crypto onramp and registers your app as a trusted application. Then add your Stripe keys to your Meld account as in provider setup, together with the Link OAuth client ID, client secret and headless API version Stripe gives you, and point a Stripe webhook for
crypto.onramp_session.updatedat the webhook URL the Meld dashboard shows for the integration. In sandbox, Meld provides the Stripe integration: see Headless testing. - Link. Stripe signs the customer in to Link with the email on the Meld customer, and sends the one-time code to the phone on that Link account.
- Identity. Stripe runs its own KYC, and the SDK fills it from Unified KYC, so the customer only types their SSN. Meld doesn’t refuse a Stripe order without Unified KYC, but the customer then fills in Stripe’s forms by hand. Stripe can also ask for an ID document or a selfie, depending on the amount and its own risk checks.
- Cards.
CREDIT_DEBIT_CARDruns the same flow, with Stripe collecting the card. It needs no Apple setup.
Coinbase
- Merchant of record. Coinbase takes the payment on its own checkout, and the SDK opens Coinbase’s Apple Pay sheet from it. You need no Apple setup.
- Before the order. Verify the email and phone with
serviceProvider: "COINBASEPAY", and record the customer’s acceptance of Coinbase’s agreements. Both are in Eligibility. - Limits. Coinbase caps each customer weekly and over their lifetime. Over the lifetime cap, the order is refused with
CUSTOMER_NOT_PAYMENT_READYuntil the customer completes thelimitUpgradeprocess. - Quote. Send
walletAddresson the headless quote, so Coinbase prices the same checkout the order uses. - Settlement. Meld creates the transaction once Coinbase reports the payment, usually a minute or more after
onPaymentSubmitted. An order the customer never pays sends no webhook. - Sandbox. Sandbox covers everything up to creating the order. The current SDKs can’t present a sandbox Coinbase order (it ends in
PRESENTATION_FAILED), so test the sheet in production with a small order.
Before you begin
- Create the customer, and give them what the provider needs before the order (see Providers)
- Configure webhooks
- Do the Apple setup below, once per provider that needs it
Apple Developer setup
Mercuryo, Banxa and Stripe need a merchant identifier and a payment processing certificate. Coinbase needs neither. You will need:- An Apple Developer account with admin rights on your team
- The payment processing CSR, which your Meld representative provides. For Stripe, see Stripe’s certificate
- Xcode, to add the capability and regenerate provisioning profiles
1
Create a merchant identifier
A merchant identifier names your app to Apple Pay. It lives under your Apple Developer account, not Meld’s.
- Go to Certificates, Identifiers & Profiles
- Click Identifiers in the sidebar, then +
- Select Merchant IDs, then Continue
- Enter a description and an identifier — it must start with
merchant.(e.g.merchant.com.yourcompany.yourapp) - Click Continue, review, then Register
2
Create a payment processing certificate
This certificate is what the Apple Pay token is encrypted to. It must be created from a CSR Meld provides — never generate your own for this step, because the processor holds the matching private key.Once you have the
.certSigningRequest file from your Meld representative:- Go to Certificates, Identifiers & Profiles
- Click Identifiers, filter by Merchant IDs, and select the one from Step 1
- Under Apple Pay Payment Processing Certificate, click Create Certificate
- Upload the
.certSigningRequestfile Meld provided - Click Continue, then Download to save the
.cerfile - Send the
.cerfile back to your Meld representative
3
Configure Xcode
- Open your project in Xcode and select your app target
- Go to the Signing & Capabilities tab
- Click + Capability and select Apple Pay
- Under the Apple Pay capability, click + and add the merchant identifier from Step 1
- Regenerate provisioning profiles
Certificate expiry. Apple payment processing certificates expire every 25 months. When yours approaches expiry, repeat Step 2 — Meld will provide a fresh CSR. An expired certificate fails every payment.
Supporting more than one provider
Use one merchant identifier per processor. Apple encrypts a merchant identifier’s tokens to a single payment processing certificate, so two processors cannot share one. If you offer Apple Pay through two providers, run the setup once for each, with its own identifier. Your app’s Apple Pay entitlement must hold every identifier: add each in Step 3, or list each in the Expo plugin’smerchantIds. The sheet does not open for an identifier the entitlement lacks.
Stripe’s certificate
Stripe decrypts the token, so the certificate comes from a CSR issued by the Stripe account the order runs on:- Production: your Stripe account. Download the CSR from the Stripe Dashboard’s iOS certificate settings, and upload the
.cerfile Apple returns to Stripe, not to Meld. - Sandbox: Meld’s Stripe sandbox. Your Meld representative gives you the CSR, and you send them the
.cerfile.
400 PAYMENT_METHOD_NOT_SUPPORTED.
Registering your domain — web only
On the web there is no native sheet: the button renders on your origin, so that origin has to be registered with the provider before Apple will let it present one. Registration is not self-serve. Contact your Meld representative with the domains you need registered — Meld brokers each one with the provider, so allow for a round trip per domain, and do it before you plan to go live. Every domain you serve the button from needs its own registration, staging included. Native-only integrations skip this entirely.Flow overview
An Apple Pay purchase, with the system sheet presented over the app
1. Quote, then check eligibility
Every order starts here, not just the first one. Get a quote withintegrationMode=HEADLESS. It prices the order and names the providers that can take it. Name the chain with destinationNetworkCode on the quote request, and send the same value on the order. Then check eligibility for the provider you picked, and collect whatever is outstanding before you create the order.
2. Create the order
Endpoint:POST /crypto/order/headless/onramp
Headers: Meld-Version: 2026-05-01, X-Idempotency-Key: <uuid>
clientIpAddress. Creating the order charges nothing.
Response, for this Mercuryo order. ... marks values elided here:
paymentMethodResponseDetails and headlessPresentation depend on the provider: a Stripe order carries a bootstrap for Stripe’s SDK, and a Coinbase order a link to Coinbase’s checkout. You don’t read them. Return the whole order to your client verbatim, and don’t log it: it carries short-lived credentials for this order.
3. Present the sheet
Check the device can pay before you offer the button, then hand the order to the SDK.onCancel fires when the user dismisses the sheet. Return them to the amount screen. Every onError code, and whether a payment may exist, is in Error codes.
Stripe and Coinbase run only in an iOS app. Check Meld.capabilities before you offer the button.
4. Settlement
onPaymentSubmitted means the user authorised the payment. Authorisation is not settlement.
Unmount when it fires and move the user to your own processing screen. Credit them when Meld’s TRANSACTION_CRYPTO_COMPLETE webhook reaches your backend. No SDK event tells you the money moved.