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

# KYC WebSDK

> The hosted verification flow: create the customer, launch them into Etherfuse, and the customer completes every step in the widget.

The default flow. You create the customer and launch them; the customer does everything else in the widget at `/idv`.

## The flow

**1. Create the customer's organization**

Create a `personal` organization with [`POST /ramp/organization`](https://docs.etherfuse.com/api-reference/organizations/create-child-org). **You generate the `id`.** This UUID is the customer's org id and the `customer_id` you use everywhere else.

```bash Sandbox theme={null}
curl -X POST https://api.sand.etherfuse.com/ramp/organization \
  -H "Authorization: <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "<customer_uuid>",
    "displayName": "Ana Ejemplo",
    "accountType": "personal",
    "userInfo": {
      "email": "ana@example.com",
      "displayName": "Ana Ejemplo"
    }
  }'
```

```bash Production theme={null}
curl -X POST https://api.etherfuse.com/ramp/organization \
  -H "Authorization: <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "<customer_uuid>",
    "displayName": "Ana Ejemplo",
    "accountType": "personal",
    "userInfo": {
      "email": "ana@example.com",
      "displayName": "Ana Ejemplo"
    }
  }'
```

> [!WARNING]
>
> **Send `userInfo.email`.** An email address is required for the customer's verification record and status notifications. A customer with no email on file cannot start verification.

**2. Launch the customer into /idv**

An [Identity verification](https://docs.etherfuse.com/guides/user-launch-flows.md#identity-verification) launch, using [JWT User Authentication](https://docs.etherfuse.com/guides/jwt-authentication.md#sign-a-user-jwt).

```html theme={null}
<form method="POST" action="https://sandbox.etherfuse.com/auth/launch">
  <input type="hidden" name="grant_type" value="urn:ietf:params:oauth:grant-type:jwt-bearer" />
  <input type="hidden" name="assertion" value="<verification_scoped_jwt>" />
  <input type="hidden" name="target" value="/idv" />
</form>
```

> [!WARNING]
>
> **The JWT `sub` MUST equal the org `id` from step 1.** Any other `sub` registers a brand-new person instead, and the verification won't attach to your customer.

> [!TIP]
>
> Append **`&lang=es`** to the target (`/idv?lang=es`) for Spanish. Pass an optional `return_url` on the launch to send the customer back to your app when they finish.

**3. The customer completes the steps in the widget**

Everything in the [Requirements List](https://docs.etherfuse.com/guides/onboarding.md#requirements-list), plus any [country-specific](https://docs.etherfuse.com/guides/onboarding.md#country-specific-requirements) requirement, in one authenticated session. The widget takes them through the [stages](https://docs.etherfuse.com/guides/onboarding.md#requirements-unlock-in-stages) in order, so you send nothing. The customer can leave and come back; progress is kept.

**4. Watch for the result**

The [`kyc_updated`](https://docs.etherfuse.com/guides/verifying-webhooks) webhook fires with `status: "approved"` and the customer's wallet becomes order-eligible. See [Tracking verification status](https://docs.etherfuse.com/guides/onboarding.md#tracking-verification-status).

## Error handling

Failures specific to launching. Verification outcomes (`denied`, needs-work) are in [Tracking verification status](https://docs.etherfuse.com/guides/onboarding.md#tracking-verification-status); a rejected customer is resubmitted by launching them again.

| What you see | Meaning | What to do |
| - | - | - |
| The launch never reaches `/idv` | The JWT was rejected: wrong scope, expired, bad signature, or an unrecognized `target`. | See [Authentication errors](https://docs.etherfuse.com/guides/authentication-errors.md). |
| The customer lands in `/idv` as a new person | The JWT `sub` wasn't the org `id`. | Re-mint with `sub` = the org `id`. Don't reuse the old session. |
| The liveness scan never starts in an iframe | Camera permission. The bare `allow="camera"` grants only the iframe's own origin, but the scan runs from a nested frame. | Set `allow="camera *; microphone *"` on the iframe. A top-level tab or popup needs nothing extra. |

## Sandbox

The document checks don't run, so any document images and any selfie will pass. Mexico's RFC check does run: a Mexican customer must enter first name `CARLOS`, last name `RAMIREZ LOPEZ` and RFC `HEGL900101AB6`, plus any CURP in the right format. Every sandbox customer is also asked for a proof of address, because sandbox reads identity documents as test data with no address; any image passes. See [Country-specific requirements](https://docs.etherfuse.com/guides/onboarding.md#country-specific-requirements) and [Test environment](https://docs.etherfuse.com/test-environment.md).

## When to reach for something else

> [card] [KYC API](https://docs.etherfuse.com/guides/kyc-api.md)
>
> You already collect identity data and documents in your own UI.

> [card] [Sumsub shared token](https://docs.etherfuse.com/guides/kyc-sumsub-shared-token.md)
>
> You already verified the customer in your own Sumsub account.


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