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

# PayLinks

> Create pre-authorized budgets, publish them to agents, and charge against accepted grants.

# PayLinks

## Create a PayLink

```bash theme={null}
POST /merchant/paylinks
Authorization: Bearer sk_mch_...
```

<ParamField body="label" type="string">
  What the budget is for, e.g. `"Retainer mensual data"`. Shown to the agent before accepting.
</ParamField>

<ParamField body="budgetUsdCents" type="integer" required>
  Total ceiling in USD cents across all draws.
</ParamField>

<ParamField body="perChargeUsdCents" type="integer">
  Max size of any single draw.
</ParamField>

<ParamField body="maxUses" type="integer">
  Max number of draws.
</ParamField>

<ParamField body="expiresInHours" type="integer">
  Lifetime of the link.
</ParamField>

```json theme={null}
// 201 Created
{
  "paylinkId": "pl_8eb56b59f563e9ed",
  "code": "h83YpjKQ",
  "business": null,
  "label": "Retainer mensual data",
  "budgetMinor": 500,
  "perChargeMinor": null,
  "maxUses": null,
  "uses": 0,
  "remainingMinor": 500,
  "expiresAt": null,
  "status": "active",
  "acceptUrl": "/pl/h83YpjKQ/accept"
}
```

## Public view

Everything an agent needs to decide. No auth required.

```bash theme={null}
GET /pl/h83YpjKQ
```

```json theme={null}
{
  "paylinkId": "pl_...",
  "code": "h83YpjKQ",
  "business": "Acme Digital Goods",
  "label": "Retainer mensual data",
  "budgetMinor": 500,
  "perChargeMinor": null,
  "maxUses": null,
  "uses": 0,
  "remainingMinor": 500,
  "expiresAt": null,
  "status": "active"
}
```

## Accept a PayLink (agent)

Creates the grant, the auditable human authorization. Idempotent per (link, agent) pair.

```bash theme={null}
POST /pl/h83YpjKQ/accept
Authorization: Bearer pz_sk_...
```

```json theme={null}
{
  "grantId": "plg_8045a45414bdb863",
  "paylink": { "...": "public view..." }
}
```

Fires `paylink.accepted` to the merchant's webhooks.

## Charge against a grant

```bash theme={null}
POST /merchant/paylinks/:code/charge
Authorization: Bearer sk_mch_...
```

<ParamField body="agentId" type="string" required>
  Which agent's grant to draw from. The agent must have accepted first.
</ParamField>

<ParamField body="amountUsdCents" type="integer" required>
  Draw amount in USD cents.
</ParamField>

<ParamField body="description" type="string">
  What this draw pays for.
</ParamField>

```json theme={null}
// 200 OK
{
  "paid": true,
  "charge": {
    "chargeId": "chg_610149bd78ab4857",
    "status": "paid",
    "method": "paylink",
    "reference": "PAY_82A95A672F30D580"
  },
  "spentMinor": 150,
  "remainingMinor": 350,
  "exhausted": false
}
```

### Error catalog

| Status | `error`                                    | Meaning                                                             |
| ------ | ------------------------------------------ | ------------------------------------------------------------------- |
| `402`  | `excede_presupuesto_restante_<N>`          | Draw exceeds the agent's remaining budget (`N` = cents left).       |
| `402`  | `excede_tope_por_uso`                      | Draw larger than `perChargeUsdCents`.                               |
| `402`  | *(policy reason)*                          | The agent's hard policy limits blocked it (daily cap, category...). |
| `409`  | `paylink_exhausted`                        | Budget fully used. A `budget.exhausted` webhook already fired.      |
| `409`  | `max_uses_alcanzado`                       | Draw count limit reached.                                           |
| `409`  | `paylink_expired` / `sin_grant_del_agente` | Link expired, or this agent never accepted.                         |
| `404`  | `paylink_not_found`                        | Wrong code or link belongs to another merchant.                     |

<Tip>
  The remaining budget is enforced **before** the wallet is touched; a rejected draw never leaves a partial charge behind.
</Tip>
