reference:"reference": {
"type": "PAYMENT_LINK",
"id": "pl_AAAA..."
}reference.type | Source |
|---|---|
PAYMENT_LINK | Payment Links |
FAILED, and their next attempt creates a new one. Failed charges are a normal part of checkout, not an incident.GET /v1/charges — pass the source's ID as reference_id. The response is a paginated list, one entry per attempt:{
"items": [
{
"id": "ch_BBBB...",
"reference": { "type": "PAYMENT_LINK", "id": "pl_AAAA..." },
"status": "COMPLETED",
"chain_id": "eip155:8453",
"unexpected": false,
"currency": "USDC",
"amount": "10.00",
"completed_at": null,
"failed_at": null,
"cancelled_at": null,
"created_at": "2026-07-20T14:18:40.123Z",
"updated_at": "2026-07-20T14:20:00.456Z"
},
{
"id": "ch_AAAA...",
"reference": { "type": "PAYMENT_LINK", "id": "pl_AAAA..." },
"status": "FAILED",
"chain_id": "eip155:8453",
"unexpected": false,
"currency": "",
"amount": "0",
"completed_at": null,
"failed_at": null,
"cancelled_at": null,
"created_at": "2026-07-20T14:15:22.123Z",
"updated_at": "2026-07-20T14:16:05.789Z"
}
],
"meta": { "total": 2, "limit": 50, "offset": 0, "next": "/v1/charges?limit=50&offset=50" }
}COMPLETED — that's the money. The rest are attempts that didn't land.external_id to the source ID at creation time. Given a charge, reference.id points back to that source; given a source, reference_id returns everything paid against it.| Filter | Value |
|---|---|
statuses | Comma-separated statuses, e.g. COMPLETED,FAILED |
reference_types | Comma-separated; currently only PAYMENT_LINK is recognized |
reference_id | A single source UID — every charge made against it |
ids | Comma-separated charge UIDs |
created_at_from / created_at_to | ISO-8601 range |
limit / offset | limit 1–100, defaults to 50 |
meta.next is always present and doesn't indicate that more results exist — compare offset + limit against meta.total to know when to stop.| Field | Meaning |
|---|---|
id | Charge UID, prefixed ch_ |
reference | What created this charge — type and the source's id |
status | See below |
amount / currency | What was paid, and in which token — USDC or USDT |
chain_id | The network the payment settled on, in CAIP-2 format — for example eip155:8453 for Base |
unexpected | true when the charge was reconstructed from an on-chain transaction found by chain scanning, rather than created by a customer going through checkout |
created_at / updated_at | When the attempt started, and when it last changed |
amount and currency are populated on COMPLETED charges. On any other status they come back as "0" and an empty string — treat those as "no amount", not as an amount of zero.updated_at together with status to know when a charge last changed state.| Status | Meaning |
|---|---|
PENDING | Attempt started, not yet confirmed on-chain |
COMPLETED | Transaction confirmed on-chain |
FAILED | This attempt didn't go through — the customer can start a new one |
FAILED is final for that charge, but not for the request behind it: as long as the payment link is still open, the customer can retry, which creates a new charge.| Event | Fires when |
|---|---|
charge.created | A customer started checkout — an attempt is open |
charge.completed | The payment confirmed on-chain and settled |
charge.failed | The attempt failed — a reverted transaction, or a timeout |
charge.* events carry the payment facts — token, amount, network — which makes them the right feed for reconciliation and for reporting across every collection method.payment_link.completed. Fulfil orders on the source event, not on charge.failed: a failed attempt doesn't mean the order is lost.{
"code": 401,
"message": "Invalid authorization token"
}| Status | Meaning |
|---|---|
401 Unauthorized | Missing or invalid API key, wrong environment, or blocked by the token's IP allowlist |
404 Not Found | No charge with that ID — including charges that belong to another branch |
429 Too Many Requests | Rate limit exceeded. Check the Retry-After header |
500 Internal Server Error | Something went wrong on our end — contact support |