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

# Connected accounts

> Onboard your own end clients (sellers and buyers) to KYB/KYC through the API, server-to-server.

Connected accounts let you — the integrator — run KYB (businesses) or KYC (individuals) **on behalf of your own end clients**, server-to-server, without redirecting anyone to a hosted flow. Each connected account is a receiver at our settlement partner that is private to your organization and bound to one mode (test or live).

Two roles:

* **`seller`** — a business or individual that will *receive* payments and settle to its own bank/PIX. On approval, Caratuva provisions settlement rails so the seller is *payout-ready*.
* **`buyer`** — a payer you verify ahead of a payment.

<Note>
  This is the onboarding/verification surface. v1 makes a connected **seller** payout-ready (verified receiver + off-ramp wallet + registered PIX destination), but routing a payment intent's funds to a connected seller — and letting a connected buyer pay without re-KYC — are a follow-on. Buyer KYC for the hosted payment flow is unchanged ([Buyer KYC](/buyer-kyc)).
</Note>

## Authentication & scopes

All routes use your API key (`X-API-Key: pk_<test|live>_...`). The key's prefix fixes the mode — a connected account created with a `pk_test_` key is invisible to live and routes to the settlement partner sandbox. Routes require the relevant scope (keys with no scopes set are unrestricted, for backward compatibility):

| Scope                      | Grants                                         |
| -------------------------- | ---------------------------------------------- |
| `connected_accounts:write` | create, ToS, upload-url, submit, payout-config |
| `connected_accounts:read`  | get, list                                      |

## The lifecycle

```
create ──▶ (tos-session ▶ tos-accepted) ──▶ [upload-url …] ──▶ submit ──▶ verifying ──▶ approved | rejected
                                                                                    │
                                                                 seller approved ───▶ settlement provisioned
                                                                                    └▶ payout-config (PIX)
```

`status` values: `created` (local shell, no receiver yet) · `verifying` (submitted to the settlement partner) · `approved` · `rejected`.

## 1. Create

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/connected-accounts \
  -H "X-API-Key: $CARATUVA_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "role": "seller",
    "entityType": "business",
    "externalId": "merchant-42",
    "legalName": "Acme Comércio LTDA",
    "country": "BR"
  }'
```

| Field                                                   | Type                       | Required | Notes                                                                                                                                            |
| ------------------------------------------------------- | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `role`                                                  | `seller` \| `buyer`        | yes      | What the end client will do once verified.                                                                                                       |
| `entityType`                                            | `business` \| `individual` | yes      | Selects the verification path on `submit`.                                                                                                       |
| `externalId`                                            | string (1–200)             | no       | Your primary key for this end client. Unique per `(org, mode)`. Re-creating with the same value returns the existing account — safe under retry. |
| `email`, `legalName`, `displayName`, `country`, `taxId` | string                     | no       | Identity hints; finalised on `submit`.                                                                                                           |

Returns a `ConnectedAccount` with `status: "created"`.

## 2. Terms of Service (per end client)

Our settlement partner requires ToS acceptance before a receiver can be created. Mint a session, direct your end client to the URL, and record the `tos_id` from the redirect.

```bash theme={null}
# Mint a session
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/tos-session \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{ "redirectUrl": "https://app.example.com/onboarding/{id}/tos-done" }'
# -> { "url": "https://...", "idempotencyKey": "..." }

# After the redirect carries ?tos_id=...
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/tos-accepted \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{ "tosId": "tos_..." }'
```

`tos-accepted` requires a session minted first (it binds the redirect to this account, closing the cross-account `tos_id` replay window). You may also pass `tosId` directly on `submit`; it must match the recorded value.

## 3. Documents (optional)

Provide your own pre-hosted HTTPS URLs in the `submit` body, **or** mint short-lived signed upload URLs:

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/upload-url \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{ "kind": "id_doc_front", "contentType": "image/jpeg" }'
# -> { uploadUrl, publicUrl, uploadHeaders, uploadMethod, expiresAt }
```

`kind`: `selfie` · `id_doc_front` · `id_doc_back` · `proof_of_address` · `incorporation_doc` · `proof_of_ownership_doc`. For business beneficial owners, pass `ownerIndex` (a zero-based integer, 0–20). PUT the bytes to `uploadUrl` with the returned headers, then pass `publicUrl` in `submit`. Returns `503 KycStorageDisabled` if document storage isn't configured — use pre-hosted URLs instead.

## 4. Submit to the settlement partner

One endpoint; the fields required depend on `(role, entityType)`. Missing fields return `400 ConnectedAccountMissingFields` with the offending paths.

**Seller business** (`createKyb`, Brazilian CNPJ):

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/submit \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{ "email": "ops@acme.com.br", "legalName": "Acme Comércio LTDA", "cnpj": "12345678000199" }'
```

**Individual** (`createKyc`):

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/submit \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{
    "email": "jane@example.com",
    "firstName": "Jane", "lastName": "Doe",
    "dateOfBirth": "1990-04-12",
    "idDocCountry": "US", "idDocType": "PASSPORT",
    "selfieFile": "https://...", "idDocFrontFile": "https://..."
  }'
```

**Buyer business** (`createBuyerKyb`) requires `legalName`, `formationDate`, `taxId`, `website`, `country`, address fields, `incorporationDocFile`, `proofOfOwnershipDocFile`, and at least one `owners[]` beneficial owner (`role`, name, `dateOfBirth`, `taxId`, address, `idDocType`, `selfieFile`, `idDocFrontFile`, `proofOfAddressDocType`, `proofOfAddressDocFile`).

`submit` is idempotent while the account is `verifying`/`approved` — it returns the current submission rather than creating a second receiver. In the sandbox, KYB auto-approves; KYC resolves to `verifying` and completes via webhook.

## 5. Seller payout destination (PIX)

After a seller is approved, register where it gets paid. The raw PIX key is sent to our settlement partner and never stored by Caratuva.

```bash theme={null}
curl -X POST https://api.caratuva.com/v1/connected-accounts/{id}/payout-config \
  -H "X-API-Key: $CARATUVA_API_KEY" -H "content-type: application/json" \
  -d '{ "pixKey": "acme@pix.example.com", "accountHolderName": "Acme Comércio LTDA" }'
```

Sellers only, and the account must be `approved` first (`400 ConnectedAccountNotApproved` otherwise). After this, the account reports `payoutConfigured: true`.

## Read

```bash theme={null}
curl https://api.caratuva.com/v1/connected-accounts/{id} -H "X-API-Key: $CARATUVA_API_KEY"
curl "https://api.caratuva.com/v1/connected-accounts?role=seller&status=approved&limit=50" \
  -H "X-API-Key: $CARATUVA_API_KEY"
```

The `ConnectedAccount` object includes `status`, `receiverId`, `tosAccepted`, `payoutConfigured`, and `approvedAt` / `rejectedAt`. List is cursor-paginated (`nextCursor`), filterable by `role` and `status`.

## How status updates land

The settlement partner's verification decision arrives at Caratuva's signed inbound webhook; Caratuva resolves the receiver to your connected account and updates its status (idempotently). A terminal decision (`approved`/`rejected`) also purges any documents Caratuva stored for the account.

To observe the result today, **poll** `GET /v1/connected-accounts/:id` (or `GET /v1/connected-accounts?status=verifying`) until `status` is terminal. In the sandbox, seller-business KYB auto-approves synchronously on `submit`, so the `submit` response already carries `approved`.

<Note>
  Outbound webhook *events* for connected-account status changes (e.g. `connected_account.approved`) are a follow-on — unlike payment intents, a connected account isn't tied to an invoice timeline. For now, poll the read endpoints.
</Note>
