Cashier & POS API
A stable server-to-server contract for cash registers, kiosks, order-management systems, and multi-merchant commerce platforms.
Keep credentials off the register
Integration flow
Create
Send an integer minor-unit amount, external order ID, register context, and a durable idempotency key.
Present
Display the returned QR image or open the hosted action while the order remains unpaid.
Confirm
Verify the signed webhook, deduplicate its stable event ID, then retrieve the intent if needed.
Reconcile
Record XRPay as an external tender only after succeeded, preserving the intent and provider references.
Create a payment intent
Amounts are exact integer minor units: 1250 USD means USD 12.50, while 1250 JPY means JPY 1,250. Reuse an idempotency key only for the same logical request.
Persist the returned id, external_order_id, status, amount, currency, location, terminal, and idempotency key with the cashier order. The complete schemas and error responses are in the OpenAPI 3.1 contract.
Direct Mobile Money — no checkout page
For an API-owned customer journey, set collection_mode to direct and provide exactly one Mobile Money method. XRPay validates the country, currency, network, number, and merchant route before submitting one approval request to the customer's phone.
The response never returns the full phone number or an underlying provider name. It returns only mobile_money.phone_last4 and a truthful next_action: approve_on_phone, submit_otp, or wait_for_confirmation. If an OTP is requested, POST {"otp":"123456"} to /api/v1/payment-intents/{id}/confirm.
Do not retry an uncertain submission with a new key
processing or asks you to wait, retrieve the same intent and wait for a signed webhook. Creating another intent may charge the customer twice.Cashier status behavior
| Status | Required behavior |
|---|---|
| requires_customer_action | Hosted: display the QR or open hosted_url. Direct Mobile Money: follow next_action and tell the customer to approve on their phone. Keep the order unpaid. |
| processing | Lock the tender attempt and continue reconciliation. |
| succeeded | Record an external tender and close the order. |
| failed / expired | Release the attempt and let the operator retry with a new idempotency key. |
| canceled | The unpaid attempt was canceled. Still accept a later authoritative event at the payment boundary. |
Deterministic sandbox
Test credentials do not submit external payments, send phone prompts, or create canonical cashier intents on a ledger. Create either a hosted or direct intent, then POST /api/v1/payment-intents/{id}/simulate with {"outcome":"succeeded"}, failed, or expired.
A successful local-currency simulation credits that business's isolated virtual payout balance exactly once. The response reports the credit directly:
Repeating the successful simulation returns idempotent_replay: true and does not add the amount twice. A payment configured to settle as XRP, RLUSD, or another crypto asset does not create a local-currency payout balance.
Test the complete payout flow without sending money
livemode: false, simulated: true, and external_transfer_sent: false. XRPay changes only virtual balances and contacts no bank, Mobile Money operator, or external payout provider. Live and test balances never mix.Exercise cancellation, retry, duplicate delivery, network loss, and full/partial refund paths before certification.
Signed, durable webhooks
Register a public HTTPS URL with POST /api/v1/webhooks using the test or live credential mode it should receive. Verify X-XRPay-Signature over the exact raw request bytes, durably record the body before returning 2xx, and deduplicate on the stable event id. The required top-level livemode flag provides an additional environment check.
Inspect failures with GET /api/v1/webhook-deliveries?status=failed and replay a delivery with POST /api/v1/webhook-deliveries. Payment and refund failures are retried with exponential backoff.
Refunds and platforms
Create a full or partial refund with POST /api/v1/refunds and an idempotency key. Pending refunds reserve the refundable balance, preventing concurrent over-refunds. Live non-custodial refunds require merchant approval and become final only at completed.
Multi-merchant platforms use OAuth 2.0 Authorization Code with PKCE. Request only the required checkout, transaction, refund, and webhook scopes; every resource remains isolated to its connected merchant and live/test mode.