API reference

One base URL per environment, one key per environment, JSON in and out. The full OpenAPI 3.1 document is the authority for schemas; this page is the map.

Authentication

A bearer API key, issued per environment and shown once. Keys carry scopes, so a key that reads credits cannot approve a payout even if it leaks.

http
Authorization: Bearer nvk_live_01J9...
Content-Type: application/json
Idempotency-Key: <your key, on every write>
Rotation has a grace window: a new key is issued while the old one still works, so nothing has to be redeployed under time pressure. Revoke the old one when your deploy is green.

Conventions

  • Money is { currency, value } with value a two-decimal string. Never a float.
  • Times are ISO 8601 in UTC. Date filters are inclusive of both ends, in your product’s timezone.
  • Lists are cursor-paginated: ?limit=&cursor=, with next_cursor in the response.
  • Ids are prefixed by kind — crd_, hld_, pay_ — so a wrong one is obvious in a log.

Endpoints

Accounts and directory

The addresses money arrives on, and who they belong to.

GET/v1/accountsEvery virtual account, with its holder and group.
GET/v1/accounts/{id}One account, with its credits.
POST/v1/accountsIssue an account number for a holder.
GET/v1/groupsYour hierarchy, in your vocabulary.
GET/v1/holders/{id}One holder and their accounts.

Credits

Money that arrived. Immutable — a correction is a new entry.

GET/v1/credits?from=&to=&group_id=Credits in a range, filterable by group.
GET/v1/credits/{id}One credit with its fee breakdown and ledger lines.
GET/v1/credits/{id}/postingsThe journal entries it wrote.

Wallets

Derived balances. Never stored, always computed.

GET/v1/wallets/{owner}/balanceThe balance, as of an instant it names.
GET/v1/wallets/{owner}/statement?from=&to=Postings by value date with a running balance.
POST/v1/transfersMove value between two wallets in the same product. Needs an Idempotency-Key.

Payouts

Money leaving. Recorded here, executed at the bank.

GET/v1/payouts?status=Payouts by status, with ageing.
POST/v1/payoutsRequest one against a group wallet. Posts nothing — it reserves.
POST/v1/payouts/{id}/approveMove it into payout clearing. Needs payouts:approve.
POST/v1/payouts/{id}/paidRecord the bank reference once it is actually paid.

Settlements

What the bank paid, and which credits it covered.

GET/v1/settlements?from=&to=&status=Cycles with totals and reconciliation state.
GET/v1/settlements/{id}One cycle with its identity checks.
GET/v1/settlements/{id}/creditsThe credits it covers.

Delivery

What we sent you, and what you said back.

GET/v1/deliveries?event_id=&status=Deliveries, filterable.
GET/v1/deliveries/{event_id}/attemptsEvery attempt, with status, latency and response snippet.
POST/v1/deliveries/{event_id}/replayReplay one, reusing the event id.
POST/v1/webhooks/{id}/pauseQueue events without dead-lettering them.

Reports

Read from the ledger, never recomputed.

GET/v1/reports/collections?granularity=By day, week or month; filterable by group.
GET/v1/reports/feesThe fee split over a range.
GET/v1/reports/balancesBalances by owner.
POST/v1/exportsCSV for any report. Under 5,000 rows is synchronous.

What is built today

Nineveh is in pilot. The consoles, the ledger, delivery, settlement, reconciliation and payouts are built and running against a real database; the HTTP surface above is specified in the OpenAPI document and is being exposed endpoint by endpoint as the first product needs it. Ask before you build against one — we will tell you honestly whether it exists yet.

The sandbox console is the fastest way to see the whole thing behave: sign in and press Simulate a top-up.