Skip to main content
PayHubDeveloper docs
简体中文

API reference

The 16 API endpoints, authentication and environments, request headers, data formats, pagination, compatibility, rate limits and the fields of 8 objects.

Last updated 2026-10-20 · API contract v1.0.0

Overview

The API has 16 endpoints. Fields, constraints, enums and examples are all generated from the API contract. Click an endpoint to open its detail page.

ResourceEndpointSummaryScopesIdempotency key
PaymentPOST/v1/paymentsCreate paymentpayments:writeRequired
PaymentGET/v1/paymentsList paymentspayments:read—
PaymentGET/v1/payments/{payment_id}Get paymentpayments:read—
PaymentPOST/v1/payments/{payment_id}/confirmConfirm paymentpayments:writeRequired
PaymentPOST/v1/payments/{payment_id}/cancelCancel paymentpayments:writeRequired
Checkout sessionPOST/v1/checkout/sessionsCreate hosted checkout sessionpayments:writeRequired
Checkout sessionGET/v1/checkout/sessions/{session_id}Get checkout sessionpayments:read—
RefundPOST/v1/refundsCreate refundrefunds:writeRequired
RefundGET/v1/refundsList refundsrefunds:read—
RefundGET/v1/refunds/{refund_id}Get refundrefunds:read—
Balances and balance transactionsGET/v1/balancesList balancesfinance:read—
Balances and balance transactionsGET/v1/balance-transactionsList balance transactionsfinance:read—
Settlements and payoutsGET/v1/settlementsList settlementsfinance:read—
Settlements and payoutsGET/v1/settlements/{settlement_id}Get settlementfinance:read—
Settlements and payoutsGET/v1/payouts/{payout_id}Get payoutfinance:read—
EventGET/v1/events/{event_id}Get eventDepends on the event type—

Note

The API doesn't support changing your payout account, changing rates, adjusting balances or executing payouts. Do these in the merchant portal, or contact the platform.

Caution

Use API keys only on your server. In the browser, use hosted checkout, or call the API through a proxy on your own server. The docs site doesn't offer interactive API testing.

Basic conventions

  • Use HTTPS and JSON (UTF-8). Paths include the version, /v1.
  • API address: https://api.payhub.example. Test and live use the same address, and your API key determines the environment.
  • Every response body includes a request_id. Give it to support when you troubleshoot, or search for it in the merchant portal to find the call (API call logs (opens the merchant portal in a new tab) (Requires Owner, Admin or Developer)).
  • Requests have no merchant ID field and don't accept one: the merchant and environment are derived from the API key alone.

Authentication and environments

Send the request header Authorization: Bearer <API_KEY>. A missing, invalid, revoked or expired key returns 401 unauthenticated.

  • Test keys start with sk_test_ and can access only test objects. Live keys start with sk_live_. Retrieving a live object with a test key returns 404, and the platform doesn't reveal whether the object exists.
  • The scope each endpoint needs is shown in the header area of its endpoint page. A key without the required scope returns 403 forbidden.
ScopeEndpoints you can call
payments:readlistPayments, getPayment, getCheckoutSession; payment.* and dispute.* events in getEvent
payments:writecreatePayment, confirmPayment, cancelPayment, createCheckoutSession
refunds:readlistRefunds, getRefund; refund.* events in getEvent
refunds:writecreateRefund
finance:readlistBalances, listBalanceTransactions, listSettlements, getSettlement, getPayout; settlement.* events in getEvent

Who can create keys, and with which scopes:

CreatorScopes they can choose
Owner, AdminAll 5
DeveloperOnly scopes within their "grantable API scopes" (by default payments:read, payments:write and refunds:read)
Finance, ViewerCan't create keys

The Developer role can't grant finance:read by default, so use a key created by an Owner or Admin. Direct card also requires the platform to enable the "direct card" capability for you, which is separate from scopes. To get a test key, open the API Key page in the merchant portal (opens the merchant portal in a new tab) (Test environment; Requires Owner, Admin or Developer).

Request headers

HeaderEndpointsRequiredDescription
AuthorizationAll 16YesBearer <API_KEY>. Use server keys on your server only
Content-TypecreatePayment, confirmPayment, createCheckoutSession, createRefundYesapplication/json. cancelPayment has no request body, so it doesn't need this header
Idempotency-KeycreatePayment, confirmPayment, cancelPayment, createCheckoutSession, createRefundYes1–255 characters. If it's missing, the API returns 400 (error.field is Idempotency-Key). Use one key per submission, reuse the same key when you retry after a network error, and use a new key for a new submission such as a card change. See Idempotency, retries and status checks

Data formats

  • ID: A prefix, an underscore and a random string, up to 64 characters. Store IDs as opaque, case-sensitive strings and don't parse them. Common prefixes: pay_ payment, pat_ payment attempt, auth_ authentication session, cs_ checkout session, ref_ refund, dsp_ dispute, stl_ settlement, po_ payout, btx_ balance transaction, ltx_ ledger transaction, evt_ event, del_ delivery, mer_ merchant, req_ request.
  • Time: ISO 8601 with a time zone, UTC by default, for example 2026-09-23T09:00:00Z. period_start and period_end are dates in the business time zone.
  • Amount: An integer in the smallest currency unit, always appearing together with currency. USD 10000 means 100.00 and JPY 10000 means 10,000. Signed amounts appear only in BalanceTransaction.amount, SettlementItem.amount and Balance.net_position.
  • Currency: An uppercase three-letter code. You can use only the currencies enabled for you. Never add amounts in different currencies.
  • metadata: Up to 20 keys. A key can be up to 40 characters, and a value is a string of up to 200 characters. Don't put sensitive data such as card numbers in it. The platform rejects requests in which it detects such data.

Pagination

  • Lists return 20 items per page by default and up to 100 (limit).
  • next_cursor is an opaque string. Don't parse it or build one yourself. When you fetch the next page, send the same filters as for the first page.
  • Results are ordered by creation time, newest first, with ties broken by unique ID in descending order, so the order is stable (balance transactions are ordered by booked_at).
  • Time ranges are half-open: created_gte is inclusive and created_lt is exclusive. For example, created_gte=2026-09-23T00:00:00Z&created_lt=2026-09-24T00:00:00Z covers exactly the whole of September 23 (UTC).
Node.js: iterate over a full day of payments
const API_BASE = 'https://api.payhub.example';

// Iterate over every payment on 2026-09-23 (UTC): while has_more is true, continue with next_cursor and the same filters
export async function* listPaymentsOfDay() {
  const filters = {
    created_gte: '2026-09-23T00:00:00Z',
    created_lt: '2026-09-24T00:00:00Z',
    limit: '100'
  };
  let cursor;
  do {
    const query = new URLSearchParams({ ...filters, ...(cursor ? { cursor } : {}) });
    const res = await fetch(`${API_BASE}/v1/payments?${query}`, {
      headers: { Authorization: `Bearer ${process.env.PAYHUB_API_KEY}` },
      signal: AbortSignal.timeout(20_000)
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const page = await res.json();
    yield* page.data;
    cursor = page.has_more ? page.next_cursor : undefined; // Opaque string: don't parse it or build one yourself
  } while (cursor);
}

Compatibility and versions

Your client must:

  1. Ignore new fields it doesn't recognize.
  2. Never treat an unknown status as success.
  3. Tolerate unknown error codes (handle them by HTTP status), unknown event types (return 2xx and ignore them) and new next_action.type values (treat them as "not completed" and query the payment).

Versioning policy: adding fields, enum values, event types, error codes or optional parameters is a compatible change and doesn't bump /v1. Removing or renaming a field, changing semantics or adding a required parameter is a breaking change. It ships as a new version, and you get advance notice.

Rate limits and timeouts

  • 429 rate_limited: The request was not executed. Wait for Retry-After seconds, then retry with the original idempotency key. Using a different API key doesn't get around the merchant's overall limit. The platform doesn't publish specific rate limit values.
  • 503 temporarily_unavailable: This request was also not accepted (the platform has paused new transactions on this channel). Retry later with the original idempotency key. Treat every other 5xx as an unknown outcome; see Error codes and HTTP status.
  • Client timeouts: Set at least 20 seconds for creating and confirming payments. The platform waits synchronously for the provider for about 15 seconds. Beyond that it returns 202 processing, and you get the result later through a query or a webhook.

Objects

Payment

The main payment object, which corresponds one-to-one with a merchant business order. A Payment can have multiple attempts, but at most one normal successful charge. Besides status, it has separate outcome fields; version increases with every effective business change and is used for notification deduplication and concurrency control.

NameTypeRequiredDescription
id
stringRequired

Platform payment ID.

Example: pay_demo_001

merchant_order_no
stringRequired

Merchant order ID, case-sensitive as sent.

Example: ORDER-DEMO-001

environment
stringRequired

Environment: test is the test environment and live is the live environment. Test and live objects are isolated from each other.

  • test
  • live
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: test

amount
integer(int64)Required

Order amount, in the smallest currency unit. It can't be changed after the first submission to the provider.

Constraints: ≥ 1

Example: 10000

currency
stringRequired

Uppercase three-letter currency code.

Constraints: Format ^[A-Z]{3}$

Example: USD

status
stringRequired

Payment status. Clients must not treat an unknown status as success.

  • created: the order has been created and no valid charge attempt has been submitted yet; new attempts are allowed within the validity period
  • processing: submitted and being processed, or the outcome isn't confirmed yet; new attempts aren't allowed
  • requires_action: the current attempt needs the payer to complete an action such as authentication; new attempts aren't allowed
  • failed: the latest attempt clearly failed; this is not a terminal state, and an explicit retry is possible when the deadline, attempt limit and risk conditions are met
  • succeeded: payment confirmed as successful
  • canceled: cancellation confirmed as safe
  • expired: no unresolved attempt, and the order has expired and closed
  • created: The order has been created and no valid charge attempt has been submitted yet; new attempts are allowed within the validity period
  • processing: Submitted and being processed, or the outcome isn't confirmed yet; new attempts aren't allowed
  • requires_action: The current attempt needs the payer to complete an action such as authentication; new attempts aren't allowed
  • failed: The latest attempt clearly failed; this is not a terminal state, and an explicit retry is possible when the deadline, attempt limit and risk conditions are met
  • succeeded: Payment confirmed as successful
  • canceled: Cancellation confirmed as safe
  • expired: No unresolved attempt, and the order has expired and closed
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: requires_action

resolution_status
stringRequired

Outcome confirmation.

  • known: outcome confirmed
  • needs_query: outcome unknown; the platform is running a status query against the provider using the original identifiers
  • manual_review: past the automatic query window and handed over to manual follow-up; never marked as failed automatically
  • known: Outcome confirmed
  • needs_query: Outcome unknown; the platform is running a status query against the provider using the original identifiers
  • manual_review: Past the automatic query window and handed over to manual follow-up; never marked as failed automatically
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: known

captured_amount
integer(int64)Required

The amount confirmed as captured; equal to amount on success.

Constraints: ≥ 0

Example: 0

refunded_amount
integer(int64)Required

The confirmed effective refunded principal: the total of successful refunds minus confirmed refund returns. It excludes refunds that are still processing and platform exception refunds.

Constraints: ≥ 0

Example: 0

refund_returned_amount
integer(int64)Required

The cumulative refund principal confirmed as returned.

Constraints: ≥ 0

Example: 0

refund_reserved_amount
integer(int64)Required

Principal reserved for refunds that are under review or processing.

Constraints: ≥ 0

Example: 0

refund_status
stringRequired

Refund summary status, derived from refunded_amount (the effective refunded principal): none, partial, full.

  • none
  • partial
  • full
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: none

authentication_status
stringNullableRequired

The 3DS authentication status of the current attempt, taken from the authentication session status: not_required, pending, challenge, authenticated, failed, abandoned, expired. Tolerate new values. Successful authentication (authenticated) doesn't mean the charge succeeded, so don't use it to decide the payment outcome. It's null when there is no attempt yet or the attempt hasn't entered authentication.

Example: challenge

reconciliation_status
ReconciliationStatusRequired

The progress of the platform's funds processing, for reconciliation reference only. It doesn't indicate whether the payment succeeded or when you'll be paid out.

  • pending
  • matched
  • difference
  • resolved
  • More values may be added in the future. Don't treat a status you don't recognize as success.
upstream_receipt_status
UpstreamReceiptStatusRequired

The progress of the platform's funds processing, for reconciliation reference only. It doesn't indicate whether the payment succeeded or when you'll be paid out.

  • not_received
  • partially_received
  • received
  • reversed
  • More values may be added in the future. Don't treat a status you don't recognize as success.
latest_attempt_id
stringNullableRequired

ID of the latest payment attempt; null if no attempt has been submitted yet.

Example: pat_demo_001

attempt_count
integer(int32)Required

The number of attempts started. The default maximum is 3.

Constraints: ≥ 0

Example: 1

version
integer(int64)Required

Object version, which increases with every effective business change. Compare versions to discard older events, and don't order events by status name.

Constraints: ≥ 1

Example: 2

next_action
NextActionNullableRequired

The action the payer must complete when status=requires_action; null in all other cases.

type
stringRequired

The initial release of the public API exposes only redirect_to_url. Clients must tolerate types that are added in the future.

  • redirect_to_url
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: redirect_to_url

authentication_session_id
stringRequired

Authentication session ID, linked to a specific payment attempt.

Example: auth_demo_001

url
string(uri)Required

The URL of the platform's authentication page.

Example: https://pay.payhub.example/auth/<SHORT_LIVED_TOKEN>

expires_at
string(date-time)Required

The time the authentication access expires (10 minutes at most).

Example: 2026-09-23T09:10:00Z

failure
PaymentFailureNullableRequired

The reason when the attempt that latest_attempt_id points to has clearly failed; otherwise null.

code
stringRequired

Failure reason code.

Example: card_declined

message
stringRequired

Sanitized description.

Example: The issuer declined this transaction.

attempt_id
stringRequired

ID of the failed payment attempt.

Example: pat_demo_001

description
stringNo

Order summary.

Constraints: Max length 256

Example: Example order

customer_reference
stringNo

Merchant-side customer reference.

Constraints: Max length 128

Example: CUSTOMER-DEMO-001

metadata
objectNo

Custom key-value pairs set by the merchant: up to 20 keys. A key can be up to 40 characters, and a value is a string of up to 200 characters. Don't put sensitive data such as card numbers in it. The platform checks for such data and rejects the request.

Constraints: Up to 20 keysMax value length 200

Example: {"business_order_type":"one_time_purchase"}

card
CardSummaryNullableRequired

Masked details of the card used in the latest attempt; null when there are no card details yet.

brand
stringRequired

Card brand.

Example: visa

last4
stringRequired

Last four digits of the card number.

Constraints: Format ^[0-9]{4}$

Example: 1234

created_at
string(date-time)Required

Creation time.

Example: 2026-09-23T09:00:00Z

succeeded_at
string(date-time)NullableRequired

The time the payment was confirmed as successful; null if it hasn't succeeded.

Example: null

expires_at
string(date-time)Required

The deadline for starting a new attempt, fixed at creation (by default 30 minutes after creation; the platform can adjust it to between 5 and 120 minutes, so go by this field). Expiry only closes the entry point for new attempts. It doesn't invalidate a payment that was already submitted.

Example: 2026-09-23T09:30:00Z

  • failed is not a terminal state. While the payment is within its validity period and attempt limit and passes risk checks, a new attempt can start and eventually succeed. If a refund happens after succeeded, the payment status stays succeeded; check refund_status for the refund.
  • resolution_status=needs_query means the outcome is unknown and the platform is running a status query with the provider, using the original identifiers. manual_review means the payment is past the automatic query window and has been handed over to manual follow-up. The platform never marks it as failed automatically.
  • authentication_status is the 3DS authentication status. Successful authentication doesn't mean the charge succeeded, so don't use it to decide the payment outcome.
  • version increases with every effective business change. Use it to discard older events, and don't order events by status name.
  • reconciliation_status and upstream_receipt_status track the platform's funds processing. They're for reconciliation reference only: they don't indicate whether the payment succeeded or when you'll be paid out.
  • expires_at is the deadline for starting a new attempt (30 minutes after creation by default). Expiry only closes the entry point for new attempts. It doesn't invalidate a payment that was already submitted.
Payment status transitions
Payment status transitions
  1. The payer can retry after failed, so you can't order events or statuses by status name. Compare version instead.
  2. When a succeeded payment is refunded, the payment status doesn't change. Refunds are tracked on the refund and in the payment's refund_status.

Refund

A refund request against the original payment. A payment supports multiple partial refunds, each with its own refund ID.

NameTypeRequiredDescription
id
stringRequired

Platform refund ID.

Example: ref_demo_001

version
integer(int64)Required

Object version, which increases with every effective business change (status, failure reason, returned amount). Compare versions to discard older events, and don't order events by status name.

Constraints: ≥ 1

Example: 1

payment_id
stringRequired

Original payment ID.

Example: pay_demo_001

merchant_refund_no
stringRequired

Merchant refund ID, unique within one merchant and environment.

Example: REFUND-DEMO-001

amount
integer(int64)Required

Refund principal, in the smallest currency unit.

Constraints: ≥ 1

Example: 4000

currency
stringRequired

Refund currency, inherited from the original payment.

Constraints: Format ^[A-Z]{3}$

Example: USD

status
stringRequired

Refund status.

  • pending_review: accepted and waiting for review; the funds stay reserved
  • processing: approved and submitted, or the provider's result is being confirmed; the funds stay reserved
  • succeeded: the provider confirmed the refund succeeded; the reserved funds become a final deduction
  • failed: the refund clearly did not succeed; the reserved funds are released
  • rejected: rejected in review and not submitted to the provider; the reserved funds are released
  • canceled: canceled by an authorized person before submission to the provider; the reserved funds are released
  • returned: all or part of the funds were actually returned after a refund that had been confirmed as succeeded
  • pending_review: Accepted and waiting for review; the funds stay reserved
  • processing: Approved and submitted, or the provider's result is being confirmed; the funds stay reserved
  • succeeded: The provider confirmed the refund succeeded; the reserved funds become a final deduction
  • failed: The refund clearly did not succeed; the reserved funds are released
  • rejected: Rejected in review and not submitted to the provider; the reserved funds are released
  • canceled: Canceled by an authorized person before submission to the provider; the reserved funds are released
  • returned: All or part of the funds were actually returned after a refund that had been confirmed as succeeded
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: pending_review

reason
stringRequired

Refund reason.

Example: requested_by_customer

returned_amount
integer(int64)Required

The cumulative principal actually returned after the refund succeeded.

Constraints: ≥ 0

Example: 0

failure
RefundFailureNullableRequired

The reason when status is failed or rejected; otherwise null.

code
stringRequired

Failure reason code.

Example: refund_rejected

message
stringRequired

Sanitized description.

Example: The refund request didn't pass review.

metadata
objectNo

Custom key-value pairs set by the merchant: up to 20 keys. A key can be up to 40 characters, and a value is a string of up to 200 characters. Don't put sensitive data such as card numbers in it. The platform checks for such data and rejects the request.

Constraints: Up to 20 keysMax value length 200

Example: {"business_order_type":"one_time_purchase"}

created_at
string(date-time)Required

The time the request was accepted.

Example: 2026-09-23T10:00:00Z

completed_at
string(date-time)NullableRequired

The time the refund entered succeeded, failed, rejected or canceled; null if it hasn't ended yet.

Example: null

  • For reason, we recommend a reason code: requested_by_customer, duplicate, fraudulent, order_canceled or other.
  • returned means the refunded funds came back after the refund had been confirmed as succeeded. The original success is kept on record, and returned_amount is the returned principal.
  • Platform exception refunds (the platform returns a duplicate charge, or an overcharge caused by an amount mismatch, to the cardholder's original payment method) aren't returned by the API and don't count toward the payment's refunded_amount or refund_status. The platform notifies you separately with an in-app notification and an email.
Refund status transitions
Refund status transitions

While the outcome of a processing refund is unknown, the funds stay reserved and the platform keeps running status queries. It doesn't cancel the refund locally.

Checkout session

A hosted checkout session. It's linked to the order's Payment and doesn't create a second, separate payment order.

NameTypeRequiredDescription
id
stringRequired

Checkout session ID.

Example: cs_demo_002

payment_id
stringRequired

The related Payment.

Example: pay_demo_002

status
stringRequired

Checkout session status.

  • open: payment can be submitted
  • completed: appears only after the related Payment succeeds
  • expired: new submissions are no longer allowed; this doesn't mean the related payment failed
  • open: Payment can be submitted
  • completed: Appears only after the related Payment succeeds
  • expired: New submissions are no longer allowed; this doesn't mean the related payment failed
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: open

checkout_url
string(uri)Required

The checkout page URL. It carries a short-lived credential bound to this session only, and contains no merchant server-side key. Use it only for a full-page redirect of the payer's browser: don't write it to logs, analytics tools or error reporting, and don't share it with anyone.

Example: https://pay.payhub.example/checkout/<SHORT_LIVED_TOKEN>

expires_at
string(date-time)Required

The time the session expires, fixed at creation. A session lasts at most 30 minutes (the platform can shorten this) and never longer than the time the order has left to be paid. During the read-only period after expiry (fixed at creation; 24 hours by default, which is also the maximum), the payer can still use the original link to view the session and the payment result (read-only, no submissions). After that, the link stops working.

Example: 2026-09-23T09:30:00Z

return_url
string(uri)Required

The merchant's return URL after the payment ends.

Example: https://merchant.example/payment/return

cancel_url
string(uri)NullableRequired

The URL the payer goes to when they click "Return to merchant". Clicking it doesn't cancel a charge that was already submitted. It's null if not provided.

Example: https://merchant.example/payment/cancel

locale
stringRequired

Checkout page language.

Example: zh-CN

created_at
string(date-time)Required

Creation time.

Example: 2026-09-23T09:00:00Z

  • checkout_url contains a checkout token. Use it only for a full-page redirect of the payer's browser. Don't write it to logs, analytics tools or error reporting, and don't share it with anyone.
  • A session lasts at most 30 minutes, and never longer than the time the order has left to be paid. After it expires, it enters a read-only period (24 hours by default, which is also the maximum). During that period the link shows the result but can't accept submissions. After that, the link stops working.
  • When the payer clicks "Return to merchant" (cancel_url), that doesn't cancel the charge.

Balance

The merchant's balance buckets for a single currency. Any given amount is in exactly one bucket. Pending recovery is a separate receivable and is never hidden as a negative number in another bucket. Amounts in different currencies must not be added together.

NameTypeRequiredDescription
currency
stringRequired

Currency.

Constraints: Format ^[A-Z]{3}$

Example: USD

pending
integer(int64)Required

Pending settlement: the net amount from payments that succeeded but haven't yet met all the conditions for funds receipt, settlement period or reconciliation; it can't be paid out.

Constraints: ≥ 0

Example: 9650

available
integer(int64)Required

Settleable: the amount that meets the release conditions and isn't reserved; the only bucket that can be used for payouts.

Constraints: ≥ 0

Example: 8650

reserve
integer(int64)Required

Reserve: the amount held back under the rules and waiting to be released.

Constraints: ≥ 0

Example: 1000

risk_hold
integer(int64)Required

Risk hold: the held amount tied to a specific risk action or dispute.

Constraints: ≥ 0

Example: 0

refund_pending
integer(int64)Required

Reserved for refunds: the amount reserved by refunds that are under review or processing.

Constraints: ≥ 0

Example: 0

payout_pending
integer(int64)Required

Reserved for payouts: the amount reserved by an active settlement whose payout isn't confirmed as complete yet.

Constraints: ≥ 0

Example: 0

merchant_receivable
integer(int64)Required

Pending recovery: a receivable the platform holds against the merchant, created by an actual forced debit and similar cases; it isn't part of the merchant's available funds.

Constraints: ≥ 0

Example: 0

book_payable
integer(int64)Required

The merchant's book payable balance = pending + available + reserve + risk_hold + refund_pending + payout_pending.

Constraints: ≥ 0

Example: 19300

net_position
integer(int64)Required

The merchant's net position (for display only) = book_payable - merchant_receivable. It can be negative and can't replace available.

Example: 19300

Balance bucketNameMeaningUsable for payouts
pendingPending settlementMerchant net amount from payments that succeeded but haven't yet met all the conditions for funds receipt, settlement period or reconciliationNo
availableSettleableMeets the release conditions and isn't reservedYes
reserveReserveHeld back under the rules, waiting to be releasedNo
risk_holdRisk holdA hold tied to a specific risk action or disputeNo
refund_pendingReserved for refundsReserved for refunds that are under review or processingNo
payout_pendingReserved for payoutsReserved by an active settlement, payout not yet confirmedNo
merchant_receivablePending recoveryAmount you owe the platform (listed separately, not a negative balance)Not part of available funds

book_payable is the sum of the first 6 buckets. net_position = book_payable − merchant_receivable. It's for display only and can be negative.

Warning

Only available can be used for payouts. Never add balances in different currencies to get a "total balance".

Balance transaction

A single increase or decrease in one balance bucket. A posted balance transaction can't be modified; corrections are made with a reversal and a new balance transaction.

NameTypeRequiredDescription
id
stringRequired

Balance transaction ID.

Example: btx_demo_001

type
stringRequired

Posting type, for example payment_captured (payment captured), refund_reserved (reserved for refunds), settlement_reserved (reserved for settlement) or funds_released (funds released). Tolerate new values.

Example: payment_captured

source_type
stringRequired

Source business object type, for example payment, refund, dispute, settlement, payout, payout_return (payout return) or adjustment.

Example: payment

source_id
stringRequired

Source business object ID.

Example: pay_demo_001

bucket
stringRequired

Balance bucket: pending, available, reserve, risk_hold, refund_pending, payout_pending, merchant_receivable.

  • pending
  • available
  • reserve
  • risk_hold
  • refund_pending
  • payout_pending
  • merchant_receivable
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: available

amount
integer(int64)Required

Signed amount, in the smallest currency unit: a positive value increases the balance bucket and a negative value decreases it.

Example: 9650

currency
stringRequired

Currency.

Constraints: Format ^[A-Z]{3}$

Example: USD

occurred_at
string(date-time)Required

The time the business event occurred.

Example: 2026-09-23T09:05:00Z

booked_at
string(date-time)Required

Posting time. A late-arriving fact is never made to look as if it arrived on time.

Example: 2026-09-23T09:05:01Z

ledger_transaction_id
stringRequired

The related ledger transaction ID. The two balance transactions of a transfer between buckets share the same ID.

Example: ltx_demo_001

  • amount is signed: a positive value increases the balance bucket and a negative value decreases it. A transfer between buckets is two balance transactions under the same ledger_transaction_id, one decrease and one increase.
  • Each balance transaction carries both the time the event occurred (occurred_at) and the time it was posted (booked_at). created_gte and created_lt apply to booked_at, so a late-arriving fact appears at the time it was actually posted, and history isn't rewritten.
  • type is the posting type, for example payment_captured (a successful payment is posted), refund_reserved (funds reserved for a refund), settlement_reserved (funds reserved for a settlement) and funds_released (funds released). Tolerate new values.

Settlement

The settlement and its source line items.

NameTypeRequiredDescription
id
stringRequired

Settlement ID.

Example: stl_demo_001

currency
stringRequired

Settlement currency.

Constraints: Format ^[A-Z]{3}$

Example: USD

period_start
string(date)Required

The business date on which the settlement period starts (inclusive), in the merchant's settlement business time zone.

Example: 2026-09-21

period_end
string(date)Required

The business date on which the settlement period ends (inclusive).

Example: 2026-09-21

status
stringRequired

Settlement status.

  • pending_review: generated by the system and pending review; the selected merchant balance has been reserved atomically
  • approved: approved and pending execution
  • rejected: rejected in review; the reserved funds are released
  • paying: handed over for execution, or the payout outcome isn't determined yet; the funds stay reserved
  • paid: payout confirmed as successful after review
  • failed: the payout clearly didn't succeed this time; the reserved funds are released
  • canceled: not sent out yet and canceled by an authorized user; the reserved funds are released
  • returned: the bank returned the payout after it had succeeded
  • pending_review: Generated by the system and pending review; the selected merchant balance has been reserved atomically
  • approved: Approved and pending execution
  • rejected: Rejected in review; the reserved funds are released
  • paying: Handed over for execution, or the payout outcome isn't determined yet; the funds stay reserved
  • paid: Payout confirmed as successful after review
  • failed: The payout clearly didn't succeed this time; the reserved funds are released
  • canceled: Not sent out yet and canceled by an authorized user; the reserved funds are released
  • returned: The bank returned the payout after it had succeeded
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: paid

reserved_amount
integer(int64)Required

S, the balance this settlement reserves by moving it from available to payout_pending.

Constraints: ≥ 0

Example: 8650

fee_amount
integer(int64)Required

Settlement fee F. The default is 0.

Constraints: ≥ 0

Example: 0

payout_amount
integer(int64)Required

Actual bank payout amount = S - F.

Constraints: ≥ 0

Example: 8650

payout_account
PayoutAccountRequired

A masked snapshot of the payout account, taken when the settlement was generated.

holder_name
stringRequired

Account holder.

Example: Demo Merchant Ltd

bank_name
stringRequired

Bank name.

Example: Example Bank

account_last4
stringRequired

Last four digits of the account number.

Constraints: Format ^[0-9A-Za-z]{4}$

Example: 6789

payout_id
stringNullableRequired

The corresponding payout record; null until it has been executed.

Example: po_demo_001

created_at
string(date-time)Required

The time the settlement was generated.

Example: 2026-09-22T02:00:00Z

items
array<SettlementItem>Required
source_type
stringRequired

Source type, for example payment, refund or adjustment.

Example: payment

source_id
stringRequired

Source object ID.

Example: pay_demo_001

amount
integer(int64)Required

The signed amount counted toward this settlement, in the same currency as the settlement.

Example: 8650

  • payout_amount = reserved_amount - fee_amount.
  • payout_account is a masked snapshot taken when the settlement is generated. Changing your payout account later doesn't affect existing settlements.
  • Refunds, chargebacks and reserve releases don't rewrite past settlements.

Payout

The outgoing payout record for one settlement, linked to the settlement and to a unique reference number.

NameTypeRequiredDescription
id
stringRequired

Payout ID.

Example: po_demo_001

settlement_id
stringRequired

The corresponding settlement.

Example: stl_demo_001

amount
integer(int64)Required

Payout amount, in the smallest currency unit.

Constraints: ≥ 1

Example: 8650

currency
stringRequired

Currency.

Constraints: Format ^[A-Z]{3}$

Example: USD

status
stringRequired

Payout status: created, processing, unknown, succeeded, failed, canceled, returned. When unknown, the related settlement stays paying and the funds aren't released automatically.

  • created
  • processing
  • unknown
  • succeeded
  • failed
  • canceled
  • returned
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: succeeded

reference
stringRequired

Unique payout reference assigned by the platform; it's never reused for a new transfer.

Example: PAYOUT-REF-DEMO-001

executed_at
string(date-time)NullableRequired

The time the payout was executed; null if it hasn't been executed yet.

Example: 2026-09-22T03:00:00Z

completed_at
string(date-time)NullableRequired

The time the payout was confirmed, after review, as succeeded or failed; null if it hasn't been confirmed yet.

Example: 2026-09-22T05:00:00Z

  • The API can retrieve a payout only by ID (getPayout). Take the payout ID from the settlement's payout_id. There's no endpoint for listing payouts. View the list in the merchant portal.
  • unknown means the bank's result can't be confirmed for now: the settlement stays paying, the funds aren't released, and the platform runs a status query first. It never pays out twice.

Event

A merchant event. When the same event is retried, its ID and payload don't change. It never contains full card numbers, CVCs, server-side keys or authentication secrets.

NameTypeRequiredDescription
id
stringRequired

Event ID, used for deduplication.

Example: evt_demo_001

type
stringRequired

Event type. For the values, see EventType in webhooks.v1.yaml; clients must tolerate unknown types.

Example: payment.succeeded

api_version
stringRequired

The API version of the payload.

Example: v1

created_at
string(date-time)Required

The time the event was created. Don't use it in place of the signature time.

Example: 2026-09-23T09:05:00Z

environment
stringRequired

Environment: test is the test environment and live is the live environment. Test and live objects are isolated from each other.

  • test
  • live
  • More values may be added in the future. Don't treat a status you don't recognize as success.

Example: test

merchant_id
stringRequired

Merchant ID.

Example: mer_demo_001

data
EventDataRequired
object
objectRequired

A snapshot of the business object (Payment, Refund, Dispute or Settlement) at the time of the event. It contains only the minimum necessary data the merchant is allowed to see, including id and version.

Example: {"id":"pay_demo_001","merchant_order_no":"ORDER-DEMO-001","amount":10000,"currency":"USD","status":"succeeded","latest_attempt_id":"pat_demo_001","version":4}

  • For the values of type, see Webhook event types. Tolerate new types.
  • created_at is the business time, not the signature time. data.object is a snapshot of the object when the event occurred, and it contains at least id and version.
Was this page helpful?