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

# API changelog

> Changes to what the MoonPay Enterprise API accepts, returns, and does, newest first. Covers dated API versions and changes that apply to every version.

This page lists changes to the API contract: new endpoints and fields, changed behavior, and new validation. For new products and features, see [What's new](/whats-new).

There are two kinds of entry:

* **Every version.** Dated by the day it shipped, and applies whatever `X-API-Version` you send, including none. Most are additive. Entries tagged `Action required` add a check that can reject a request that used to succeed.
* **API version entries** are tagged `API version`. Each dated version is a frozen contract: once cut, its response and request shapes never change under you. The entry lists what changed relative to the version before it, and only applies when you send that `X-API-Version`.

Every change also says who it affects: `Business customers`, `Individual customers`, or `All customers`.

<Note>
  `GET /spec/versions` lists the supported versions machine-readably, and each version's full shape is at `/spec/<date>`. See [API Versions](/versioning) for the header itself.
</Note>

Errors from `POST /api/customers/{id}/identifications/v2` below name the `code` you get on `2026-08-01` or later. Earlier versions return the `message` as a plain string instead.

<Update label="2026-10-15" description="Tax ID not needed where none is issued" tags={["Relaxed", "Action required", "Individual customers", "Business customers"]}>
  **You don't need a tax ID for parties in jurisdictions that don't issue one.**

  *Relaxed · Individual customers, Business customers*

  On `POST /api/customers/{id}/identifications/v2`, when a party's tax residence is a jurisdiction that doesn't issue tax IDs, any `tax_identification_number` you send is ignored and an identifier from the submission is used instead:

  * `Person` and person beneficiaries: `identity.identity_number`, from any identity document type.
  * Companies, including nested business beneficiaries: `registration_number`.

  `company_info.tax_identification_number` is now optional in the schema. Companies registered elsewhere still need it, and a missing one returns `400` [`tin_required`](/errors#tin_required). US persons (US address, US nationality, or a US-issued identity document) are never covered by this. See [Tax ID where none is issued](/kyb#tax-id-where-none-is-issued).

  **Beneficiaries tax-resident there need `identity.identity_number`.**

  *Action required · Business customers*

  A person beneficiary whose role needs a tax ID, and whose `tax_jurisdiction_country_code` is a jurisdiction that doesn't issue tax IDs, must send `identity.identity_number`. Without it the submission returns `400` [`tin_required`](/errors#tin_required), even if you sent `tax_identification_number`.
</Update>

<Update label="2026-10-15" description="Stable webhook-id across retries" tags={["Webhooks", "All customers"]}>
  **`webhook-id` identifies the event and stays the same across retries.**

  *Webhooks · All customers*

  Every retry of an event now carries the same `webhook-id`, including a retry you trigger from the Partner Area. Earlier, each delivery attempt got a new one. Store the `webhook-id` of each event you process and skip any delivery whose `webhook-id` you've already handled. The value is still a UUID, but no longer a version 4 UUID, so don't validate its version. See [Webhooks](/webhooks#http-headers).
</Update>

<Update label="2026-10-15" description="API version" tags={["API version", "Action required", "Individual customers", "Business customers"]}>
  **`intended_use` splits payments into family and third parties.**

  | | |
  | - | - |
  | Affects | Request |
  | Kind | Additive (new values, every version), deprecation, version-gated rejection |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Person`, `Token`) |

  `intended_use` gains two values: `PaymentToFriendsAndFamily` for payments to people your customer knows, and `PaymentToThirdParties` for payments to anyone else. Both are accepted on every version, including unversioned calls.

  `PaymentToFriendsFamilyorOthers` is deprecated. Under this version or later, a submission that sends it is rejected with `400` [`intended_use_deprecated`](/errors#intended_use_deprecated). Earlier and unversioned callers can keep sending it, but should switch to one of the two new values.

  **`source_of_wealth` gains six values.**

  | | |
  | - | - |
  | Affects | Request |
  | Kind | Additive (new values, every version) |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Person`, `Token`) |

  The KYC questionnaire's `source_of_wealth` now also accepts `SaleOfAssetsOrSettlement`, `Pension`, `CompanyProfits`, `SoleProprietorIncome`, `RentalIncome`, and `Inheritance`. They're accepted on every version. See [KYC questionnaire fields](/reliance-kyc-token-sharing#kyc-questionnaire-fields).

  **Business beneficiaries declare why they are a UBO.**

  | | |
  | - | - |
  | Affects | Request, validation |
  | Kind | Additive fields, version-gated requirement |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  `CompanyBeneficiary` gains `ubo_subtype` and `nature_of_control`. `ubo_subtype` is `Ownership` for an individual who owns part of the company, or `Control` for an individual who controls it without owning it, for example through voting rights or a trust. A `Control` beneficiary sets `nature_of_control` (up to 255 characters) and sends no `share_percentage`.

  Under this version or later:

  * Every root-level beneficiary with the `UltimateBeneficialOwner` role must set `ubo_subtype`. Nested UBOs can omit it, and accept only `Ownership`. A missing value is rejected with `400` [`ubo_subtype_invalid`](/errors#ubo_subtype_invalid).
  * A company other than a sole proprietorship must list at least one person beneficiary with the `UltimateBeneficialOwner` role. A corporate beneficiary doesn't satisfy this. If nobody owns enough to qualify, submit the individual who controls the company as a `Control` beneficiary. Without any, the submission is rejected with [`structure_invalid`](/errors#structure_invalid).
  * The ownership disclosure threshold applies to `Ownership` beneficiaries only. A person with `ubo_subtype: "Ownership"` below it is rejected with [`ubo_share_below_threshold`](/errors#ubo_share_below_threshold), including when they hold another role.
  * `Control` is accepted only on root-level person beneficiaries of a company that isn't a sole proprietorship.

  Earlier and unversioned callers can't send the new fields. A request that includes them is rejected with `ubo_subtype_invalid`. Everything else about their submissions is unchanged. See [Migrating to API Version 2026-10-15](/kyb#migrating-to-api-version-2026-10-15) for the steps and examples.

  **`Person` submissions require `tax_residence_country`.**

  | | |
  | - | - |
  | Affects | Validation |
  | Kind | Version-gated requirement |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Person`) |

  Under this version or later, every `Person` submission must set `tax_residence_country`, whether or not it includes `tax_identification_number`. A missing value is rejected with `400` [`tin_required`](/errors#tin_required). Earlier and unversioned callers can still omit it when no tax ID is sent. See [TIN Format Validation](/tin-format-validation#tax-residence-country).
</Update>

<Update label="2026-10-08" description="UK postal codes validated, newlines in wire_message" tags={["Action required", "Relaxed", "All customers"]}>
  **UK postal codes on fiat addresses are validated.**

  *Action required · All customers*

  `POST /api/addresses/fiat` now checks the format of `bank_details.address.postal_code` when the address country is `GB`. A postal code that isn't a valid UK format, such as `LE3-2JB` or `LE3 2J`, is rejected with `400` and the plain-string message `"Invalid UK postal code format"`. A valid code is stored uppercased with a single space, so `le32jb` is saved as `LE3 2JB`. Send the full UK postcode for UK recipients. See [Fiat Addresses](/fiat-addresses#request-fields).

  **`wire_message` accepts line breaks.**

  *Relaxed · All customers*

  On `POST /api/autoramps`, `wire_message` now accepts newline characters (`\n`) alongside letters, digits, spaces, and `/ - ? : ( ) . +`. Use them to split the reference across up to 4 lines of 35 characters. The 140-character limit is unchanged. See [Offramp](/offramp).
</Update>

<Update label="2026-10-08" description="Three Generic questionnaire fields removed" tags={["Changed", "Business customers"]}>
  **`requires_aml_program`, `estimated_annual_revenue`, and `customer_funds_handling_details` are no longer part of the `Generic` business questionnaire.**

  *Changed · Business customers*

  On `Business` submissions with `questionnaire.type: "Generic"`, these three fields have been removed from the schema, so you don't need to send them. If you still do, the request is accepted and the values are ignored. The `SoleProp` questionnaire still requires `estimated_annual_revenue`. See [KYB](/kyb).
</Update>

<Update label="2026-10-08" description="Identity document expiry date on beneficiaries" tags={["Added", "Business customers"]}>
  **Person beneficiaries accept the identity document's expiry date.**

  *Added · Business customers*

  On `Business` submissions, a person beneficiary's `identity` object accepts an optional `identity_document_valid_until` (`YYYY-MM-DD`). Send it when the document has an expiry date. See [KYB](/kyb).
</Update>

<Update label="2026-10-07" description="bips_decimal on fee profiles" tags={["Added", "All customers"]}>
  **Fee profiles accept fractional basis points.**

  *Added · All customers*

  `POST /api/fee-profiles` accepts `transaction_fee_bips_decimal`, a decimal string such as `"12.5"`. It takes precedence over `transaction_fee_bips` when you send both. Fee responses always include `bips_decimal`. The integer `bips` and `transaction_fee_bips` fields are deprecated and still required on requests. They return the value rounded to the nearest whole bip. See [Fees and invoices](/fees-and-invoices).
</Update>

<Update label="2026-10-05" description="Optional birth_place, 8 documents per company" tags={["Changed", "Business customers"]}>
  **`birth_place` is optional on person beneficiaries, and companies can carry up to 8 documents.**

  *Changed · Business customers*

  On `Business` submissions, a person beneficiary's `birth_place` is no longer required. When you send it, the same rules apply as before, including `state` for countries with administrative subdivisions. Each company in a submission (the root company, and each nested business beneficiary) can now carry up to 8 documents, up from 6. All other document validation is unchanged. See [KYB](/kyb).
</Update>

<Update label="2026-10-01" description="API version" tags={["API version", "Changed", "All customers"]}>
  **Customer requirements come back as a structured list.**

  | | |
  | - | - |
  | Affects | Response |
  | Kind | New response shape (version-gated), deprecation |
  | Endpoints | `GET /api/customers/{id}/requirements` |

  Under this version or later, the response sorts every requirement into four lists: `complete`, `pendingReview`, `pending`, and `issues`. It also returns `requirements_due`, `preflight_summary`, `general_review_comment`, and a nullable top-level `identification_id`. Each requirement has a typed `code` and a `description`. A pending questionnaire lists its `missing_questions`.

  When migrating, read `pending` for work awaiting customer input (previously `missing`) and `pendingReview` for work awaiting review (previously `pending`). Read every bucket: a customer can have items awaiting review and corrections to make at the same time.

  Problems with a submission come back as data, not as an HTTP error. The request returns `200`, and each problem is an entry in `issues` with `retryable`, `review_comment`, `reject_reasons[].error_code`, and per-document `steps`. Read `reject_reasons[].error_code` instead of legacy `reject_labels`, including the reasons in each document step. Switch on `error_code`, not on `description`. See [Verification rejection codes](/errors#verification-rejection-codes) for their meanings.

  Show customer-facing feedback from `general_review_comment`, `issues[].review_comment`, and `issues[].steps[].review_comment`. An issue's nullable `retryable` value tells you whether a correction is supported; `null` does not authorize a retry. See [Checking Outstanding Requirements](/onboarding#checking-outstanding-requirements) for the response example and [Displaying Onboarding Comments](/onboarding#displaying-onboarding-comments-to-your-customer) for implementation guidance.

  Earlier and unversioned callers keep the previous response shape, and the endpoint is marked deprecated for them. `step_status` on the identification object is deprecated under this version. It keeps working, but read outstanding requirements from this endpoint instead.
</Update>

<Update label="2026-10-01" description="User-Agent on webhooks" tags={["Webhooks", "All customers"]}>
  **Webhook deliveries send a `User-Agent` header.**

  *Webhooks · All customers*

  Every webhook delivery now carries `User-Agent: MoonPay-Enterprise-Webhooks/1.0`. Earlier deliveries sent none, which some firewalls and CDNs block. If you allowlist by user agent, match the `MoonPay-Enterprise-Webhooks/` prefix so a version bump doesn't break you. The signature is unchanged. See [Webhooks](/webhooks#http-headers).
</Update>

<Update label="2026-09-30" description="country_not_supported replaces a 500" tags={["Changed", "Business customers"]}>
  **Unsupported company countries return `400`.**

  *Changed · Business customers*

  `POST /api/customers/{id}/identifications/v2` with a `Business` submission whose company country we don't support now returns `400` with `code` [`country_not_supported`](/errors#country_not_supported) on `X-API-Version` `2026-08-01` or later. Earlier it returned `500`. Check the country against [Countries](/country) before you submit, and don't retry.
</Update>

<Update label="2026-09-30" description="Liveness RFIs close on approval" tags={["Changed", "All customers"]}>
  **A liveness RFI closes on its own when the new selfie is approved.**

  *Changed · All customers*

  A `liveness` RFI now moves straight to `closed` when the identification it reset is approved. When that identification is rejected, the RFI moves to `needs_review` as before. If you wait for `needs_review` before treating a liveness RFI as answered, also handle `closed`. See [Information Requests](/rfi).
</Update>

<Update label="2026-09-29" description="Completed RFIs, outcome removed" tags={["Added", "Changed", "All customers"]}>
  **List completed RFIs, and `outcome` leaves the `Rfi` object.**

  *Added · Changed · All customers*

  `GET /api/rfis` takes a new `state` query parameter: `open` (the default) returns RFIs waiting on you or under review, and `completed` returns closed RFIs, newest closure first. The `Rfi` object no longer includes `outcome`. A closed RFI has `status` `closed` and a `closed_at` timestamp, and there's nothing for you to do on it. If your code reads `outcome`, switch to `status`. See [Information Requests](/rfi).
</Update>

<Update label="2026-09-29" description="Steps awaiting review return Pending" tags={["Changed", "All customers"]}>
  **Steps awaiting review return `Pending`.**

  *Changed · All customers*

  In `step_status` on an `Identification` (for example from `GET /api/identifications/{id}`), a step your customer has submitted but that hasn't been reviewed yet now returns `{ "result": "Pending", "comment": null, "retry": false }`. Earlier it returned `null`, the same as a step that was never asked for. Steps still waiting on your customer stay `null`, so `step_status` now agrees with `GET /api/customers/{id}/requirements`. If your code treats every non-null step as reviewed, handle `Pending`.
</Update>

<Update label="2026-09-29" description="SWIFT account number validation" tags={["Action required", "All customers"]}>
  **SWIFT `account_number` must be 1-34 letters, digits, or spaces.**

  *Action required · All customers*

  Requests that carry a `BankAccountSWIFTIdentifier`, such as `POST /api/addresses/fiat` with a SWIFT account, now reject an `account_number` that is longer than 34 characters, ends in a space, or contains anything other than ASCII letters, digits, and spaces. Invisible formatting characters, such as those pasted from a PDF, fail too. The request returns `400`. Strip the value before you send it. See [Fiat addresses](/fiat-addresses).
</Update>

<Update label="2026-09-28" description="Liveness RFIs" tags={["Added", "All customers"]}>
  **RFIs gain a `liveness` type.**

  *Added · All customers*

  An RFI with `type` `liveness` asks your customer to redo the liveness check. It carries a `liveness_url` to send them, takes no answers (`POST /api/rfis/{rfi_id}/rounds/{round_id}/response` returns `400`), and moves to `needs_review` once the new identification is approved or rejected. If you switch on `type` with no default branch, add one for `liveness`. See [Information Requests](/rfi).
</Update>

<Update label="2026-09-22" description="AML/CFT policy document, 6 documents per company" tags={["Added", "Business customers"]}>
  **AML/CFT policy document and up to 6 documents per company.**

  *Added · Business customers*

  `AmlCftPolicy` is a new company document type on `Business` submissions. It's always optional and doesn't count toward any required document group. Each company in a submission (the root company, and each nested business beneficiary) can now carry up to 6 documents, up from 4. See [KYB](/kyb).
</Update>

<Update label="2026-09-15" description="blocking_abilities, all_deposit_rails_blocked, sandbox FX" tags={["Added", "Action required", "Sandbox", "All customers", "Individual customers"]}>
  **`blocking_abilities` shows which rails a customer can't use, and why.**

  *Added · All customers*

  The `Identification` object and `GET /api/customers/{id}/abilities` gain `blocking_abilities`: a map from a rail (for example `ach` or `sepa_thirdparty`) to the reason that rail is unavailable for the customer. It's always present, and empty when nothing is blocked.

  **A `Person` submission is rejected when every deposit rail is blocked.**

  *Action required · Individual customers*

  When every deposit rail configured for your account is blocked for the applicant, a `Person` submission to `POST /api/customers/{id}/identifications/v2` now returns `400` with one `all_deposit_rails_blocked` entry per rail, and no identification is created. When only some rails are blocked, the submission goes ahead and the blocked rails are listed in `blocking_abilities`. `Business` and `Token` submissions aren't rejected by this check.

  **Sandbox transactions price at the live FX rate.**

  *Sandbox · All customers*

  `POST /api/sandbox/transaction` without `fx_rate` now uses the live mid-market rate for the pair instead of `1.0`, and computes `amount_out` as `(amount - fee) * fx_rate`. If no rate is available for the pair, it returns `500`. See [Sandbox](/sandbox).
</Update>

<Update label="2026-09-11" description="Company address state, non-US foundations" tags={["Relaxed", "Action required", "Business customers"]}>
  **Company address `state` is required for countries with subdivisions.**

  *Action required · Business customers*

  A `Business` submission whose `company_data.company_info.address` is in a country with ISO 3166-2 administrative subdivisions must include `state`. A missing or blank value returns `400` `invalid_request` ("Address state is required for countries with administrative subdivisions"). The same rule already applied to a beneficiary's `birth_place.state`.

  **A non-US `PrivateFoundation` no longer needs a beneficiary with an ownership share.**

  *Relaxed · Business customers*

  A non-US `Business` with `company_type` `PrivateFoundation` skips the qualifying-owner check. It still needs at least one root `Director`. See [KYB](/kyb).
</Update>

<Update label="2026-09-10" description="RFI endpoints, documents on Token identifications" tags={["Added", "All customers", "Individual customers"]}>
  **Read and answer information requests through the API.**

  *Added · All customers*

  New endpoints for RFIs:

  * `GET /api/rfis` and `GET /api/customers/{customer_id}/rfis` list requests.
  * `GET /api/rfis/{rfi_id}` gets one.
  * `POST /api/rfis/{rfi_id}/rounds/{round_id}/document-link-opened` records that the document upload link was opened.
  * `POST /api/rfis/{rfi_id}/rounds/{round_id}/response` submits answers.

  RFIs don't emit webhooks, so poll `GET /api/rfis`. See [Information Requests](/rfi).

  **`Token` identifications accept a proof of address.**

  *Added · Individual customers*

  The `Token` variant of `POST /api/customers/{id}/identifications/v2` takes an optional `documents` array. It accepts one `ProofOfAddress` document: base64 `file`, a `name` with a file extension, 10 MB at most. See [SumSub Token Sharing](/reliance-kyc-token-sharing).
</Update>

<Update label="2026-09-08" description="Duplicate customer emails rejected" tags={["Action required", "All customers"]}>
  **Two active customers can't share an email.**

  *Action required · All customers*

  `POST /api/customers` and `PUT /api/customers/{id}` now return `400` when another of your `Active` customers already has the same email address. The comparison ignores case. Customers in any other status don't count.

  ```json theme={null}
  "Email address already in use by another active customer"
  ```
</Update>

<Update label="2026-09-04" description="UK applicants checked at submission" tags={["Action required", "All customers"]}>
  **UK applicants are rejected at submission when UK onboarding isn't enabled.**

  *Action required · All customers*

  If UK onboarding isn't enabled for your account, a `Person` or `Business` submission for a UK applicant now fails at `POST /api/customers/{id}/identifications/v2` with `400` [`uk_customers_not_enabled`](/errors#uk_customers_not_enabled). Earlier it was only rejected later, at review.
</Update>

<Update label="2026-08-31" description="Brazil digital driver's license" tags={["Added", "All customers"]}>
  **`DigitalDriversLicense` identity document type.**

  *Added · All customers*

  Identity documents accept `DigitalDriversLicense` for Brazil's single-image CNH Digital. Send the front image only. It's accepted when the document's issuing country is Brazil, on `Person` submissions and on `Business` beneficiaries. See [KYC](/kyc).
</Update>

<Update label="2026-08-27" description="Private IP addresses rejected" tags={["Action required", "All customers"]}>
  **`ip_address` must be a public address.**

  *Action required · All customers*

  A `Person` or `Business` submission to `POST /api/customers/{id}/identifications/v2` now rejects an `ip_address` that isn't globally routable (private, loopback, link-local, CGNAT, documentation, or reserved ranges, IPv4 and IPv6) with `400` `invalid_request` ("IP address is not a globally routable public address"). Send the IP of your customer's device, not your server's internal address. `Token` submissions aren't checked.
</Update>

<Update label="2026-08-26" description="Miscellaneous industry deprecated" tags={["Action required", "Business customers"]}>
  **`Miscellaneous` is no longer accepted as an industry.**

  *Action required · Business customers*

  A `Business` submission with `business_details.industry` `Miscellaneous` is rejected with [`miscellaneous_industry_deprecated`](/errors#miscellaneous_industry_deprecated). Pick the closest specific industry instead. See [KYB](/kyb).
</Update>

<Update label="2026-08-24" description="Fewer required fiat address fields" tags={["Relaxed", "All customers"]}>
  **USD and SWIFT fiat addresses need fewer fields.**

  *Relaxed · All customers*

  `POST /api/addresses/fiat` no longer requires `bank_details.email_address` or `bank_details.phone_number` for USD accounts, or `bank_details.bank_address` for SWIFT accounts. A `phone_number` you do send is still validated and stored in E.164 format. SWIFT account numbers for banks in 19 European countries, including the UK, no longer have to be IBANs. See [Fiat addresses](/fiat-addresses).
</Update>

<Update label="2026-08-21" description="Prohibited industries rejected at submission" tags={["Changed", "Business customers"]}>
  **Prohibited industries are rejected at submission.**

  *Changed · Business customers*

  A `Business` submission whose industry resolves to a prohibited industry is now rejected at `POST /api/customers/{id}/identifications/v2` with `400` [`prohibited_industry`](/errors#prohibited_industry), instead of going to manual review. See [Prohibited industries](/kyb#prohibited-industries).
</Update>

<Update label="2026-08-13" description="external_id reusable after archiving" tags={["Relaxed", "All customers"]}>
  **Archiving a customer frees its `external_id`.**

  *Relaxed · All customers*

  `POST /api/customers` and `PUT /api/customers/{id}` no longer reject an `external_id` that only archived customers hold. `GET /api/customers/{external_id}/external` still searches archived customers too, so once you reuse an `external_id` it can return either the archived or the active customer. Look customers up by `id` after you reuse one.
</Update>

<Update label="2026-08-12" description="Sandbox sends Processed before Approved" tags={["Sandbox", "Webhooks", "All customers"]}>
  **Sandbox auto-approval sends `Processed` before `Approved`.**

  *Sandbox · Webhooks · All customers*

  In sandbox, an auto-approved identification now sends an `identification_status` webhook with `Processed` and then one with `Approved`, the same sequence as a production review. It used to send only `Approved`. See [Sandbox](/sandbox).
</Update>

<Update label="2026-08-11" description="TIN step-up for EEA customers" tags={["Added", "Individual customers"]}>
  **Ask an approved EEA customer for their tax ID.**

  *Added · Individual customers*

  `POST /api/customers/{id}/identifications/tin-step-up` returns a hosted link that asks an approved EEA customer only for their tax identification number. Their approved status doesn't change. It returns `400` if the customer isn't approved or isn't in the EEA, and `409` if a tax ID is already on file. See [Trigger Customer TIN Step-Up](/reference/customer/trigger-customer-tin-step-up).
</Update>

<Update label="2026-08-07" description="Backfill tax IDs, US registry match" tags={["Added", "Relaxed", "Business customers", "Individual customers"]}>
  **Backfill a customer's tax ID.**

  *Added · Individual customers*

  `PATCH /api/customers/{id}/identification-data` adds `tax_identification_number` and `tax_residence_country` to a person customer's existing identification, without re-verification. `tax_residence_country` is required whenever you send a `tax_identification_number`. See [Update Customer Identification Data](/reference/customer/update-customer-identification-data).

  **US companies that match the official registry skip company documents.**

  *Relaxed · Business customers*

  A US `Business` that matches the official company registry by name and registration number no longer needs the root company's documents. Nested business beneficiaries still need theirs. See [Automatic verification for US companies](/kyb#automatic-verification-for-us-companies).
</Update>

<Update label="2026-08-05" description="Two new webhook events" tags={["Added", "Webhooks", "All customers"]}>
  **`transaction_refunded` and `customer_fiat_abilities` webhooks.**

  *Added · Webhooks · All customers*

  `transaction_refunded` fires when a refund is recorded for a transaction. `customer_fiat_abilities` fires when a customer's fiat deposit or payout rails change, so you can stop polling `GET /api/customers/{id}/abilities`. See [Supported event types](/webhooks#supported-event-types).
</Update>

<Update label="2026-08-01" description="API version" tags={["API version", "All customers", "Business customers"]}>
  **New customers sign the terms before identification.**

  | | |
  | - | - |
  | Affects | Behavior, response |
  | Kind | Changed (customer lifecycle, pinned per customer) |
  | Endpoints | `POST /api/customers`, `GET /api/customers/{id}/required-signings`, `POST /api/customers/{id}/signings` |

  A customer created under this version starts in `SigningsRequired` instead of `IdentificationRequired`. Fetch the document with `GET /api/customers/{id}/required-signings`, present it, and record acceptance with `POST /api/customers/{id}/signings`. The customer then moves to `IdentificationRequired`. The terms contain the data sharing agreement, so they now come before KYC or KYB data collection instead of after approval. New customers sign a single global terms document instead of a regional one.

  The version is pinned to the customer when you create it and drives that customer's onboarding for its lifetime. Customers created on an earlier version keep the previous flow: they start in `IdentificationRequired` and sign after their identification is approved. See [Create a new customer](/onboarding).

  **`required-signings` returns an empty list when nothing is outstanding.**

  | | |
  | - | - |
  | Affects | Response |
  | Kind | Changed (status code) |
  | Endpoints | `GET /api/customers/{id}/required-signings` |

  Under this version, the endpoint returns `200` with `[]` when the customer owes no documents. Earlier and unversioned callers keep getting `409 Conflict`. This follows the version you send, not the customer's pin.

  **Identification failures return structured, machine-readable errors.**

  | | |
  | - | - |
  | Affects | Response |
  | Kind | Changed (`400` body shape) |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`, `Person`, `Token`) |

  A failed `Business`, `Person`, or `Token` identification submission now returns `400` with an array of `{code, message, docs_url, beneficiary_index}` objects instead of a plain error string, so your integration can branch on `code` instead of pattern-matching English text. See [Identification Errors](/errors) for the full list of codes.

  Most checks return a single entry, but the four document-requirement codes (`company_details_required`, `legal_presence_required`, `ownership_structure_required`, `control_structure_required`) can each appear once per company in the submission that's missing that group. A non-US `Business` submission checks all four independently, so several can genuinely be missing at once.

  <Note>
    Callers on an earlier or unversioned `X-API-Version` keep receiving today's plain error string on `400`, unchanged.
  </Note>

  **Business questionnaires get a granular `industry` field.**

  | | |
  | - | - |
  | Affects | Request |
  | Kind | Additive (new field), deprecation (`industry_type`), version-gated requirement |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  `business_details` on a `Business` submission gains a new field, `industry`, which exposes Sumsub's full industry taxonomy (136 values) in place of the 36 broad categories on the existing `industry_type` field. `industry_type` is now deprecated. It keeps working indefinitely, so no integration needs to change immediately, but `industry` is required for any submission made under this version or later. Callers on an earlier or unversioned `X-API-Version` can keep sending `industry_type` alone; `industry` stays optional for them. If a submission includes both fields, `industry` takes precedence and `industry_type` is silently ignored.

  **A nested business beneficiary now needs only Company Details and Ownership Structure documents.**

  | | |
  | - | - |
  | Affects | Behavior only, no request or response shape changes |
  | Kind | Relaxed validation |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  A `Shareholder` that's a legal entity (a nested company) previously needed the same document groups as the root company, up to all four for a non-US root. It now always needs just Company Details and Ownership Structure, regardless of the root company's own requirement or the nested entity's registered country. See [Company Documents](/kyb#company-documents).

  **A US company `Business` submission's CDD certification falls back to a 10% ownership threshold instead of requiring 25%.**

  | | |
  | - | - |
  | Affects | Behavior only, no request or response shape changes |
  | Kind | Relaxed validation |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  Previously, a US non-sole-proprietorship `Business` submission was rejected with `cdd_certification_invalid` if no beneficiary owned 25% or more, even when that's genuinely true of the company. The generated CDD certification (31 CFR 1010.230) now lists whoever owns 25% or more in its ownership section as before, but if nobody does, it falls back to listing whoever owns 10% or more instead of rejecting the submission. For a company where nobody owns even 10%, see the qualifying-owner requirement below, which applies this same threshold to every country. The attesting party's control-person section is still required as before. See [Company Documents](/kyb#company-documents).

  **A `ubo_share_below_threshold` beneficiary now falls back to a 10% disclosure threshold, in every country.**

  | | |
  | - | - |
  | Affects | Behavior only, no request or response shape changes |
  | Kind | Relaxed validation |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  Previously, a beneficiary whose only role was `UltimateBeneficialOwner` was rejected with `ubo_share_below_threshold` whenever their `share_percentage` was 25 or below, with no fallback. The only way to submit such a beneficiary was to give them an additional role (for example `Director`), which dropped the `UltimateBeneficialOwner` tag entirely. Now, if nobody at that beneficiary's level (the root company, or a nested company) owns 25% or more, the threshold for keeping the `UltimateBeneficialOwner` tag drops to 10% instead of rejecting outright. A UBO-only beneficiary owning, say, 15% is now accepted and keeps the tag as long as nobody else at that level already owns 25% or more; nobody rejects until nobody at that level owns even 10%. This applies in every country, not just US submissions. See [`ubo_share_below_threshold`](/errors#ubo_share_below_threshold).

  **A beneficiary's `birth_place.state` is optional for countries with no administrative subdivisions.**

  | | |
  | - | - |
  | Affects | Request |
  | Kind | Relaxed validation (field no longer required) |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  Previously, every beneficiary's `birth_place.state` was required, even for countries with no ISO 3166-2 administrative subdivisions (Vatican City, Malta, and Hong Kong, for example), leaving no legitimate value to send. `state` is now optional, and validation only rejects a missing value for a birth country that actually has subdivisions. Existing integrations that already send `state` are unaffected. See [Business API Field Reference](/kyb#business-api-field-reference).

  **A `Business` submission now requires a root-level Director and a root-level qualifying owner, in every country.**

  | | |
  | - | - |
  | Affects | Behavior only, no request or response shape changes |
  | Kind | New validation (`400` on submissions that previously succeeded) |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  Previously, a non-sole-proprietorship `Business` submission outside the US could validate with zero beneficiaries, or with beneficiaries holding only, say, `Shareholder` or `UltimateBeneficialOwner` roles, with nobody holding `Director` and nobody disclosing enough ownership to matter. US submissions never fully hit this: the mandatory CDD attesting party always requires a Director, and (as of the CDD fallback-tier change above) a qualifying owner, but that's incidental to the US CDD flow, not an independent floor, and ROW had no equivalent at all. Every non-sole-proprietorship company, in every country, now must name at least one root-level beneficiary with the `Director` role, and at least one root-level beneficiary owning 25% or more (or 10% or more, if nobody owns 25% or more), or the submission is rejected with `structure_invalid`. A `Representative`-only beneficiary never satisfies the ownership half of this, regardless of their disclosed `share_percentage`: MoonPay Enterprise never independently verifies a Representative-only beneficiary's identity, so their disclosure can't count as ownership evidence. Combined shares of everyone who does count as a qualifying owner (any `UltimateBeneficialOwner`, or any other non-`Representative`-only beneficiary) still can't exceed 100%. Neither requirement applies to sole proprietorships (still exactly one beneficiary, 100% owned, no Director needed) or to nested business beneficiaries' own sub-beneficiary lists (which remain documentation-only). See [`structure_invalid`](/errors#structure_invalid).

  **A `PrivateFoundation` `Business` submission now requires an accepted `purpose_and_intended_use`.**

  | | |
  | - | - |
  | Affects | Behavior only, no request or response shape changes |
  | Kind | New validation (`400` on submissions that previously succeeded) |
  | Endpoints | `POST /customers/{id}/identifications/v2` (`Business`) |

  A `Business` submission with `company_type` `PrivateFoundation` is now rejected with `foundation_intended_use_not_supported` unless `planned_activities.purpose_and_intended_use` is one of a limited set of values accepted for that entity type. See [`foundation_intended_use_not_supported`](/errors#foundation_intended_use_not_supported).
</Update>

<Update label="2026-07-01" description="API version" tags={["API version", "All customers"]}>
  **Adds the FedNow deposit rail.**

  | | |
  | - | - |
  | Affects | Response |
  | Kind | Added (union variant) |
  | Endpoints | Any response containing an `Autoramp` object: `POST /autoramps`, `GET /autoramps`, `GET /autoramps/{autoramp_id}`, `PATCH /autoramps/{autoramp_id}`, `GET /autoramps/{external_id}/external`, `POST /autoramps/{autoramp_id}/quotes` |

  The `deposit_rails` array can now include a `FedNow` member, for autoramps whose deposit account supports FedNow. This is additive to the `DepositRail` union: every existing member (`Iban`, `AchWire`, `Swift`, and the rest) is unchanged.

  <Warning>
    If your integration matches on `deposit_rails` with an exhaustive switch and no default case, add a `FedNow` branch before sending `X-API-Version: 2026-07-01`. Callers on `2025-03-13` never see this variant, so there is no rush to migrate.
  </Warning>
</Update>

<Update label="2025-03-13" description="API version" tags={["API version", "All customers"]}>
  Initial version. Served when no `X-API-Version` header is sent.
</Update>
