> ## 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/businesses/get-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 6 hours after creation (`expiresAt`). If the business owner visits an expired link, they are redirected to your `refreshURL` where you can generate a new link. Progress is saved as the owner completes each step, so a new link resumes where they left off.
</Note>

<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 using the PATCH endpoint.

<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`. Use [`PATCH /v1/businesses/{businessId}/kyb`](/api-reference/workforce/businesses/update-kyb) to fill in scalar fields, but note that PATCH cannot **add** principals — to add a principal, re-`POST` the full submission (allowed while the status is `initialized`, `incomplete`, `awaiting-principal-kyc`, or `needs-additional-info`). A re-`POST` replaces the entire principal list.
</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/businesses/submit-kyb" />

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

### Updating KYB Information

Use PATCH to add or correct fields after the initial submission. 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/businesses/update-kyb" />

<Warning>
  When updating principals in a PATCH request, you **must** include the principal's `id` (returned from [GET KYB](#check-kyb-status)). PATCH can only update existing principals — a principal with an unknown `id` is silently ignored (the request still returns `204`), 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>

### 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/businesses/get-kyb-for-a-business" />

**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

You must provide information for individuals 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.

| 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`                        | Type: `ssn` or `passport`              |
| 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 SSN verification fails     |
| ID document (back)  | `principals[].identifier.identityBackPageFileId` | Required if SSN 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.

***

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

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