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

# Individual (KYC)

> Onboard a person end to end — create, documents, verification

Onboarding a person takes three calls: create them, upload a photo ID, upload a
selfie. Everything else is optional.

<Steps>
  <Step title="Create the customer" icon="user-plus">
    [`POST /api/v0/customer`](/api-reference/onboarding/create-customer) with identity
    fields, the questionnaire and custom fields. The whole payload is validated
    first — one bad field and nothing is created.

    ```json Required fields theme={null}
    {
      "email": "jane.doe@example.com",
      "firstName": "Jane",
      "lastName": "Doe",
      "dateOfBirth": "01-01-1990",
      "country": "ARE",
      "questionnaire": { "sections": { } },
      "customFields": {
        "nationalIdNumber": "784-1990-1234567-1",
        "whatsappNumber": "+971500000000"
      }
    }
    ```

    Returns `201` with the `userId`. **Save it — every later call uses it.**

    ```json theme={null}
    {
      "userId": "6c4ba9af-978a-45ff-953f-729c593f14af",
      "userType": "INDIVIDUAL",
      "status": "INITIATED",
      "sumsubApplicantId": "6a99986facbfab05e54c5719"
    }
    ```
  </Step>

  <Step title="Upload the photo ID" icon="passport">
    [`POST /api/v0/customer/{userId}/documents`](/api-reference/onboarding/upload-document)
    as `multipart/form-data`.

    ```bash theme={null}
    curl -X POST https://qa-api.endl.xyz/api/v0/customer/$USER_ID/documents \
      -H "API-KEY: $ENDL_API_KEY" \
      -F "document=@passport.jpg;type=image/jpeg" \
      -F "idDocType=PASSPORT" \
      -F "country=ARE"
    ```

    This **auto-submits** the applicant — status moves to `PENDING` once the
    provider has everything it needs.
  </Step>

  <Step title="Upload the selfie" icon="camera">
    Same endpoint, `idDocType=SELFIE`.

    ```bash theme={null}
    curl -X POST https://qa-api.endl.xyz/api/v0/customer/$USER_ID/documents \
      -H "API-KEY: $ENDL_API_KEY" \
      -F "document=@selfie.png;type=image/png" \
      -F "idDocType=SELFIE" \
      -F "country=ARE"
    ```

    The response's `missing` array tells you what is still outstanding:

    ```json theme={null}
    { "accepted": true, "status": "SUBMITTED", "missing": ["SELFIE"] }
    ```
  </Step>
</Steps>

***

## Identity fields

| Field                                             | Required | Notes                                                                        |
| ------------------------------------------------- | -------- | ---------------------------------------------------------------------------- |
| `email`                                           | Yes      | Unique. Immutable after creation.                                            |
| `firstName` / `lastName`                          | Yes      | Maximum 100 characters each.                                                 |
| `dateOfBirth`                                     | Yes      | `DD-MM-YYYY`. A real past date, and at least 18 years ago.                   |
| `country`                                         | Yes      | ISO 3166-1 alpha-3 — `ARE`, `GBR`, `USA`.                                    |
| `questionnaire`                                   | Yes      | See the [questionnaire reference](/api-reference/onboarding/questionnaires). |
| `customFields`                                    | Yes      | `nationalIdNumber` and `whatsappNumber` are required.                        |
| `phone`                                           | No       | Maximum 50 characters.                                                       |
| `nationality`                                     | No       | ISO alpha-3. Defaults to `country`.                                          |
| `gender`                                          | No       | `M` or `F`.                                                                  |
| `tin`, `taxResidenceCountry`, `placeOfBirth`      | No       | Extra identity fields.                                                       |
| `addressLine1`/`2`, `city`, `state`, `postalCode` | No       | Address.                                                                     |
| `externalReferenceId`                             | No       | Your own reference. Echoed back, not stored.                                 |

## Document types

`idDocType` is validated — a value outside this list returns `400`.

`PASSPORT` · `ID_CARD` · `DRIVERS_LICENSE` · `RESIDENCE_PERMIT` · `SELFIE`

<Note>
  **`side` is not validated.** `FRONT` and `BACK` are meaningful only for two-sided
  documents (`ID_CARD`, `DRIVERS_LICENSE`). For a passport or selfie it is ignored,
  and any value — even nonsense — is accepted and passed through.
</Note>

Files must be JPEG, PNG or PDF, at most 2 MB. Content is **sniffed, not trusted by
extension**: a text file renamed `.jpg` returns `400`.

## Hosted verification instead of uploads

If you would rather not handle documents yourself,
[generate a KYC link](/api-reference/onboarding/generate-kyc-link) and send the
customer to it.

```json theme={null}
{
  "url": "https://in.sumsub.com/websdk/p/sbx_example",
  "userId": "6c4ba9af-978a-45ff-953f-729c593f14af",
  "ttlSeconds": 3600,
  "expiresAt": "2026-09-09T18:36:03Z"
}
```

The link expires — `ttlSeconds` is one hour. Requesting one for an already
verified customer returns `409`.

## Importing an already-verified customer

Pass a `shareToken` instead of the identity payload. Only `email` is required
alongside it; identity comes from the token, and any identity fields you send are
ignored and listed back in `warnings`.

```json Request theme={null}
{ "shareToken": "_act-sbx-jwt-…", "email": "jane.imported@example.com" }
```

<Warning>
  Share tokens are **single-use per partner**. Reusing one returns `400`, and the
  message is a generic `Bad Request`. Use a fresh token each time.
</Warning>

## Deleting

[Delete](/api-reference/onboarding/delete-customer) is a soft delete. The customer
stops appearing in listings and a later `GET` returns `404`. The **email is
released**, so the same person can be onboarded again.

A customer holding a balance cannot be deleted — that returns `409`, and the
amount is never disclosed.
