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

# Register & Verify Businesses

> How business registration and KYB verification work end to end: what you need in place, the sequence of calls, and how to track an application to a decision.

## Overview

Fluz KYB (Know Your Business) lets your platform onboard a business onto Fluz rails from your own UI. Across a small set of operations you:

1. Resolve the business category and sub-category the entity trades under,
2. Submit the legal entity record — legal name, structure, tax ID, state of incorporation, legal address, and intended use of the account — together with the beneficial ownership roster,
3. Get identity verification completed for the owners who require it, and
4. Track the resulting **KYB case** to an approval or a decline.

The submission itself is a single mutation, [registerBusiness](/business-registration). It returns an `accountId` immediately with a `kybStatus` of `SUBMITTED`.

<Note>
  **Registration is validation, not approval.** A `success` response confirms the payload passed validation and a KYB case was opened. It does **not** mean the business is approved. Build your integration so it waits for an approved status before attempting to fund the account or issue cards.
</Note>

### What a business account unlocks

Once KYB is approved, the business account can be used for the commercial side of the platform:

* Business spend accounts and balances
* Commercial virtual cards, including bulk issuance
* Authorized users and card-level spend controls
* Approval workflows for cards, transfers, and reimbursements
* Business-level transaction reporting and expense annotation

### When to use these endpoints

Use this flow when you want to collect entity and ownership data in your own UI rather than sending users into a Fluz-hosted experience. If you would rather Fluz host the collection and document upload, talk to your account manager about the widget-based onboarding option instead.

***

## KYB flow

### Step-by-step

<Steps>
  <Step title="Step 0 — Satisfy the prerequisites">
    None of this is part of the flow, but all of it must be true before you call `registerBusiness`. Each row links to the detail below. See [prerequisites](#prerequisites)
  </Step>

  <Step title="Resolve the business category and sub-category">
    Call [getBusinessCategories](/business-categories) and let the user pick a category and one of that category's sub-categories.
  </Step>

  <Step title="Upload an authorized-signer document, if applicable">
    Required only when the applicant owns less than 25% of the business **and** is not the control person. Upload the document first, then pass the returned URL in `authorizedSignerDocumentUrl`. See [Submit business documents](/submit-business-documents).
  </Step>

  <Step title="Submit the registerBusiness mutation">
    Send the full entity record, the ownership certifications, and every owner in one call. Validation errors are returned inside the payload — see [Response details](/business-registration#response-details).
  </Step>

  <Step title="Get the remaining owners verified">
    Read [getBusiness](/business-status) to see each owner's expected verification and current progress. For owners on the document path, generate a link with [requestOwnerDocumentVerificationLink](/owner-verification-link) and send it to them. Invited owners are emailed by Fluz and verify themselves.
  </Step>

  <Step title="Wait for the KYB decision, then provision">
    The application starts under review. Surface that state to your user rather than implying they are live. Once the status moves to `APPROVED`, create spend accounts and issue cards.
  </Step>
</Steps>

### End-to-end sequence

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant App as Your Application
    participant API as Fluz GraphQL API
    participant Files as Fluz File Upload (REST)
    participant KYB as Fluz Compliance / KYB
    participant Owner as Business Owner

    Note over App,API: Step 0 — the applicant is already a verified Fluz user
    App->>API: query getBusinessCategories
    API-->>App: businessCategoryId + businessSubCategoryId values

    opt Applicant is an authorized signer
        App->>Files: Upload authorization document
        Files-->>App: document URL
    end

    Note over App,API: Step 1 — submit the business
    App->>API: mutation registerBusiness(input)
    alt Validation fails
        API-->>App: success false, with error code and message
        App->>App: Correct the field and resubmit
    else Validation passes
        API-->>App: accountId plus kybStatus SUBMITTED
        API->>KYB: Open KYB case
    end

    Note over App,Owner: Step 2 — owners verify identity
    opt Owner must verify by document
        App->>API: requestOwnerDocumentVerificationLink
        API-->>App: verificationLink
        App->>Owner: Forward the link
        Owner->>KYB: Completes verification
    end

    Note over KYB,App: Step 3 — asynchronous review
    KYB->>KYB: Entity, tax ID, address, and owner checks
    KYB-->>API: Decision (or request for more documentation)
    App->>API: KYB_STATUS_UPDATE webhook, or query getBusiness
    API-->>App: Updated KYB status and owner roster

    Note over App,API: Step 4 — go live
    App->>API: Create spend accounts and issue cards
```

***

## Prerequisites

| Prerequisite                                                                                                  | If missing  |
| ------------------------------------------------------------------------------------------------------------- | ----------- |
| Your application requests the [`REGISTER_BUSINESS` permission scope](#application-permission-scopes)          | `AUTH-0031` |
| The applicant has [authorized your application](#applicant-authorization) for the business scopes it requests | `AUTH-0008` |
| The applicant is [already CIP verified](#the-applicant-must-already-be-identity-verified)                     | `ARG-0001`  |
| The applicant has [no KYB application already in flight](#one-open-application-per-user)                      | `BS-0007`   |
| You hold [a Bearer token of the account type each operation requires](#access-tokens)                         | `AUTH-0002` |
| An authorized-signer document is uploaded, if the applicant is an authorized signer                           | `ARG-0001`  |
| The business legal address is a real, verifiable address                                                      | `BS-0002`   |

### Application permission scopes

Select **`REGISTER_BUSINESS`** in your application's permission scopes in the Fluz dashboard. Every KYB operation requires it, and a token can only carry scopes your application is configured to request. See [Application Scopes](/fluz-dashboard/application-scopes).

Subscribing to the [`KYB_STATUS_UPDATE` webhook](#tracking-an-application) requires the same scope.

### Applicant authorization

The applicant must have completed OAuth authorization for your application, and that authorization must cover every business scope your application requests. If you later add a scope, existing users have to re-authorize before they can register a business — otherwise registration fails with `AUTH-0008`.

### The applicant must already be cip-verified

The Bearer token identifies the **applicant**: the user submitting the application. Exactly one owner in the roster must match the token's user by **email** (case-insensitive) or **phone number**, and that owner cannot be marked `isInvited: true`.

KYB verifies the business and the *other* owners. It does not verify the applicant, so the applicant must reach a verified state beforehand. The `isUsPerson` value you send for them decides which check applies:

| Applicant `isUsPerson` | Required state before registration                                |
| ---------------------- | ----------------------------------------------------------------- |
| `true`                 | A successful SSN (CIP) verification already on file for that user |
| `false`                | A successful Document verification                                |

Identity verification happens outside the KYB surface, with the `VERIFY_KYC` scope, using `verifyUserInformation`, `verifyUserPrefillInformation`, or `requestDocumentVerificationLink`. See [identity verification (KYC)](/docs/user-kyc-verification). If the person has no Fluz account at all yet, create one with [registerUser](/user-registration) first.

### One open application per user

A user cannot start a new registration while an existing application is still open — that returns `BS-0007`.

<Warning>
  There is no idempotency key and no API to cancel an in-flight application. A rejected application leaves nothing behind and can be resubmitted, but a **successful** one blocks the user from registering again until it resolves. Validate before submitting, and contact your account manager with the `accountId` if a case appears stalled.
</Warning>

### Access tokens

Each operation requires a Bearer token of a specific account type:

| Operation                                                        | Token account type | Required scope      |
| ---------------------------------------------------------------- | ------------------ | ------------------- |
| [getBusinessCategories](/business-categories)                    | `CONSUMER`         | `REGISTER_BUSINESS` |
| [registerBusiness](/business-registration)                       | `CONSUMER`         | `REGISTER_BUSINESS` |
| [getBusiness](/business-status)                                  | `BUSINESS`         | `REGISTER_BUSINESS` |
| [requestOwnerDocumentVerificationLink](/owner-verification-link) | `BUSINESS`         | `REGISTER_BUSINESS` |

<Note>
  Mint Bearer tokens with `generateUserAccessToken` — see the Authentication section of the API reference.
</Note>

***

## KYB status lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> SUBMITTED: registerBusiness returns accountId
    SUBMITTED --> PENDING: Case under review
    PENDING --> PENDING: Owners still verifying, or more documentation requested
    PENDING --> APPROVED: Entity and ownership checks cleared
    PENDING --> DECLINED: Checks not cleared
    APPROVED --> [*]: Business can transact
    DECLINED --> [*]: New submission required
```

| Status      | What it means                                                                                                      | What your app should do                                                                     |
| ----------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| `SUBMITTED` | Returned by `registerBusiness` only. The submission was accepted and a KYB case was opened.                        | Store the `accountId`. Show an "under review" state.                                        |
| `PENDING`   | Reported by `getBusiness`. The case is under review, awaiting screening results, or waiting on an owner to verify. | Keep tracking. Do not attempt to fund the account or issue cards.                           |
| `APPROVED`  | KYB cleared. The business account is usable.                                                                       | Provision spend accounts, issue cards, unlock your business UI.                             |
| `DECLINED`  | KYB did not clear.                                                                                                 | Surface a neutral message and direct the user to support. Do not auto-retry the submission. |

<Note>
  `SUBMITTED` is only ever returned by `registerBusiness`. [getBusiness](/business-status) reports a three-value status, and the state immediately after registration reads as `PENDING` there — the two are the same moment described with different vocabulary.
</Note>

***

## Tracking an application

Two ways to follow an application to its final status. Use whichever fits your infrastructure; many integrations use the webhook for latency and an occasional read for reconciliation.

<Tabs>
  <Tab title="Webhook">
    Subscribe to the **`KYB_STATUS_UPDATE`** event in the Fluz dashboard: register your callback URL and select the event. Your application needs the `REGISTER_BUSINESS` scope to subscribe.

    Fluz `POST`s to your endpoint when a business's KYB status changes.

    ```json theme={null}
    {
      "accountId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "previousStatus": "PENDING",
      "newStatus": "APPROVED",
      "externalReferenceId": "your-partner-user-id-123"
    }
    ```

    | Field                 | Type     | Description                                                                                  |
    | --------------------- | -------- | -------------------------------------------------------------------------------------------- |
    | `accountId`           | `UUID`   | The business account whose status changed — the same `accountId` `registerBusiness` returned |
    | `previousStatus`      | `String` | Status before the change: `PENDING`, `APPROVED`, or `DECLINED`                               |
    | `newStatus`           | `String` | Status after the change: `PENDING`, `APPROVED`, or `DECLINED`                                |
    | `externalReferenceId` | `String` | Your own reference, when you supplied one at registration. Omitted otherwise                 |

    Two things to handle:

    * **Treat delivery as at-least-once.** Make your handler idempotent, keyed on `accountId` plus `newStatus`.
    * **You may receive events where `previousStatus` equals `newStatus`.** The case moved between internal states that both surface as the same public status. Treat those as no-ops.

    <Note>
      The payload carries the business status only — it does not include the owner roster. Call [getBusiness](/business-status) when you need per-owner progress.
    </Note>
  </Tab>

  <Tab title="Reading status directly">
    Call [getBusiness](/business-status) with a business-account token. It returns the same `kybStatus` plus the current owner roster, which makes it the only way to see whether an individual owner still needs to verify.

    ```graphql theme={null}
    query GetBusiness {
      getBusiness {
        accountId
        kybStatus
        owners {
          id
          name
          verificationType
          status
        }
      }
    }
    ```

    Read it when the user returns to your business onboarding screen, and on a low-frequency background schedule — hourly, not per page load. Keep going until `kybStatus` is final **and** every owner reports `READY`.
  </Tab>
</Tabs>

<Info>
  Reviews are typically resolved within one to two business days, but can take longer when additional documentation is requested or an owner has not completed their identity verification. If a case appears stalled, contact your account manager with the `accountId` rather than resubmitting — a second submission will be blocked by `BS-0007`.
</Info>

***

## Identifying businesses with `externalReferenceId`

Fluz identifies a business by its `accountId`, a UUID minted at registration. `externalReferenceId` is an optional identifier **you** supply instead, so you can work with Fluz using the ID your own system already uses for that customer.

Pass it once, on [registerBusiness](/business-registration):

```json theme={null}
{ "externalReferenceId": "your-partner-user-id-123" }
```

It is stored on the business account and gives you three things:

* **Token minting without storing Fluz IDs.** Mint a business-account access token by reference instead of by `userId` and `accountId`.
* **Webhook correlation.** The reference comes back on every [`KYB_STATUS_UPDATE`](#tracking-an-application) event, so you can match an event to your own record without a lookup table.

It is optional. If you omit it, everything works — you just have to store the `accountId` yourself, which you should do regardless.

### Rules

| Scenario                                                  | Result                                                                                                                  |
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Omitted                                                   | The business account is created without an external reference                                                           |
| Provided, not already in use                              | The reference is stored on the new business account                                                                     |
| Provided, already on the applicant's own consumer account | The reference moves off the consumer account onto the new business account, so it resolves to the business from then on |
| Provided, already on another business                     | Registration fails with `AUTH-0008`. The existing business keeps the reference                                          |

<Warning>
  **Use one unique value per business.** A reference can only point at one business account, so reusing a value across two businesses fails the second registration. Derive it from your own primary key rather than from something reusable like an email address.
</Warning>

<Note>
  Two different references are in play and they are easy to conflate. The reference **already carried by your access token** is used to locate the applicant's existing authorization. The reference **in the `registerBusiness` input** is the one written onto the new business account. They serve different purposes.
</Note>

***

## Related pages

<CardGroup cols={2}>
  <Card title="Register a business" icon="building" href="/business-registration">
    The `registerBusiness` mutation: full parameter reference, ownership rules, and error codes.
  </Card>

  <Card title="Business categories" icon="list" href="/business-categories">
    Fetch the category and sub-category IDs required by the mutation.
  </Card>

  <Card title="Submit business documents" icon="file-arrow-up" href="/submit-business-documents">
    Upload authorization documents and respond to KYB documentation requests.
  </Card>

  <Card title="Business KYB status" icon="arrows-rotate" href="/business-status">
    Read KYB status and per-owner verification progress.
  </Card>

  <Card title="Owner verification link" icon="id-card" href="/owner-verification-link">
    Generate a shareable identity-verification link for an owner.
  </Card>

  <Card title="Register customers" icon="user-plus" href="/user-registration">
    Create the Fluz user who will act as the applicant.
  </Card>
</CardGroup>
