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

# Onboard a Beneficiary

> Take a Beneficiary from nothing to ready to pay: register them through the API, import them with a verified base, or invite them to enter their own details.

Onboard a Beneficiary and leave them ready to be paid. For developers wiring
onboarding into their product. Every path below onboards the same
Beneficiary (the payee), Jane Doe, and ends with her `status` reading `ready`.

<Note>
  **Agents:** fetch this page as plain markdown at
  `https://docs.usecleff.com/guides/onboard-a-beneficiary.md`.
</Note>

You need a sandbox API key exported as `CLEFF_API_KEY`; the
[Quickstart](/quickstart) shows how to mint one. What `ready` means, and which
destination a payout to Jane goes to, is on
[Beneficiaries & compliance](/concepts/beneficiaries).

## Pick a path

| You hold | Path | Jane's destination |
| - | - | - |
| Jane's verified identity and bank details | [Register Jane through the API](#register-jane-through-the-api) | The bank account you register |
| The same, for Jane and many others | [Import Jane with the rest of your base](#import-jane-with-the-rest-of-your-base) | The bank account in her row |
| Jane's name and email address | [Invite Jane to enter her own details](#invite-jane-to-enter-her-own-details) | The bank account or card she chooses |

<Warning>
  Pick one path per Beneficiary. An email address belongs to one active Beneficiary per environment,
  so creating Jane a second time with `jane@example.com` is refused.
</Warning>

## Register Jane through the API

<Steps>
  <Step title="Create Jane and attest to her compliance">
    Passing `acknowledged: true` records that your Business has independently
    verified Jane's identity, which makes her `compliant` straight away.

    ```bash theme={null}
    curl -X POST https://api.usecleff.com/v1/beneficiaries \
      -H "Authorization: Bearer $CLEFF_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "beneficiary_type": "person",
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "jane@example.com",
        "country_of_residence": "US",
        "acknowledged": true
      }'
    ```

    Capture `beneficiary.id` from the response:

    ```bash theme={null}
    export BEN_ID="<beneficiary.id>"
    ```

    Jane's `status` is now `action_required`: she is `compliant` but has nowhere to
    be paid.
  </Step>

  <Step title="Register her bank account">
    ```bash theme={null}
    curl -X POST https://api.usecleff.com/v1/beneficiaries/$BEN_ID/bank-accounts \
      -H "Authorization: Bearer $CLEFF_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "account_holder_name": "Jane Doe",
        "country": "US",
        "currency": "USD",
        "account_number": "000123456789",
        "routing_code": "021000021"
      }'
    ```

    ```json theme={null}
    {
      "bank_account": {
        "id": "8d6f3c2a-51b7-4e0f-9a3d-7c1e2b4f6a90",
        "kind": "bank",
        "account_holder_name": "Jane Doe",
        "currency": "USD",
        "country": "US",
        "status": "verified",
        "validation_status": "validated",
        "payout_usable": true,
        "rail_rejection_reason": null,
        "last4": "6789",
        "account_type": null
      }
    }
    ```

    Because Jane is already `compliant`, the account is `verified` on arrival, and a
    routing number that passes Cleff's format checks makes it `validated`. Together
    they give `payout_usable: true`.
  </Step>
</Steps>

Jane holds one destination and has declared none, so a payout that omits
`destination_id` goes to this account. [Confirm she is ready](#confirm-jane-is-ready-to-pay).

## Import Jane with the rest of your base

[Import](/api-reference/beneficiaries-import) creates each Beneficiary, registers
their bank account and records your attestation in one request, for up to 500
rows. Every row needs `acknowledged: true`, and the call needs a key with the
`business_admin` role.

```bash theme={null}
curl -X POST https://api.usecleff.com/v1/beneficiaries/import \
  -H "Authorization: Bearer $CLEFF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
      {
        "beneficiary_type": "person",
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "jane@example.com",
        "country_of_residence": "US",
        "acknowledged": true,
        "bank": {
          "account_holder_name": "Jane Doe",
          "country": "US",
          "currency": "USD",
          "account_number": "000123456789",
          "routing_code": "021000021"
        }
      }
    ]
  }'
```

```json theme={null}
{
  "results": [
    {
      "index": 0,
      "status": "created",
      "beneficiary_id": "3b9e1f4c-2a6d-4c8e-b1f0-5d7a9c3e2b18",
      "bank_account_id": "8d6f3c2a-51b7-4e0f-9a3d-7c1e2b4f6a90",
      "payout_usable": true
    }
  ],
  "created_count": 1,
  "failed_count": 0
}
```

Jane's row was created, and `payout_usable: true` means her account can be paid
already. A row can be `created` with `payout_usable: false`; the
[reference](/api-reference/beneficiaries#import-beneficiaries-you-have-already-verified)
explains per-row failures and what to resend.

```bash theme={null}
export BEN_ID="<results[0].beneficiary_id>"
```

[Confirm she is ready](#confirm-jane-is-ready-to-pay).

## Invite Jane to enter her own details

Inviting keeps Jane's identity details and account number out of your systems,
and it is the only path on which she can choose a debit card or pick which
destination she is paid to.

<Steps>
  <Step title="Invite her">
    [Bulk invites](/api-reference/beneficiaries-bulk-invites) create an
    identity-only Beneficiary per row and email each one a link to a form where
    they enter their own details.

    ```bash theme={null}
    curl -X POST https://api.usecleff.com/v1/beneficiaries/bulk-invites \
      -H "Authorization: Bearer $CLEFF_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "rows": [
          {
            "beneficiary_type": "person",
            "first_name": "Jane",
            "last_name": "Doe",
            "email": "jane@example.com"
          }
        ]
      }'
    ```

    ```json theme={null}
    {
      "invited": [
        {
          "index": 0,
          "id": "3b9e1f4c-2a6d-4c8e-b1f0-5d7a9c3e2b18",
          "email": "jane@example.com"
        }
      ],
      "failed": []
    }
    ```

    ```bash theme={null}
    export BEN_ID="<invited[0].id>"
    ```

    Jane's `status` is `pending_details` until she submits the form.
  </Step>

  <Step title="Wait for her to submit">
    Jane fills in her identity details and adds a destination: a bank account, or,
    in production, a debit card if your Business is approved for card payouts.
    The destination she adds becomes her declared destination.

    Subscribe to [`beneficiary.details_submitted`](/api-reference/webhook-events-beneficiary)
    to hear when she is done, or poll her until her `status` moves from
    `pending_details` to `pending_kyc`:

    ```bash theme={null}
    curl https://api.usecleff.com/v1/beneficiaries/$BEN_ID \
      -H "Authorization: Bearer $CLEFF_API_KEY"
    ```

    Once it reads `pending_kyc`, her details are in, and they wait on your
    attestation.
  </Step>

  <Step title="Attest to her compliance">
    Check the identity Jane submitted, then acknowledge it:

    ```bash theme={null}
    curl -X POST https://api.usecleff.com/v1/beneficiaries/$BEN_ID/compliance-acknowledgment \
      -H "Authorization: Bearer $CLEFF_API_KEY"
    ```

    Jane becomes `compliant`, and the destination she added is verified with her.
  </Step>
</Steps>

## Confirm Jane is ready to pay

Whichever path you took, read Jane back:

```bash theme={null}
curl https://api.usecleff.com/v1/beneficiaries/$BEN_ID \
  -H "Authorization: Bearer $CLEFF_API_KEY"
```

```json theme={null}
{
  "id": "3b9e1f4c-2a6d-4c8e-b1f0-5d7a9c3e2b18",
  "beneficiary_type": "person",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "compliance_status": "compliant",
  "reacknowledgment_required": false,
  "declared_destination_id": "8d6f3c2a-51b7-4e0f-9a3d-7c1e2b4f6a90",
  "status": "ready",
  "environment": "sandbox"
}
```

The response is trimmed to the fields that matter here. Read two of them:

| Field | Expect | Recovery |
| - | - | - |
| `status` | `ready` | Find the value in the [status table](/concepts/beneficiaries#read-the-beneficiary-status) and follow its Recovery. |
| `declared_destination_id` | The destination Jane chose if you invited her; `null` if you registered or imported her | Nothing to fix. With `null`, a payout goes to her one destination, or to the one you name. |

Jane is ready to pay. A payout to her needs only `beneficiary_id`: with a
declared destination it goes there, and without one it goes to the only
destination she holds.


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