Getting started

PayXiro is a payment orchestration platform: your application makes one API call, and PayXiro handles provider selection, the hosted Cashier, status tracking, risk and routing, the ledger, and the signed webhook back to you.

Base URL

base url
https://payxiro.com/api/v1

The host is provisional. There is no environment in the URL or a header — the environment is selected by your API key prefix.

Authentication

Every request authenticates with a bearer secret key scoped to one (merchant, environment) pair.

header
Authorization: Bearer sk_live_9f2Kj...
Key typePrefixEnvironment
Live secret keysk_live_live
Test secret keysk_test_sandbox
  • Keys are created and revoked in the Merchant Portal; the full key is shown exactly once at creation.
  • Only a SHA-256 hash of the key is stored — there is no "reveal key" feature.
  • A sk_test_ key can never read or write live data, and vice versa.
  • A merchant may hold up to two active keys per environment (create new, deploy, then revoke the old).

Idempotency

Every POST that creates money movement (/payments, /checkout_sessions) requires an Idempotency-Key header. A request without it is rejected with invalid_request.

  • Use a stable reference from your own database (e.g. your deposit row ID) so a retry is naturally safe.
  • Replay: the same key with the same body returns the stored original response with header Idempotency-Replayed: true — no second Payment.
  • Conflict: the same key with a different body returns 409 (idempotency_key_reuse).
  • In flight: the same key while the first is executing returns 409 (idempotency_key_in_flight) — retry with backoff.

Conventions

  • Amounts are strings in JSON ("500.00"), never numbers, rendered to the asset's display decimals.
  • Asset codes are CODE or CODE.NETWORK (MYR, USDT.TRC20). USDT.TRC20 and USDT.ERC20 are distinct assets.
  • Timestamps are ISO-8601 UTC with a Z suffix; field names end in _at.
  • Public IDs are <prefix>_<ULID> (pay_, cust_, cs_, evt_, ...).
  • v1 evolves additively only. Ignore unknown fields and tolerate unknown enum values on read.

The error envelope

Errors always return this shape. Branch on type and code, never on message text.

error
{
  "error": {
    "type": "invalid_request",
    "code": "amount_below_minimum",
    "message": "Amount 5.00 MYR is below the minimum of 10.00 MYR for this payment method.",
    "param": "amount",
    "request_id": "req_01J9ZTW4C8"
  }
}
TypeHTTPMeaning
invalid_request400 / 422Malformed body, missing/invalid parameter, missing Idempotency-Key
authentication401Missing, revoked, or malformed API key
permission403Valid key, but the operation is not allowed
not_found404Resource absent in this merchant + environment (no cross-tenant leaks)
conflict409Idempotency conflicts, invalid state transitions
rate_limit429Too many requests; Retry-After header set
provider402Provider rejected after routing/fallback was exhausted
internal500PayXiro fault; safe to retry with the same Idempotency-Key

The four-step integration flow

  1. Create a Checkout Session server-side, with an Idempotency-Key set to your own deposit ID, so a retry never creates a second Payment.
  2. Present the Cashier using one of the four modes (redirect, popup, embedded, or headless).
  3. Credit only on the signed webhook (or a verified server-side GET) — never on the browser redirect or a client event. The webhook and the redirect race; either can arrive first.
  4. Optionally poll status as a reconciliation fallback for a missed webhook.

Continue with Checkout Sessions.

View this page as markdown·Sourced from the PayXiro engineering docs — the contract wins on any technical claim.