API Reference
The Yona API is a REST API with JSON bodies. These pages are generated from the API’s own OpenAPI document, so they describe what the API serves. You can download the document at /openapi.json.
Base URL
https://gp.useyona.com
Sandbox and live use the same host. The API key chooses: sk_test_ keys reach the sandbox, sk_live_ keys the live service.
Authentication
Send your API key as a Bearer token:
Authorization: Bearer sk_test_your_key_hereThe x-api-key header is not accepted. Keys are created in the Yona app under API keys, with a preset (read_only, invoicing or full_integration) or an explicit list of capabilities. A request that needs a capability the key lacks is answered 403 with AUTH019.
Some operations are for signed-in users only, such as creating API keys, connecting to the tax authority and registering webhook endpoints. Each page says so next to the operation; a key gets 403 with AUTH018 there.
Services and prefixes
| Prefix | What lives there |
|---|---|
/i/v1 | Invoices, buyers, items, tax connection, received invoices, reference data |
/b/v1 | Billing: plans, balance, transactions, payments, sandbox credits |
/a/v1 | Organisation, members, invitations, roles, API keys |
/n/v1 | Webhooks: endpoints, deliveries, events |
Response envelope
Every response carries meta and data. meta.requestId identifies the request in our logs; quote it when you contact support.
{
"meta": {
"statusCode": 200,
"success": true,
"message": "Success",
"errors": [],
"timestamp": "2026-10-01T10:00:00.000Z",
"requestId": "01K6P3Z0X7Q4N2M8R9V1T5B3Y7"
},
"data": { }
}A list adds meta.pagination with total, page, pageSize, totalPages, hasNext and hasPrevious; see Pagination.
An error puts the code in meta.errorCode and the detail in meta.errors. For a validation failure, errors is a list of { "field": "message" } pairs:
{
"meta": {
"statusCode": 400,
"success": false,
"message": "Validation failed",
"errorCode": "VAL001",
"errors": [{ "invoiceKind": "must be one of B2B, B2C, B2G, G2B" }],
"timestamp": "2026-10-01T10:00:00.000Z",
"requestId": "01K6P3Z0X7Q4N2M8R9V1T5B3Y7"
},
"data": null
}A resource that belongs to another organisation is answered exactly like one that does not exist: 404 with RES001.
Error codes you will meet
| Code | Status | Meaning |
|---|---|---|
AUTH004 | 401 | No usable token on the request |
AUTH021 | 401 | The API key is not valid |
AUTH022 | 401 | The API key has expired |
AUTH041 | 401 | The API key was revoked |
AUTH018 | 403 | This operation is for signed-in users, not API keys |
AUTH019 | 403 | The key lacks a capability the operation needs |
AUTH005 | 403 | Forbidden |
BIZ006 | 403 | The organisation is not approved for live access |
BIZ005 | 403 | Live mode is switched off |
VAL001 | 400 | Validation failed; see meta.errors |
VAL002 | 400 | A required field is missing |
VAL021 | 413 | The body is too large |
BIZ001 | 402 | Not enough credits; nothing was done |
RES001 | 404 | Not found, or not yours |
RES002 | 409 | It already exists |
RES003 | 409 | If-Match did not match the current version |
BIZ004 | 409 | The resource is not in a state that allows this |
BIZ201 | 409 | The invoice is not in a state that allows this |
BIZ205 | 409 | Additional sellers are not available; the organisation is the seller |
BIZ107 | 409 | The same Idempotency-Key was reused with a different request |
SYS005 | 429 | Too many requests; wait for Retry-After |
SYS001 | 500 | Internal error; quote meta.requestId |
SYS002 | 503 | A service is unavailable; retry later |
SYS003 | 504 | A service timed out; retry later |
Rate limits
Limits are per API key: 50 requests per second in bursts and 600 per minute sustained, plus per-operation limits on the heavier calls. A refused request is 429 with SYS005, a Retry-After header in seconds, and X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.
Idempotency
Where an operation lists an Idempotency-Key header, send a unique value per logical request; a retry with the same key is answered once. Reusing a key with a different body is refused with BIZ107.