The API, written out.

Everything the console does is one HTTPS call. Base URL https://api.rion.dev/v1, bearer token in the Authorization header.

Sandbox

Every account starts in sandbox. Sandbox keys move fake money on real rails' timing models, so a payout that would take two days in production takes two days in sandbox — you can fast-forward it, but only deliberately.

# sandbox keys are prefixed, so they can never be confused for live ones
export RION_KEY=sk_sandbox_8f2a...

Authentication

Bearer tokens, scoped per environment and per capability. A token with read scope cannot move money, which is the token you want in anything that only builds reports.

curl https://api.rion.dev/v1/accounts \
  -H "Authorization: Bearer $RION_KEY"

Creating accounts

An account belongs to an entity and a currency. Sub-accounts nest by passing parent; the ledger keeps the tree, you do not have to.

curl https://api.rion.dev/v1/accounts \
  -H "Authorization: Bearer $RION_KEY" \
  -d '{"entity":"ent_4Kd","currency":"EUR","name":"Escrow — Kestrel"}'

{ "account": "acc_7Qm2", "iban": "DE89 3704 0044 0532 0130 00", "balance": 0 }

Sending a payout

Pass an amount and a destination; the rail is chosen for you. Always send an Idempotency-Key: a retried payout is the one mistake that is expensive to undo.

curl https://api.rion.dev/v1/payouts \
  -H "Authorization: Bearer $RION_KEY" \
  -H "Idempotency-Key: 7c1f9a2e" \
  -d '{"from":"acc_7Qm2","to":"ben_2Lp","amount":1840000,"currency":"EUR"}'

{ "payout": "po_9Kd2Ra", "rail": "sepa_instant", "state": "pending" }

Amounts are integers in the currency's minor unit. There are no floats anywhere in this API, for the reason you would expect.

Webhooks

Events are signed with HMAC-SHA256 over the raw body. Verify before you parse, and return a 2xx quickly, because anything slower than 5 s is retried with backoff for 24 hours.

  • payout.settled: the money actually landed, not merely accepted.
  • payout.failed: carries the bank's own reason code.
  • card.authorisation: fires before the decision; you may decline.
  • ledger.entry: one per side of every double entry.

API reference

MethodPathScope
GET/v1/accountsread
POST/v1/accountswrite
GET/v1/accounts/:id/balanceread
POST/v1/payoutsmove
GET/v1/payouts/:idread
POST/v1/cardswrite
GET/v1/ledger/entriesread

Errors

Errors carry a stable code, a human message, and where relevant the upstream bank's reason. Never branch on the message.

{ "error": { "code": "beneficiary_iban_mismatch",
             "message": "The IBAN does not match the beneficiary name on file.",
             "bank_reason": "AC03" } }

Security

Keys are scoped per environment and revocable individually. Ledger entries are immutable; a correction is a new pair of entries, never an edit. Auditor access is read-only and scoped to a date range.

Status & uptime

Scale carries a 99.95% commitment and Enterprise 99.99%, measured on the payout API rather than on the marketing site. Incidents are posted before they are resolved, not after.