# Onboarding Businesses

Onboarding a business means completing KYB. Unlike an individual application, which is a single object you fill in and submit, a business application is a **tree**: the business itself, one or more related parties, and a set of document requests that Jiko derives from what you tell it. You submit once, when the whole tree is complete.

When the application reaches `APPROVED`, Jiko creates a **customer**, and the application's `customer_id` is populated. That customer can then hold pockets.

div
## Prerequisites

### Feature flags

Feature flags are set by Jiko per partner and evaluated against the API user making the request. A call that needs a flag you do not have fails with `403`. Ask your Jiko point of contact for the ones you need.

| Flag | Needed for | Without it |
|  --- | --- | --- |
| `non_us_id_citizenships` | Submitting `INTERNATIONAL_ID` identification on a related party. A comma-separated list of ISO 3166-1 alpha-2 citizenship codes; a non-empty list enables the feature, empty or absent disables it | `403` where your partnership has no allowlist at all, and `422` where it has one but the related party's `citizenship` is not on it |


Nothing else about business onboarding is flag-gated. `POST /api/v1/business-applications/` and the rest of the tree are available to every partner.

### Everything else

- **The [Partner Obligations](/products/partner-api/partner-obligation) discharged before you start.** Verify ownership of the phone number and the email address on the application, and display Jiko's agreements — fetched from `GET /api/v1/agreements/` — recording the `version` shown and the timestamp of consent. Re-fetch for every new application; the current version changes, and consent against a stale version is not consent to what Jiko is obliged to have shown. None of this is checked by the API.
- **API credentials for the environment you are calling.** Build against sandbox first: a business application is a tree assembled over several calls, and the document list moves as you fill it in. The [sandbox status simulator](#sandbox-testing) makes every terminal state reachable in seconds.
- **A way to upload PNGs.** Document uploads require a `Content-Type` of `image/png`; anything else is rejected at the header. Convert before you upload.
- **Exactly one related party carrying `CONTROL_PERSON`.** None is `CONTROL_PRONG_MISSING` at submission; more than one is `MULTIPLE_CONTROL_PRONGS`. Both block submission outright.
- **Ownership percentages that add up.** Each related party's `ownership_percentage` is a string parseable to a number between 0 and 1 — `"0.51"` is 51% — and the percentages across active beneficial owners cannot total more than 100%.
- **`agreement_consent` given by a control person or authorized representative.** The API does not check this — `agreement_consent` carries only a version and a timestamp, with no signer field — so enforce it in your own UI and record on your side who accepted.
- **A complete `risk_info` block before you read the document list.** Document requests are derived from the entity type, the industry, the risk categories and the related parties. Read the list thin and it changes under you.
- **Every derived document request uploaded and not `INVALID`.** An `INVALID` document does not fail the application, but the application will not move until it is replaced.
- **A path for answering RFIs.** There is no webhook for an RFI. An application sitting in `MANUAL_REVIEW` with an open RFI is waiting on you, and it waits silently.
- **A webhook subscription** for `application.approved`, `application.manual_review`, `application.documents_needed` and `application.rejected`. The payload is `application_id` only, so each event means "fetch the application" — including the approval, which is the only place `customer_id` appears. Subscriptions are recorded against the API user that creates them.


## The shape of the flow

1. **Create the business application.** `POST /api/v1/business-applications/`
2. **Add related parties.** Every control person and authorized representative gets their own application.
3. **Read the document requests.** Jiko derives them from the entity type and the risk answers — you cannot know them up front.
4. **Upload each document.**
5. **Submit.** `POST /api/v1/business-applications/{application_id}/apply/`
6. **Respond to RFIs**, if Jiko's review raises any.
7. **Wait for a terminal status**, delivered by webhook.


Steps 1–4 are incremental. The application starts in `CREATED` and every field is optional on the create call, so you can build it up over repeated `PATCH /api/v1/business-applications/{application_id}/` calls as your own UI collects the data. Validation of completeness happens at submission, not at creation. Related parties can be updated and deleted the same way, right up until you submit.

**Step 4 is a loop.** Supplying the last outstanding document does not resume the review: the application moves from `DOCUMENTS_NEEDED` to `PENDING`, which means "nothing is outstanding, and Jiko is waiting for you to resubmit". You call `apply` again. An application parked in `PENDING` is waiting on you, and no webhook will say so.

### Relevant API endpoints

| Step | Purpose | Endpoint |
|  --- | --- | --- |
| 1 | Fetch the agreements to display | GET `/api/v1/agreements/` |
| 2 | Create the business application | POST `/api/v1/business-applications/` |
| 3 | Add fields incrementally as your UI collects them | PATCH `/api/v1/business-applications/{application_id}/` |
| 4 | Add a related party | POST `/api/v1/business-applications/{application_id}/related-party-applications/` |
| 5 | Correct or remove a related party before submission | PATCH / DELETE `/api/v1/business-applications/{application_id}/related-party-applications/{related_party_application_id}/` |
| 6 | Read the derived document checklist | GET `/api/v1/business-applications/{application_id}/documents/` |
| 7 | Upload a document (`Content-Type: image/png`) | POST `/api/v1/documents/{document_id}/` |
| 8 | Submit, and resubmit after a `DOCUMENTS_NEEDED` round | POST `/api/v1/business-applications/{application_id}/apply/` |
| 9 | Read the status and, on approval, `customer_id` | GET `/api/v1/business-applications/{application_id}/` |


## Create the business application

```
POST /api/v1/business-applications/
```

| Field | Notes |
|  --- | --- |
| `id` | Optional client-supplied UUID |
| `name` | Legal name |
| `entity_type` | `SOLE_PROPRIETOR`, `CORPORATE`, `LLC`, `PARTNERSHIP`, `INCORPORATED_ASSOCIATION`, `UNINCORPORATED_ASSOCIATION`, `NON_BANK_FINANCIAL_INSTITUTION`, `NON_PROFIT`, `TRUST` and others |
| `doing_business_as` | DBA name, where it differs from the legal name |
| `identification_number` | EIN or equivalent |
| `address` | ISO-format address |
| `website` |  |
| `contact` | Business contact — name, email, phone |
| `formation_date` |  |
| `industry` | An `industry` code, plus `other_industry` free text when the code is "other" |
| `risk_info` | See below |
| `agreement_consent` | Consent to Jiko's agreements. See [Who may consent to the agreements](#who-may-consent-to-the-agreements) |


### `risk_info` drives the rest of the application

This block is what determines which documents Jiko asks for and whether the application routes to manual review. Fill it in properly and the document list settles early; leave it thin and the list changes under you.

These are always required: `business_activity_location`, `account_usage`, `monthly_transactions`, `first_month_deposit`, `source_of_funds`, `annual_revenue` and `company_mission`.

These become required depending on what else you sent:

| When | Also required |
|  --- | --- |
| `risk_categories` contains `CRYPTOCURRENCY` | `has_current_enforcement_actions` |
| `risk_categories` contains `FINANCIAL_OR_MONEY_MOVEMENT` | `has_current_enforcement_actions` and `primary_regulator` |
| `source_of_funds` is `CLIENT_OR_EXTERNAL_FUNDS` | `source_of_funds_explanation` |


`primary_regulator` is a free-text string in the API, but the answers Jiko expects are a short set: `FRB`, `OCC`, `FDIC`, `FINRA`, `CFTC`, `FinCEN (MSB registration)`, `State regulatory agency`, `Other`. Offer those rather than an open box.

| Field | Values |
|  --- | --- |
| `risk_categories` | `INTERNET_GAMBLING`, `CANNABIS`, `CRYPTOCURRENCY`, `CROWDFUNDING`, `FINANCIAL_OR_MONEY_MOVEMENT`, `NON_US_ENTITY`, `FINTECH_OR_BAAS` |
| `company_mission` | Free text |
| `has_current_enforcement_actions` | Boolean |
| `primary_regulator` | Free text; see the accepted answers above |
| `business_activity_location` | `PRIMARILY_US`, `MIX_OF_US_AND_NON_US`, `PRIMARILY_NON_US` |
| `source_of_funds` | `INTERNAL_FUNDS`, `CLIENT_OR_EXTERNAL_FUNDS`, `CRYPTOCURRENCY_EXCESS_RESERVES` and others, with `source_of_funds_explanation` |
| `account_usage` | `MONEY_STORAGE`, `MONEY_STORAGE_US_BANKS`, `MONEY_STORAGE_NON_US_BANKS`, `CRYPTOCURRENCY_EXCESS_RESERVES` and others |
| `annual_revenue` | Banded, for example `PRE_REVENUE` |
| `monthly_transactions` | Banded |
| `first_month_deposit` | Banded |
| `is_finra_registered_broker_dealer` | Boolean |


Declaring `CRYPTOCURRENCY` as a risk category, for instance, pulls in a distinct set of document requests — legal analysis of the business model, coins and tokens listed, coin rating policy, blockchain analytics used, market manipulation policy, BSA/AML/OFAC policies, independent AML audit report, internal risk assessment. Those requests do not appear until the category is declared.

## Related party applications

```
POST /api/v1/business-applications/{application_id}/related-party-applications/
GET  /api/v1/business-applications/{application_id}/related-party-applications/
GET  /api/v1/business-applications/{application_id}/related-party-applications/{related_party_application_id}/
```

| Field | Notes |
|  --- | --- |
| `name` |  |
| `address` | ISO-format address |
| `date_of_birth` |  |
| `identification_number` | SSN, passport, TIN, driver's license or international ID. Returned masked |
| `phone_number` | E.164 |
| `email` |  |
| `title` | Their role in the business, free text |
| `roles` | `CONTROL_PERSON` and/or `AUTHORIZED_REPRESENTATIVE` — the only two values the API accepts |
| `ownership_percentage` | A string parseable to a number between 0 and 1. `"0.51"` is 51% |
| `citizenship` | ISO 3166 country code |


`address.state` is required only when `address.country` is `US`.

There are only two roles, so a beneficial owner or a member of senior management who is neither the control person nor an authorized representative is still registered as a related party — recorded through `title` and `ownership_percentage` rather than through a role of their own.

### The identification number is masked, and that is a trap on update

`identification_number` comes back masked on every read — `*****6789`. There is no way to read the real value back.

The consequence: **do not echo it into a `PATCH`.** An update that sends the object you just fetched will write the mask over the real number, and the application then carries `*****6789` as the related party's identification. Send only the fields you are actually changing.

**Exactly one related party must carry `CONTROL_PERSON`.** Submitting with none, or with more than one, is rejected — the submission exception reasons are explicit about this: `CONTROL_PRONG_MISSING` and `MULTIPLE_CONTROL_PRONGS`.

### Who may consent to the agreements

The `agreement_consent` on the business application may only be given by a related party holding the `CONTROL_PERSON` or `AUTHORIZED_REPRESENTATIVE` role.

The API does not check this. `agreement_consent` carries only a `version` and a `timestamp` — there is no signer field, and submission does not compare the consent against the related parties. Enforce it in your own UI: present the agreements only to a party carrying one of those roles, and record on your side who accepted them.

### Non-US identification

`INTERNATIONAL_ID` is accepted as an identification type for a related party only where the party's citizenship is on your partnership's allowlist. Outside that allowlist, an international ID is rejected at validation. If you onboard non-US control persons, confirm the allowlist with your Jiko point of contact before building the form.

## Document requests

```
GET /api/v1/business-applications/{application_id}/documents/
```

Document requests are **derived**, not chosen. They depend on the entity type, the industry, the risk categories and the related parties you have entered, so the list is only meaningful once the rest of the application is filled in. Read it, do not hard-code it.

The set spans entity-formation documents (`ARTICLES_OF_INCORPORATION`, `OPERATING_AGREEMENT`, `PARTNERSHIP_AGREEMENT`, `BYLAWS`, `ARTICLES_OF_ORGANIZATION`, `CORPORATE_CHARTER`, `TRUST_FORMATION_RECORDS`, `LIST_OF_TRUSTEES`, `TRUST_VERIFICATION_DOCUMENT`, `PROOF_OF_501_STATUS`, `CERTIFICATE_OF_GOOD_STANDING`), identity documents for related parties (`ID_FRONT`, `ID_BACK`, `PASSPORT`, `SELFIE`, `ADDRESS_VERIFICATION`, `IDENTIFICATION_NUMBER_VERIFICATION`), financial documents (`BANK_STATEMENTS_1`–`3`, `FLOW_OF_FUNDS`, `EIN_CONFIRMATION`, `ORG_CHART`, `BUSINESS_DESCRIPTION`) and the risk-driven policy documents above.

Upload against the document's own ID:

```
POST /api/v1/documents/{document_id}/
```

Uploads must carry `Content-Type: image/png`. The header is pattern-matched, so a JPEG or a PDF is rejected before the file is read — worth knowing early, because most of what a business will hand you is a PDF.

Each document carries a status: `PENDING_UPLOAD` → `PENDING_REVIEW` → `APPROVED` or `INVALID`. An `INVALID` document needs to be re-uploaded; it does not fail the application on its own, and it carries an `exception_reason` saying what was wrong with it. Surface that to whoever is uploading.

You do not have to wait for review to finish before submitting. The bar is that every request is `APPROVED` **or** `PENDING_REVIEW` — that is, nothing is still `PENDING_UPLOAD` or `INVALID`.

**One set of requests is an either/or.** Where `INTERNAL_KYC_AUDIT`, `EXTERNAL_KYC_AUDIT` and `KYC_POLICIES_AND_PROCEDURES` are all requested, the business satisfies them with either `EXTERNAL_KYC_AUDIT` on its own, or `INTERNAL_KYC_AUDIT` together with `KYC_POLICIES_AND_PROCEDURES`. A UI that insists on all three will block a business that has done nothing wrong.

## Submit

```
POST /api/v1/business-applications/{application_id}/apply/
```

Submit only when the business application, every related party application and every document request are complete. If anything is missing, the response tells you exactly what, via `exception_reasons`:

`NAME_MISSING`, `DATE_OF_BIRTH_MISSING`, `ADDRESS_MISSING`, `PHONE_NUMBER_MISSING`, `EMAIL_MISSING`, `AGREEMENT_CONSENT_MISSING`, `ENTITY_TYPE_MISSING`, `FORMATION_DATE_MISSING`, `INDUSTRY_MISSING`, `OTHER_INDUSTRY_MISSING`, `BUSINESS_CONTACT_MISSING`, `RISK_PROFILE_MISSING`, `RISK_CATEGORY_MISSING`, `COMPANY_MISSION_MISSING`, `ACCOUNT_USAGE_MISSING`, `PRIMARY_REGULATOR_MISSING`, `SOURCE_OF_FUNDS_MISSING`, `RELATED_PARTIES_INCOMPLETE`, `CONTROL_PRONG_MISSING`, `MULTIPLE_CONTROL_PRONGS`, `CITIZENSHIP_MISSING`, `ROLES_MISSING`.

Surface these to whoever is filling in your form. They map one-to-one onto fields.

## Lifecycle

| Status | Meaning | Who it is waiting on |
|  --- | --- | --- |
| `CREATED` | Being filled in. Not yet submitted | You |
| `SUBMITTED` | Submitted, under evaluation | Jiko |
| `DOCUMENTS_NEEDED` | Jiko needs more documents. Read the checklist and upload | You |
| `PENDING` | Every outstanding document has been supplied. **Call `apply` again** | You |
| `MANUAL_REVIEW` | Under human review at Jiko | Jiko |
| `APPROVED` | KYB passed. A customer now exists; read `customer_id`. Terminal | — |
| `REJECTED` | KYB failed. Terminal | — |
| `CLOSED` | Closed for inactivity. Terminal | — |


`PENDING` is the one to read carefully. It does not mean "in processing" — it is where an application lands once you have cleared the document requests, and it moves no further until you resubmit. `CLOSED` is worth designing for too: an application that nobody finishes does not sit in `CREATED` forever.

## Sandbox testing

In sandbox the business's `identification_number` — the EIN — decides the outcome, so every status is reachable without real KYB. The first digit controls what happens on the first `apply`:

| Prefix | Status after `apply` |
|  --- | --- |
| `2` | `DOCUMENTS_NEEDED` |
| `4` | `APPROVED` |
| `5` | `REJECTED` |
| Anything else | `MANUAL_REVIEW` |


A `2` behaves differently on the way back than the individual path does. Once you have uploaded the requested documents and applied again, a business application goes to `MANUAL_REVIEW` — not to `APPROVED`. To reach an approved business customer in sandbox, start from a `4`.

Sandbox appends a unique suffix to the identification number you submit, so the same EIN can be reused across applications without colliding. The number you read back is therefore not the one you sent.

## Requests for information (RFIs)

Where review needs something a document request cannot express, Jiko opens an RFI — a message thread on the application.

```
GET  /api/v1/business-applications/{application_id}/rfis/
GET  /api/v1/business-applications/{application_id}/rfis/{rfi_id}/
POST /api/v1/business-applications/{application_id}/rfis/{rfi_id}/messages/
POST /api/v1/business-applications/{application_id}/rfi-messages/{message_id}/documents/
GET  /api/v1/business-applications/{application_id}/rfi-messages/{message_id}/documents/{document_id}/
```

An RFI moves through `CREATED` → `REQUESTED` → `ANSWERED` → `APPROVED` or `REJECTED`, and can be `CANCELED`. Messages are typed `OPS` (from Jiko) or `CUSTOMER` (from you), and a message can carry documents.

An application sitting in `MANUAL_REVIEW` with an open RFI is waiting on **you**, not on Jiko. Poll the RFI list, or surface the thread into your own support tooling, or the application stalls silently.

## Webhooks

| Event | Meaning |
|  --- | --- |
| `application.approved` | KYB passed; a customer exists |
| `application.manual_review` | Routed to human review |
| `application.documents_needed` | More documents required |
| `application.rejected` | KYB failed |


Payload: `application_id`. Fetch the application to learn what changed and, on approval, to read `customer_id`.

There is **no event for an RFI**. RFIs must be polled.

## After approval

The application's `customer_id` is the handle for everything downstream:

```
GET  /api/v1/customers/{customer_id}/
POST /api/v2/customers/{customer_id}/pockets/
GET  /api/v2/customers/{customer_id}/pockets/
```

### An approved customer does not necessarily have a pocket

For most partnerships, approval creates the **customer** and nothing else. Opening a pocket is a call you make.

Automatic pocket-and-portal creation at approval does exist, but it is a legacy behavior limited to an explicit allowlist of partner IDs held in Jiko's configuration. If your partnership is on that list, an approved customer already has a pocket and a virtual bank account portal with a routing and account number. If it is not, `GET /api/v2/customers/{customer_id}/pockets/` comes back empty and stays empty until you create one. Ask your Jiko point of contact which case applies, and read the pocket list rather than assuming either answer.

A customer may hold up to **20 pockets per partner** by default. The limit counts every pocket ever created for that customer, **including closed ones** — closing a pocket does not free a slot. Create pockets for durable purposes; do not use them as per-transaction or per-invoice containers. Portals, which are uncapped on the bank rails, are the right tool for that.

## Endpoints

| Operation | Endpoint |
|  --- | --- |
| List agreements to display | `GET /api/v1/agreements/` |
| Create a business application | `POST /api/v1/business-applications/` |
| Get a business application | `GET /api/v1/business-applications/{application_id}/` |
| Update a business application | `PATCH /api/v1/business-applications/{application_id}/` |
| Create a related party application | `POST /api/v1/business-applications/{application_id}/related-party-applications/` |
| List related party applications | `GET /api/v1/business-applications/{application_id}/related-party-applications/` |
| Get a related party application | `GET /api/v1/business-applications/{application_id}/related-party-applications/{related_party_application_id}/` |
| Update a related party application | `PATCH /api/v1/business-applications/{application_id}/related-party-applications/{related_party_application_id}/` |
| Delete a related party application | `DELETE /api/v1/business-applications/{application_id}/related-party-applications/{related_party_application_id}/` |
| List document requests | `GET /api/v1/business-applications/{application_id}/documents/` |
| Upload a document | `POST /api/v1/documents/{document_id}/` |
| Submit | `POST /api/v1/business-applications/{application_id}/apply/` |
| List / get RFIs | `GET /api/v1/business-applications/{application_id}/rfis/` |
| Reply to an RFI | `POST /api/v1/business-applications/{application_id}/rfis/{rfi_id}/messages/` |


## See also

- [Onboarding individuals](/products/partner-api/guides/building/onboarding-individuals)
- [Partner Obligations](/products/partner-api/partner-obligation) — phone, email, disclosures, identity proofing
- [Businesses reference](/products/partner-api/reference/businesses)
- [Pockets](/products/partner-api/reference/pockets/list-pockets-v2)
- [Webhooks](/products/partner-api/guides/building/webhooks)