Docs

REST API

Payouts

POST/api/payouts

Create a payout draft under a mandate. Amounts have at most two decimals.

Request

JSON
{
  "beneficiaryId": "9596acc9-0320-4b89-8cc8-475f04fe3948",
  "mandateId": "fde3a3a0-8125-4ea1-b6fc-a3e1c7138ead",
  "amount": 50,
  "currency": "EUR",
  "reason": "Invoice 2026-091"
}

Response 200

JSON
{
  "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

JSON
{
  "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

JSON
{
  "event": "kyc_approved"
}

Response 200

JSON
{
  "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

JSON
{
  "event": "kyc_rejected"
}

Response 400

JSON
{
  "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

JSON
{
  "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

JSON
{
  "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

JSON
{
  "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

JSON
{
  "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

JSON
{
  "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

JSON
{
  "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"
      }
    ]
  }
}