Payments
Generated page, from the OpenAPI specification the gateway serves (
GET /v1/openapi.json). Do not edit it by hand: it is rewritten on every build.
| Method | Path | Description |
|---|---|---|
GET |
/v1/payments |
List payments |
POST |
/v1/payments |
Create a payment (hosted checkout) |
GET |
/v1/payments/{id} |
Retrieve a payment |
GET /v1/payments
List payments
Served by the read model, from a replica: no report can ever slow a payment down.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
page |
query | no | Page, starting at 1. |
per_page |
query | no | Page size, 100 at most. |
Responses
200— OK (OperationList)401— API key missing or rejected (Error)403— The key does not carry the required scope, or the account is not active (Error)429— The key's request budget is exhausted (300/min) — honour Retry-After (Error)
POST /v1/payments
Create a payment (hosted checkout)
Creates a collection operation and returns what you need to charge the customer — a payment URL, a deep link or a QR, depending on the rail. asset_id is an identifier, not a symbol: GET /v1/assets and GET /v1/corridors give the ones this account may use. Omitting rail lets routing choose; naming one forces it, and fails rather than falling back.
Naming the corridor: platform_id or platform_code. Both are accepted and neither is deprecated. ⚠️ platform_code — orange, wave, yas — is the only one of the two that means the same platform everywhere: numeric ids are assigned by database insertion order, so a platform_id read in sandbox can name a different rail in production. Prefer the code. Sending both is accepted only when they agree; otherwise the route answers 422 platform_conflict rather than picking one.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
Idempotency-Key |
header | no | An idempotency key specific to THIS operation. Replaying the same key with the same payload returns the original; replaying it with a different payload is refused (409). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
asset_id |
integer | yes | The asset, by its id (GET /v1/assets). |
amount_minor |
string | yes | Amount in MINOR UNITS, as a string. Never a floating-point number: both lose centimes. The asset's decimal count comes from GET /v1/assets. |
country |
string | yes | The operation's country, ISO 3166-1 alpha-2. |
platform_id |
integer | no | The corridor's numeric id. ⚠️ NOT PORTABLE BETWEEN ENVIRONMENTS: platform ids are assigned by database insertion order, so an id read from sandbox may name a different rail in production. Prefer platform_code. Send either; sending both is accepted only when they agree, and refused with 422 platform_conflict when they do not. |
platform_code |
string | no | The corridor's STABLE code — 'orange', 'wave', 'yas'. Case-insensitive. Means the same platform in every environment, which platform_id does not. Send this or platform_id. |
platform_account_handle |
string | no | The sub-account to credit. Empty = the corridor's primary account. |
rail |
string | no | Forces one specific rail instead of letting routing choose. |
payer |
object | no | The payer. On reads, the contact details are masked. |
payer.name |
string | no | |
payer.phone |
string | no | |
payer.email |
string | no | |
payer.country |
string | no | ISO 3166-1 alpha-2 |
client_ref |
string | no | Your own reference. It comes back on reads and on webhooks. |
description |
string | no | |
channel |
string | no | |
expires_in_seconds |
integer | no | How long the payment intent stays valid. |
success_url |
string | no | Where the payer returns after a hosted payment page (Wave, Orange). Success. return_url is accepted as a synonym — it is the legacy platform's contract, and a merchant integrated against it sends that spelling. ⚠️ The hosted rails REFUSE without both: the driver stops before any network call. |
return_url |
string | no | Where the payer returns after a hosted payment page (Wave, Orange). Success. success_url is accepted as a synonym — it is the legacy platform's contract, and a merchant integrated against it sends that spelling. ⚠️ The hosted rails REFUSE without both: the driver stops before any network call. |
failed_url |
string | no | Where the payer returns after a hosted payment page (Wave, Orange). Cancellation or failure. cancel_url is accepted as a synonym — it is the legacy platform's contract, and a merchant integrated against it sends that spelling. ⚠️ The hosted rails REFUSE without both: the driver stops before any network call. |
cancel_url |
string | no | Where the payer returns after a hosted payment page (Wave, Orange). Cancellation or failure. failed_url is accepted as a synonym — it is the legacy platform's contract, and a merchant integrated against it sends that spelling. ⚠️ The hosted rails REFUSE without both: the driver stops before any network call. |
Responses
201— Operation created (Operation)401— API key missing or rejected (Error)403— The key does not carry the required scope, or the account is not active (Error)409— Idempotency key replayed with a different payload (Error)422— Well-formed but refused: missing field, closed corridor, insufficient balance (Error)429— The key's request budget is exhausted (300/min) — honour Retry-After (Error)503—platform_codemomentarily unresolvable: the platform catalogue cannot be read (temporarily_unavailable). This is not a refusal — send the same request again after Retry-After (Error)
GET /v1/payments/{id}
Retrieve a payment
A local read: nothing is asked of the rail. The payer's details are masked, because the read model never holds the raw values.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id |
path | yes | Internal identifier, the operation's reference, or your own client_ref. |
Responses
200— OK (Operation)401— API key missing or rejected (Error)403— The key does not carry the required scope, or the account is not active (Error)404— Unknown, or belonging to another account (Error)429— The key's request budget is exhausted (300/min) — honour Retry-After (Error)
Schemas
The shapes the operations above return.
OperationList
| Field | Type | Description |
|---|---|---|
data |
Operation[] | |
data[].id |
string | The operation's public id. It is the one in the /v1/payments/{id} paths. |
data[].ref |
string | Our internal, readable reference. Distinct from the id: quote this one to support. |
data[].client_ref |
string | The reference you supplied at creation, returned unchanged. |
data[].kind |
string | payin | payout | withdrawal | refund | chargeback | adjustment | transfer | rebalance. The same object serves all five families; this field says which. |
data[].status |
string | The rail's detailed state. ⚠️ To decide whether the money arrived, read outcome: status carries journey detail and its vocabulary depends on the rail. |
data[].outcome |
string | pending | succeeded | failed | cancelled | expired | reversed. The only field to base a business decision on. |
data[].asset_id |
integer | The operation's asset, by its id (GET /v1/assets). |
data[].amount_minor |
string | The GROSS amount in minor units, as a string. |
data[].fee_minor |
string | The fee taken, in minor units. |
data[].net_minor |
string | The net in minor units: amount_minor less fee_minor. |
data[].platform_id |
integer | The platform that carried the operation. Absent while a hosted collection is still waiting for the payer to choose. |
data[].is_test |
boolean | True for an operation created with a test key. No real money moves. |
data[].payment_url |
string | The hosted payment page, when the rail provides one. Absent until submission has succeeded. |
data[].deeplink |
string | The deep link into the rail's app, when it provides one. |
data[].qrcode_url |
string | The QR to show the payer, when the rail provides one. |
data[].risk |
Risk | The state of the risk check (FRAML). Absent when the operation was not assessed — which is not the same thing as “clear”. The outbound webhook and this read return the same block. |
data[].risk.status |
string | held: the funds have not moved. review: the payment ran its course, something is being looked at. clear: nothing to report. |
data[].risk.case_ref |
string | The operational case reference, to quote to support. Null when the hold is a compliance review. |
data[].risk.case_kind |
string | Accompanies case_ref, or nothing at all. |
data[].risk.reason |
string | The only free text this block carries, and it is identical for every hold. |
data[].risk.signals |
object[] | Product signals, advisory. Absent when there are none. |
data[].risk.signals[].code |
string | |
data[].risk.signals[].detail_fr |
string | |
data[].amount_refunded_minor |
string | Collections only: the sum of SUCCEEDED refunds, in minor units. |
data[].amount_refund_pending_minor |
string | Collections only: the sum of refunds IN PROGRESS, in minor units. |
data[].amount_refundable_minor |
string | Collections only: what can be refunded NOW, in minor units — the original amount less succeeded and in-progress refunds, or "0" when the refund rule allows none (collection not successful, Wave period passed after a partial refund…). |
data[].refund_count |
integer | Collections only: the number of refunds that did not fail. |
data[].partial_refund_deadline |
string | Wave collections only: until when a partial refund is possible (RFC 3339). Absent for other rails, or when Wave partial refunds are disabled. |
page |
integer | |
per_page |
integer |
Error
| Field | Type | Description |
|---|---|---|
error |
object | |
error.code |
string | |
error.message |
string |
Operation
One money operation — collection, payout, refund, transfer or rebalance. The same object across all five families.
| Field | Type | Description |
|---|---|---|
id |
string | The operation's public id. It is the one in the /v1/payments/{id} paths. |
ref |
string | Our internal, readable reference. Distinct from the id: quote this one to support. |
client_ref |
string | The reference you supplied at creation, returned unchanged. |
kind |
string | payin | payout | withdrawal | refund | chargeback | adjustment | transfer | rebalance. The same object serves all five families; this field says which. |
status |
string | The rail's detailed state. ⚠️ To decide whether the money arrived, read outcome: status carries journey detail and its vocabulary depends on the rail. |
outcome |
string | pending | succeeded | failed | cancelled | expired | reversed. The only field to base a business decision on. |
asset_id |
integer | The operation's asset, by its id (GET /v1/assets). |
amount_minor |
string | The GROSS amount in minor units, as a string. |
fee_minor |
string | The fee taken, in minor units. |
net_minor |
string | The net in minor units: amount_minor less fee_minor. |
platform_id |
integer | The platform that carried the operation. Absent while a hosted collection is still waiting for the payer to choose. |
is_test |
boolean | True for an operation created with a test key. No real money moves. |
payment_url |
string | The hosted payment page, when the rail provides one. Absent until submission has succeeded. |
deeplink |
string | The deep link into the rail's app, when it provides one. |
qrcode_url |
string | The QR to show the payer, when the rail provides one. |
risk |
Risk | The state of the risk check (FRAML). Absent when the operation was not assessed — which is not the same thing as “clear”. The outbound webhook and this read return the same block. |
risk.status |
string | held: the funds have not moved. review: the payment ran its course, something is being looked at. clear: nothing to report. |
risk.case_ref |
string | The operational case reference, to quote to support. Null when the hold is a compliance review. |
risk.case_kind |
string | Accompanies case_ref, or nothing at all. |
risk.reason |
string | The only free text this block carries, and it is identical for every hold. |
risk.signals |
object[] | Product signals, advisory. Absent when there are none. |
risk.signals[].code |
string | |
risk.signals[].detail_fr |
string | |
amount_refunded_minor |
string | Collections only: the sum of SUCCEEDED refunds, in minor units. |
amount_refund_pending_minor |
string | Collections only: the sum of refunds IN PROGRESS, in minor units. |
amount_refundable_minor |
string | Collections only: what can be refunded NOW, in minor units — the original amount less succeeded and in-progress refunds, or "0" when the refund rule allows none (collection not successful, Wave period passed after a partial refund…). |
refund_count |
integer | Collections only: the number of refunds that did not fail. |
partial_refund_deadline |
string | Wave collections only: until when a partial refund is possible (RFC 3339). Absent for other rails, or when Wave partial refunds are disabled. |