Checkouts API
Checkout sessions are the core of the Coal payment flow. Create a session to generate a unique payment URL, then redirect your customer to complete payment. Coal verifies the on-chain transfer and notifies your server via webhook.
The Checkout Session Object
1{2 "id": "clxxx789",3 "merchantId": "clmerchant456",4 "slug": "my-product",5 "amount": "49.99",6 "currency": "USDC",7 "status": "pending",8 "payoutAddress": "0xabc123...",9 "txHash": null,10 "redirectUrl": "https://yoursite.com/success",11 "productId": "clxxx123",12 "expiresAt": "2026-03-22T12:15:00.000Z",13 "confirmedAt": null,14 "createdAt": "2026-03-22T12:00:00.000Z"15}
| Field | Type | Description |
|---|---|---|
id | string | Unique session ID (CUID) |
merchantId | string | ID of the owning merchant |
slug | string | Payment link slug this session was created from |
amount | string | Amount for this session (decimal string) |
currency | string | Session settlement currency |
status | string | pending → verifying → confirmed, or failed / expired |
payoutAddress | string | Merchant's Base wallet address |
txHash | string | null | On-chain transaction hash once confirmed |
redirectUrl | string | null | Where to redirect after payment |
payerInfoConfig | object | null | Buyer info fields Coal should collect before payment |
payerInfo | object | null | Collected payer details once the buyer fills them in |
expiresAt | ISO 8601 | Session expiry (24 hours from creation) |
confirmedAt | ISO 8601 | null | When on-chain confirmation was verified |
Create a Checkout Session
Creates a new checkout session and returns the session ID and checkout URL. Use the URL to redirect your customer.
Authentication: x-api-key: coal_live_*
Request body:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | number | required | Amount to charge for the session |
currency | string | optional | Settlement currency. Defaults to the merchant's configured currency. |
productId | string | optional | Optional product ID to associate with the session |
productName | string | optional | Optional display name for the checkout |
productDescription | string | optional | Optional product description shown in checkout |
productImage | string | optional | Optional product image URL |
redirectUrl | string | optional | Where to send the buyer after payment |
callbackUrl | string | optional | Optional server-side callback endpoint for payment events |
splitConfigId | string | optional | Optional split configuration ID to apply at settlement |
payerInfo | { required: boolean; fields: string[] } | optional | Collect payer details before checkout. Example fields: fullName, email, phone, company, country. |
1curl -X POST https://api.usecoal.xyz/api/checkouts \2 -H "x-api-key: coal_live_your_key_here" \3 -H "Content-Type: application/json" \4 -d '{5 "amount": 49.99,6 "productName": "Pro Plan",7 "redirectUrl": "https://yoursite.com/success",8 "payerInfo": {9 "required": true,10 "fields": ["fullName", "email"]11 }12 }'
1{2 "data": {3 "id": "clxxx789",4 "url": "https://usecoal.xyz/pay/checkout/clxxx789",5 "status": "pending",6 "amount": 49.99,7 "currency": "USDC",8 "expiresAt": "2026-03-22T12:15:00.000Z"9 }10}
Session Expiry
Sessions expire after 24 hours. If the customer doesn't complete payment in that window, create a new session. The old session will transition to expired status.
Collecting Payer Info
Use payerInfo to ask for buyer details before payment. Coal stores the collected values on the checkout session and includes them in the checkout.session.completed webhook payload.
Get Session Status
Poll this endpoint or use it in your redirect handler to check whether a payment has been confirmed.
1curl https://api.usecoal.xyz/api/pay/status/clxxx789
1{2 "status": "confirmed",3 "txHash": "0xdeadbeef...",4 "redirectUrl": "https://yoursite.com/success"5}
Status values:
| Status | Description |
|---|---|
pending | Session created, awaiting customer payment |
verifying | Transaction hash received and on-chain verification is running |
confirmed | Payment verified on-chain |
failed | Payment transaction failed or was invalid |
expired | Session timed out without payment |
Confirm a Payment (Merchant-Initiated)
Called by the checkout widget after the customer's wallet submits the transaction. You do not call this from your server — it's an internal step handled by Coal's frontend.
This endpoint is called by the Coal checkout widget, not by your integration. Your server should rely on webhooks or status polling to detect payment confirmation.
List Sessions (Console only)
Returns all checkout sessions for the authenticated merchant, newest first. This is a dashboard route, not the primary public merchant API.
Authentication: Authorization: Bearer <Privy JWT>
Query parameters:
| Param | Type | Description |
|---|---|---|
status | string | Filter by status: pending, confirmed, failed, expired |
limit | number | Max results per page (default: 50, max: 100) |
cursor | string | Cursor for pagination (from previous response) |
1curl "https://api.usecoal.xyz/api/console/checkouts?status=confirmed&limit=20" \2 -H "Authorization: Bearer <Privy JWT>"
1{2 "data": {3 "sessions": [4 {5 "id": "clxxx789",6 "amount": "49.99",7 "currency": "USDC",8 "status": "confirmed",9 "txHash": "0xdeadbeef...",10 "confirmedAt": "2026-03-22T12:03:41.000Z",11 "createdAt": "2026-03-22T12:00:00.000Z"12 }13 ],14 "nextCursor": null,15 "total": 116 }17}
Capture a Payment (Console only)
This is a dashboard route for legacy or internal hold flows. See Authorize & Capture for the legacy walkthrough.
Authentication: Authorization: Bearer <Privy JWT>
1curl -X POST https://api.usecoal.xyz/api/console/checkouts/clxxx789/capture \2 -H "Authorization: Bearer <Privy JWT>" \3 -H "Content-Type: application/json" \4 -d '{ "amount": 49.99 }'
1{2 "data": {3 "id": "clxxx789",4 "status": "confirmed",5 "capturedAt": "2026-03-22T15:00:00.000Z",6 "amount": "49.99"7 }8}
Void an Authorization (Console only)
Releases a reserved authorization without capturing funds.
1curl -X POST https://api.usecoal.xyz/api/console/checkouts/clxxx789/void \2 -H "Authorization: Bearer <Privy JWT>"
1{2 "data": {3 "id": "clxxx789",4 "status": "voided",5 "voidedAt": "2026-03-22T15:00:00.000Z"6 }7}
Webhook Events
| Event | Fired when |
|---|---|
checkout.confirmed | Payment verified on-chain |
checkout.failed | Transaction failed or invalid |
checkout.expired | Session timed out |
checkout.authorized | Auth & Capture — funds reserved |
checkout.voided | Authorization released |
See Webhooks Overview and Signature Verification for integration details.
Error Codes
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Session or slug does not exist |
SESSION_EXPIRED | 410 | Session has passed its 15-minute window |
ALREADY_CONFIRMED | 409 | Session has already been paid |
UNAUTHORIZED | 401 | Missing or invalid API key |
INVALID_AMOUNT | 400 | Capture amount exceeds authorized amount |
