Skip to content
Create account or Sign in
The Stripe Docs logo
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
OverviewAccept a paymentUpgrade your integration
Online payments
OverviewFind your use case
Use Payment Links
Use a prebuilt checkout page
Build a custom integration with Elements
Build an in-app integration
Use Managed Payments
Recurring payments
In-person payments
Terminal
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment operations
Analytics
Balances and settlement time
Compliance and security
Currencies
Declines
Disputes
Fraud prevention
Radar fraud protection
Payouts
ReceiptsRefunds and cancellations
Advanced integrations
Custom payment flows
Flexible acquiring
Off-Session Payments
Multiprocessor orchestration
Beyond payments
Incorporate your company
Crypto
    Overview
    Fiat-to-crypto onramp
      Overview
      Get started
      Embedded onramp
      Embedded onramp extended guide
      Stripe-hosted onramp
      Embedded Components onramp
      Embedded Components onramp integration guide
      Embedded Components onramp quickstart
Agentic commerce
Machine payments
Financial Connections
Climate
Verify identities
United States
English (United States)
HomePaymentsCryptoFiat-to-crypto onramp

Integrate the Embedded Components onrampPrivate preview

Step-by-step integration guide for the Embedded Components onramp.

This guide walks you through integrating the Embedded Components onramp into your mobile app with minimal Stripe branding.

Before you begin

  • The Embedded Components onramp is only available in the US (excluding Hawaii).

  • The Embedded Components API is in private preview. To request access:

    1. Submit your application
    2. Sign up to join the waitlist
  • After you get access to the Embedded Components onramp, obtain your secret and publishable API keys from the API keys page.

Mobile SDK configuration

Step 1: Install the Stripe React Native SDK

Follow the installation instructions in the README to install the Stripe React Native SDK.

Step 2: Add the onramp dependency Client-side

By default, the onramp dependency isn’t included in the Stripe React Native SDK to reduce bundle size. Include it as follows, depending on your platform.

# android/gradle.properties StripeSdk_includeOnramp=true # ios/Podfile – add pod pod 'stripe-react-native/Onramp', path: '../node_modules/@stripe/stripe-react-native'

Step 3: Use StripeProvider Client-side

Wrap your app with StripeProvider at a high level so Stripe functionality is available throughout your component tree. Key properties:

  • publishableKey – Your Stripe publishable key.
  • merchantIdentifier – Your Apple Merchant ID (required for Apple Pay).
  • urlScheme – Required for return URLs in authentication flows.

This component is essential for initializing the Stripe SDK in your React Native application before using payment-related features.

import { StripeProvider } from '@stripe/stripe-react-native'; function App() { return ( <StripeProvider publishableKey="pk_test_..." merchantIdentifier="merchant.identifier" urlScheme="your-url-scheme" > {/* Your app components */} </StripeProvider> ); }

Step 4: Configure the onramp SDK Client-side

Before any onramp APIs can be called successfully, you’ll need to configure the SDK using the configure method. It’s provided by the useOnramp() hook. configure takes an instance of Onramp.Configuration to customize your business display name and lightly customize elements in Stripe-provided interfaces, such as the user’s wallet, one-time passcode authorization, and identity verification UI.

import { useOnramp } from '@stripe/stripe-react-native'; function OnrampComponent() { const { configure } = useOnramp(); const setupOnramp = useCallback(async () => { const result = await configure({ merchantDisplayName: 'My Crypto App', appearance: { lightColors: { primary: '#2d22a1', contentOnPrimary: '#ffffff', borderSelected: '#07b8b8' }, darkColors: { primary: '#800080', contentOnPrimary: '#ffffff', borderSelected: '#526f3e' }, style: 'ALWAYS_DARK', primaryButton: { cornerRadius: 8, height: 48 } } }); if (result.error) { console.error('Configuration failed:', result.error.message); } }, []); React.useEffect(() => { setupOnramp(); }, []); return null; }

Authentication

Step 1: Check for a Link account Client-side

The user must have a Link account to use the onramp APIs. Use hasLinkAccount to determine if the user’s email is associated with an existing Link account. See the HasLinkAccountResult for the return type and the OnrampError for the error type.

  • If they have an account, proceed to Authorize.
  • If they don’t, use Register a new Link user, then proceed to Authorize.
const { hasLinkAccount, registerLinkUser, authorize } = useOnramp(); const linkResult = await hasLinkAccount('user@example.com'); if (linkResult.error) return; if (linkResult.hasLinkAccount) { // Proceed to authorization. } else { // Register the user first (see next step). }

View example

function AuthComponent() { const { hasLinkAccount, registerLinkUser } = useOnramp(); const handleAuth = useCallback(async () => { const linkResult = await hasLinkAccount('user@example.com'); if (linkResult.error) return; if (linkResult.hasLinkAccount) { // Proceed to authorization. } else { const userInfo = { email: 'user@example.com', phone: '+12125551234', country: 'US', fullName: 'John Smith', }; const registerResult = await registerLinkUser(userInfo); if (registerResult.error) { } else if (registerResult.customerId) { // Proceed to authorization. } } }, []); return <Button title="Authenticate" onPress={handleAuth} />; }

Step 2: Register a new Link user (if needed) Client-side

If the user doesn’t have a Link account, use registerLinkUser to create one with user information collected from your UI. Upon successful account creation, proceed to Authorize. See the RegisterLinkUserResult for the return type and the OnrampError for the error type.

const userInfo = { email: 'user@example.com', phone: '+12125551234', country: 'US', fullName: 'John Smith', }; const registerResult = await registerLinkUser(userInfo); if (registerResult.error) return; if (registerResult.customerId) { // Proceed to authorization. }

Step 3: Authorize Client-side Server-side

The primary method of authentication is via two-factor authorization.

3a. Create a LinkAuthIntent

A LinkAuthIntent tracks scopes of the OAuth requests and the status of user consent. Your backend calls the Create a LinkAuthIntent API with the onramp OAuth scopes, get authIntentId, and send it to the client.

OAuth scopes used when creating a LinkAuthIntent:

Scope (string)Description
kyc.status:readRead the user’s KYC verification status.
crypto:rampAdd crypto wallets to deposit from the user’s account on their behalf.
// createAuthIntent is a client-side function you must implement. // Call your back end to create a LinkAuthIntent using the API. const authIntentResponse = await createAuthIntent( email, // This is your OAUTH_CLIENT_ID, which identifies your application in the Link OAuth flow. authToken, 'kyc.status:read,crypto:ramp' ); const authIntentId = authIntentResponse.data.authIntentId;

3b. User consents

The client calls authorize with the authIntentId to complete consent. The authorize SDK looks up and verifies the user’s Link session, shows them what your app is requesting (the OAuth scopes) on a consent screen or inline on the OTP screen, and collects their approval.

The SDK then sends that consent to Stripe so your backend can exchange the intent for an access token and finish the flow. The result includes a customerId that must be used for all subsequent onramp API calls. See the AuthorizeResult for the return type and the OnrampError for the error type.

const result = await authorize(authIntentId); if (result?.error) { // An error occurred. Stop here. } else if (result?.status === 'Consented' && result.customerId) { // Authorization successful; exchange for access token. } else if (result?.status === 'Denied') { // The user denied authorization. Stop here. } else { // The user canceled authorization. Stop here. }

3c. Request access tokens

If the result is Consented, your backend calls the Retrieve Access Tokens API to request access tokens. Store the access token and use it on all subsequent onramp API requests (for example, in the Stripe-OAuth-Token header).

# Request curl -X POST https://login.link.com/v1/link_auth_intent/{authIntentId}/tokens \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" # Response { "access_token": "liwltoken_xxx", "token_type": "Bearer", "expires_in": 3600, "refresh": { "refresh_token": "liwlrefresh_xxx", "expires_in": 7776000 } }

Identity

Step 1: Check if KYC collection is needed Server-side

Your backend calls the Retrieve a CryptoCustomer API with the customerId. Inspect the response verifications array. If it includes an entry with type kyc_verified and status not_started, proceed to Collect KYC.

curl https://api.stripe.com/v1/crypto/customers/{customerId} \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"

View example

async function getCryptoCustomer(req, res) { const { id } = req.params; const oauthToken = req.headers['stripe-oauth-token']; const response = await fetch( `https://api.stripe.com/v1/crypto/customers/${id}`, { headers: { Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`, 'Stripe-OAuth-Token': oauthToken ?? '', }, } ); const customer = await response.json(); const verifications = customer.verifications ?? []; const kycVerified = verifications.find((v) => v.name === 'kyc_verified'); const idDocVerified = verifications.find( (v) => v.name === 'id_document_verified' ); res.json({ customerId: customer.id, providedFields: customer.provided_fields ?? [], kycStatus: kycVerified?.status ?? 'not_started', idDocStatus: idDocVerified?.status ?? 'not_started', }); }

Step 2: Collect KYC (if needed) Client-side

If the customer needs KYC verification, your client calls attachKycInfo to collect and submit user KYC data. Present your own interface to the user to collect this KYC information. See the KycInfo for the return type and the OnrampError for the error type.

import { useOnramp } from '@stripe/stripe-react-native'; function AttachKYCComponent() { const { attachKycInfo } = useOnramp(); const handleAttachKycInfo = useCallback(async () => { const kycInfo = { firstName: "FirstName", lastName:"LastName", idNumber: '000000000', dateOfBirth: { day: 1, month: 1, year: 1990, }, address: { line1: '123 Main St', line2: 'Apt 4B', city: 'San Francisco', state: 'CA', postalCode: '94111', country: 'US', }, }; const result = await attachKycInfo(kycInfo) if (result?.error) { // KYC information failed to attach. } else { // KYC information attached successfully. } }, []); return <Button title="Attach KYC" onPress={handleAttachKycInfo} />; }

Step 3: Verify KYC (if needed) Client-side

When a user already has KYC information, use presentKycInfoVerification so the SDK can present a screen with the user’s existing KYC information for verification. Currently, we only support users updating their address. See the VerifyKycResult for the return type and the OnrampError for the error type.

import { useOnramp } from '@stripe/stripe-react-native'; function VerifyKYCComponent() { const { presentKycInfoVerification } = useOnramp(); const handlePresentKycVerification = useCallback( async (updatedAddress: Address | null) => { const result = await presentKycInfoVerification(updatedAddress); if (result?.error) { if (result.error.code === 'Canceled') { // KYC Verification was canceled by the user. } else { // An error occurred during verification. } } else if (result?.status === 'Confirmed') { // KYC information was verified by the user. } else if (result?.status === 'UpdateAddress') { // User indicated that their address needs to be updated. } else { // KYC Verification was canceled by the user. } }, []); return <Button title="Verify KYC" onPress={handlePresentKycVerification} />; }

Step 4: Verify identity (if needed) Client-side

Some users must verify their identity before continuing with checkout. When required, use the verifyIdentity method. It presents a Stripe-hosted flow where the user uploads an identity document and a selfie.

Verification is asynchronous. After the user completes the flow, your backend can call the Retrieve a CryptoCustomer API and inspect the verifications array to see the results.

import { useOnramp } from '@stripe/stripe-react-native'; function VerifyIdentityComponent() { const { verifyIdentity } = useOnramp(); const handleVerifyIdentity = useCallback(async () => { const result = await verifyIdentity(); if (result?.error) { if (result.error.code === 'Canceled') { // Identity verification was cancelled. } else { // Error occurred during verification. } } else { // Identity verification was completed. } }, []); return <Button title="Verify Identity" onPress={handleVerifyIdentity} />; }

Payment

Step 1: Register a crypto wallet Client-side Server-side

A ConsumerWallet must be registered before you can create a PaymentToken. This validates that the address is valid for the given network. Your backend can call the List ConsumerWallets API to see whether the user already has wallets on file.

If the list is empty or the user wants to add another address, have the client call registerWalletAddress with the user’s chosen address and network. Replace the address and network with user-provided values. A previously registered wallet can be reused in future sessions.

curl "https://api.stripe.com/v1/crypto/customers/{customerId}/crypto_consumer_wallets" \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"

Step 2: Collect a payment method Client-side Server-side

A payment method must first be collected before a transaction can occur. Your backend can call the List PaymentTokens API to see which payment methods the user already has. If the list is empty or the user wants to use a different method, have the client call collectPaymentMethod.

Card, Bank Account, and Apple Pay are supported. For Card and Bank Account, collectPaymentMethod presents Stripe’s wallet user interface, which lists existing stored payment methods, allows the user to add new ones, and select one. Upon successful payment method selection, it returns an instance of CollectPaymentMethodResult, which includes a displayData property (icon, label, sublabel) that you can use in your UI to show the selected payment method.

curl https://api.stripe.com/v1/crypto/customers/{customerId}/payment_tokens \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"

To collect Apple Pay, first check isPlatformPaySupported in useStripe(). See Apple Pay on React Native. If the user chooses Apple Pay, pass an instance of PlatformPay.PaymentMethodParams into collectPaymentMethod.

Step 3: Create a payment token Client-side

Create a PaymentToken by calling createCryptoPaymentToken. Use the returned token when creating the CryptoOnrampSession.

import { useOnramp } from '@stripe/stripe-react-native'; function CreatePaymentTokenComponent() { const { createCryptoPaymentToken } = useOnramp(); const handleCreateCryptoPaymentToken = useCallback(async () => { const result = await createCryptoPaymentToken(); if (result?.error) { // An error occurred while creating a crypto payment token. } else { // Use result.cryptoPaymentToken in your payment session. } }, []); return <Button title="Create Payment Token" onPress={handleCreateCryptoPaymentToken} />; }

Step 4: Create a crypto onramp session Server-side

From your UI, determine the amount, source currency (for example, usd), destination currency (for example, usdc), and network. Your backend calls the Create a CryptoOnrampSession API to create a CryptoOnrampSession. The Stripe React Native SDK doesn’t provide APIs for creating a crypto onramp session. It happens on your backend. The example below shows how a client application might call your backend. Adapt it to your use case.

When the user is paying with ACH, you can optionally pass settlement_speed on create session (private feature; contact us if you need this).

function CreateOnrampSessionComponent() { const handleCreateOnrampSession = useCallback(async () => { // createOnrampSession is a client-side function you must implement. // Call your back end to create a CryptoOnrampSession using the API. const result = await createOnrampSession( "headless", cryptoCustomerId, cryptoPaymentToken, 100.0, "usd", "usdc", walletAddress, Onramp.CryptoNetwork.bitcoin ); if (result.success) { const sessionId = result.data.id; } else { // An error occurred. } }, []); return <Button title="Create onramp Session" onPress={handleCreateOnrampSession} />; }

Step 5: Perform checkout Client-side Server-side

Call performCheckout to run the checkout flow for a crypto onramp session. It presents a UI for any required actions such as 3DS.

You must implement the client-side callback fetchClientSecretFromBackend, which the SDK invokes to retrieve the checkout client secret. Have it call your back end, which calls the onramp session checkout endpoint with the session ID. The response includes the client_secret, which your callback can then return to the SDK.

For ACH, the API may indicate that mandate_data is missing. Collect acceptance and send it on a later checkout call if required.

import { useOnramp } from '@stripe/stripe-react-native'; function CheckoutComponent() { const { performCheckout } = useOnramp(); const handleCheckout = useCallback(async () => { const result = await performCheckout(sessionId, async () => { // fetchClientSecretFromBackend is a client-side function you must implement. // It calls your back end, which calls the onramp session checkout endpoint with the session ID // and returns the client_secret from the response. // Return the client secret on success, or throw an Error on failure. const clientSecret = await fetchClientSecretFromBackend(sessionId); return clientSecret; }); if (result.error) { if (result.error.code === 'Canceled') { // The checkout process was canceled by the user. } else { // An error occurred while checking out. } } else { // Checkout was completed successfully. } }, []); return <Button title="Complete Purchase" onPress={handleCheckout} />; }

When the API returns 200 or 202 but the purchase isn’t done, the response body includes the CryptoOnrampSession object with transaction_details.last_error set. Use that value to decide the next step:

last_errorDescriptionHow to handle
action_requiredUser must complete a payment step (for example, 3D Secure).Run the SDK’s 3DS handling. After the user completes the step, call checkout again.
missing_kycKYC verification is required.Have the user complete KYC in the SDK (for example, attachKycInfo). Then call checkout again.
missing_document_verificationIdentity document verification is required.Have the user complete verification in the SDK (for example, verifyIdentity). Then call checkout again.
charged_with_expired_quoteQuote expired.Call Refresh a Quote API, then call checkout again.
transaction_limit_reachedUser’s limit exceeded.Display an error message.
location_not_supportedUser’s location isn’t supported.Show that the service isn’t available in their region.
transaction_failedGeneric failure.Display a generic error message.
missing_consumer_walletThe wallet address doesn’t exist for the current user.Have the user register the wallet, then call checkout again.

Main objects

CryptoCustomer

A Crypto Customer represents a Link user in the context of your platform’s crypto onramp. It ties together user’s KYC and verification state, their consumer wallets, and their payment tokens. You use customerId in all onramp API calls to check what’s missing (for example, KYC or identity verification), to list wallets and payment tokens, and to create crypto onramp sessions.

AttributeTypeDescription
idstringUnique identifier for the object (for example, crc_xxx).
provided_fieldsarray of stringsThe set of KYC fields. See KycField.
verificationsarray of VerificationList of verifications and their outcome. See Verification.

KycField

ValueDescription
first_nameCustomer’s first name.
last_nameCustomer’s last name.
id_typeType of ID document (for example, passport or driver’s license).
id_numberID document number.
dobDate of birth.
address_line_1Address line 1.
address_line_2Address line 2.
address_cityCity.
address_stateState or region.
address_postal_codePostal or ZIP code.
address_countryCountry of address.
birth_countryCountry of birth.
birth_cityCity of birth.
nationalitiesNationality or nationalities.
id_documentIdentity document (for example, image or verification reference).
selfieSelfie image for verification.

Verification

AttributeTypeDescription
namestring (enum)VerificationType
statusstring (enum)VerificationStatus
errorsarray of strings (enum)VerificationError

VerificationType

ValueDescription
kyc_verifiedVerification that the customer has submitted required KYC information.
id_document_verifiedVerification that the customer has submitted and verified their identity documents.

VerificationStatus

ValueDescription
not_startedCustomer has not provided the info.
pendingVerification has been submitted and is processing.
rejectedVerification failed. See VerificationError for details.
verifiedVerification complete. The customer may continue.

VerificationError

ValueDescription
id_document_verification_failedIdentity document verification didn’t succeed (for example, document was rejected or couldn’t be verified).
user_has_reached_max_verification_attemptThe user has reached the maximum number of verification attempts and must wait or contact support before trying again.

CryptoOnrampSession

See Stripe API docs for the object’s attributes.

PaymentToken

A Payment Token is a read-only representation of a payment method that belongs to a CryptoCustomer and applies only to crypto onramp.

AttributeTypeDescription
idstringUnique identifier for the payment token (for example, cpt_xxx).
typestring (enum)PaymentMethodType
cardobject (optional)Card
us_bank_accountobject (optional)UsBankAccount

PaymentMethodType

ValueDescription
cardCard payment method.
us_bank_accountUS bank account payment method.

Card

AttributeTypeDescription
brandstring (optional)Card brand (for example, amex, mastercard, visa).
last4string (optional)Last four digits of the card.
exp_monthinteger (optional)Two-digit expiration month (1–12).
exp_yearinteger (optional)Four-digit expiration year.
fundingstringCard funding type (for example, credit, debit, prepaid, unknown).
walletobject (optional)Wallet

Wallet

AttributeTypeDescription
typestring (enum)WalletType

WalletType

ValueDescription
apple_payApple Pay wallet.

UsBankAccount

AttributeTypeDescription
account_typestring (enum, optional)AccountType
last4string (optional)Last four digits of the bank account number.
bank_namestring (optional)Name of the bank.

AccountType

ValueDescription
checkingChecking account.
savingsSavings account.

ConsumerWallet

A Consumer Wallet is a cryptocurrency wallet address linked to a CryptoCustomer. It’s the destination where purchased crypto is sent. The user registers wallet addresses during account setup.

AttributeTypeDescription
idstringUnique identifier for the consumer wallet.
livemodebooleanWhether this wallet is in live mode (true) or test mode (false).
networkstring (enum)Network
wallet_addressstringThe blockchain address (for example, the destination address for crypto delivery).

Network

ValueDescription
bitcoinBitcoin network.
ethereumEthereum network.
solanaSolana network.
polygonPolygon network.
baseBase network.
avalancheAvalanche network.
stellarStellar network.
aptosAptos network.
optimismOptimism network.
worldchainWorldchain network.
xrplXRP Ledger network.

API specs

Retrieve a CryptoCustomer

Retrieves the details of a CryptoCustomer. Use the response to check the customer’s KYC and verification status so you can prompt the user to complete setup (for example, KYC or identity verification) before creating an onramp session.

curl https://api.stripe.com/v1/crypto/customers/{customerId} \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"
// Response { "id": "crc_XXXX", "object": "object.public_crypto_customer", "provided_fields": ["first_name", "last_name"], "verifications": [ { "name": "kyc_verified", "status": "verified", "errors": [] }, { "name": "id_document_verified", "status": "rejected", "errors": ["id_document_verification_failed"] } ] }

Parameters

ParameterTypeDescription
idstring (required)The crypto customer ID (for example, crc_xxx).

Returns

Returns a CryptoCustomer object.

Errors

HTTP statusCause
400Missing OAuth token. The request didn’t include the Stripe-OAuth-Token header.
403Invalid or insufficient OAuth token. The token is missing, invalid, expired, has wrong scopes (for example, missing kyc.status:read), or wrong livemode.
403Customer belongs to another user. The CryptoCustomer exists but is tied to a different Link consumer than the one identified by the OAuth token.
404Customer not found. The :id isn’t a valid crypto customer ID.
404Headless onramp not enabled. The request is from a business that doesn’t have the headless onramp gate/feature enabled.

List ConsumerWallets

Returns a list of ConsumerWallet for a CryptoCustomer. Use this to see which wallet addresses are on file and whether the user needs to register a new one. Each wallet has an id, network, and address.

curl "https://api.stripe.com/v1/crypto/customers/{customerId}/crypto_consumer_wallets" \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"
// Response { "data": [ { "id": "ccw_xxx", "object": "crypto.consumer_wallet", "livemode": false, "network": "ethereum", "wallet_address": "0x1234567890abcdef1234567890abcdef12345678" } ], "has_more": false }

Parameters

ParameterTypeDescription
idstring (required)The crypto customer id (for example, crc_xxx).
limitinteger (optional)Maximum number of wallets to return. Default is 10; maximum is 20.
starting_afterstring (optional)A wallet id. Return wallets after this id (for forward pagination).
ending_beforestring (optional)A wallet id. Return wallets before this id (for backward pagination).

Returns

FieldTypeDescription
dataarrayList of ConsumerWallet objects.
has_morebooleanWhether there are more wallets after this page.
urlstringThe URL of this list.

Errors

HTTP statusCause
400Missing required param.
403Invalid request: invalid or expired OAuth token, wrong scopes, livemode mismatch, or crypto customer belongs to a different consumer.
404No such cryptocustomer: customer id invalid or not found.
404Headless onramp not enabled for this business.

List PaymentTokens

Returns a list of PaymentToken for a CryptoCustomer. Use this to see which saved payment methods the user has before asking them to add one.

curl https://api.stripe.com/v1/crypto/customers/{customerId}/payment_tokens \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"
// Response { "url": "/v1/crypto/customers/crc_xxx/payment_tokens", "data": [ { "id": "cpt_xxx", "object": "crypto.payment_token", "type": "card", "card": { "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2028, "funding": "credit" } } ], "has_more": false }

Parameters

ParameterTypeDescription
idstring (required)The crypto customer id (for example, crc_xxx). Must belong to the consumer identified by the OAuth token.
limitinteger (optional)Maximum number of payment tokens to return. Default is 10.
starting_afterstring (optional)A payment token id. Return tokens after this id (for forward pagination).
ending_beforestring (optional)A payment token id. Return tokens before this id (for backward pagination).

Returns

FieldTypeDescription
dataarrayList of PaymentToken objects.
has_morebooleanWhether there are more payment tokens after this page.
urlstringThe URL of this list.

Errors

HTTP statusCause
400Missing required param: HTTP_HEADER[Stripe-OAuth-Token]. Send the Stripe-OAuth-Token header with a valid OAuth access token.
403Invalid request: invalid or expired OAuth token, missing crypto:ramp scope, livemode mismatch, or crypto customer belongs to a different consumer.
404No such crypto customer: customer id invalid or not found.
404Headless onramp not enabled for this business.

Checkout

Completes a CryptoOnrampSession by confirming the payment and executing the quote so crypto is delivered to the customer’s wallet. Call this after creating an onramp session. If the response indicates more steps (for example, 3DS), have the user complete them in the SDK and call checkout again.

curl -X POST https://api.stripe.com/v1/crypto/onramp_sessions/{sessionId}/checkout \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"
// Response { "id": "cos_xxx", "object": "crypto.onramp_session", "status": "fulfillment_complete", "transaction_details": { "wallet_address": "0xx", "source_amount": "100.00", "source_currency": "usd", "destination_amount": "0.05", "destination_currency": "eth", "destination_network": "ethereum", "quote_expiration": 1756238966, "transaction_id": "0xx" } }

Parameters

ParameterTypeDescription
idstring (required)The onramp session id (for example, cos_xxx) to checkout. The session must have been created with ui_mode=headless and be in a state that allows checkout.
mandate_dataobject (optional)Details for creating a mandate when required (for example, for certain payment method types or regions). Include when the API or payment method requires it.

Returns

Returns the updated CryptoOnrampSession object.

Errors

HTTP statusCause
400Invalid request: missing or invalid parameters, unsupported currency or network, or invalid or missing OAuth token.
400MissingKYC: user has not completed KYC.
400InvalidWallet: wallet not attached to this user.
400InvalidPaymentMethod: payment method not attached to this user.
400Unauthorized: OAuth token invalid or missing.
404Session not found or not owned by this business.

Refresh a Quote

Refreshes the quote for a CryptoOnrampSession. Use this when checkout returns charged_with_expired_quote so you can get a new quote and call checkout again on the same session instead of creating a new one.

curl -X POST https://api.stripe.com/v1/crypto/onramp_sessions/{sessionId}/quote \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -H "Stripe-OAuth-Token: $ACCESS_TOKEN"
// Response { "id": "cos_XXXX", "object": "crypto.onramp_session", "status": "requires_payment", "transaction_details": { "wallet_address": "0x1234567890abcdef1234567890abcdef12345678", "source_amount": "100.00", "source_currency": "usd", "destination_amount": "0.05", "destination_currency": "eth", "destination_network": "ethereum", "quote_expiration": 1756238966 } }

Parameters

ParameterTypeDescription
idstring (required)The crypto onramp session ID (for example, cos_xxx). Provided in the URL path.

Returns

Returns a CryptoOnrampSession object with an updated quote.

Errors

HTTP statusCause
403Quote locked. The session quote is in a locked state. Create a new session and call checkout on it instead.
403Internal error. The session has no consumer account, or the liquidity provider account couldn’t be found.
404Session not found. The id isn’t a valid crypto onramp session ID or the session doesn’t exist.
404Headless onramp not enabled. The request is from a business that doesn’t have the headless onramp gate/feature enabled.
499Partner exchange error. The quote provider returned an error or timeout.

Create a LinkAuthIntent

Creates a LinkAuthIntent to start a Log in with Link flow. Send the OAuth client id and scopes you need. The API returns an intent id and expiration.

This API is still in private preview. Sign up to get access to additional API info.

curl -X POST https://login.link.com/v1/link_auth_intent \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -d email=user@example.com \ -d oauth_client_id=$OAUTH_CLIENT_ID \ -d oauth_scopes=kyc.status:read,crypto:ramp
// Response { "id": "lai_xxxx", "expires_at": 1756238966 }

Parameters

ParameterTypeDescription
emailstring (required)The user’s email for looking up an existing Link consumer. Provide either email or hashed_email, not both.
hashed_emailstring (required*)A SHA256 hash of the plain text email for privacy-sensitive flows. Provide either email or hashed_email, not both.
oauth_client_idstring (required)Your OAuth client id (for example, from Link). Identifies your application in the OAuth flow.
oauth_scopesstring (required)Comma-separated list of OAuth scopes (for example, kyc.status:read,crypto:ramp). Defines the permissions you’re requesting.
data_sharing_merchantstring (optional)When set, the recipient business ID for data-sharing (for example, crypto onramp). Must be a valid business ID enabled to receive OAuth tokens.

Returns

FieldTypeDescription
idstringUnique identifier for the LinkAuthIntent (for example, lai_xxx).
expires_atintegerUnix timestamp when the intent expires.

Errors

HTTP statusCause
400Missing or invalid request body.
403CreateLinkAuthIntent not enabled for business or invalid or missing API key.
404OAuth client not found for authIntentId or no active Link consumer for the provided email.
409Link consumer previously revoked connection with this partner.

Retrieve Access Tokens

Exchanges a consented LinkAuthIntent for an OAuth access token. Call this after the user has completed authorization. Use the access token (for example, in the Stripe-OAuth-Token header) on subsequent onramp API requests for that user.

This API is still in private preview. Sign up to get access to additional API info.

curl -X POST https://login.link.com/v1/link_auth_intent/{authIntentId}/tokens \ -H "Authorization: Bearer $STRIPE_SECRET_KEY"
// Response { "access_token": "liwltoken_xxx", "expires_in": 3600, "token_type": "Bearer", "refresh": { "refresh_token": "liwlrefresh_xxx", "expires_in": 7776000 } }

Parameters

ParameterTypeDescription
idstring (required)The Link Auth Intent id (for example, lai_xxx).

Returns

FieldTypeDescription
access_tokenstringOAuth access token. Send it on subsequent API requests for this user (for example, in the Stripe-OAuth-Token header).
token_typestringToken type. Always Bearer.
expires_inintegerSeconds until the access token expires.
refreshobject (optional)Present when a refresh token was issued. Use it to obtain a new access token when the current one expires. See Refresh an Access Token.
refresh.refresh_tokenstringOAuth refresh token. Store it securely and use it to obtain new access tokens. See Refresh an Access Token.
refresh.expires_inintegerSeconds until the refresh token expires.

Errors

HTTP statusCause
403Feature not available.
403LinkAuthIntent has not been consented.
403Invalid or missing API key.
404LinkAuthIntent not found (invalid id or intent belongs to another business).

Refresh an Access Token

Exchanges a refresh token for a new access token. When your access token expires, use the refresh token you received from Retrieve Access Tokens to obtain a new access token without requiring the user to re-authorize.

This API is still in private preview. Sign up to get access to additional API info.

curl -X POST https://login.link.com/auth/token \ -H "Authorization: Bearer $STRIPE_SECRET_KEY" \ -d "grant_type=refresh_token" \ -d "refresh_token=$REFRESH_TOKEN" \ -d "client_id=$OAUTH_CLIENT_ID" \ -d "client_secret=$OAUTH_CLIENT_SECRET"
// Response { "token_type": "Bearer", "access_token": "liwltoken_xxx", "expires_in": 3600, "refresh": { "refresh_token": "liwlrefresh_xxx", "expires_in": 7776000 }, "scope": "kyc.status:read crypto:ramp" }

Parameters

ParameterTypeDescription
grant_typestring (required)Must be refresh_token.
refresh_tokenstring (required)The refresh token previously obtained from Retrieve Access Tokens.
client_idstring (required)Your OAuth client ID provided by Link.
client_secretstring (required)Your OAuth client secret provided by Link.

Returns

FieldTypeDescription
token_typestringToken type. Always Bearer.
access_tokenstringOAuth access token. Expires in 1 hour. Send it on subsequent API requests (for example, in the Stripe-OAuth-Token header).
expires_inintegerTTL in seconds (3600, that is, 1 hour).
refreshobject (optional)Present when a new refresh token was issued. A new refresh token is returned each time you use the old one; store it for future refresh requests.
refresh.refresh_tokenstringOAuth refresh token. Store it securely for obtaining new access tokens when the current one expires.
refresh.expires_inintegerSeconds until the refresh token expires.
scopestringThe OAuth scopes granted.

React Native SDK

SDK methodPresents UI?What the user sees
authorize(authIntentId)YesLink consent screen (or consent inline on OTP screen).
attachKycInfoOptionalYou can collect KYC in your own UI and pass data in.
presentKycInfoVerificationYesStripe screen showing existing KYC for the user to verify.
verifyIdentityYesStripe-hosted flow (document + selfie).
collectPaymentMethod (Card / BankAccount)YesStripe wallet UI: list saved methods, add new, choose one.
performCheckoutMaybeOnly when needed (for example, 3DS).
registerWalletAddressNoNo UI. You pass address and network.
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Chat with Stripe developers on Discord.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc
On this page