Pay
Related guides: Accept Payments · Pay Sessions
Payment execution is gated
Heads up: bill-payment execution is currently gated off. POST /v1/pay/payments returns 501 PAYMENT_EXECUTION_NOT_AVAILABLE until the pay pillar is enabled. Minting pay tokens and storing payment methods work today; do not integrate against the payment-initiation endpoint yet — track availability in the changelog.
/v1/pay/token/createServer-to-server. Mint a short-lived pay_token (15-minute TTL) that authorizes the hosted Elements add-payment-method / pay flows. Requires client credentials; the client_id is taken from the credential — a mismatched body value is rejected with 403.
Request body
| client_user_id*string | Your unique identifier for the end user |
| bill_idstring | Bill to pay (required for the pay flow; omit for add-payment-method only) |
| amountobject | { value: integer (minor units), currency: string } — the amount to authorize |
| payment_method_idstring | Pre-bind a saved payment method |
| metadata_jsonstring | Opaque JSON string echoed back on the token |
See the Pay Sessions reference for the full pay-token lifecycle (validate + scope).
curl -X POST https://sandbox.api.billerapi.com/v1/pay/token/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BILLERAPI_API_KEY" \
-d '{
"client_user_id": "user_12345",
"bill_id": "bill_abc123",
"amount": { "value": 1299, "currency": "USD" }
}'{
"success": true,
"pay_token": "payt_5f3c…",
"pay_token_id": "ptid_789xyz",
"expires_at": "2026-06-29T12:15:00Z"
}/v1/pay/payment-methodsStore a payment method. In production the PAN is tokenized by the hosted Elements page and never touches your servers; this endpoint accepts the card details from that BillerAPI-hosted surface and returns a reusable payment_method_id. Authenticate with a bearer token, a pay token, or client credentials.
Request body
| pan*string | Primary account number (digits, 13–19 chars) |
| expiry_month*integer | Expiry month (1–12) |
| expiry_year*integer | Expiry year (4-digit) |
| cvvstring | Card verification value (3–4 digits) |
| bucketstring | Bucket label, e.g. "primary" |
The returned payment_method_id is what you pass to POST /v1/pay/payments. Never send raw card data from your own frontend — use the hosted Elements page.
curl -X POST https://sandbox.api.billerapi.com/v1/pay/payment-methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer at_sandbox_xyz789" \
-d '{
"pan": "4242424242424242",
"expiry_month": 12,
"expiry_year": 2030,
"cvv": "123",
"bucket": "primary"
}'{
"payment_method_id": "pm_abc123",
"bucket": "primary"
}/v1/pay/paymentsInitiate a bill payment against a stored payment method. Gated: returns 501 PAYMENT_EXECUTION_NOT_AVAILABLE until payment execution is enabled. An idempotency_key is required (via the Idempotency-Key header or the body field).
Request body
| bill_id*string | The bill to pay |
| payment_method_id*string | A stored payment method id |
| idempotency_keystring | Retry-safe key (or send the Idempotency-Key header) |
| amount_minor_unitsinteger | Amount in minor units (cents). Defaults to the bill amount. |
| currencystring | 3-letter ISO currency code |
Outcomes are confirmed by the pay.succeeded / pay.failed webhooks — a 202 means the attempt was scheduled, not that it settled. See Webhooks.
curl -X POST https://sandbox.api.billerapi.com/v1/pay/payments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer at_sandbox_xyz789" \
-H "Idempotency-Key: idem_2026-06-25_bill_abc123" \
-d '{
"bill_id": "bill_abc123",
"payment_method_id": "pm_abc123",
"amount_minor_units": 1299,
"currency": "USD"
}'{
"payment_attempt_id": "patt_01HX5...",
"bill_id": "bill_abc123",
"status": "SCHEDULED"
}/v1/pay/payments/:attemptIdRetrieve a payment attempt by id. This endpoint is not gated — it proxies straight to pay-service. Because payment initiation is gated off today, there are no attempts to retrieve yet; once execution is enabled and POST /v1/pay/payments creates attempts, this returns their current status.
Path parameters
| attemptId*string | The payment attempt id |
curl https://sandbox.api.billerapi.com/v1/pay/payments/patt_01HX5 \
-H "Authorization: Bearer at_sandbox_xyz789"{
"payment_attempt_id": "patt_01HX5...",
"bill_id": "bill_abc123",
"status": "SUCCEEDED",
"amount": "12.99",
"currency": "USD",
"confirmation_number": "CNF-998877"
}The Payment Attempt object
A Payment Attempt records a single attempt to pay a bill. It progresses from SCHEDULED to a terminal state, mirrored by the pay.* webhooks.
Attributes
| payment_attempt_id*string | Unique identifier for the payment attempt |
| bill_id*string | The bill this attempt is paying |
| status*string | SCHEDULED | SUCCEEDED | FAILED | ESCALATED |
| amountstring | Decimal amount string in `currency` units, when available |
| currencystring | ISO 4217 currency code, e.g. "USD" |
| confirmation_numberstring | Biller-side confirmation / reference number, when the payment succeeds |
{
"payment_attempt_id": "patt_01HX5...",
"bill_id": "bill_abc123",
"status": "SUCCEEDED",
"amount": "12.99",
"currency": "USD",
"confirmation_number": "CNF-998877"
}