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

# Onboarding tools

> KYC identity verification and bank account management via MCP.

Six tools cover the onboarding prerequisite for running an offramp. Call `veil_get_account_status` first — it tells you exactly which step is needed.

***

### veil\_get\_account\_status

Returns the current onboarding stage: KYC status, bank account presence, and an overall `stage` field that tells the assistant what to do next.

**Inputs**

None.

**Outputs**

<ResponseField name="status" type="string" required>
  `authenticated`, `unauthenticated`, or `error`.
</ResponseField>

<ResponseField name="user" type="object">
  User profile. Present when `status` is `authenticated`. Contains `id`, `email`, `onboardingStatus`, `accountType`, `username`, and `displayUsername`.
</ResponseField>

<ResponseField name="kyc" type="object">
  KYC summary with `status` (`not_started`, `in_progress`, `approved`, `failed`, or `error`), `verifiedAt`, and `failureReason`.
</ResponseField>

<ResponseField name="bankAccount" type="object">
  Bank account summary with `present` (boolean), `verified`, `suffixLast4`, `currency`, and `holderName`.
</ResponseField>

<ResponseField name="stage" type="string">
  Overall stage: `needs_kyc`, `kyc_in_progress`, `needs_bank_account`, or `ready`.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description when `status` is `error`.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_get_account_status]
→ status: "authenticated", stage: "ready",
  kyc.status: "approved", bankAccount.present: true, bankAccount.suffixLast4: "1234"
```

***

### veil\_kyc\_start

Start a KYC identity verification session. Returns a Veil-hosted link the user must open in a browser.

**Inputs**

None.

**Outputs**

<ResponseField name="status" type="string" required>
  `approved` if KYC is already complete. `in_progress` with a `kycUrl` if a new session was created. `noah_unavailable` if the verification service is temporarily down. `error` on other failures.
</ResponseField>

<ResponseField name="kycUrl" type="string">
  Link to open in a browser. Present when `status` is `in_progress`.
</ResponseField>

<ResponseField name="message" type="string">
  Human-readable note about the session.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description when `status` is `error`.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_kyc_start]
→ status: "in_progress", kycUrl: "https://veil.co/kyc/link/abc123"
Assistant: Please open this link to complete identity verification: https://veil.co/kyc/link/abc123
```

***

### veil\_kyc\_check\_status

Poll KYC status after the user has completed the verification form.

**Inputs**

None.

**Outputs**

<ResponseField name="status" type="string" required>
  `not_started`, `in_progress`, `approved`, `failed`, or `error`.
</ResponseField>

<ResponseField name="onboardingStatus" type="string">
  Overall account onboarding status.
</ResponseField>

<ResponseField name="verifiedAt" type="string">
  ISO 8601 timestamp when verification was approved. Null if not yet approved.
</ResponseField>

<ResponseField name="failureReason" type="string">
  Reason for failure when `status` is `failed`.
</ResponseField>

<ResponseField name="startedAt" type="string">
  When the KYC session was started.
</ResponseField>

<ResponseField name="updatedAt" type="string">
  When the KYC record was last updated.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description when `status` is `error`.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_kyc_check_status]
→ status: "approved", verifiedAt: "2026-05-14T12:00:00Z"
```

***

### veil\_bank\_account\_get

Retrieve a bank account by ID, or the primary account if no ID is provided. Returns a safe view — no IBAN, routing numbers, or other sensitive data.

**Inputs**

<ParamField body="id" type="string">
  Optional. Bank account ID. Omit to fetch the primary account.
</ParamField>

**Outputs**

<ResponseField name="present" type="boolean" required>
  Whether a bank account was found.
</ResponseField>

<ResponseField name="id" type="string">
  Account ID.
</ResponseField>

<ResponseField name="scheme" type="string">
  Payment scheme: `eu_sepa`, `us_ach`, `us_fedwire`, `global_wire`, `br_pix`, or `uk_local`.
</ResponseField>

<ResponseField name="currency" type="string">
  Account currency (e.g. `EUR`, `USD`).
</ResponseField>

<ResponseField name="holderName" type="string">
  Account holder name.
</ResponseField>

<ResponseField name="bankName" type="string">
  Bank name. Null if not available.
</ResponseField>

<ResponseField name="suffixLast4" type="string">
  Last four digits of the account. Null if not available.
</ResponseField>

<ResponseField name="verified" type="boolean">
  Whether the account has passed verification.
</ResponseField>

<ResponseField name="isPrimary" type="boolean">
  Whether this is the wallet's primary payout bank.
</ResponseField>

<ResponseField name="createdAt" type="string">
  ISO 8601 timestamp when the account was added.
</ResponseField>

<ResponseField name="updatedAt" type="string">
  ISO 8601 timestamp of the last update.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description on failure.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_bank_account_get]
→ present: true, scheme: "eu_sepa", currency: "EUR",
  holderName: "J. Smith", suffixLast4: "1234", verified: true, isPrimary: true
```

***

### veil\_bank\_accounts\_list

List all active bank accounts for the authenticated user. The primary account appears first.

**Inputs**

None.

**Outputs**

<ResponseField name="bankAccounts" type="array">
  Array of bank account records. Each has: `id`, `scheme`, `currency`, `holderName`, `bankName`, `suffixLast4`, `verified`, `isPrimary`, `createdAt`, `updatedAt`.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description on failure.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_bank_accounts_list]
→ bankAccounts: [
    { id: "ba_abc", scheme: "eu_sepa", currency: "EUR", suffixLast4: "1234", isPrimary: true },
    { id: "ba_def", scheme: "us_ach", currency: "USD", suffixLast4: "5678", isPrimary: false }
  ]
```

***

### veil\_bank\_account\_get\_form\_url

Get a link to the Veil-hosted bank account entry form. The user opens the URL in a browser, fills in their bank details, then returns to the chat.

Requires KYC to be approved first. Call `veil_kyc_start` if `veil_get_account_status` shows `stage: needs_kyc`.

**Inputs**

None.

**Outputs**

<ResponseField name="url" type="string">
  URL to the bank account form. Open in a browser to add bank details.
</ResponseField>

<ResponseField name="reason" type="string">
  Error description on failure.
</ResponseField>

**Example**

```dialog theme={null}
[calls veil_bank_account_get_form_url]
→ url: "https://veil.co/bank-account/add?session=abc123"
Assistant: Please open this link to add your bank account: https://veil.co/bank-account/add?session=abc123
```

## See also

* [In-chat flow](/mcp/in-chat-flow) — how onboarding fits into the full offramp conversation
* [KYC](/concepts/kyc) — identity verification overview
* [Bank accounts](/concepts/bank-accounts) — how bank accounts work in Veil
