Skip to Content
API referenceOverview

API Reference

Every endpoint below speaks JSON, lives under https://api.infraio.xyz (prod) or https://api-dev.infraio.xyz (test), and authenticates via HMAC-SHA256 — see Authentication for the signing ritual and Errors for the error envelope shape.

This page is the index. Each row links to the deepest existing write-up; if a row only references a path, the endpoint exists today but is documented inline in the relevant concept page rather than its own reference page.

Gateway path prefixes and their auth model:

  • /b2b/v1/* — HMAC-signed with your secret key (sk_…). The merchant backend surface.
  • /payment/v1/* — Bearer JWT (dashboard sessions). Used by the merchant dashboard frontend; not for third-party integrators.
  • /pub/v1/* — Bearer-of-truth in the path (an rfqt_… token for refund requests). No credentials. Safe to call from a browser.
  • /checkout/:key/* — Public prefix for the hosted checkout flow. key is the cst_… session key returned at create time; the buyer’s browser is the only caller. No credentials.

Checkout

MethodPathPurposeNotes
POST/b2b/v1/checkout-sessions/quickCreate a session in one call — order + checkout-session minted together.See Quickstart for the request body and sample.
POST/b2b/v1/checkout-sessionsCreate a session against an existing order. Use when your platform already has its own order model and you want one session per attempt.The two-step flow.
GET/b2b/v1/checkout-sessions/by-order/{order_id}List all sessions ever minted for an order.Useful when a buyer abandoned a session and you want to surface the previous attempts in your dashboard.
GET/checkout/{session_key}Public — the hosted checkout page fetches this. Buyer-facing fields only (no internal references).No signing; takes the session_key as the bearer-of-truth.
POST/checkout/{session_key}/intentPublic — pick a payment method on the hosted page. Emits a PaymentIntent with the deposit address.Called by checkout-web on user method selection.
POST/checkout/{session_key}/verifyPublic — let the buyer paste a tx hash to short-circuit confirmation wait.Falls through to chain watcher if hash is wrong.

Orders

Orders are the timeless billable entity. A single order can back multiple checkout sessions (e.g. buyer abandons, retries).

MethodPathPurposeNotes
POST/b2b/v1/ordersCreate an order without a session.Use when you want to send the buyer a payment link later instead of redirecting them immediately.
GET/b2b/v1/orders/{id}Read a single order with line items + status.Status: PENDINGPAID | PARTIAL_PAID | CANCELED. After refund: PARTIALLY_REFUNDED | REFUNDED.
GET/b2b/v1/orders/by-merchant/{merchant_id}List your orders, cursor-paginated.See Cursor pagination for the cursor protocol.
PATCH/b2b/v1/orders/{id}/cancelMark an unpaid order canceled. Emits order.canceled.Fails if the order is already paid.
PATCH/b2b/v1/orders/{id}/reopenReverse an auto-cancel (canceled_reason=payment_timeout).Useful if the buyer comes back after the TTL expired.

Refunds

See Refunds concept page for the saga flow and token lifecycle.

Merchant-initiated

MethodPathPurposeNotes
POST/b2b/v1/merchants/{merchant_id}/refundsMerchant-initiated refund. Auto-approved (skips PENDING).Emits payment.refund.approved immediately.

Customer-initiated — refund-request tokens

The buyer fills the refund form on our hosted page; you only mint the token and deliver the URL. Two mint paths (HMAC for backends, JWT for the dashboard), three public token paths (read context, submit, request a renewal), and two dashboard-only paths for handling renewals.

MethodPathAuthPurpose
POST/b2b/v1/merchants/{merchant_id}/refund-requestsHMAC (sk_…)Mint a token from your backend. Body: {ref_type, ref_value, amount, ttl_seconds?, metadata?, hide_summary?, hide_header?}. ref_type is one of order_id / order_number / session_id / session_key; ref_value is the matching identifier. amount is required and locks the maximum the buyer can submit. Default TTL 30 min. Emits refund_request.created (source: b2b).
POST/payment/v1/merchants/{merchant_id}/refund-requestsJWT (dashboard)Mint a token from the merchant dashboard’s Issue Refund modal. Same body shape as the B2B variant. Default TTL 24 h. Emits refund_request.created (source: dashboard).
GET/pub/v1/refund-requests/{token}Token in pathPublic — checkout-web reads the form context (order summary, locked amount, current effective state).
POST/pub/v1/refund-requests/{token}/submitToken in pathPublic — buyer submits the form. Body: {reason, refund_to_address, amount?, metadata?}. amount is optional — when omitted, the merchant-locked link amount is used; when present, the server enforces amount ≤ locked amount. Creates the Refund row, emits payment.refund.requested, returns {link_token, refund_id} for the receipt page.
POST/pub/v1/refund-requests/{token}/request-renewalToken in pathPublic — buyer asks for a fresh link after expiry. Body: {customer_note?}. Emits refund_request.renewal_requested.
GET/payment/v1/merchants/{merchant_id}/refund-requests/renewalsJWT (dashboard)List pending RENEWAL_REQUESTED tokens for the merchant’s renewal widget. Cursor-paginated.
POST/payment/v1/merchants/{merchant_id}/refund-requests/renewals/{token}/issue-newJWT (dashboard)Approve a renewal — mints a new ACTIVE token, retires the old one. Emits refund_request.renewed + refund_request.created (source: renewal).
GET/payment/v1/merchants/{merchant_id}/refund-requests/by-order/{order_id}JWT (dashboard)List every refund-request token ever minted against an order with effective state. Newest first.
POST/payment/v1/merchants/{merchant_id}/refund-requests/{token}/send-emailJWT (dashboard)Queue an email delivery of the refund-request link to the customer. Body: {to}. Emits refund_request.email_send_requested.
POST/payment/v1/merchants/{merchant_id}/refund-requests/{token}/cancelJWT (dashboard)Merchant kill-switch — flips ACTIVE or RENEWAL_REQUESTEDCANCELED. Body: {reason?}. Idempotent: a second call after the status has already moved returns success without re-emitting. Emits refund_request.canceled on the first transition.

Refund lifecycle (post-create)

Applies to both flows. The endpoints below operate on the Refund row (id starts rfn_…), not the request token.

MethodPathPurposeNotes
GET/b2b/v1/refunds/{id}Read one refund.Status: PENDINGAPPROVEDEXECUTED | REJECTED.
GET/b2b/v1/refunds/by-merchant/{merchant_id}List your refunds, cursor-paginated.
POST/b2b/v1/refunds/{id}/approveApprove a PENDING refund (customer-initiated only — merchant-initiated lands APPROVED already).Crypto: lands APPROVED, you call /submit-tx next.
POST/b2b/v1/refunds/{id}/rejectDeny a PENDING refund.Emits payment.refund.rejected.
POST/b2b/v1/refunds/{id}/submit-txCrypto only — stamp the on-chain tx hash you broadcast.Body: {tx_hash, network, token_address} — all three required.

Catalog (read-only)

MethodPathPurpose
GET/v1/supported/networksAll chains InfraIO can settle on (mainnet + testnet, filtered by env).
GET/v1/supported/tokensAll stablecoins on those chains.
GET/v1/supported/currenciesFiat currencies accepted for order.currency.
GET/v1/merchants/payment-methodsMethods THIS merchant has enabled — combine of platform catalog + per-merchant toggles. Used by checkout-web.
GET/v1/public/merchants/{merchant_id}/brandingPublic — what the checkout page reads to skin itself.

Health

MethodPathAuthPurpose
GET/healthNone (public)Plain liveness probe — returns {"status":"ok"}. This (no /v1 prefix) is the only unauthenticated health endpoint — point your k8s / uptime monitors here.
GET/payment/v1/merchants/{merchant_id}/healthDashboard JWTPer-merchant health view — recent intent settlement rate, sweep backlog. Useful for your own status pages. Requires a dashboard session token, not a B2B API key. Reachable only under the /payment/ gateway prefix — the bare /v1/... path is not publicly routed.
GET/payment/v1/stats/healthDashboard JWTAggregate health across a merchant’s workspace tree. Not a public liveness probe — it sits behind the same JWT auth under the /payment/ gateway prefix.

Cursor pagination

Every list endpoint accepts the same query params, returns the same envelope. We use opaque cursors (base64url-encoded (created_at, id)) rather than offsets so a page never shifts when a row lands mid-scroll.

Query paramTypeDefaultNotes
cursorstringOpaque — copy the previous response’s next_cursor verbatim.
limitint201..100.
sort_dir'asc' | 'desc'descSort by (created_at, id).
from / toRFC3339Optional time-window filter.
searchstringFree-text filter where supported.

Response envelope:

{ "orders": [ /* page rows */ ], "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wNS0...", "has_next": true }

has_next is always present. next_cursor is omitted when has_next is false. Don’t try to parse the cursor — its shape is internal and will change.

What’s missing from this page

This index covers the merchant-facing surface — endpoints under /admin/* (dashboard tools, KYB review, network management) and internal gRPC routes are intentionally not listed. The OpenAPI spec generated by swag covers the full surface; if you need it, ping support and we’ll share a current snapshot.