Conventions

Every endpoint follows the same rules, so a client written once handles them all.

Response envelope

{
  "success": true,
  "data": { … },
  "page": { "size": 20, "number": 0, "total_elements": 134, "total_pages": 7, "has_next": true },
  "meta": { "traceId": "4bf92f35…", "timestamp": "2026-10-04T10:00:00Z", "version": "v1" }
}

page appears on list responses only. Quote meta.traceId when you contact support.

Errors

{
  "success": false,
  "error": {
    "code": "validation.failed",
    "type": "https://errors.finaiq.ai/validation.failed",
    "title": "Bad Request",
    "status": 400,
    "detail": "Only a VALIDATED (or previously EXPORT_FAILED) document can be exported",
    "fields": { "email": "must be a well-formed email address" }
  },
  "meta": { "traceId": "…" }
}

Branch on error.code (stable); show error.detail to people.

StatusWhen
400Invalid input or the action isn't allowed in the document's current state.
401Missing, invalid or expired access token — refresh and retry once.
403Signed in, but not allowed (role or workspace).
404Not found, or not visible to you.
409Conflict, e.g. a duplicate.
429Rate limited — wait until the time in X-RateLimit-Reset.

Pagination

List endpoints take ?page= (0-based) and ?size= (default 20) and return page. Keep requesting while page.has_next is true.

Rate limits

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time, in seconds, when the window refills). Reads allow 60 requests a minute, writes 30, and exports 10. On 429, back off until the reset.

Idempotency

Endpoints that require it document an Idempotency-Key header (1–255 characters, e.g. a UUID). Retrying with the same key and body returns the original result; the same key with a different body is rejected with 409.

Dates and money

Timestamps are ISO 8601 in UTC (2026-10-04T10:00:00Z); dates are yyyy-MM-dd; amounts are decimal numbers in the document's currency (currencyCode, ISO 4217).