> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloud.coinbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Limits Upgrade

Guest Checkout users start with conservative spending limits. The [Limits Upgrade API](https://docs.cdp.coinbase.com/api-reference/v2/rest-api/onramp/request-limit-upgrade) lets eligible users increase those limits permanently by verifying their identity with just two pieces of information — the last 4 digits of their SSN and their date of birth.

<Info>
  Limits Upgrade is only available for Guest Checkout (Headless Onramp) users. Authenticated Coinbase users have separate limit management through their Coinbase account.
</Info>

## Default and upgraded limits

| Limit                 | Default                          | After upgrade |
| --------------------- | -------------------------------- | ------------- |
| Weekly spending       | \$500 USD (rolling 7-day window) | \$2,500 USD   |
| Lifetime transactions | 15 total purchases               | Unlimited     |

Once approved, the upgrade is permanent. Users never need to re-verify.

## Integration flow

### 1. Check limits and upgrade eligibility

Call [POST /v2/onramp/limits](/api-reference/v2/rest-api/onramp/get-onramp-user-limits) before or during the onramp flow to retrieve the user's current limits and determine whether an upgrade is available.

```bash theme={null}
cdpcurl -X POST 'https://api.cdp.coinbase.com/platform/v2/onramp/limits' \
  -k ~/Downloads/cdp_api_key.json \
  -d '{
    "paymentMethodType": "GUEST_CHECKOUT_APPLE_PAY",
    "userIdType": "phone_number",
    "userId": "+14155551234"
  }'
```

Both `GUEST_CHECKOUT_APPLE_PAY` and `GUEST_CHECKOUT_GOOGLE_PAY` are supported and yield identical limits.

**Response — upgrade available:**

```json theme={null}
{
  "limits": [
    { "limitType": "weekly_spending", "limit": "500", "remaining": "400", "currency": "USD" },
    { "limitType": "lifetime_transactions", "limit": "15", "remaining": "12" }
  ],
  "limitUpgradeOptions": [
    {
      "status": "unrequested",
      "fields": ["ssnLast4", "dateOfBirth"],
      "limitUpgrades": [
        { "limitType": "weekly_spending", "maxUpgrade": "2500" },
        { "limitType": "lifetime_transactions", "maxUpgrade": "-1" }
      ]
    }
  ]
}
```

**Response — upgrade not available:**

```json theme={null}
{
  "limits": [
    { "limitType": "weekly_spending", "limit": "500", "remaining": "500", "currency": "USD" },
    { "limitType": "lifetime_transactions", "limit": "15", "remaining": "15" }
  ]
}
```

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:

| Status        | Meaning                                                                     | Action                                                                  |
| ------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `unrequested` | User has never submitted. `fields` lists what to collect.                   | Show upgrade prompt and call `/limits/upgrade`.                         |
| `resubmit`    | Previous submission was rejected but can be retried. `fields` is populated. | Show corrected-entry prompt and call `/limits/upgrade` again.           |
| `pending`     | Submission is under review by Coinbase.                                     | Show a "pending" state. Poll `/limits` until a terminal status appears. |
| `active`      | Terminal. Upgrade approved — user has higher limits.                        | Show upgraded limits. No further action.                                |
| `inactive`    | Terminal. Upgrade permanently blocked.                                      | Do not retry. Do not show the upgrade prompt again.                     |

<Warning>
  Only show the upgrade prompt when `limitUpgradeOptions` is present **and** status is `unrequested` or `resubmit`.
</Warning>

### 2. Submit identity fields

When status is `unrequested` or `resubmit`, collect the required fields and submit them to [POST /v2/onramp/limits/upgrade](https://docs.cdp.coinbase.com/api-reference/v2/rest-api/onramp/request-limit-upgrade). The endpoint returns HTTP 202 immediately — processing is asynchronous.

```bash theme={null}
cdpcurl -X POST 'https://api.cdp.coinbase.com/platform/v2/onramp/limits/upgrade' \
  -k ~/Downloads/cdp_api_key.json \
  -d '{
    "userIdType": "phone_number",
    "userId": "+14155551234",
    "fields": {
      "ssnLast4": "1234",
      "dateOfBirth": {
        "day": "15",
        "month": "08",
        "year": "1990"
      }
    }
  }'
```

```
HTTP/1.1 202 Accepted
```

After receiving 202, re-poll `/limits` — the status immediately advances to `pending`.

<Warning>
  Do not store `ssnLast4` on your servers. Collect it, submit it, and discard it immediately.
</Warning>

#### Field validation

| Field               | Requirements                                             |
| ------------------- | -------------------------------------------------------- |
| `ssnLast4`          | Exactly 4 numeric digits. No dashes, spaces, or letters. |
| `dateOfBirth.day`   | 2-digit zero-padded day string (e.g., `"05"`, `"15"`).   |
| `dateOfBirth.month` | 2-digit zero-padded month string (e.g., `"01"`, `"08"`). |
| `dateOfBirth.year`  | 4-digit year string (e.g., `"1990"`).                    |

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

### 3. Poll until terminal status

Poll [POST /v2/onramp/limits](/api-reference/v2/rest-api/onramp/get-onramp-user-limits) after the 202 response until `limitUpgradeOptions[0].status` reaches a terminal state.

```bash theme={null}
cdpcurl -X POST 'https://api.cdp.coinbase.com/platform/v2/onramp/limits' \
  -k ~/Downloads/cdp_api_key.json \
  -d '{
    "paymentMethodType": "GUEST_CHECKOUT_APPLE_PAY",
    "userIdType": "phone_number",
    "userId": "+14155551234"
  }'
```

**Response when upgrade is approved:**

```json theme={null}
{
  "limits": [
    { "limitType": "weekly_spending", "limit": "2500", "remaining": "2500", "currency": "USD" },
    { "limitType": "lifetime_transactions", "limit": "-1", "remaining": "-1" }
  ],
  "limitUpgradeOptions": [
    {
      "status": "active",
      "limitUpgrades": [
        { "limitType": "weekly_spending", "maxUpgrade": "2500" },
        { "limitType": "lifetime_transactions", "maxUpgrade": "-1" }
      ]
    }
  ]
}
```

<Tip>
  A `limit` or `remaining` value of `"-1"` means unlimited. Display this to users as "Unlimited" rather than a raw number.
</Tip>

**Polling guide:**

* Start polling immediately after receiving the 202 response
* Poll every 1–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 call `/limits/upgrade` 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.

Calling `/limits/upgrade` when status is already `pending` or `active` is safe — the endpoint returns 202 and nothing changes.

## UI recommendations

| Status        | Suggested UI                                                                                  |
| ------------- | --------------------------------------------------------------------------------------------- |
| `unrequested` | "Increase your weekly limit to \$2,500 and unlock unlimited lifetime transactions."           |
| `pending`     | "Your limit increase request is under review. You can still transact at your current limits." |
| `resubmit`    | "We couldn't verify your information. Please check your SSN and date of birth and try again." |
| `active`      | "Your limits have been increased to \$2,500/week with unlimited lifetime transactions."       |
| `inactive`    | "Your account is not eligible for a limit increase at this time."                             |

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.

## Error reference

### POST /v2/onramp/limits errors

| HTTP | Cause                         | Resolution                                   |
| ---- | ----------------------------- | -------------------------------------------- |
| 400  | Missing or invalid field      | Check `errorMessage` for the specific field. |
| 401  | Missing or invalid API key    | Verify your API key and JWT generation.      |
| 429  | App-level rate limit exceeded | Back off and retry with exponential backoff. |

### POST /v2/onramp/limits/upgrade errors

| HTTP | Message                                                    | Cause                                   | Resolution                                                                                 |
| ---- | ---------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------ |
| 400  | `fields.ssnLast4 is required`                              | ssnLast4 missing                        | Include `fields.ssnLast4`.                                                                 |
| 400  | `ssnLast4 must be exactly 4 digits`                        | Wrong length                            | Validate length client-side.                                                               |
| 400  | `ssnLast4 must be numeric`                                 | Non-digit characters                    | Strip dashes and spaces before submitting.                                                 |
| 400  | `fields.dateOfBirth is required`                           | dateOfBirth missing                     | Include `fields.dateOfBirth`.                                                              |
| 400  | `invalid dateOfBirth`                                      | Invalid date                            | Validate the date client-side.                                                             |
| 400  | `account does not meet requirements for a limit upgrade`   | App not on allowlist or user ineligible | Do not retry. [Contact us](https://discord.com/invite/cdp) if your app should be eligible. |
| 400  | `limit upgrade is not available for this user`             | Upgrade permanently blocked             | Do not retry. Do not show the upgrade prompt again.                                        |
| 401  | `unauthorized`                                             | Missing or invalid API key              | Verify your API key.                                                                       |
| 403  | `We couldn't verify your details. Please try again later.` | Identity verification failed            | Do not retry immediately. Wait for status to return to `resubmit` before prompting again.  |
| 429  | `rate_limit_exceeded`                                      | App-level rate limit exceeded           | Back off and retry with exponential backoff.                                               |

**Error response shape:**

```json theme={null}
{
  "errorType": "invalid_request",
  "errorMessage": "InvalidRequest: ssnLast4 must be exactly 4 digits",
  "errorLink": "https://docs.cdp.coinbase.com/api-reference/v2/errors#invalid_request",
  "correlationId": "966fe3870ecf2368"
}
```

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.

### POST /v2/onramp/limits sandbox responses

| Phone number          | Status        | Limits                                          |
| --------------------- | ------------- | ----------------------------------------------- |
| `+00000000000`        | `unrequested` | Base (\$500/week, 15 transactions)              |
| `+00000000001`        | `pending`     | Base                                            |
| `+00000000002`        | `resubmit`    | Base                                            |
| `+00000000003`        | `active`      | Upgraded (\$2,500/week, unlimited transactions) |
| `+00000000004`        | `inactive`    | Base                                            |
| `+00000000005`        | —             | Dependency error (503)                          |
| `+00000000006`        | —             | Rate limit exceeded (429)                       |
| `+00000000007`        | —             | Invalid request (400)                           |
| Any other `+0` number | `unrequested` | Base                                            |

### POST /v2/onramp/limits/upgrade sandbox responses

| Phone number                     | Response                 |
| -------------------------------- | ------------------------ |
| `+00000000000` to `+00000000003` | 202 Accepted             |
| `+00000000004`                   | 422 LimitsUpgradeBlocked |
| `+00000000005`                   | 503 Dependency error     |
| `+00000000006`                   | 429 Rate limit exceeded  |
| `+00000000007`                   | 400 Invalid request      |
| Any other `+0` number            | 202 Accepted             |

In sandbox, `ssnLast4` and `dateOfBirth` values are not validated — pass any well-formed values.

<CardGroup cols={2}>
  <Card title="POST /v2/onramp/limits" icon="arrow-right" href="/api-reference/v2/rest-api/onramp/get-onramp-user-limits">
    Full API reference for checking user limits.
  </Card>

  <Card title="POST /v2/onramp/limits/upgrade" icon="arrow-up" href="https://docs.cdp.coinbase.com/api-reference/v2/rest-api/onramp/request-limit-upgrade">
    Full API reference for submitting an upgrade request.
  </Card>
</CardGroup>
