REST API
Payouts
POST/api/payouts
Create a payout draft under a mandate. Amounts have at most two decimals.
Request
{
"beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
"mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
"amount": 50,
"currency": "EUR",
"reason": "Invoice 2026-091"
}Response 200
{
"ok": true,
"data": {
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
"mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
"amount": 50,
"currency": "EUR",
"reason": "Invoice 2026-091",
"provider": "outsourced-provider",
"status": "draft",
"createdAt": "2026-09-23T18:42:40.628Z",
"updatedAt": "2026-09-23T18:42:40.628Z",
"history": [
{
"status": "draft",
"timestamp": "2026-09-23T18:42:40.628Z",
"note": "Draft created under mandate SHOP-001"
}
]
}
}POST/api/payouts/{id}/submit
Send the draft to KYC review. With a provider configured (the simulated rail) the decision arrives on its own — poll the payout. Without one, record it with /events.
Response 200
{
"ok": true,
"data": {
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"status": "pending_kyc",
"provider": "outsourced-provider",
"nextAction": "The provider answers on its own; poll the payout status until it leaves pending_kyc.",
"message": "KYC and payment checks are outsourced to the provider."
}
}POST/api/payouts/{id}/events
Record a provider decision yourself when no provider is configured: kyc_approved, kyc_rejected, payment_processing, payment_paid, payment_failed, payment_returned.
Recording a decision:
Request
{
"event": "kyc_approved"
}Response 200
{
"ok": true,
"data": {
"payoutId": "934dda3f-915f-4ac1-9c95-62ac759df5b7",
"status": "approved",
"provider": "outsourced-provider",
"message": "KYC approved by provider. Current status: approved."
}
}When a provider already decided, the event is refused:
Request
{
"event": "kyc_rejected"
}Response 400
{
"ok": false,
"error": "Cannot apply event kyc_rejected when payout is in status draft. Valid from states: pending_kyc."
}POST/api/payouts/{id}/confirm
Human confirmation before execution.
Response 200
{
"ok": true,
"data": {
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"status": "processing",
"provider": "outsourced-provider",
"message": "Payout confirmation accepted. Awaiting provider settlement."
}
}POST/api/payouts/{id}/execute
Send the payout through the rail. The outcomes are described under Payout statuses.
Settled — simulated rail, an ordinary amount:
Response 200
{
"ok": true,
"data": {
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"status": "paid",
"provider": "sepa-simulation",
"environment": "SANDBOX",
"providerReference": "SIM-5DC8B5E2",
"debitedAccountIban": "NL91ABNA0417164300",
"counterpartyIban": "DE89370400440532013000",
"counterpartyName": "Acme Supplies BV",
"amount": "-50.00",
"currency": "EUR",
"balanceAfter": "950.00",
"mandateReference": "SHOP-001",
"message": "Payout 702cc3c2-071c-45a0-bc92-2c22b1608e04 settled as sepa-simulation payment SIM-5DC8B5E2."
}
}No confirmation from the rail — simulated .03. The payout stays processing; the outcome arrives later. Do not resend:
Response 200
{
"ok": true,
"data": {
"payoutId": "de2a4e0d-7484-4caf-9802-1915e5cc9417",
"status": "processing",
"unresolved": true,
"provider": "sepa-simulation",
"environment": "SANDBOX",
"debitedAccountIban": "NL91ABNA0417164300",
"counterpartyIban": "DE89370400440532013000",
"counterpartyName": "Acme Supplies BV",
"amount": "-20.03",
"currency": "EUR",
"balanceAfter": null,
"mandateReference": "SHOP-001",
"message": "Payout de2a4e0d-7484-4caf-9802-1915e5cc9417 could not be confirmed (No response from the rail within the timeout.). The payment may or may not have been sent; sepa-simulation will report which. Do not resend."
}
}No rail configured:
Response 400
{
"ok": false,
"error": "Real payment execution is not available: No settlement rail is configured. This deployment authorizes payments and does not move money."
}GET/api/payouts/{id}
Read a payout with its history.
Response 200
{
"ok": true,
"data": {
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
"mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
"amount": 50,
"currency": "EUR",
"reason": "Invoice 2026-091",
"provider": "outsourced-provider",
"status": "approved",
"createdAt": "2026-09-23T18:42:40.628Z",
"updatedAt": "2026-09-23T18:42:40.630Z",
"history": [
{
"status": "draft",
"timestamp": "2026-09-23T18:42:40.628Z",
"note": "Draft created under mandate SHOP-001"
}
]
}
}GET/api/payouts?status=paid
List payouts; ?status= filters.
Response 200
{
"ok": true,
"data": {
"payouts": [
{
"payoutId": "de2a4e0d-7484-4caf-9802-1915e5cc9417",
"beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
"mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
"amount": 20.03,
"currency": "EUR",
"reason": "Invoice 2026-092",
"provider": "sepa-simulation",
"status": "paid",
"createdAt": "2026-09-23T18:42:40.733Z",
"updatedAt": "2026-09-23T18:42:40.838Z",
"history": [
{
"status": "draft",
"timestamp": "2026-09-23T18:42:40.733Z",
"note": "Draft created under mandate SHOP-001"
}
],
"providerReference": "SIM-87118C03",
"executedAt": "2026-09-23T18:42:40.838Z"
},
{
"payoutId": "702cc3c2-071c-45a0-bc92-2c22b1608e04",
"beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
"mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
"amount": 50,
"currency": "EUR",
"reason": "Invoice 2026-091",
"provider": "sepa-simulation",
"status": "paid",
"createdAt": "2026-09-23T18:42:40.628Z",
"updatedAt": "2026-09-23T18:42:40.733Z",
"history": [
{
"status": "draft",
"timestamp": "2026-09-23T18:42:40.628Z",
"note": "Draft created under mandate SHOP-001"
}
],
"providerReference": "SIM-5DC8B5E2",
"executedAt": "2026-09-23T18:42:40.733Z"
}
]
}
}