---
title: codespar_kyc
description: Identity verification. Persona (default INTL), Sift (fraud-score), Konduto (BR fraud), Truora (LATAM-wide). Async — track via verificationStatus.
---

import { Callout } from "fumadocs-ui/components/callout";

# codespar_kyc

<Callout title="Meta-tool" type="info">
**Sell-side.** Your agent is the merchant: it collects from, invoices, ships to, or verifies a counterparty.

`codespar_kyc` issues KYC inquiries across multiple providers. Use it as a gate before high-value `codespar_charge` / `codespar_pay` calls or when a regulated workflow demands proof of identity. The call returns immediately with an `inquiry_id`; track the verdict via `verificationStatus(toolCallId)` or the streaming sibling.
</Callout>

There is no typed wrapper for `codespar_kyc` itself — call via `session.execute()`. Tracking has typed wrappers: `session.verificationStatus(toolCallId)` and `session.verificationStatusStream(toolCallId, opts)`.

## Rails

| Rail | Coverage | Country | Provider | Notes |
|---|---|---|---|---|
| `identity` | INTL | INTL | Persona | Default. `inquiry_template_id` stamped per-tenant in `connection_metadata` |
| `risk-score` | Fraud-score | INTL | Sift | Risk-score variant. HTTP Basic auth |
| `risk-score` | BR fraud | BR | Konduto | BR-focused fraud signals. HTTP Basic auth |
| `identity` | LATAM | INTL | Truora | Wider LATAM ID-document coverage |
| `onboarding` | BR | BR | Licensed BaaS partner | BR account onboarding (background check + documentoscopy) |

## Direct execute

```ts
const inquiry = await session.execute("codespar_kyc", {
  operation: "create_inquiry",
  subject: {
    name: "Maria Silva",
    document: "12345678900",
    email: "maria@example.com",
    document_type: "cpf",
  },
  metadata: { order_id: "1234" },
});

console.log(inquiry.tool_call_id, inquiry.inquiry_id, inquiry.status); // "pending"
```

Then poll until terminal:

```ts
let v = await session.verificationStatus(inquiry.tool_call_id);
while (v.status === "pending") {
  await new Promise((r) => setTimeout(r, 3000));
  v = await session.verificationStatus(inquiry.tool_call_id);
}
// v.status is now approved | rejected | review | expired
```

Or stream:

```ts
await session.verificationStatusStream(inquiry.tool_call_id, {
  onUpdate: (s) => console.log("kyc:", s.status),
});
```

## Args shape

| Field | Type | Required | Description |
|---|---|---|---|
| `operation` | `string` | Yes | `create_inquiry` (today) |
| `subject` | `object` | Yes | `{ name, document, document_type, email?, phone?, address? }` |
| `provider` | `string` | No | Force a specific rail (`persona`, `sift`, `konduto`, `truora`) |
| `metadata` | `object` | No | Arbitrary key-value pairs persisted on the `tool_calls` row |

## Result shape

```ts
type KYCResult = {
  tool_call_id: string;
  inquiry_id: string;
  status: "pending"; // always pending; terminal state via verificationStatus
  inquiry_url?: string; // Persona hosted flow URL when subject must complete steps
};
```

Terminal verification states (returned by `verificationStatus`), in poll-priority order:

1. `approved` — KYC passed.
2. `rejected` — KYC failed.
3. `review` — manual review pending (provider human-in-the-loop).
4. `expired` — verification window timed out.
5. `pending` — still processing.

The polling priority matters: when multiple events have landed for the same `tool_call_id` (e.g. `review` then `approved`), the endpoint returns the highest-priority terminal state.

## Operator setup

- **Persona (default)** — API key (`api_key` auth_type). **Important: stamp `inquiry_template_id` in `connection_metadata`** when the operator connects Persona — this is per-tenant operator-stamped, not passed at execute time. Without it the inquiry creation will fail.
- **Sift** — HTTP Basic auth (API key as username, blank password).
- **Konduto** — HTTP Basic auth.
- **Truora** — API key.

The Persona `inquiry_template_id` lives in `connected_accounts.connection_metadata` (jsonb) — the dashboard's Persona connect modal renders an extra input for it.

## Async verification

Verification follows the same correlation chain as payments — `idempotency_key` ↔ `external_reference` resolved via webhook. See [async settlement → Verification (KYC) sibling](/docs/concepts/async-settlement#verification-kyc-sibling) for the full flow.

## See also

- [SDK reference — verificationStatus](/docs/api/sdk#verificationstatustoolcallid-promiseverificationstatusresult)
- [Async settlement → KYC sibling](/docs/concepts/async-settlement#verification-kyc-sibling)
- [SSE streaming](/docs/concepts/sse-streaming) — `verificationStatusStream`
- [KYC Agent cookbook](/docs/cookbooks/kyc-agent) — end-to-end gating example
- [Tools & meta-tools](/docs/concepts/tools) — full meta-tool list
