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/v1The 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 type | Prefix | Environment |
|---|---|---|
| Live secret key | sk_live_ | live |
| Test secret key | sk_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
CODEorCODE.NETWORK(MYR,USDT.TRC20).USDT.TRC20andUSDT.ERC20are distinct assets. - Timestamps are ISO-8601 UTC with a
Zsuffix; 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"
}
}| Type | HTTP | Meaning |
|---|---|---|
| invalid_request | 400 / 422 | Malformed body, missing/invalid parameter, missing Idempotency-Key |
| authentication | 401 | Missing, revoked, or malformed API key |
| permission | 403 | Valid key, but the operation is not allowed |
| not_found | 404 | Resource absent in this merchant + environment (no cross-tenant leaks) |
| conflict | 409 | Idempotency conflicts, invalid state transitions |
| rate_limit | 429 | Too many requests; Retry-After header set |
| provider | 402 | Provider rejected after routing/fallback was exhausted |
| internal | 500 | PayXiro fault; safe to retry with the same Idempotency-Key |
The four-step integration flow
- Create a Checkout Session server-side, with an
Idempotency-Keyset to your own deposit ID, so a retry never creates a second Payment. - Present the Cashier using one of the four modes (redirect, popup, embedded, or headless).
- 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. - Optionally poll status as a reconciliation fallback for a missed webhook.
Continue with Checkout Sessions.