---
updatedAt: 2026-09-30T15:54:20.000Z
---

Fetch the complete documentation index at: https://docs.avvio.xyz/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Build with AI

Connect your coding agent to Avvio and it works from the current API contract
instead of memory. Pick a server and your tool, and one click or one pasted
line sets it up.

**Docs MCP server** (Searches these docs. Read-only, no key needed.) `claude mcp add --transport http avvio-docs https://docs.avvio.xyz/mcp`

**Payments API MCP server** (Prices and sends payouts. Runs locally over stdio with your API key.) `npx -y @avvio/payments mcp`, with `AVVIO_API_KEY` and `AVVIO_ORG_ID` in its environment. A key starting avvio_test_ cannot move real money. Replace the placeholders after installing, and never paste a live key into an agent config.

The docs server searches every guide, recipe and endpoint, and holds no key.
The payments server calls the API with your key, so give it a test key and keep
that key in your client's private settings. The project configs (`.mcp.json`,
`.vscode/mcp.json`) reference it through `${AVVIO_API_KEY}` or an input prompt,
so they can be committed without it. Your organization ID is on the
dashboard's **Developer** page.

What each server exposes, and the files agents read, are in
[For agents](/build-with-ai/for-agents/).

## Prompts

Click a task to copy its prompt or open it in an assistant.

**Integrate Avvio payouts.** Adds recipients, payouts and status tracking to your app.

```text
Integrate Avvio payouts into this app. Read https://docs.avvio.xyz/llms-full.txt first (or use the avvio-docs MCP server at https://docs.avvio.xyz/mcp).
Use the sandbox and read the key from AVVIO_API_KEY; never hardcode it.
Create a recipient, send the payout in one call (POST /payouts) with an Idempotency-Key you save and reuse on retry, and track status from webhooks.
Show me the diff and how to run it.
```

**Add webhook verification.** An endpoint that verifies signatures and drops duplicate events.

```text
Add an Avvio webhook endpoint to this app. Read https://docs.avvio.xyz/llms-full.txt first (or use the avvio-docs MCP server at https://docs.avvio.xyz/mcp).
Verify the signature on the raw body before parsing, reject stale timestamps, and dedupe by event id.
Update payout status from the events and return 2xx fast. Add a test with a signed sample event.
```

**Test a sandbox payout.** Sends one sandbox payout and reports what happened.

```text
Send one test payout through the Avvio sandbox. Read https://docs.avvio.xyz/llms-full.txt first (or use the avvio-docs MCP server at https://docs.avvio.xyz/mcp).
Use only the avvio_test_ key in AVVIO_API_KEY. Walk the quickstart: recipient, one-call payout with a saved Idempotency-Key, then follow events to a final status.
Report each request id, the final status, and anything in the docs that was unclear.
```

### Sandbox test

Hand this to a coding agent with a test key. It runs the happy path and the
timeout branch, and stops where a human is required. Replace the two
placeholders and change nothing else.

```text title="Sandbox test prompt" prompt
Integrate Avvio Payouts for me in sandbox. Test key: `avvio_test_…`. Organization id: `cmsx…`. Base URL: `https://api.avvio.xyz/business/api/v1` (if your Avvio contact gave you a different base URL, a dedicated or sandbox host, use that one; the paths are identical); send `x-api-key` on every call. Read `https://docs.avvio.xyz/llms-full.txt` first, then do exactly this: (1) `GET /payments/organizations/{orgId}/policy` and read your `limits`, `approvals` and `rateLimits`; keep every amount below the caps. (2) `GET /recipients/{orgId}/corridors`, choose MXN, and build the recipient from the fields it lists; invent none. (3) `POST /payments/organizations/{orgId}/sandbox/fund` for 500 USD with an `Idempotency-Key` (a UUID you save). (4) Create one recipient whose account number ends in `0003`. (5) `POST /payments/organizations/{orgId}/payouts` for 50 USD with a new saved `Idempotency-Key` and `reference: "test-1"`. A payout that is accepted answers 200 with the payout body. If you get 202, stop and tell me a human must approve it in the dashboard. (6) Register a webhook endpoint and verify `svix-signature` on the first delivery. (7) Poll `GET /payments/organizations/{orgId}/events?since=` until the payout shows `completed` and then `failed` with `returned_by_bank`. On any timeout, retry with the same `Idempotency-Key`; never mint a new one. Report the `payoutId`, the event `sequence` values and every error `type` you saw.
```

What a correct run reports

- The policy first: `mode: test`, `limits` (strings or `null`, never exceeded),
  `approvals.thresholdUsd` (`null` unless payouts are held) and `rateLimits`
  per minute.
- One recipient built from the corridor's fields. The MXN field has
  `checksum: "clabe"`, so a wrong 18th digit is `400 VALIDATION_ERROR`; the
  sandbox accepts only `012345678901234567` as a wrong-digit exception, and
  production never does.
- A `500.00` USD funding, then a `50.00` USD payout answered `200` with
  `reference: "test-1"`, a `payoutId` and a `fee` (`{currency, amount}` or `null`).
- Events in ascending `sequence`, one per observed transition:
  `payout.pending`, `payout.completed`, then `payout.returned` with
  `status: failed`, `failureCode: returned_by_bank`, `fundsReturned: true`.
  A `payout.processing` may be missed (the sandbox ticks every ten seconds and
  `0003` holds it for eight); `0002` reliably shows it.
- On `0003`, `completed` at 10 seconds and the return at 40, so polling
  continues a minute past `completed`. In production a return can take days.
- A delivery whose `svix-id` equals the event `id`, verified. Deliveries go
  out every 15 seconds, often in bursts; the deliveries log is a bare array,
  newest first.
- The first `/events` call has no `since` (or `since=0`); each later one sends
  the previous `nextSince`.
- Every id treated as an opaque string: `sbx_…` in the sandbox, cuids for
  events, and live rails mint their own.
- `GET /balance_transactions` with the `+500.00` funding, the `-50.00` debit
  (its `fee`, and `net` the amount less that fee) and a `+50.00`
  `payout_return`; `GET /balance` back at `500.00`. The sandbox refunds the fee
  too; a live rail may keep it, so read the return row's `amount`.
- No error `type`, or a `202 pending_approval` and a stop.
- Any retry reported as a replay of the same `Idempotency-Key`.

Anything else (an invented field, a `400 VALIDATION_ERROR`, a second
`payoutId`, a `cursor` sent to `/events`) is a finding about the docs or the
agent. Send it to us with the `requestId`.

### Payroll test

The same journey for an earned-wage-access or payroll platform paying workers
for an employer. Replace the same two placeholders.

```text title="Payroll test prompt" prompt
Integrate Avvio Payouts for my earned-wage-access platform, in sandbox. Test key: `avvio_test_…`. Organization id: `cmsx…`. Base URL: `https://api.avvio.xyz/business/api/v1`; send `x-api-key` on every call. Read `https://docs.avvio.xyz/llms-full.txt` first. Three parties: I am the partner; the `endUser` is my customer, the employer paying; the recipient is the worker paid. Do this: (1) `GET /payments/organizations/{orgId}/policy`; keep every amount under `limits`. (2) `GET /recipients/{orgId}/corridors`, choose MXN, build recipients from its field list; invent nothing. (3) Fund 1000 USD via `POST .../sandbox/fund` with a saved `Idempotency-Key`. (4) Create three recipients: `externalId` = the worker's HRIS id (`hris_emp_4471` to `4473`), `endUserId: "employer_acme"`, accounts ending `0002`. (5) Pay one worker: `POST .../payouts` for 120 USD with `endUser: { id: "employer_acme" }`, `reference: "PAYROLL-2026-09-01"` and a new saved key. 200 is accepted; on 202 stop: a human must approve. (6) Pay the other two as one run: `POST .../payouts/batches` with `externalReferenceId: "PAYROLL-2026-09-01"`; if it holds at `awaiting_confirmation`, stop and show me the invalid lines. (7) Register a webhook and verify `svix-signature`. (8) Poll `GET .../events?since=` until every payout is `completed`, then match debits in `GET .../balance_transactions` by `reference`. Retry a timeout with the same `Idempotency-Key`. Report every `payoutId`, the `batchId`, the event `sequence` values and every error `type`.
```

What a correct payroll run reports

- The policy with `features` containing `mass_payouts`; without it, a stop
  before step 6 saying batches are off.
- Three recipients with `externalId` = the HRIS id and
  `endUserId: "employer_acme"`. Re-sending an HRIS id with the same account
  returns the existing recipient (`201`, same `id`).
- A `120.00` USD payout answered `200` with `reference: "PAYROLL-2026-09-01"`
  and `endUser.id: "employer_acme"`.
- A batch: `202` on submit, `status` reaching `completed`, `counts.created: 2`,
  and a `payoutId` on each line of `GET .../batches/{batchId}/items`. A hold
  at `awaiting_confirmation` is a stop, not a `confirm`.
- `payout.pending` and `payout.completed` for all three payouts, plus the
  `payout_batch.*` transitions, in ascending `sequence`; verified deliveries
  within about 15 seconds of each.
- The `+1000.00` funding and three debits in `GET /balance_transactions`, each
  with its `reference` and the batch lines with the `batchId`; the balance at
  `1000.00` less the three amounts.
- The same approval stop and idempotent retries as the sandbox run.

