API v1
The OneGate Recon API
Every gateway, batch and fee OneGate Recon checks against your bank statement and your own records, readable by your treasury system, ERP or data warehouse. Expected receipts for your cash forecast, what arrived and what paid it, what needs chasing, and the fees for your ledger.
Your first call
curl https://onegaterecon.com/api/v1/me \
-H "Authorization: Bearer $ONEGATE_RECON_KEY"{
"organization": { "id": "5f0c2a9e-…", "name": "Example Trading (Pty) Ltd" },
"key": { "prefix": "ogr_live_a1B2c3", "scopes": ["reconciliations:read", "exceptions:read", "cash:read"] },
"api_version": "v1"
}curl "https://onegaterecon.com/api/v1/reconciliations?type=gateway&limit=3" -H "Authorization: Bearer $ONEGATE_RECON_KEY"The sandbox
Feeding a treasury system
| In your treasury system | Call | Scope |
|---|---|---|
| Expected receipts for the cash forecast (the next two weeks) | GET /cash?from=2026-09-01&to=2026-09-14 | cash:read |
| Actual receipts, with the bank line that paid each settlement | GET /reconciliations/{id}/settlements?status=arrived | settlements:read |
| What to chase: overdue and short settlements, payments on one side only | GET /exceptions?status=open | exceptions:read |
| Gateway fees for the general ledger | GET /reconciliations/{id}/fees | fees:read |
| The month report for the auditors | GET /reconciliations/{id}/report?format=pdf | reports:read |
curl "https://onegaterecon.com/api/v1/cash?from=2026-09-01&to=2026-09-14" -H "Authorization: Bearer $ONEGATE_RECON_KEY"
{
"from": "2026-09-01", "to": "2026-09-14", "currency": "ZAR",
"days": [ { "date": "2026-09-01", "due": "182340.15", "received": "179880.15" }, … ],
"outstanding": [
{ "gateway": { "id": "…", "name": "Ozow" }, "method": { "id": "…", "name": "Instant EFT" },
"label": "Batch 8841", "status": "in_transit", "due_by": "2026-09-03",
"expected": "24811.40", "received": null, "currency": "ZAR", … }
]
}Every kind of reconciliation
| Kind | Id | What it reconciles | Exceptions |
|---|---|---|---|
| gateway | gw_… | Each gateway's settlements against your bank statement, and your own records against the gateway's files | Yes |
| service | sr_… | An aggregator's collections and settlements, per merchant | No |
| matching | mt_… | Two or three files against each other, on the columns you choose | Yes |
| merchant | mr_… | A merchant's figures, fees and adjustments | No |
Keys and scopes
| Scope | Reads |
|---|---|
reconciliations:read | Reconciliations of every kind: their period, status and totals |
exceptions:read | What needs a look: overdue and short settlements, payments on one side only, credits nobody explains |
cash:read | Money due and received, day by day: the cash-forecast feed |
settlements:read | Each batch, day or week a gateway owed, and the bank line that paid it |
fees:read | Commission taken and invoiced, per gateway and month |
reports:read | The month report, as an Excel workbook or a PDF |
setup:read | Gateways and sources, to label things the way the organization does |
files:write | Send files of your sources in, and bank statements as camt.053 or MT940 |
checks:write | Start a reconciliation and run its check |
decisions:write | Accept, expect next month, or note an exception |
Sending data in
| What | Call | Scope |
|---|---|---|
| A gateway's file, your records export, a commission invoice | POST /files | files:write |
| Your bank statement as camt.053 (ISO 20022) or MT940, straight from the bank or your treasury system | POST /bank-statements | files:write |
| Start the month | POST /reconciliations | checks:write |
| Check it now (up to a minute on a full month) | POST /reconciliations/{id}/check | checks:write |
| Accept, expect next month or note an exception | POST /exceptions/{id}/decisions | decisions:write |
curl -X POST "https://onegaterecon.com/api/v1/bank-statements" \
-H "Authorization: Bearer $ONEGATE_RECON_KEY" \
-H "Idempotency-Key: stmt-2026-09-30-62000000001" \
-F "file=@camt053-2026-09-30.xml"Webhooks
| Event | When |
|---|---|
check.completed | A reconciliation was checked: its totals and what needs a look |
settlement.overdue | A settlement did not reach the bank by its due day |
settlement.short | A settlement arrived, but short of what was expected |
exception.resolved | Someone accepted, linked or otherwise resolved an exception |
reconciliation.closed | A month was closed: its figures are final |
reconciliation.reopened | A closed month was reopened, with the reason |
file.processed | A file was added to a reconciliation and read |
POST /your/endpoint HTTP/1.1
Content-Type: application/json
OneGate-Event: settlement.overdue
OneGate-Delivery: 6e1f…
OneGate-Mode: live
OneGate-Signature: t=1760981400,v1=5257a869e7…
{ "id": "evt_01c2b4e6a8d0f2a4c6e8b0d2",
"type": "settlement.overdue", "created_at": "2026-10-20T18:10:00.000Z", "mode": "live",
"data": { "reconciliation_id": "gw_…", "gateway": { "id": "…", "name": "Ozow" }, "method": { "id": "…", "name": "Instant EFT" },
"label": "Batch 8841", "due_by": "2026-09-24", "expected": "21500.00", "received": null, "currency": "ZAR" } }import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, header, rawBody) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Conventions
| Topic | How it works |
|---|---|
| Money | A decimal string with its currency: "amount": "10308.00", "currency": "ZAR", never a number, so nothing is rounded on the way. |
| Days | ISO 8601: 2026-08-06. Moments carry their offset. |
| Lists | { data: [...], next_cursor }. Pass ?cursor= for the next page until it is null; limit is 1-200. |
| Unknown parameters | Refused with a 400, not ignored, so a typo never silently returns everything. |
| Versions | This is v1. Fields may be added at any time; nothing is removed or changes meaning within v1. Read the changelog in the reference. |
Errors and limits
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
{ "type": "/developers#errors-missing_scope", "title": "This key may not read this",
"status": 403, "detail": "It needs the \"cash:read\" scope.", "code": "missing_scope" }| Status | Code | What it means |
|---|---|---|
| 400 | invalid_parameter | A parameter is not valid, or is not one the endpoint knows. The detail says which. |
| 401 | no_key / invalid_key | No key was sent, or it was revoked or has expired. |
| 403 | missing_scope / ip_not_allowed | The key may not read this, or not from this address. |
| 404 | not_found | No such reconciliation in this organization. |
| 429 | rate_limited | More than 600 requests a minute with this key. Wait for Retry-After seconds. |
| 500 | internal | Something went wrong on our side. Quote the Request-Id header to support. |
Coming next
Tell us what your system needs first: it decides the order.