Skip to main content
Guest Checkout users start with conservative spending limits. Limits Upgrade lets eligible users increase those limits permanently by verifying their identity with two pieces of information: the last 4 digits of their SSN and their date of birth.
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, the upgrade is permanent. Users never need to re-verify.

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 an upgrade is available. Only offer an upgrade, in either mode, to eligible users.
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, the user does not yet meet the eligibility criteria. 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 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.
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.