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.GUEST_CHECKOUT_APPLE_PAY and GUEST_CHECKOUT_GOOGLE_PAY are supported and yield identical limits.
Response (upgrade available):
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:
Interaction modes
Limits Upgrade supports two interaction modes, selected with theinteractionMode 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
interactionModeis omitted or set toapi. - 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.
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 isunrequested or resubmit, collect the required fields and submit them to POST /v2/onramp/limits/upgrade. The endpoint returns HTTP 202 immediately; processing is asynchronous.
/limits; the status immediately advances to pending.
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 untillimitUpgradeOptions[0].status reaches a terminal state.
- 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, orresubmit
Resubmission and rate limits
If status returns toresubmit, 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, callPOST /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.
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)
LoadupgradeUrl 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
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 receivesonramp_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 anupgradeUrl with interactionMode: "embedded".
Error response shape:
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 anupgradeUrl 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.