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

# Payouts Quickstart

> Pay a payroll end to end in under five minutes

This walkthrough does the full "pay a payroll" flow: calculate an employee's
net salary, then create a payout for that amount and watch it settle.

<Warning>
  Sandbox payouts are handled by an in-process **mock provider** — no real funds
  are moved. Every response carries `mock: true` and the `X-Clevis-Mock: true`
  header.
</Warning>

## 1. Calculate the payroll

Run a normal payroll calculation and capture `summary.net_salary`. We'll use
a Colombia 2026 `ordinario` example.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.clevis.dev/v1/payroll/calculate \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "country": "CO",
      "scheme": "ordinario",
      "year": 2026,
      "period": {
        "type": "monthly",
        "start_date": "2026-05-01",
        "end_date": "2026-05-31",
        "days": 30
      },
      "employee": {
        "id": "emp-001",
        "monthly_salary": "5000000",
        "overrides": { "aplica_auxilio_transporte": false }
      },
      "employer": { "id": "employer-001" }
    }'
  ```

  ```python Python theme={null}
  import httpx

  calc = httpx.post(
      "https://api.clevis.dev/v1/payroll/calculate",
      headers={"Authorization": "Bearer YOUR_API_KEY"},
      json={
          "country": "CO",
          "scheme": "ordinario",
          "year": 2026,
          "period": {
              "type": "monthly",
              "start_date": "2026-05-01",
              "end_date": "2026-05-31",
              "days": 30,
          },
          "employee": {
              "id": "emp-001",
              "monthly_salary": "5000000",
              "overrides": {"aplica_auxilio_transporte": False},
          },
          "employer": {"id": "employer-001"},
      },
  ).json()

  net_salary = calc["summary"]["net_salary"]   # e.g. "4600000.00" — keep as string
  ```

  ```javascript Node.js theme={null}
  const calc = await fetch("https://api.clevis.dev/v1/payroll/calculate", {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      country: "CO",
      scheme: "ordinario",
      year: 2026,
      period: {
        type: "monthly",
        start_date: "2026-05-01",
        end_date: "2026-05-31",
        days: 30,
      },
      employee: {
        id: "emp-001",
        monthly_salary: "5000000",
        overrides: { aplica_auxilio_transporte: false },
      },
      employer: { id: "employer-001" },
    }),
  }).then((r) => r.json());

  const netSalary = calc.summary.net_salary; // keep as string
  ```
</CodeGroup>

<Tip>
  Treat `net_salary` as an opaque string. Don't `Number()`/`float()` it before
  passing it to `/v1/payouts` — that's where floating-point precision sneaks in.
</Tip>

## 2. Create the payout

Pass `net_salary` straight through as the `amount`. Setting `processing.step_seconds: 0`
runs the mock state machine **synchronously** so the response already has
`status: "PAID"` — exactly what you want in scripts and tests.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.clevis.dev/v1/payouts \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Idempotency-Key: payroll-co-2026-05-emp-001" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": "4600000.00",
      "currency": "COP",
      "country": "CO",
      "external_id": "payroll-co-2026-05-emp-001",
      "description": "Nómina mayo 2026 — Juan Pérez",
      "beneficiary": {
        "name": "Juan Pérez",
        "document_type": "CC",
        "document_id": "1023456789",
        "bank_account": {
          "bank_code": "1007",
          "account_type": "CHECKING",
          "account_number": "12345678901"
        }
      },
      "payroll_ref": {
        "country": "CO",
        "scheme": "ordinario",
        "year": 2026,
        "concept": "net_salary"
      },
      "processing": { "step_seconds": 0 }
    }'
  ```

  ```python Python theme={null}
  payout = httpx.post(
      "https://api.clevis.dev/v1/payouts",
      headers={
          "Authorization": "Bearer YOUR_API_KEY",
          "Idempotency-Key": f"payroll-co-2026-05-{calc['employee_id']}",
      },
      json={
          "amount": net_salary,           # string, straight through
          "currency": "COP",
          "country": "CO",
          "external_id": f"payroll-co-2026-05-{calc['employee_id']}",
          "description": "Nómina mayo 2026 — Juan Pérez",
          "beneficiary": {
              "name": "Juan Pérez",
              "document_type": "CC",
              "document_id": "1023456789",
              "bank_account": {
                  "bank_code": "1007",
                  "account_type": "CHECKING",
                  "account_number": "12345678901",
              },
          },
          "payroll_ref": {
              "calculation_id": calc["id"],
              "country": "CO",
              "scheme": "ordinario",
              "year": 2026,
              "concept": "net_salary",
          },
          "processing": {"step_seconds": 0},  # synchronous terminal state
      },
  ).json()

  assert payout["status"] == "PAID"
  assert payout["mock"] is True
  ```

  ```javascript Node.js theme={null}
  const payout = await fetch("https://api.clevis.dev/v1/payouts", {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
      "Idempotency-Key": `payroll-co-2026-05-${calc.employee_id}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: netSalary,
      currency: "COP",
      country: "CO",
      external_id: `payroll-co-2026-05-${calc.employee_id}`,
      description: "Nómina mayo 2026 — Juan Pérez",
      beneficiary: {
        name: "Juan Pérez",
        document_type: "CC",
        document_id: "1023456789",
        bank_account: {
          bank_code: "1007",
          account_type: "CHECKING",
          account_number: "12345678901",
        },
      },
      payroll_ref: {
        calculation_id: calc.id,
        country: "CO",
        scheme: "ordinario",
        year: 2026,
        concept: "net_salary",
      },
      processing: { step_seconds: 0 },
    }),
  }).then((r) => r.json());

  console.log(payout.status); // "PAID"
  console.log(payout.mock);   // true
  ```
</CodeGroup>

## 3. Read the response

```json theme={null}
{
  "id": "po_01JABCXYZ...",
  "object": "payout",
  "mock": true,
  "mode": "sandbox",
  "status": "PAID",
  "status_detail": "Payout received and queued.",
  "status_code": "200",
  "amount": "4600000.00",
  "currency": "COP",
  "country": "CO",
  "external_id": "payroll-co-2026-05-emp-001",
  "payment_method_id": "BANK_TRANSFER",
  "beneficiary": { ... },
  "payroll_ref": {
    "country": "CO",
    "scheme": "ordinario",
    "year": 2026,
    "concept": "net_salary"
  },
  "created_at": "2026-05-12T15:04:05Z",
  "updated_at": "2026-05-12T15:04:05Z",
  "status_history": [
    { "status": "PENDING",    "at": "2026-05-12T15:04:05Z", "detail": "Payout received and queued." },
    { "status": "PROCESSING", "at": "2026-05-12T15:04:05Z" },
    { "status": "PAID",       "at": "2026-05-12T15:04:05Z" }
  ]
}
```

<Tip>
  Without `processing.step_seconds: 0`, the response would come back with
  `status: "PENDING"` and advance to `PROCESSING` then `PAID` on a 2-second
  timer (configurable). Use `GET /v1/payouts/{id}` to poll, or subscribe to
  [webhooks](/payouts/webhooks) for push notifications.
</Tip>

## 4. Try a deterministic failure

Force the mock to reject the payout by prefixing `external_id` with
`MOCK_REJECT_BANK_`:

```bash theme={null}
curl -X POST https://api.clevis.dev/v1/payouts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "4600000.00",
    "currency": "COP",
    "country": "CO",
    "external_id": "MOCK_REJECT_BANK_demo-001",
    "beneficiary": { ... },
    "processing": { "step_seconds": 0 }
  }'
```

The response comes back with `status: "REJECTED"`, `status_code: "301"`, and
`status_detail` ending in `"(mock trigger)."`. The full menu of triggers is on
the [Magic triggers](/payouts/magic-triggers) page.

## Next steps

<CardGroup cols={2}>
  <Card title="Status lifecycle" icon="diagram-project" href="/payouts/status-lifecycle">
    Every legal state transition the mock can make.
  </Card>

  <Card title="Idempotency" icon="arrow-rotate-right" href="/payouts/idempotency">
    Safely retry create calls without double payments.
  </Card>

  <Card title="Webhooks" icon="bell" href="/payouts/webhooks">
    Get pushed on every status change.
  </Card>

  <Card title="Country requirements" icon="globe" href="/payouts/country-requirements">
    Beneficiary fields and check-digits for every supported country.
  </Card>
</CardGroup>
