> ## 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.

# Requirements

Requirements are outstanding actions that must be resolved before a capability becomes `active`. They appear as a map on the customer object, keyed by field name, with each entry describing the status and which capabilities it affects.

For most customers with straightforward identity verification, requirements resolve automatically in under 60 seconds with no action needed. This page covers the cases where something is outstanding.

## Requirements map

`requirements` is a `map<string, Requirement>` keyed by field name. The key itself is the requirement type:

```json theme={null}
"requirements": {
  "fullSsn":            { "status": "pending", "impact": ["custodyFiat", "custodyStablecoin", "transferFiat"] },
  "addressSubdivision": { "status": "due",     "impact": ["custodyFiat", "custodyStablecoin", "transferFiat"] },
  "tos":                { "status": "due",     "impact": ["custodyFiat"] }
}
```

| Field      | Description                                                                    |
| ---------- | ------------------------------------------------------------------------------ |
| key        | The field name that is required (e.g., `fullSsn`, `addressSubdivision`, `tos`) |
| `status`   | Current state. See [Requirement statuses](#requirement-statuses) below         |
| `deadline` | Optional. Deadline for submission (ISO 8601)                                   |
| `impact`   | Which capabilities this requirement is blocking                                |

## Requirement statuses

| Status           | Meaning                                           |
| ---------------- | ------------------------------------------------- |
| `eventually_due` | Possible future requirement; no action needed yet |
| `due`            | Must be submitted (may have a `deadline`)         |
| `pending`        | Submitted, awaiting verification                  |
| `rejected`       | Verification failed; resubmit the field           |
| `overdue`        | Deadline passed without submission                |

Requirements in `due`, `rejected`, or `overdue` states need action. Requirements in `pending` are being processed asynchronously.

## Requirement keys and resolution

All field-based requirements resolve by submitting the corresponding field via `POST /v2/customers/{customerId}`. The only non-field key is `tos`.

| Requirement key                                                                                | Resolved by                                                                                          |
| ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `firstName`, `lastName`                                                                        | Submit `individual.firstName`, `individual.lastName`                                                 |
| `dateOfBirth`                                                                                  | Submit `individual.dateOfBirth` as `{ "day", "month", "year" }`                                      |
| `ssnLast4`                                                                                     | Submit `individual.ssnLast4`                                                                         |
| `fullSsn`                                                                                      | Submit `individual.fullSsn`                                                                          |
| `addressLine1`, `addressCity`, `addressSubdivision`, `addressPostalCode`, `addressCountryCode` | Submit the corresponding `individual.address.*` fields                                               |
| `email`                                                                                        | Submit `email`                                                                                       |
| `phoneNumber`                                                                                  | Submit `phone`                                                                                       |
| `citizenship`                                                                                  | Submit `individual.citizenship`                                                                      |
| `purposeOfAccount`, `sourceOfFunds`                                                            | Submit `individual.purposeOfAccount`, `individual.sourceOfFunds`                                     |
| `employmentStatus`, `occupation`, `expectedVolume`                                             | Submit corresponding `individual.*` fields                                                           |
| `tos`                                                                                          | Present ToS to customer and submit `tosAcceptances`. See [Terms of Service](#terms-of-service) below |

<Note>
  Requirement keys use canonical field names (e.g., `addressSubdivision`, `addressPostalCode`), which map to the address shape in the request body (`state`, `postCode`). A requirement keyed `addressSubdivision` is resolved by submitting `individual.address.state`.
</Note>

## The resolution loop

A typical requirements-resolution pattern:

```javascript theme={null}
async function ensureCapabilityActive(customerId, requiredCapability) {
  let customer = await getCustomer(customerId);

  while (customer.capabilities[requiredCapability]?.status !== 'active') {
    // Find requirements affecting this capability that need action
    const actionable = Object.entries(customer.requirements)
      .filter(([, req]) => req.impact?.includes(requiredCapability))
      .filter(([, req]) => ['due', 'rejected', 'overdue'].includes(req.status));

    if (actionable.length === 0) {
      // All requirements submitted; wait for async verification
      await waitForCapabilityUpdate(customerId, requiredCapability);
      customer = await getCustomer(customerId);
      continue;
    }

    for (const [fieldName, req] of actionable) {
      if (fieldName === 'tos') {
        // ToS URL is included in the requirement; present it to the customer
        await presentTosAndSubmitAcceptance(customerId, req.url);
        continue;
      }

      // All other requirements resolve by resubmitting the corresponding identity field
      const value = await collectFromCustomer(fieldName);
      await postCustomerUpdate(customerId, buildPatch(fieldName, value));
    }

    // Use webhooks in production instead of polling
    await waitForCapabilityUpdate(customerId, requiredCapability);
    customer = await getCustomer(customerId);
  }
}
```

## Special cases

### Terms of Service

When a `tos` requirement is present, the requirement entry includes a `url` with the current Terms of Service link:

1. Read the `url` from `requirements.tos` and render the Terms of Service to the customer. This is required; do not skip.
2. Submit the acceptance:

```json theme={null}
POST /v2/customers/{customerId}
{
  "tosAcceptances": [
    {
      "versionId": "us_individual_2026-05-29",
      "language": "en",
      "acceptedAt": "2026-05-01T10:01:00Z"
    }
  ]
}
```

### Rejected requirements

A requirement with `status: rejected` means the submitted value failed verification. Collect the field again from the customer and resubmit via `POST /v2/customers/{customerId}`.

## What you cannot resolve

Some `inactive` capability states are driven by compliance decisions that cannot be unlocked via the API:

* Sanctions matches
* Adverse media
* Manual compliance holds

<Warning>
  Never expose compliance-specific reasons to end-users. Show a generic message such as "We're unable to complete this request. Please contact support." Coinbase handles these compliance decisions so you don't have to make or surface them in your product.
</Warning>

## Monitoring via webhooks

Subscribe to `customer.capability.status_changed` to be notified when requirements are resolved and capabilities transition. This avoids polling the customer endpoint in your integration.

```json theme={null}
{
  "type": "customer.capability.status_changed",
  "data": {
    "customerId": "customer_af2937b0-...",
    "capability": "custodyFiat",
    "previousStatus": "pending",
    "status": "active",
    "requirements": {}
  }
}
```

<Note>
  Webhook event names are provisional and subject to change until the webhooks documentation ships.
</Note>
