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

# Integrate customer onboarding and verification

> A copy-paste prompt that builds Lumx KYC and KYB end to end — terms, documents, associated parties, RFI, and the sandbox sentinels to test it.

Paste this prompt into your coding agent to onboard businesses and individuals up to an approved customer that can move money. The agent creates the customer, collects terms, the questionnaire, and documents, registers associated parties for businesses, and drives verification to a final status.

## Before you start

* A Sandbox API key. See [Authentication](/get-started/authentication).
* A page on your own domain to host the terms of service redirect.
* A webhook endpoint registered under **Developers > Webhooks** in the [Dashboard](https://dashboard.lumx.io). See [Webhooks](/developer/webhooks).

## Prompt

```text Prompt theme={null}
You are a senior backend engineer building Lumx customer onboarding — KYB for businesses, KYC for individuals — inside an existing product.

Ground truth. Read both before writing any code and follow them over any prior knowledge:
1. https://docs.lumx.io/llms.txt — the documentation index. Every page has a .md twin at its own path.
2. https://lumx-docs-public-prod.s3.us-east-1.amazonaws.com/api-production.yaml — the OpenAPI 3.1 spec. Every enum below is long and closed; read it from the spec rather than from memory.

Work against sandbox at https://api-sandbox.lumx.io with a server-side key sent as "Authorization: Bearer <key>".

1. Create the customer with POST /customers. The body is a union on type and both branches require email and country: BUSINESS adds legalName, taxId and incorporationDate, INDIVIDUAL adds name, taxId and birthDate. Each branch keeps its required list in an allOf sibling rather than on the branch itself, so read it there — the branch alone declares nothing required. INDIVIDUAL country is an enum with a single value today (BRA) while BUSINESS country is a free string; do not widen the individual form past the enum. Request fiat currencies in "accounts" in the same call.
2. Get terms accepted with POST /customers/{id}/tos. It returns a url and an expiresAt — redirect a human to it and handle the expiry, do not automate acceptance.
3. Send the questionnaire with PATCH /customers/{id}/additional-information. It is a union on type and the enums are closed: jurisdictions, involvedActivities, transactionCounterparties, sourceOfFunds, and companyType for businesses. Build your form from the spec values.
4. Upload documents with POST /customers/{id}/documents as multipart with file, type from the document enum and country (ISO alpha-3). Add side for ID_CARD, PASSPORT and DRIVERS_LICENSE, and associatedPartyId when the document belongs to an associated party.
5. For a business, register every UBO, shareholder and representative with POST /customers/{id}/associated-parties, then start review with POST /customers/{id}/verifications and send no body. The spec says associatedPartyIds retries named parties in isolation and does not restart the customer's overall verification, so it is not how you open the first review.
6. Keep the two vocabularies apart. The webhook events are customer.created, customer.under_verification, customer.rfi, customer.approved and customer.final_rejection; polling GET /customers/{id} gives verification.status, whose spec enum is NOT_STARTED, UNDER_VERIFICATION, APPROVED, TEMPORARY_REJECTION and FINAL_REJECTION. There is no created state and no RFI string in that enum — the docs call that same state RFI. Do not match an event name against a status field, and flag the naming conflict instead of choosing a side. The state is resumable; FINAL_REJECTION is terminal.
7. Test every branch in sandbox with the taxId sentinel: last digit 1 gives NOT_STARTED, 2 gives the RFI state the spec enum calls TEMPORARY_REJECTION, 3 gives FINAL_REJECTION, any other digit gives APPROVED.

Constraints:
- Never hardcode an enum you did not read in the spec today. Flag any value your form needs that is not there.
- Wallets are absent from the create response by design. Read them from GET /customers/{id} or wait for customer.approved.
- Do not state a rate limit. None is published. Handle 429 TOO_MANY_REQUESTS with exponential backoff.

Deliverables:
- A typed onboarding client covering the seven endpoints above.
- A resumable state machine with an explicit RFI path.
- A sandbox suite that drives all four sentinel outcomes.
```

## How to use

1. Decide first whether you onboard businesses, individuals, or both — the two paths differ in required fields and in which documents a reviewer will ask for.
2. Host the terms redirect yourself. The agent builds the handler, but the URL has to live on a domain your customers already trust.
3. Run the sandbox suite before you show the form to anyone: the `RFI` branch is the one real onboarding hits and the one teams skip.

## What the prompt builds

| **Endpoint** | **What the agent uses it for** |
| :- | :- |
| `POST /customers` | Creates a business or individual customer |
| `POST /customers/{id}/tos` | Returns the terms of service link and its expiry |
| `PATCH /customers/{id}/additional-information` | Sends the onboarding questionnaire |
| `POST /customers/{id}/documents` | Uploads identity and company documents |
| `POST /customers/{id}/associated-parties` | Registers UBOs, shareholders, and representatives |
| `POST /customers/{id}/verifications` | Submits the customer for review |
| `GET /customers/{id}` | Reads the verification status |

## Errors to expect

These codes come from the [errors catalog](/developer/errors), for the resources this prompt uses. Match on `code`, not on `message`.

| **Code** | **Status** | **When it happens** |
| :- | :- | :- |
| `VALIDATION_ERROR` | 400 | Request body failed validation. Details in `validationErrors`. |
| `CUSTOMER_NOT_FOUND` | 404 | Customer does not exist. |
| `CUSTOMER_LIMIT_REACHED` | 403 | Project reached its maximum number of customers. |
| `RESOURCE_ALREADY_EXISTS` | 409 | A resource with the same unique value already exists. |
| `INVALID_OR_EXPIRED_TOKEN` | 401 | Terms of service token is invalid or expired. |

## Related resources

<CardGroup cols={2}>
  <Card title="Create a customer" href="/guides/create-a-customer">
    The first call in every integration.
  </Card>

  <Card title="Identity verification" href="/compliance/identity-verification">
    KYC, KYB, and sandbox outcomes.
  </Card>

  <Card title="Integrate local-currency virtual accounts" href="/prompts/integrate-virtual-accounts">
    Collect in local currency through accounts in your customer's name.
  </Card>

  <Card title="Integrate webhooks with signature checks" href="/prompts/integrate-webhooks">
    Receive signed events that survive retries and secret rotation.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.