> ## 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.

# Charges

> Create charges, check their status, let agents pay them from wallets or on-chain via x402.

# Charges

## Create a charge

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

<ParamField body="amountUsdCents" type="integer" required>
  Amount in USD cents. `499` = \$4.99. Must be > 0.
</ParamField>

<ParamField body="description" type="string">
  Human- (and agent-) readable description. Shows up in the agent's audit trail.
</ParamField>

<ParamField body="externalId" type="string">
  Your own id (order, invoice). Echoed back for reconciliation.
</ParamField>

```json theme={null}
// 201 Created
{
  "chargeId": "chg_834e692669a3f8ad",
  "merchantId": "mch_c8fdac10d39c0c4d",
  "agentId": null,
  "amountMinor": 200,
  "currency": "USD",
  "description": "API credits pack",
  "externalId": null,
  "status": "pending",
  "method": null,
  "reference": null,
  "createdAt": "...",
  "paidAt": null
}
```

Fires a `charge.created` webhook.

## Get a charge

Public by `chargeId` (treat the id as the capability).

```bash theme={null}
GET /charges/chg_834e692669a3f8ad
```

Returns the [charge object](/concepts/charges#charge-object), or `404`.

## Pay from an agent wallet

```bash theme={null}
POST /charges/chg_xxx/pay
Authorization: Bearer pz_sk_...   # the paying agent's key
```

### Success: paid instantly

```json theme={null}
{
  "paid": true,
  "charge": { "status": "paid", "method": "ledger", "reference": "PAY_...", "...": "..." },
  "merchantBalanceMinor": 200
}
```

### Success: needs human approval

```json theme={null}
{
  "pendingApproval": true,
  "reason": "Monto $200 supera umbral de aprobación humana ($30 USDC)",
  "approvalId": "apr_f097d968cdb81c8d",
  "charge": { "status": "pending", "...": "..." }
}
```

Nothing was charged. If approved later (`POST /approvals/:id/grant` with console auth), you receive `payment.succeeded` + `charge.succeeded` webhooks.

### Rejected

```json theme={null}
{ "error": "Categoría 'services' no está en las categorías permitidas: ..." }
```

| Status | Meaning                                                      |
| ------ | ------------------------------------------------------------ |
| `402`  | Policy rejected (limit/category/balance). Body explains why. |
| `401`  | Not a valid agent key.                                       |
| `409`  | Charge not in `pending` state.                               |

## Pay on-chain (x402)

For agents without a Payzor wallet, payment happens in USDC on-chain.

### Step 1: request terms

```bash theme={null}
GET /charges/chg_xxx/x402
```

If unpaid, returns **`402 Payment Required`**:

```json theme={null}
{
  "x402Version": 1,
  "error": "Paga este cargo firmando USDC y reintentando con X-PAYMENT.",
  "accepts": [
    {
      "scheme": "exact",
      "network": "base-sepolia",
      "maxAmountRequired": "10000",
      "resource": "https://host/charges/chg_xxx/x402",
      "payTo": "0xc80B...",
      "asset": "0x036Cb...",
      "extra": { "name": "USDC", "version": "2" }
    }
  ]
}
```

(Already-paid charges return the charge object with `200` instead.)

### Step 2: retry signed

Repeat the same GET with the signed payload in the header:

```bash theme={null}
GET /charges/chg_xxx/x402
X-PAYMENT: <base64url-encoded x402 payload>
```

Payzor verifies and settles against the facilitator, marks the charge paid (method `x402`, reference = tx hash) and responds:

```json theme={null}
{
  "chargeId": "chg_xxx",
  "status": "paid",
  "settlement": { "success": true, "transaction": "0x..." }
}
```

Failure modes are still `402`s with an explanation (`Pago inválido`, `Liquidación fallida`); the client can fix and retry.
