An outbound payment is asynchronous. POST /v1/outbound-payments returns 201 with the payment's id straight away, and the payment then moves through compliance screening and the payment rail on its own. Poll GET /v1/outbound-payments/{id} until it reaches a terminal status.
Statuses
| Status | Terminal | What it means | What to do |
|---|---|---|---|
Scheduled | No | The payment has a future valueDate and has not entered the lifecycle yet. | Wait for the value date, or cancel it. |
AwaitingFunds | No | The debiting account did not have enough available balance when the balance check ran. | Fund the account; the payment resumes on its own. |
Processing | No | Screening has passed and the payment is with the payment rail. | Keep polling. |
Sent | Yes | The bank executed the payment. The account is debited at this point. | Reconcile against GET /v1/transactions. |
Rejected | Yes | The payment could not be completed, for example because the receiving bank rejected it. No funds have been moved. | Fix the cause, and create a new payment with a new idempotencyKey. |
Returned | Yes | The payment completed and was subsequently returned by the beneficiary bank. | Reconcile against GET /v1/transactions. |
Cancelled | Yes | You cancelled the payment before it was sent for processing. | Nothing further. |
The same values are accepted by the status filter on GET /v1/outbound-payments, which is the efficient way to sweep everything still in flight.
The path a payment takes
- Created. A payment created over the Client API goes straight into compliance approval. The manual approval stages of the portal are skipped, so an API payment is never held in
Draft. - Value-date gate. A payment with a future
valueDateparks asScheduledand only continues on that date. The gate runs asynchronously; a future-dated payment may readProcessingfor a few seconds beforeScheduled. - Balance check. The available balance on the debiting account is checked against the ledger. If it is short, the payment stops at
AwaitingFundsand resumes once the balance is there. - Compliance screening. A rejection ends the payment at
Rejected; an acceptance lets it continue. - Initiation and execution. The payment moves to
Processingwhile it is with the payment rail, then toSentwhen the bank executes it. The debit hits the ledger onSent, not before.
Polling
You can receive status changes by webhook or by polling. Webhook endpoints are registered by your account manager; GET /v1/events returns the same events for 90 days and is the recovery path if your endpoint was down. When polling the payment itself, back off between attempts and stop when it reaches a terminal status or parks at Scheduled or AwaitingFunds. Both of those wait on something outside the API (a date, or a credit landing) rather than on us. The detail read also returns an events array holding the events raised for that payment, in the same shape as a row from GET /v1/events.
Internal payments
POST /v1/internal-payments moves funds between two of the same client's accounts in a single currency. There is no approval stage and no payment rail, so the transfer completes immediately when the debiting account has sufficient available balance and there is no lifecycle to poll. Idempotency works exactly as it does for outbound payments, except that the 409 body carries existingInternalPaymentId.
Inbound payments
Inbound payments are created by money arriving from outside, not by you. Read them with GET /v1/inbound-payments and GET /v1/inbound-payments/{id}. In the sandbox, POST /v1/simulations/inbound-payments drives the same command chain a real upstream credit would, which is how you fund an account before testing an outbound flow.
Testing every outcome
The sandbox reaches all of these statuses deterministically: a reference that starts with a documented trigger token produces that outcome, and any other reference takes the happy path. See Sandbox Outcome Triggers for the trigger vocabulary.
Remember that a payment id is only useful if you kept it. If a create response was lost, do not create the payment again: retry the identical request with the same idempotencyKey and you will get 200 with the original id back. See Idempotency.
Cancelling
POST /v1/outbound-payments/{id}/cancel cancels a payment that has not yet been sent for processing and returns 204. reason is required and must be one of incorrect_amount, incorrect_payee or payment_not_required.
- A payment already with the payment processor or the bank cannot be cancelled:
422. - A payment that is already cancelled:
409. - A payment belonging to another client:
404.