Payments
The Payments API is the public surface for the platform's payment session model. A payment session is a short-lived, tenant-scoped record that ties together an account, an amount, an optional invoice, and the payment page (CMS slug) that will collect the funds. The collection itself happens in the gateway (Stripe Elements, Zuora hosted page, etc.); this API is the orchestrator and the audit boundary, not the card-data path.
A typical flow:
POST /api/v1/payments— create a session for(accountId, amountCents, currency), optionally bound to aninvoiceIdand apaymentPageSlug.The customer is redirected to the rendered payment page; the gateway widget completes the charge.
POST /api/v1/payments/{id}/complete— the gateway callback (or a webhook handler) marks the session complete; the corresponding invoice (if any) is settled.GET /api/v1/payments/{id}— read the resolved session for receipts / reconciliation.
All endpoints require an API key. Writes use the commerce scope, reads use read. Card data is never accepted by this API; it always flows through the gateway directly.
paymentPageSlug is resolved within the tenant scope of the calling API key — page slugs are unique per tenant, not globally, so two tenants may safely reuse the same slug.
See also: Invoices (POST /invoices/{id}/pay is the invoice-driven entry point), PaymentMethods.
Endpoints
POST /api/v1/payment-links
Returns a link to a payment page that opens for one billing account and pays toward one open invoice. The link expires at the invoice due date (or today, if already past due) plus the tenant's grace window, never more than 30 days out. It stays usable until that invoice has no open balance, so a partial payment can be finished and a declined card retried from the same link; saving a payment method without paying uses it up. url is null when no active hostname serves the page yet; path is always returned. Typical use: a billing-system workflow issues the link when an invoice posts and writes it into the invoice field its email template includes.
Scoped secret API key — send an sk_live_… value (keys issued before the typed format carry a bare pk_<hex> prefix and are also secret; they still work). A publishable pk_live_…/pk_test_… key is browser-safe, carries no scopes, and is refused by every endpoint in this spec with publishable_key_not_allowed. Coarse scopes: read, commerce, admin (admin covers everything below). Narrow per-resource scopes: journeys|pages :read|write|publish|delete, productsets :read|write|publish|delete, components|rules :read|write|delete, context :read (read-only context tier), catalog :read|write-native. publish is never implied by write.
Slug of the payment page the link opens
Billing-system account id
Open invoice the link is for (id or invoice number)
Link issued
Validation error
Payment page not found
Payment links are not set up, the signing key is unavailable, or the invoice is not open (not_configured, signing_key_unavailable, invoice_not_open, verification_unsupported, no_billing_integration)
The billing system could not be reached
POST /api/v1/payment-links HTTP/1.1
Host: api.peakcommerce.app
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 57
{
"pageSlug": "text",
"accountId": "text",
"invoiceId": "text"
}{
"data": {
"url": "text",
"path": "text",
"expiresAt": "2026-01-01T00:00:00.000Z",
"invoiceId": "text",
"pageSlug": "text"
}
}Notes, examples, or caveats for POST /payment-links go here.
GET /api/v1/payments
Scoped secret API key — send an sk_live_… value (keys issued before the typed format carry a bare pk_<hex> prefix and are also secret; they still work). A publishable pk_live_…/pk_test_… key is browser-safe, carries no scopes, and is refused by every endpoint in this spec with publishable_key_not_allowed. Coarse scopes: read, commerce, admin (admin covers everything below). Narrow per-resource scopes: journeys|pages :read|write|publish|delete, productsets :read|write|publish|delete, components|rules :read|write|delete, context :read (read-only context tier), catalog :read|write-native. publish is never implied by write.
Max items to return (1–100, default 20)
20Number of items to skip (default 0)
0Field to sort by
Sort direction
ascPossible values: Filter by status
Paginated list of payment sessions
API key missing or invalid
GET /api/v1/payments HTTP/1.1
Host: api.peakcommerce.app
X-API-Key: YOUR_API_KEY
Accept: */*
No content
Returns every payment session for the calling tenant in a single page (no cursor pagination yet). Useful for reconciliation and reporting; not intended as a customer-facing list. Filter / sort client-side by status, accountId, or createdAt.
Requires the read scope. Sessions stay in the response after completion; treat the row as immutable once status reaches a terminal state.
POST /api/v1/payments
Scoped secret API key — send an sk_live_… value (keys issued before the typed format carry a bare pk_<hex> prefix and are also secret; they still work). A publishable pk_live_…/pk_test_… key is browser-safe, carries no scopes, and is refused by every endpoint in this spec with publishable_key_not_allowed. Coarse scopes: read, commerce, admin (admin covers everything below). Narrow per-resource scopes: journeys|pages :read|write|publish|delete, productsets :read|write|publish|delete, components|rules :read|write|delete, context :read (read-only context tier), catalog :read|write-native. publish is never implied by write.
Idempotency key to safely retry without creating duplicates
Payment session created
No content
Validation error
POST /api/v1/payments HTTP/1.1
Host: api.peakcommerce.app
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
Content-Length: 98
{
"accountId": "text",
"amountCents": 1,
"currency": "text",
"invoiceId": "text",
"paymentPageSlug": "text"
}No content
Creates a new payment session. The session captures intent, not a charge — no funds move until the gateway widget confirms.
Provide paymentPageSlug to bind the session to a specific CMS-authored payment page (recommended; the rendered page knows which gateway widget to mount). Provide invoiceId to bind the session to an open invoice; on completion the invoice will be marked paid via the active billing adapter.
Requires the commerce scope. Returns 201 and a nextActions hint pointing to the rendered payment-page URL and POST /payments/{id}/complete.
GET /api/v1/payments/{id}
Scoped secret API key — send an sk_live_… value (keys issued before the typed format carry a bare pk_<hex> prefix and are also secret; they still work). A publishable pk_live_…/pk_test_… key is browser-safe, carries no scopes, and is refused by every endpoint in this spec with publishable_key_not_allowed. Coarse scopes: read, commerce, admin (admin covers everything below). Narrow per-resource scopes: journeys|pages :read|write|publish|delete, productsets :read|write|publish|delete, components|rules :read|write|delete, context :read (read-only context tier), catalog :read|write-native. publish is never implied by write.
Payment session details
No content
GET /api/v1/payments/{id} HTTP/1.1
Host: api.peakcommerce.app
X-API-Key: YOUR_API_KEY
Accept: */*
Payment session details
No content
Returns the full payment-session record including its current status, the linked invoiceId (if any), the resolved gateway transaction id once the session has completed, and the audit metadata. Safe to poll while waiting for a webhook to mark the session complete.
Requires the read scope.
POST /api/v1/payments/{id}/complete
Scoped secret API key — send an sk_live_… value (keys issued before the typed format carry a bare pk_<hex> prefix and are also secret; they still work). A publishable pk_live_…/pk_test_… key is browser-safe, carries no scopes, and is refused by every endpoint in this spec with publishable_key_not_allowed. Coarse scopes: read, commerce, admin (admin covers everything below). Narrow per-resource scopes: journeys|pages :read|write|publish|delete, productsets :read|write|publish|delete, components|rules :read|write|delete, context :read (read-only context tier), catalog :read|write-native. publish is never implied by write.
Payment session completed
No content
POST /api/v1/payments/{id}/complete HTTP/1.1
Host: api.peakcommerce.app
X-API-Key: YOUR_API_KEY
Accept: */*
Payment session completed
No content
Idempotent terminator for a session. Use this from the gateway success callback or from a webhook handler once the gateway confirms funds. Settles the linked invoice through the active billing adapter, writes payment.complete to the audit log, and emits the payment.succeeded event to subscribed webhooks.
Calling complete on a session that is already in a terminal state is a no-op (returns 200). Calling it on a session whose gateway transaction has not actually succeeded is a programming error — this endpoint trusts the caller and does not re-verify the gateway side.
Requires the commerce scope.
Last updated
Was this helpful?
