Skip to main content
Requirements are the outstanding actions a customer must complete before a requested capability becomes active. They appear as a map on the customer object, keyed by field name, with each entry describing its status and which capabilities it affects. Requirements are only shown for capabilities that have been requested, and when a requirement is satisfied it disappears from the map. Identity verification runs asynchronously. After you submit the required information, Coinbase evaluates it, and the affected capabilities transition out of pending once verification completes.

Requirements map

requirements is keyed by field name; the key itself is the requirement:
"requirements": {
  "fullSsn": { "status": "rejected", "impact": ["tradeCrypto"] },
  "sourceOfFunds": { "status": "due" },
  "citizenship": { "status": "due" },
  "tos": {
    "status": "due",
    "impact": ["tradeCrypto", "transferFiat"],
    "tosVersions": [
      {
        "versionId": "us_individual_2026-05-29",
        "languages": ["en"],
        "url": "https://docs.cdp.coinbase.com/legal/terms/us_individual_2026-05-29"
      }
    ]
  }
}
FieldDescription
keyThe field name that is required (e.g. fullSsn, addressSubdivision, tos, taxAttestation)
statusCurrent state — see Requirement statuses
deadlineOptional ISO 8601 deadline by which the requirement must be satisfied
impactCapabilities this requirement is blocking (sorted alphabetically)
tosVersionsPresent only on the tos key — the Terms of Service versions still to accept
taxFormsPresent only on the taxAttestation key — the tax forms still to complete

Requirement statuses

StatusMeaning
dueMust be submitted
pendingSubmitted, awaiting verification
rejectedVerification failed — resubmit the field
When verification passes, the requirement is removed from the map entirely. Requirements in due or rejected need action from you; pending requirements are being processed asynchronously.

Which capabilities require which requirements

You never have to hard-code this mapping — a customer’s requirements map only ever lists what their requested capabilities still need, and each entry’s impact array names the capabilities it is blocking. The table below is provided as a planning reference for what to collect up front. Most capabilities share a common baseline set. tradeCrypto requires additional due-diligence information on top of that baseline.
RequirementRequired for
firstName, lastNameAll capabilities
dateOfBirthAll capabilities
fullSsnAll capabilities
address (line, city, state, postal code, country)All capabilities
emailAll capabilities
phoneNumberAll capabilities
purposeOfAccountAll capabilities
sourceOfFundsAll capabilities
tosAll capabilities
taxAttestation (W-9)All capabilities
citizenshiptradeCrypto
employmentStatustradeCrypto
occupationtradeCrypto
expectedVolumetradeCrypto
This mapping is determined by Coinbase’s compliance policy and is subject to change — requirements may be added, removed, or re-scoped to different capabilities over time, and they can vary by the customer’s jurisdiction. Always treat the live requirements map on the customer object (and the API reference) as the source of truth rather than this table.

Resolving requirements

Every field-based requirement is resolved by submitting the corresponding field under individual via PUT /v2/customers/{customerId}. The two non-field requirements — tos and taxAttestation — are resolved with their own arrays.
Requirement keyResolved by
firstName, lastNameindividual.firstName, individual.lastName
dateOfBirthindividual.dateOfBirth as { "day", "month", "year" }
ssnLast4individual.ssnLast4
fullSsnindividual.fullSsn
addressLine1, addressLine2, addressCity, addressSubdivision, addressPostalCode, addressCountryCodeThe corresponding individual.address.* field
emailindividual.email
phoneNumberindividual.phoneNumber
citizenshipindividual.citizenship
purposeOfAccount, sourceOfFunds, employmentStatus, occupation, expectedVolumeThe corresponding individual.* field
tostosAcceptances — see Terms of Service
taxAttestationtaxAttestations — see Tax attestations
Requirement keys use canonical field names that map to the address shape in the request body: addressSubdivision resolves with individual.address.state, and addressPostalCode resolves with individual.address.postCode.

The resolution loop

A typical pattern: submit outstanding requirements, then wait for the affected capability to leave pending.
async function ensureCapabilityActive(customerId, requiredCapability) {
  let customer = await getCustomer(customerId);

  while (customer.capabilities[requiredCapability]?.status === "pending") {
    // Requirements that are blocking this capability and need action.
    const actionable = Object.entries(customer.requirements)
      .filter(([, req]) => req.impact?.includes(requiredCapability))
      .filter(([, req]) => req.status === "due" || req.status === "rejected");

    if (actionable.length === 0) {
      // Everything submitted — wait for async verification (use webhooks in production).
      await waitForCapabilityChange(customerId, requiredCapability);
      customer = await getCustomer(customerId);
      continue;
    }

    for (const [key] of actionable) {
      if (key === "tos") {
        await presentTosAndSubmitAcceptances(customerId, customer.requirements.tos.tosVersions);
      } else if (key === "taxAttestation") {
        await submitTaxAttestations(customerId, customer.requirements.taxAttestation.taxForms);
      } else {
        // Field requirement: collect and resubmit the corresponding identity field.
        await submitIdentityField(customerId, key);
      }
    }

    await waitForCapabilityChange(customerId, requiredCapability);
    customer = await getCustomer(customerId);
  }
}
In production, drive this off the customers.capability.changed webhook instead of polling.

Terms of Service

When a tos requirement is present, requirements.tos.tosVersions[] lists each Terms of Service version the customer must still accept, with a stable versionId, the languages it is published in, and a url to render (append ?lang=<tag> for a specific translation).
  1. Render each version’s url to the customer and capture acceptance.
  2. Submit one acceptance per required version:
PUT /v2/customers/{customerId}
{
  "tosAcceptances": [
    {
      "versionId": "us_individual_2026-05-29",
      "language": "en",
      "acceptedAt": "2026-04-10T12:00:00Z"
    }
  ]
}
language must be one of the version’s languages, or the request is rejected with unsupported_tos_language. When new versions are published, only the new versionIds appear in tosVersions[] — submit acceptances for just those.

Tax attestations

Some capabilities require a tax attestation. When a taxAttestation requirement is present, requirements.taxAttestation.taxForms[] lists the forms the customer must complete (for example, us_w9). Submit one taxAttestations entry per required form:
PUT /v2/customers/{customerId}
{
  "taxAttestations": [
    {
      "form": "us_w9",
      "isExemptBackupWithholding": true,
      "edeliveryConsent": true,
      "acceptedAt": "2026-04-17T20:00:00Z"
    }
  ]
}
The fields required per entry depend on form; the example above shows IRS Form W-9. Tax attestations are ingestion-only and never returned on read.

Rejected requirements

A requirement with status: rejected means the submitted value failed verification. Collect the field from the customer again and resubmit it via PUT /v2/customers/{customerId}. Resubmitting a corrected value starts a new verification.

What you cannot resolve

Some capabilities become inactive because of a terminal compliance decision (for example, a sanctions watchlist match). These cannot be unlocked through the API, and no requirement resubmission will clear them.
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 makes and manages these compliance decisions on your behalf.

Ongoing monitoring

Compliance does not stop at onboarding. Coinbase continuously monitors customers and may flag one for KYC re-verification. When that happens you receive a customers.kyc_refresh.flagged webhook carrying a deadline; capabilities may remain active until the deadline and are disabled afterward until the customer resubmits the requested information. A customers.kyc_refresh.completed webhook is emitted once the refresh is satisfied.

Testing in sandbox

In sandbox and test environments, Coinbase recognizes magic SSN values that force a deterministic verification outcome so you can exercise each capability state end-to-end without real PII. Submit them as individual.fullSsn (or individual.ssnLast4).
OutcomefullSsnssnLast4Effect
Approve000-00-00000000Requested capabilities become active; the satisfied requirements disappear
Decline (recoverable)000-00-00010001Affected capabilities stay pending and the requirements become rejected; the customer can resubmit corrected PII
Block (terminal)000-00-00020002Simulates a sanctions block: all requested capabilities become inactive and their requirements disappear; this is terminal and cannot be resubmitted
PUT /v2/customers/{customerId}
{
  "individual": {
    "fullSsn": "000-00-0000"
  }
}
The recoverable decline (...0001) is the only outcome you can retry — resubmitting a passing value starts a new verification and can activate the capability. The block (...0002) is terminal: resubmitting a passing SSN afterward does not lift it.
Magic values only apply in sandbox and test environments. In production they are treated as real PII and verified normally — never rely on them outside of testing.