Skip to main content
Guest Checkout users start with conservative weekly spending and lifetime transaction limits. After a user completes at least 1 transaction, the Limits Upgrade API lets them unlock unlimited lifetime transactions by verifying their identity with just two pieces of information: the last 4 digits of their SSN and their date of birth. Limits Upgrade removes the main blocker for repeat Guest Checkout users: the lifetime transaction cap. Users who would otherwise stop at about 15 purchases can continue transacting after they verify their identity. Fewer users hit weekly spending limits in practice because Coinbase’s dynamic risk model raises weekly limits based on transaction history, moving power users toward the 2,500 USD maximum over time. Submitting identity information is a positive signal for that model, but it does not immediately set the weekly limit to 2,500 USD.
Limits Upgrade is only available for Guest Checkout (Headless Onramp) users. Authenticated Coinbase users have separate limit management through their Coinbase account.

Default and upgraded limits

Once approved, unlimited lifetime transactions are permanent. Users never need to re-verify. Weekly spending limits continue to update independently based on Coinbase’s dynamic risk model.

Check limits and upgrade eligibility

1. Check limits and upgrade eligibility

Call POST /v2/onramp/limits before or during the onramp flow to retrieve the user’s current limits and determine whether the user can request a lifetime transaction upgrade. For eligible apps, limitUpgradeOptions appears only after the user has completed at least 1 transaction. Once it appears, the user is eligible to submit the listed identity fields for the lifetime transaction upgrade. You do not need to track transaction count yourself, and there is no separate risk criteria to evaluate for lifetime transaction eligibility.
Both GUEST_CHECKOUT_APPLE_PAY and GUEST_CHECKOUT_GOOGLE_PAY are supported and yield identical limits. Response (upgrade available):
Response (upgrade not available):
When limitUpgradeOptions is absent from the response, do not show the upgrade prompt. For eligible apps, this means the user has not completed the prerequisite transaction yet. This is not an error; limits is always present and accurate.

Upgrade status values

limitUpgradeOptions is a single-element array. Check limitUpgradeOptions[0].status to determine what to do next:
Only show the upgrade prompt when limitUpgradeOptions is present and status is unrequested or resubmit.

Interaction modes

Limits Upgrade supports two interaction modes, selected with the interactionMode field on POST /v2/onramp/limits/upgrade:
  • API mode (default): you collect the user’s SSN and date of birth and submit them to the API yourself. Used when interactionMode is omitted or set to api.
  • Embedded mode (interactionMode: "embedded"): you embed a Coinbase-hosted form, so the user enters their details directly into Coinbase and your app never handles their identity data.
The two modes share the same limits, eligibility check, status values, and polling; only the submission steps below differ.

API mode

In API mode you collect the user’s identity fields and submit them to the API directly. This is the default mode (interactionMode omitted or set to api).

How it works

1

Check eligibility

Confirm the user can upgrade using Check limits and upgrade eligibility above.
2

Submit identity fields

Collect the user’s SSN last 4 and date of birth and submit them to POST /v2/onramp/limits/upgrade.
3

Poll for the result

Poll POST /v2/onramp/limits until the upgrade reaches a terminal status.
4

Handle resubmission

If verification returns resubmit, collect the corrected fields and submit again.

Submit identity fields

When status is unrequested or resubmit, collect the required fields and submit them to POST /v2/onramp/limits/upgrade. The endpoint returns HTTP 202 immediately; processing is asynchronous.
After receiving 202, re-poll /limits; the status immediately advances to pending.
Do not store ssnLast4 on your servers. Collect it, submit it, and discard it immediately.

Field validation

Validate client-side before submitting to avoid unnecessary round trips. The API rejects invalid dates (e.g., February 30) and non-numeric SSN values.

Poll until terminal status

Poll POST /v2/onramp/limits after the 202 response until limitUpgradeOptions[0].status reaches a terminal state.
Response when lifetime transaction upgrade is approved:
A limit, remaining, or maxUpgrade value of "2147483647" (math.MaxInt32) is the sentinel for unlimited. Display this to users as “Unlimited” rather than a raw number.
The weekly spending limit in the response is still authoritative after the lifetime transaction upgrade is active. It may remain at the base limit or increase dynamically as Coinbase evaluates identity signals, transaction history, and other risk factors. Polling guide:
  • Start polling immediately after receiving the 202 response
  • Poll every 1 to 2 seconds. Verification typically completes within ~3 seconds
  • Set a timeout (e.g., 30 seconds) and show a “still processing” message if it expires
  • Stop polling once status is active, inactive, or resubmit

Resubmission and rate limits

If status returns to resubmit, Coinbase reviewed the submission and couldn’t verify the information. fields is re-populated; collect the corrected fields and submit again. The flow is identical to the initial submission. Users are limited to 5 upgrade submissions over a rolling 5-day window. A submission only counts when it enters Coinbase’s verification pipeline — meaning the status transitions to pending. Input validation errors, transient failures, and other non-verification errors do not count against this limit. If a user reaches the cap, hold off on further submissions until later rather than retrying in a loop. Calling /limits/upgrade when status is already pending or active is safe: the endpoint returns 202 and nothing changes.

UI recommendations

For the inactive status, do not expose the underlying reason and do not show the upgrade prompt again. Input field guidance:
  • SSN: Use a masked input (****). Validate exactly 4 numeric digits client-side.
  • Date of birth: Use a date picker or separate day/month/year fields. Validate that the date is a real calendar date.

Embedded mode

Embedded mode lets you offer Limits Upgrade without ever handling your users’ sensitive identity data. Instead of collecting the SSN and date of birth yourself and submitting them to the API, you embed a Coinbase-hosted form. The user enters their details directly into Coinbase, and your app only receives the outcome.

Prerequisites

  • A free CDP Portal account and project.
  • For web embeds, a registered embedding domain. Coinbase restricts the iframe to your approved domains with Content-Security-Policy: frame-ancestors, so the form only renders where you have registered it. Provide your domains to your Coinbase contact during onboarding.

How it works

1

Check eligibility

Confirm the user can upgrade using Check limits and upgrade eligibility above. Do not mount the embed for ineligible or already-upgraded users.
2

Request the URL

Call POST /v2/onramp/limits/upgrade with interactionMode: "embedded" to get an upgradeUrl. This is a single-use, short-lived link to the Coinbase-hosted form, bound to this specific user, that you load in the embed.
3

Embed the URL

Load upgradeUrl in an iframe (web) or webview (mobile).
4

Handle events

Listen for the post message events the page emits and branch on the outcome.

Request the URL

After confirming the user is eligible, call POST /v2/onramp/limits/upgrade with interactionMode: "embedded". Send only the user’s phone number. Do not send the fields object in embedded mode (Coinbase collects the SSN and date of birth in the form); if you include it, the request returns a 400.
Response (HTTP 200):
The upgradeUrl is single-use, short-lived, and bound to the user and your app. Mint a fresh URL for each attempt and respect expiresAt. This endpoint is rate limited, so do not request URLs in a loop. If the page emits onramp_api.load_error, request a new URL rather than reloading the old one.
See the Error reference for the errors this request can return.

Embed the URL

Both surfaces render the same page and behave identically. You can render the embed inline or inside a modal or overlay, whichever fits your flow.

Web (iframe)

Mobile (webview)

Load upgradeUrl in your platform’s webview component (for example react-native-webview, WKWebView on iOS, or Android WebView). The page detects the host webview and delivers events through the matching native bridge, so no extra configuration is needed beyond a message handler (see below).

Theming

By default the embed follows the user’s system color scheme (prefers-color-scheme). To force one, append ?theme=dark or ?theme=light to the upgradeUrl (works for both iframe and webview); any other value falls back to the system preference.

Post message events

The embedded page reports progress and outcomes through post message events. On web they are posted to the parent frame. On mobile they are delivered through whichever native bridge is present in the webview: window.ReactNativeWebView, window.webkit.messageHandlers.cbOnramp, window.androidWebView, or window.FlutterChannel. Each payload is JSON-stringified, so parse it before reading eventName.
Post message event structure
The shape of data varies by event. Error events carry errorCode and errorMessage; the resize event carries height. Branch your high-level flow on eventName; for error events, use data.errorCode to decide how to respond, and include it when logging.

Event names

The page is initializing and fetching the data needed to render the form.
The form is rendered and ready for the user.
Emitted on initial load and again whenever the embedded form’s content height changes — for example, when the page transitions between the entry form, the verifying screen, and the error screen. Use this event to resize your container so the form fits without scrolling or extra whitespace.
Set your iframe or modal height to data.height (pixels, always a positive integer) each time this event arrives.
The upgrade token could not be exchanged, for example because it is invalid or expired. Request a fresh upgradeUrl. Some possible error codes are listed below.
The user submitted their details and verification has started. At this point you can close the embed and poll for the result yourself (see Tracking the result).
Verification succeeded. The user now has upgraded limits, and you can resume checkout.
Verification is still in review after the page’s polling window. Re-check the user’s limits from your backend and notify them when a terminal status is reached.
The submission could not be completed. Branch on data.errorCode, which is one of:
The user dismissed the form without submitting.
The form handles recoverable states internally so you do not have to. Input typos and a single retryable verification result re-show the form inside the embed without emitting an event, and transient failures (network or internal errors) are retried automatically; if they persist, the embed shows a retry screen rather than emitting an error event. You only hear the terminal outcomes above.

Tracking the result

The simplest integration closes the embed when it receives onramp_api.upgrade_submit_success and then polls the user’s limits from your backend, using the same approach as API mode (see Poll until terminal status). If you instead leave the embed open, it polls for you and emits onramp_api.upgrade_approved, onramp_api.upgrade_pending, or an error event.

Error reference

POST /v2/onramp/limits is the eligibility check. POST /v2/onramp/limits/upgrade is the upgrade endpoint; it returns different errors depending on the interactionMode you use, so its errors are listed separately for API mode and embedded mode below.

POST /v2/onramp/limits errors

POST /v2/onramp/limits/upgrade errors (API mode)

Returned when you submit identity fields (interactionMode omitted or set to api).

POST /v2/onramp/limits/upgrade errors (embedded mode)

Returned by the same endpoint when requesting an upgradeUrl with interactionMode: "embedded". Error response shape:
Include correlationId when contacting Coinbase support.

Sandbox testing

Use phone numbers prefixed with +0 to test all scenarios without real verification. Only the last digit determines the scenario. In sandbox, ssnLast4 and dateOfBirth values are not validated; pass any well-formed values.

API mode

POST /v2/onramp/limits sandbox responses

POST /v2/onramp/limits/upgrade sandbox responses

Embedded mode

The request for an upgradeUrl always returns 200 with a sandbox token for any +0 number (the last digit does not affect this step). Sandbox short-circuits real verification, so the SSN and date of birth entered in the form are not validated. The scenario plays out after the user submits in the embed, and surfaces as one of the post message events below. Every successful submission also emits onramp_api.upgrade_submit_success first.

POST /v2/onramp/limits

Full API reference for checking user limits.

POST /v2/onramp/limits/upgrade

Full API reference for submitting an upgrade request.