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

# KYB Requirements

> Business verification requirements for Cadana

export const ApiExample = ({method = "GET", path, params, body, reference, tenantKey}) => {
  const baseUrl = "https://api.cadanapay.com";
  const query = params ? "?" + Object.entries(params).map(([k, v]) => `${k}=${v}`).join("&") : "";
  const url = `${baseUrl}${path}${query}`;
  const isPlatformPath = (/^\/(v1\/)?platform(\/|$)/).test(path || "");
  const includeTenantKey = tenantKey === undefined ? !isPlatformPath : tenantKey;
  let curl = `curl -X ${method} '${url}' \\\n  -H 'Authorization: Bearer YOUR_API_KEY'`;
  if (includeTenantKey) {
    curl += ` \\\n  -H 'X-MultiTenantKey: YOUR_BUSINESS_TENANT_KEY'`;
  }
  if (body) {
    const formatted = JSON.stringify(body, null, 2);
    curl += ` \\\n  -H 'Content-Type: application/json' \\\n  -d '${formatted}'`;
  }
  return <div>
      <CodeBlock language="bash" filename="bash" wrap>
        {curl}
      </CodeBlock>
      {reference && <div style={{
    marginTop: "-0.5rem",
    marginBottom: "1rem"
  }}>
          <a href={reference} style={{
    fontSize: "0.875rem"
  }}>
            Try it in the playground →
          </a>
        </div>}
    </div>;
};

Know Your Business (KYB) verification is required before a business can process payments through Cadana. This page covers all requirements and the verification process.

<Note>
  **KYB vs KYC:** KYB verifies business entities. KYC verifies individual users. See [KYC Verification](/platform/kyc-verification) for user verification.
</Note>

***

## KYB Process Flow

```mermaid theme={null}
flowchart LR
    A["Create Business"] --> B["Submit KYB"]
    B -->|All requirements met| C["pending-review"]
    B -->|Requirements outstanding| G["incomplete"]
    G --> B
    C -->|Approved| D["complete"]
    C -->|Needs info| E["needs-additional-info"]
    C -->|Rejected| F["rejected"]
    E -->|"Fix & resubmit"| C
```

### KYB Statuses

| Status                   | Description                                                                                   | Can Process Payments? |
| :----------------------- | :-------------------------------------------------------------------------------------------- | :-------------------- |
| `initialized`            | KYB record created (e.g. by generating a hosted link), nothing submitted yet                  | No                    |
| `incomplete`             | Partially submitted — required fields are still outstanding (see `requirements.currentlyDue`) | No                    |
| `pending-review`         | All requirements submitted, under review                                                      | No                    |
| `awaiting-principal-kyc` | Submitted, waiting on one or more principals to complete identity verification                | No                    |
| `needs-additional-info`  | Review complete, more information required                                                    | No                    |
| `rejected`               | Business verification rejected (terminal)                                                     | No                    |
| `complete`               | Business verified                                                                             | Yes                   |

Before the first submission (or hosted-link generation), `GET /v1/businesses/{businessId}/kyb` returns `404`.

***

## Submit KYB

You can submit KYB in two ways:

* **Hosted form** — generate a branded link and send it to your customer. The business owner completes KYB through a hosted UI — no need to build your own collection form.
* **API submission** — collect the verification data in your own UI and submit it directly via API.

### Hosted KYB Form

If you prefer to delegate KYB data collection to the business owner, generate a hosted form link and share it with them. The business owner visits the link and completes verification through a branded UI.

<ApiExample
  method="POST"
  path="/v1/businesses/{businessId}/kyb-link"
  body={{
returnURL: "https://yourapp.com/onboarding/complete",
refreshURL: "https://yourapp.com/onboarding/refresh"
}}
  reference="/api-reference/workforce/kyb/generate-kyb-link"
/>

**Response:**

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "https://app.cadanapay.com/onboarding/business/?token=eyJhbGciOi...",
  "expiresAt": 1765459752
}
```

| Field       | Description                                                                                                    |
| :---------- | :------------------------------------------------------------------------------------------------------------- |
| `id`        | Unique identifier for the KYB link                                                                             |
| `url`       | The hosted form URL — send this to the business owner. White-label platforms get the link on their own domain. |
| `expiresAt` | Unix timestamp when the link expires                                                                           |

<Note>
  Links expire 24 hours after creation by default; pass `expiresIn` (seconds, maximum 72 hours) to choose a different lifetime. The resolved expiry is returned as `expiresAt`. If the owner visits an expired link, they are redirected to your `refreshURL` where you can generate a new one. Progress is saved as the owner completes each step, so a new link resumes where they left off.
</Note>

<Tip>
  Prefer a short `expiresIn` when you redirect the owner straight into the form from your own product, and the default when you email the link.
</Tip>

<Tip>
  Webhook events (`business.kyb.reviewed`, `business.kyb.completed`) work the same regardless of whether KYB was submitted via the hosted form or the API.
</Tip>

### API Submission

Submit business and principal information for verification. You can submit all data at once or start with a partial submission and add more information later.

The two write endpoints have distinct roles:

|                        | [`POST /kyb`](/api-reference/workforce/kyb/submit-kyb)                                        | [`PATCH /kyb`](/api-reference/workforce/kyb/update-kyb)            |
| :--------------------- | :-------------------------------------------------------------------------------------------- | :----------------------------------------------------------------- |
| **Purpose**            | Provide **new** information — the initial submission, and any change to the set of principals | **Update** information already provided                            |
| **Principals**         | Always the **full list** — each POST replaces the previously submitted list                   | Only the principals being updated — each **must** include its `id` |
| **Adding a principal** | Yes — re-POST all existing principals (with their `id`s) plus the new one                     | No — a missing or unknown `id` fails with `400`                    |
| **Documents**          | Replaces                                                                                      | Appends                                                            |

<Note>
  **Incremental submission:** You can start with just the business name and address and submit the rest over time. The status stays `incomplete` — with the outstanding fields listed in `requirements.currentlyDue` — until all requirements are met, then moves to `pending-review`.
</Note>

<ApiExample method="POST" path="/v1/businesses/{businessId}/kyb" body={{ entityName: "Acme Corporation", entityType: "corporation", taxIdentificationNumber: "12-3456789", websiteURL: "https://acme.com", phoneNumber: { countryCode: "1", number: "4155551234" }, address: { line1: "123 Main Street", line2: "Suite 400", city: "San Francisco", postalCode: "94105", state: "CA", countryCode: "US" }, incorporation: { date: "2020-01-15", address: { line1: "123 Main Street", city: "San Francisco", postalCode: "94105", state: "CA", countryCode: "US" } }, principals: [{ firstName: "Jane", lastName: "Founder", ownershipPercentage: 0.75, email: "jane@example.com", phoneNumber: { countryCode: "1", number: "4155559999" }, address: { line1: "456 Oak Ave", city: "San Francisco", postalCode: "94102", state: "CA", countryCode: "US" }, isExecutive: true, title: "CEO", dateOfBirth: "1985-06-15", identifier: { type: "ssn", value: "123-45-6789" } }] }} reference="/api-reference/workforce/kyb/submit-kyb" />

Returns `204` on success. The business is now under review.

### Updating KYB Information

Use PATCH to update information already provided — filling in outstanding fields or correcting flagged ones. Only the fields you include are updated — everything else is left unchanged. Document arrays (`articlesOfIncorporation`, `bankStatements`, etc.) are **appended to**, not replaced.

<ApiExample method="PATCH" path="/v1/businesses/{businessId}/kyb" body={{ entityName: "Acme Corporation Inc.", principals: [{ id: "123e4567-e89b-12d3-a456-426614174000", identifier: { identityFileId: "file-id-front", identityBackPageFileId: "file-id-back" } }] }} reference="/api-reference/workforce/kyb/update-kyb" />

<Warning>
  When updating principals in a PATCH request, every principal — including individuals nested inside an [entity principal's](#entity-principals) `entity.individuals` — **must** include its `id` (returned from [GET KYB](#check-kyb-status)). PATCH can only update existing principals: a missing or unknown `id` fails the whole request with `400` (`"principal not found"`), and PATCH cannot add new principals. To add a principal, re-`POST` the full submission.
</Warning>

PATCH is also how you respond after a review returns `needs-additional-info`. Parse the `currentlyDue` array from the [`business.kyb.reviewed`](#webhook-events) webhook, collect the required data or documents, and PATCH them in. The status automatically moves back to review once all requirements are satisfied.

<Note>
  You cannot POST or PATCH while the KYB is in `pending-review`, `complete`, or `rejected` status — the request returns `400`.
</Note>

### Business Owner Emails

When a review returns `needs-additional-info`, Cadana emails the business's admin users with a link back to the [hosted form](#hosted-kyb-form) so they can supply what is outstanding. The link expires 24 hours after the review. Unlike a link you generate yourself, it carries no `refreshURL`, so an admin who arrives after it has expired has to come back through you.

If your platform owns the customer relationship, suppress that email and drive the follow-up yourself from the [`business.kyb.reviewed`](#webhook-events) webhook. Generating the hosted link at the moment your customer is ready to act on it keeps the link fresh, and keeps every message to your customer in your own product's voice.

Set `suppressEmailNotification` on either write endpoint:

<ApiExample method="PATCH" path="/v1/businesses/{businessId}/kyb" body={{ suppressEmailNotification: true }} reference="/api-reference/workforce/kyb/update-kyb" />

<Warning>
  `POST /kyb` always writes this field, so a later POST that omits it resets it to `false`. PATCH changes it only when the field is present. Either include `suppressEmailNotification: true` in every POST, or set it once via PATCH after your final POST.
</Warning>

### Check KYB Status

Retrieve the full KYB record at any time, including the current `status` and any outstanding requirements. `requirements.currentlyDue` lists the exact field paths still needed — the same paths used in the [`business.kyb.reviewed`](#webhook-events) webhook — so you can poll this endpoint instead of (or in addition to) listening for webhooks.

<ApiExample method="GET" path="/v1/businesses/{businessId}/kyb" reference="/api-reference/workforce/kyb/get-kyb" />

**Response (truncated):**

```json theme={null}
{
  "id": "7c74cc95-d7c6-4537-b388-6d57ed020b34",
  "tenantKey": "cad95193904",
  "entityName": "Acme Corporation",
  "status": "incomplete",
  "principals": [
    {
      "id": "c4874dfd-50ef-429a-afbe-3c8adc0ecbe9",
      "firstName": "Jane",
      "lastName": "Founder",
      "identifier": { "type": "ssn", "value": "****" }
    }
  ],
  "requirements": {
    "currentlyDue": [
      "entityType",
      "principals.0.identifier.identityFileId"
    ],
    "errors": []
  }
}
```

***

## Business Requirements

| Requirement           | API Field                 | Rules                                                                                                                                     |
| :-------------------- | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------- |
| Legal business name   | `entityName`              | Must exactly match the registered name on government records                                                                              |
| Entity type           | `entityType`              | `corporation`, `c-corporation`, `s-corporation`, `partnership`, `sole proprietorship`, `limited liability company`, `non profit`, `other` |
| Business address      | `address`                 | Must be a valid physical address; PO Boxes not allowed                                                                                    |
| Phone number          | `phoneNumber`             | Must be a reachable business phone                                                                                                        |
| EIN / Tax ID          | `taxIdentificationNumber` | Must be a valid IRS-issued EIN                                                                                                            |
| Incorporation address | `incorporation.address`   | Must match corporate records                                                                                                              |
| Incorporation date    | `incorporation.date`      | Must be a valid date                                                                                                                      |
| Website URL           | `websiteURL`              | Must be a valid website                                                                                                                   |

***

## Principal / UBO Requirements

A principal can be an **individual** or a **business entity** (see [Entity Principals](#entity-principals) below). You must provide information for principals who:

* Own **25% or more** of the business (`ownershipPercentage >= 0.25`), or
* Hold significant managerial responsibility (`isExecutive: true`)

At least one executive/representative is required, and ownership percentages must sum to at most 1 at each level.

The following fields apply to individual principals:

| Requirement         | API Field                                        | Rules                                                                                                          |
| :------------------ | :----------------------------------------------- | :------------------------------------------------------------------------------------------------------------- |
| First name          | `principals[].firstName`                         | Must match ID document                                                                                         |
| Last name           | `principals[].lastName`                          | Must match ID document                                                                                         |
| Date of birth       | `principals[].dateOfBirth`                       | Must be valid and 18+                                                                                          |
| Email               | `principals[].email`                             | Valid email address                                                                                            |
| Phone number        | `principals[].phoneNumber`                       | Reachable phone                                                                                                |
| Residential address | `principals[].address`                           | Physical address; PO Boxes not allowed                                                                         |
| Identifier          | `principals[].identifier`                        | Accepted `type` depends on the principal's country — see [Providing a principal ID](#providing-a-principal-id) |
| Ownership %         | `principals[].ownershipPercentage`               | 0-1 scale (1 = 100%)                                                                                           |
| Executive flag      | `principals[].isExecutive`                       | Required for control person                                                                                    |
| Executive title     | `principals[].title`                             | Required for control person                                                                                    |
| ID document (front) | `principals[].identifier.identityFileId`         | Required if ID number verification fails, or for the passport fallback below                                   |
| ID document (back)  | `principals[].identifier.identityBackPageFileId` | Required if ID number verification fails                                                                       |
| Address proof       | `principals[].identifier.addressFileId`          | Required if address verification fails                                                                         |

Upload documents using the [file upload flow](/reference/working-with-files) and pass the returned `fileId` values.

### Providing a principal ID

Which ID a principal can provide depends on their country. Follow this flow:

```mermaid theme={null}
flowchart TD
    A[Providing identity for a UBO] --> B{Do you have an ID number<br/>or document for this UBO?}
    B -->|No| F[Opt into direct verification —<br/>set optInForDirectVerification: true<br/>so we email the UBO a KYC link]
    B -->|Yes| C{Is that ID type accepted<br/>for the UBO's country?}
    C -->|Yes| D[Send the ID type and number]
    C -->|No| E{Is it a passport with both<br/>its number and a front-page image?}
    E -->|Yes| G[Send the passport number and image]
    E -->|No| F
    D --> H([ID accepted — KYB continues to review])
    G --> H
    F --> I([UBO completes KYC themselves;<br/>KYB waits in awaiting-principal-kyc until done])

    click C "#supported-id-types-by-country" "See the ID types accepted per country"
```

**Fields for each outcome:**

| Diagram step                | What to send                                                                                                    |
| :-------------------------- | :-------------------------------------------------------------------------------------------------------------- |
| Send the ID type and number | `identifier.type` + `identifier.value`                                                                          |
| Passport fallback           | `identifier.type: passport`, `identifier.value` (the number) and `identifier.identityFileId` (front-page image) |
| Direct verification         | `optInForDirectVerification: true` — omit the `identifier` object                                               |

<Note>
  On a PATCH, the passport fallback lets you supply either half — the number now if the image is already stored, or the image now if the number is already stored.
</Note>

<Accordion title="Supported ID types by country">
  | Country              | Code | Supported `type` values                                           |
  | :------------------- | :--- | :---------------------------------------------------------------- |
  | Argentina            | `AR` | `national_id`, `tax_id`                                           |
  | Brazil               | `BR` | `national_id`                                                     |
  | Cambodia             | `KH` | `national_id`                                                     |
  | Canada               | `CA` | `national_id`                                                     |
  | Chile                | `CL` | `national_id`                                                     |
  | China                | `CN` | `national_id`, `passport`                                         |
  | Colombia             | `CO` | `national_id`, `ppt`                                              |
  | Costa Rica           | `CR` | `national_id`                                                     |
  | Côte d'Ivoire        | `CI` | `national_id`                                                     |
  | Denmark              | `DK` | `national_id`                                                     |
  | Ecuador              | `EC` | `national_id`                                                     |
  | Ghana                | `GH` | `ghana_card`                                                      |
  | Hong Kong            | `HK` | `national_id`                                                     |
  | India                | `IN` | `national_id`, `voter_id`, `driver_license`, `tax_id`, `passport` |
  | Indonesia            | `ID` | `national_id`                                                     |
  | Italy                | `IT` | `national_id`                                                     |
  | Kenya                | `KE` | `national_id`, `passport`, `alien_card`, `kra_pin`                |
  | Malaysia             | `MY` | `national_id`                                                     |
  | Mexico               | `MX` | `national_id`, `tax_id`                                           |
  | Nigeria              | `NG` | `bvn`, `nin`, `voter_id`                                          |
  | Peru                 | `PE` | `national_id`, `tax_id`                                           |
  | Qatar                | `QA` | `national_id`                                                     |
  | Singapore            | `SG` | `national_id`                                                     |
  | South Africa         | `ZA` | `national_id`                                                     |
  | Spain                | `ES` | `national_id`                                                     |
  | Sweden               | `SE` | `national_id`                                                     |
  | Thailand             | `TH` | `national_id`                                                     |
  | United Arab Emirates | `AE` | `national_id`                                                     |
</Accordion>

### Entity Principals

When a stake of 25% or more is held by another company rather than a person, submit that company as an **entity principal**: set `isEntity: true` and provide the `entity` object instead of the individual fields (`firstName`, `lastName`, `dateOfBirth`, and `identifier` do not apply).

| Requirement        | API Field                                     | Rules                                                                |
| :----------------- | :-------------------------------------------- | :------------------------------------------------------------------- |
| Entity flag        | `principals[].isEntity`                       | Must be `true` for entity principals                                 |
| Company name       | `principals[].entity.companyName`             | Registered legal name (required)                                     |
| Entity type        | `principals[].entity.entityType`              | Same values as the business [`entityType`](#business-requirements)   |
| Tax ID             | `principals[].entity.taxIdentificationNumber` | Required                                                             |
| Registered address | `principals[].entity.address`                 | Required; physical address                                           |
| Email              | `principals[].entity.email`                   | Contact email address                                                |
| Website URL        | `principals[].entity.websiteURL`              | Must be a valid website                                              |
| Incorporation      | `principals[].entity.incorporation`           | `date` and `address` of incorporation                                |
| Ownership document | `principals[].entity.ownershipDocumentFileId` | File ID for a document evidencing the entity's stake in the business |
| Owners             | `principals[].entity.individuals`             | The entity's own principals — see below                              |

The ownership document is the only document required by default — a certificate of incorporation (`certificateOfIncorporationFileId`) and proof of address (`proofOfAddressFileId`) can also be attached; see the [API reference](/api-reference/workforce/kyb/submit-kyb). Unlike individual principals, no phone number is collected for an entity principal.

`entity.individuals` lists the entity's own principals, in the same shape as top-level principals: everyone holding **25% or more of that entity**, plus at least one **controlling person** — an executive such as the CEO, submitted with `isExecutive: true` and a `title`. If no individual crosses the 25% ownership threshold, the controlling person alone satisfies the requirement. An owner that is itself a company is another entity principal — nesting continues as deep as the ownership chain requires, until every branch ends at individuals. Identity verification (KYC) runs against those individuals, not the entity itself.

<ApiExample method="POST" path="/v1/businesses/{businessId}/kyb" body={{ entityName: "Acme Corporation", entityType: "corporation", taxIdentificationNumber: "12-3456789", address: { line1: "123 Main Street", city: "San Francisco", postalCode: "94105", state: "CA", countryCode: "US" }, principals: [{ firstName: "Jane", lastName: "Founder", ownershipPercentage: 0.4, email: "jane@example.com", phoneNumber: { countryCode: "1", number: "4155559999" }, address: { line1: "456 Oak Ave", city: "San Francisco", postalCode: "94102", state: "CA", countryCode: "US" }, isExecutive: true, title: "CEO", dateOfBirth: "1985-06-15", identifier: { type: "ssn", value: "123-45-6789" } }, { isEntity: true, ownershipPercentage: 0.6, entity: { companyName: "Acme Holdings LLC", entityType: "limited liability company", taxIdentificationNumber: "98-7654321", email: "ops@acmeholdings.com", websiteURL: "https://acmeholdings.com", address: { line1: "789 Market Street", city: "San Francisco", postalCode: "94103", state: "CA", countryCode: "US" }, incorporation: { date: "2015-03-01", address: { line1: "789 Market Street", city: "San Francisco", postalCode: "94103", state: "CA", countryCode: "US" } }, ownershipDocumentFileId: "file-id-203", individuals: [{ firstName: "John", lastName: "Owner", ownershipPercentage: 1, email: "john@acmeholdings.com", phoneNumber: { countryCode: "1", number: "4155551111" }, address: { line1: "321 Pine Street", city: "San Francisco", postalCode: "94104", state: "CA", countryCode: "US" }, isExecutive: true, title: "CEO", dateOfBirth: "1970-02-20", identifier: { type: "ssn", value: "987-65-4321" } }] } }] }} reference="/api-reference/workforce/kyb/submit-kyb" />

<Note>
  Entity principals follow the same [POST vs PATCH rules](#api-submission) as individuals: add or remove them by re-`POST`ing the full principals list, and update them via PATCH by referencing their `id` — including the `id` of each nested individual inside `entity.individuals`.
</Note>

***

## Required Documents (Conditional)

These documents are only required when automated verification fails.

| Verification failure           | Required upload                                                                               | Accepted documents                                                            |
| :----------------------------- | :-------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------- |
| EIN / Tax ID unverified        | `taxDocuments`                                                                                | IRS EIN confirmation letter (SS-4 or 147C) — must show exact legal name + EIN |
| Business registration mismatch | `articlesOfIncorporation`                                                                     | Articles of Incorporation or Certificate of Formation                         |
| Business address unverified    | `proofOfAddress`                                                                              | Utility bill, lease, or bank statement                                        |
| Principal identity unverified  | `principals[].identifier.identityFileId` and `principals[].identifier.identityBackPageFileId` | Government-issued photo ID (front and back)                                   |
| Principal address unverified   | `principals[].identifier.addressFileId`                                                       | Utility bill, lease, or bank statement                                        |
| Compliance review              | `bankStatements`                                                                              | Recent bank statements (if requested by Compliance)                           |

***

## Webhook Events

### business.kyb.reviewed

Sent after KYB has been reviewed. May indicate approval or that additional information is needed.

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "eventType": "business.kyb.reviewed",
  "version": "1.0",
  "timestamp": 1765359752,
  "data": {
    "id": "7c74cc95-d7c6-4537-b388-6d57ed020b34",
    "tenantKey": "cad95193904",
    "status": "needs-additional-info",
    "timestamp": 1765359752,
    "businessId": "7dd569f9-bd54-4fbb-a5c2-f0aaadc68adf",
    "businessName": "Acme Corporation",
    "requirements": {
      "currentlyDue": [
        "principals.0.firstName",
        "principals.0.identifier.identityFileId",
        "entityName"
      ],
      "errors": [
        {
          "field": "entityName",
          "reason": "Only english letters are allowed"
        },
        {
          "field": "principals.0.firstName",
          "reason": "Name doesn't match ID document"
        }
      ]
    }
  }
}
```

| Field                       | Description                                   |
| :-------------------------- | :-------------------------------------------- |
| `status`                    | Current KYB status                            |
| `requirements.currentlyDue` | Fields that need to be submitted or corrected |
| `requirements.errors`       | Specific validation errors with reasons       |

When you receive `needs-additional-info`:

1. Parse the `currentlyDue` array to identify required fields
2. Check `errors` array for specific issues
3. Collect the required information/documents from the business owner
4. Resubmit KYB with corrected data

By default Cadana also emails the business owner at this point. See [Business Owner Emails](#business-owner-emails) to suppress it and own the follow-up yourself.

### business.kyb.rejected

Sent when a KYB submission has been permanently rejected. This is a terminal state — the business cannot resubmit.

```json theme={null}
{
  "id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
  "eventType": "business.kyb.rejected",
  "version": "1.0",
  "timestamp": 1765359752,
  "data": {
    "id": "7dd569f9-bd54-4fbb-a5c2-f0aaadc68adf",
    "businessName": "Acme Corporation",
    "reason": "Business does not meet compliance requirements",
    "status": "rejected",
    "tenantKey": "cad95193904",
    "timestamp": 1765359752
  }
}
```

### business.kyb.completed

Sent when business verification is successful. After receiving this event, the business can process payments.

```json theme={null}
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "eventType": "business.kyb.completed",
  "version": "1.0",
  "timestamp": 1765359752,
  "data": {
    "id": "7c74cc95-d7c6-4537-b388-6d57ed020b34",
    "businessId": "7dd569f9-bd54-4fbb-a5c2-f0aaadc68adf",
    "businessName": "Acme Corporation",
    "status": "complete",
    "timestamp": 1765359752,
    "tenantKey": "cad95193904"
  }
}
```

See [Events](/reference/events) for all event types and [Webhooks](/reference/webhooks) to configure your endpoint.

***

## Timeline

| Step                                    | Duration              |
| :-------------------------------------- | :-------------------- |
| Submit KYB                              | Immediate             |
| Review (once all requirements provided) | Up to 3 business days |

***

## Sandbox Testing

Use test values to simulate different KYB outcomes without waiting for real verification.

| Test value             | Field                                 | Result                                                                          |
| :--------------------- | :------------------------------------ | :------------------------------------------------------------------------------ |
| `000-CAD-AUTO-APPROVE` | `taxIdentificationNumber`             | KYB automatically approved                                                      |
| `000-CAD-AUTO-REJECT`  | `taxIdentificationNumber`             | KYB automatically rejected (terminal)                                           |
| `000-CAD-AUTO-FLAG`    | `taxIdentificationNumber`             | Status set to `needs-additional-info`, requests all business documents          |
| `000-11-2222`          | `principals[].identifier.value` (SSN) | Requires identity documents and address files for the principal                 |
| `000-11-3333`          | `principals[].identifier.value` (SSN) | Status set to `needs-additional-info`, principal receives KYC requirement email |

<Warning>
  These test values only work in the sandbox environment and are silently ignored in production. You can't combine `000-CAD-AUTO-APPROVE` with a sentinel SSN in the same submission — the request returns `400`.
</Warning>

See [Sandbox & Testing](/reference/sandbox#kyb-testing) for all test values.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="KYC Verification" icon="id-card" href="/platform/kyc-verification">
    User identity verification
  </Card>

  <Card title="Multi-Tenant Setup" icon="building" href="/platform/multi-tenant-setup">
    Platform integration guide
  </Card>

  <Card title="Webhooks" icon="bell" href="/reference/webhooks">
    Configure webhook endpoints
  </Card>

  <Card title="Sandbox & Testing" icon="flask-vial" href="/reference/sandbox">
    Test values and simulated scenarios
  </Card>
</CardGroup>
