Skip to content

API reference

Full v1 API reference — authentication, errors, rate limits, idempotency, and every endpoint with cURL, Node, and PHP samples.

API reference

Base URL: your Biz Invoice Pay domain (local dev: http://localhost:3102). All endpoints live under /api/v1. Field names below are taken from src/server/api/spec.ts, the single source of truth.

Authentication

Pass your API key as a Bearer token:

Authorization: Bearer inv_test_9f3a2b1c...

Use inv_test_… keys in test mode, inv_live_… in live mode. See API keys.

Without a valid key you get:

{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The API key provided is invalid."
  }
}

Errors

Every error has the same shape:

{
  "error": {
    "type": "invalid_request | authentication_error | permission_error | not_found | rate_limit | payment_error | server_error",
    "code": "machine_readable_code",
    "message": "Human-readable explanation.",
    "param": "offending_field (optional)"
  }
}

Common codes: missing_reference, below_minimum, card_declined, insufficient_funds, payment_not_found, session_not_found, already_refunded.

Rate limits

60 requests per minute per key. Every response carries headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1728912000

Exceeding the limit returns 429 with error.type = rate_limit. Back off and retry after the reset time.

Idempotency

POST endpoints accept an Idempotency-Key header. If you retry a request with the same key, the original response is returned instead of performing the action twice — so a dropped connection never creates two payment sessions or two refunds.

Idempotency-Key: order-4821-attempt-1

Use a unique key per logical operation (e.g. per order), and keep the key stable across retries of that operation.

---

Create a payment session

POST /api/v1/payment-sessions

Creates a hosted checkout session and returns its URL. Redirect your customer (or show the QR) — the customer pays on Biz Invoice Pay's page and returns to your success_url or cancel_url.

Request body:

FieldTypeRequiredDescription
amount_centsintegerYesCharge amount in cents. Minimum 100 ($1.00).
currency"usd"YesOnly usd is supported.
descriptionstringYesWhat the customer is paying for (shown at checkout).
customer_emailstringNoPrefills the email on the pay page; receipt goes here.
referencestringNoYour order ID. Use it later to look up the payment.
success_urlstring (URL)YesWhere the customer goes after paying.
cancel_urlstring (URL)YesWhere the customer goes if they cancel.
metadataobject (string → string)NoCustom key/value pairs stored on the session.

Response (201): a PaymentSessionResponse:

{
  "id": "chk_9f3a2b1c",
  "url": "http://localhost:3102/checkout/chk_9f3a2b1c",
  "status": "open",
  "expires_at": "2026-10-15T03:00:00.000Z",
  "amount_cents": 5000,
  "description": "Haircut + beard trim"
}

Session status is one of open, paid, expired, canceled.

curl -X POST http://localhost:3102/api/v1/payment-sessions \
  -H "Authorization: Bearer inv_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4821-attempt-1" \
  -d '{
    "amount_cents": 5000,
    "currency": "usd",
    "description": "Haircut + beard trim",
    "customer_email": "sam@example.com",
    "reference": "order-4821",
    "success_url": "https://yourshop.com/thanks",
    "cancel_url": "https://yourshop.com/cart",
    "metadata": { "order_id": "4821" }
  }'

---

Retrieve a payment session

GET /api/v1/payment-sessions/:id

Returns the session, including its current status (open, paid, expired, canceled).

{
  "id": "chk_9f3a2b1c",
  "url": "http://localhost:3102/checkout/chk_9f3a2b1c",
  "status": "paid",
  "expires_at": "2026-10-15T03:00:00.000Z",
  "amount_cents": 5000,
  "description": "Haircut + beard trim"
}

Unknown id → 404, error.type = not_found, error.code = session_not_found.

curl http://localhost:3102/api/v1/payment-sessions/chk_9f3a2b1c \
  -H "Authorization: Bearer inv_test_YOUR_KEY"

---

Retrieve a payment

GET /api/v1/payments/:id

Returns a PaymentResponse — the authoritative record with fee and net amounts.

Response fields:

FieldTypeDescription
idstringPayment id (pay_…).
amount_centsintegerCharged amount.
application_fee_centsintegerBiz Invoice Pay fee (4.9% + 30¢).
net_to_seller_centsintegerWhat you received: amount minus fee.
statusstringprocessing, succeeded, failed, refunded, partially_refunded.
failure_codestring \nulle.g. card_declined, insufficient_funds.
refunded_centsintegerTotal refunded so far.
invoice_idstring \nullLinked invoice, if any.
session_idstring \nullLinked payment session, if any.
customer_emailstringCustomer email.
created_atstring (ISO 8601)When the payment was created.
{
  "id": "pay_7d2e9a41",
  "amount_cents": 5000,
  "application_fee_cents": 275,
  "net_to_seller_cents": 4725,
  "status": "succeeded",
  "failure_code": null,
  "refunded_cents": 0,
  "invoice_id": null,
  "session_id": "chk_9f3a2b1c",
  "customer_email": "sam@example.com",
  "created_at": "2026-10-14T21:05:00.000Z"
}
curl http://localhost:3102/api/v1/payments/pay_7d2e9a41 \
  -H "Authorization: Bearer inv_test_YOUR_KEY"

---

Find payments by reference

GET /api/v1/payments?reference=order-4821

Looks up payments created from sessions that carried your reference (e.g. your order id). Returns { "data": PaymentResponse[] }.

{
  "data": [
    {
      "id": "pay_7d2e9a41",
      "amount_cents": 5000,
      "application_fee_cents": 275,
      "net_to_seller_cents": 4725,
      "status": "succeeded",
      "failure_code": null,
      "refunded_cents": 0,
      "invoice_id": null,
      "session_id": "chk_9f3a2b1c",
      "customer_email": "sam@example.com",
      "created_at": "2026-10-14T21:05:00.000Z"
    }
  ]
}

Missing ?reference= → 400, error.code = missing_reference.

curl "http://localhost:3102/api/v1/payments?reference=order-4821" \
  -H "Authorization: Bearer inv_test_YOUR_KEY"

---

Create a refund

POST /api/v1/payments/:id/refunds

Refunds a payment in full (omit amount_cents) or partially. See fee-on-refund policy for how the Biz Invoice Pay fee is treated.

Request body:

FieldTypeRequiredDescription
amount_centsintegerNoPartial refund amount. Omit for a full refund.
reasonstringNoFree-text reason recorded on the refund.

Response (a RefundResponse):

{
  "id": "ref_3b8c1f20",
  "status": "succeeded",
  "amount_cents": 2000
}

Refund status is succeeded, pending, or failed. After the refund, the payment's status becomes refunded (full) or partially_refunded (partial), and refunded_cents increases.

curl -X POST http://localhost:3102/api/v1/payments/pay_7d2e9a41/refunds \
  -H "Authorization: Bearer inv_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: refund-pay_7d2e9a41-1" \
  -d '{ "amount_cents": 2000, "reason": "customer returned item" }'

Error examples

Missing required field (create session without success_url):

{
  "error": {
    "type": "invalid_request",
    "code": "missing_field",
    "message": "success_url is required.",
    "param": "success_url"
  }
}

Amount below the $1.00 minimum:

{
  "error": {
    "type": "invalid_request",
    "code": "below_minimum",
    "message": "Amount 50¢ is below the minimum charge of 100¢.",
    "param": "amount_cents"
  }
}

Declined test card on a hosted checkout attempt surfaces as a payment record with status: "failed" and failure_code: "card_declined" — not an API error.

Last updated: October 14, 2026

Was this page helpful?