Base URL
All routes are mounted under the/api prefix:
Route Shape
Most business resources live under a single Entity:/api/entities (list and create), /api/organizations, /api/fx-rates, /api/countries and /api/currencies, /api/onboarding/* (Superadmin only), /api/feedback, and /api/health.
Data an Organization’s Entities share lives under the Organization instead, such as its Partners, Dimensions, and Integrations:
{entityId} is always a UUID. A request for an Entity the caller cannot access returns 404, never 403, so probing does not reveal whether an unknown Entity exists.
Access and roles
Access to an Entity comes from an Organization Membership. An Organization groups the Entities a client runs as one business, and every Entity belongs to exactly one Organization. A Membership gives a User one Role in an Organization. That Role applies to every Entity of the Organization, including Entities added later.- Read covers
GETrequests on Entity routes and on the data the Organization shares, including the Organization’s Audit Trail. Write coversPOST,PUT,PATCH, andDELETE. - Sintropix work covers routes reserved for the accounting team: credentials (except Portal Logins, the bank, Getnet, SII, and Clay logins a
clientcan store too), connecting or reconnecting a bank through Fintoc, automations, Agent Channels, and FX rate sync. - Tasks are open to
staffandclient, who read and work them the same way. Aviewercan’t reach them. - Every Role,
viewerincluded, reads and writes the Organization’s Chat and reads and marks their own Notifications. - Reading the email of the Organization’s Gmail, Outlook, and Mailbox accounts takes more than reading the books:
staffandclientcan,viewercan’t. - An Entity outside your Organizations returns
404. An action your Role doesn’t allow returns403withPERMISSION_DENIED_ERROR. - No Role is global. A User with no Membership in an Organization can’t reach its Entities, whatever Role they hold elsewhere.
403 with SUPERADMIN_SESSION_REQUIRED, even a Superadmin’s, and any other User gets 403 with SUPERADMIN_REQUIRED. Being a Superadmin opens no books: a Superadmin reaches an Entity only through a Membership, like everyone else.
Linking to the App
Every record has a page in the Sintropix web app athttps://app.sintropix.com/{entityId}/<page>, where {entityId} is the same UUID as in the API route. A Ledger Entry is at /{entityId}/entries/{entryId}, a payable Invoice at /{entityId}/bills?open={invoiceId}, a Bank Movement at /{entityId}/banks/{bankAccountId}?open={movementId}. Include these links whenever you mention a record to a user. The full map is in Link to the App.
Authentication
Programmatic callers authenticate in one of two ways:- API key in the
x-api-keyheader. Keys are created in the Sintropix app; see Get an API Key. - OAuth access token in the
Authorization: Bearer <token>header. An app gets one when a User approves it for one Organization; see Connect an app with OAuth. A token acts as that User in that Organization only, with read or read and write access, and never beyond the User’s Role. Claude and ChatGPT use this to reach the Sintropix MCP server.
POST, PUT, PATCH, DELETE) made with an API key must also send a Declared Actor and a Declared Reason:
x-audit-actor is a self-reported software label (for example claude-opus-4.8) that lands in the Audit Trail, with surrounding whitespace trimmed. Omitting it on a mutation, or sending it blank, returns 400 with code AUDIT_ACTOR_REQUIRED_ERROR. A value that starts with erwin: is reserved and returns 403 with code AUDIT_ACTOR_NOT_ALLOWED_ERROR.
x-audit-reason is a one-line, plain-text explanation of why the change is being made (max 500 characters). The server trims surrounding whitespace and stores the value on the Audit Envelope. Missing or blank returns 400 with code AUDIT_REASON_REQUIRED_ERROR; longer than 500 characters returns 400 with code AUDIT_REASON_TOO_LONG_ERROR.
A mutating request made with an OAuth access token must send x-audit-reason too. It doesn’t need x-audit-actor: the Audit Trail names the approved app instead.
POST /api/feedback is the one exception: it writes nothing of an Organization, so it needs neither header, and a read-only key or Connected App can send it too.
A mutating request can also send x-audit-trigger, the Declared Trigger: what started the agent turn behind the write. Send schedule when a schedule started it, or slack, app, chat, or terminal when a person’s message in that place started it. The header is optional, and a request without it stores no trigger. Any other value returns 400 with code AUDIT_TRIGGER_UNKNOWN_ERROR and writes nothing. Its params carry header and the accepted triggers.
Request Format
Requests are plain JSON. IncludeContent-Type: application/json on any request with a body.
400. A malformed entityId returns 404, like any Entity you can’t reach.
A string anywhere in the path, query, or body can’t hold a NUL character (\u0000). A request that holds one returns 400.
Search by amount
Many list endpoints take asearch parameter. When the search reads as an amount, it also matches the amounts the endpoint’s reference page names for that search:
- A search reads as an amount when it holds only digits,
.and,separators, and spaces. It may start with one currency mark ($,US$,CLP, orUSD) and one minus sign.165,165140,165.140,$165.140,-165.140, andUS$123,45all read as amounts. A search with any other letter doesn’t. - Sintropix drops the separators and the sign, and matches the remaining digits anywhere in the amount written in minor units.
165.140and165140both find an amount of165140, and165finds it too.US$123,45finds a USD amount of12345minor units. - The sign never matters:
-165.140and165.140find the same amounts.
Response Format
Responses are the resource itself as JSON. There is no top-leveldata wrapper, no meta envelope, and no pagination block on non-paginated endpoints. Each reference page lists the fields every endpoint returns.
A single resource comes back as an object:
/pages, plus a handful of reports) returns a { rows, nextCursor } object. nextCursor is null on the last page.
Pagination is opt-in per endpoint, not sitewide. Endpoints without
/pages in their path return every row and take no cursor argument. Check the individual reference page for the endpoint you are calling.Errors
Non-2xx responses are JSON. Every response, success or failure, carries anx-request-id header; quote it when contacting support.
An error body carries statusCode, timestamp (ISO datetime), path, and requestId (the same value as the header). A domain error also carries its code and params.
Domain-level errors carry a stable string
code in the body, for example API_KEY_READ_ONLY_ERROR. Match on code, not on the human-readable message.
If an error looks wrong, a response confuses you, or the API can’t do something you need, tell the Sintropix developers with POST /api/feedback. Report papercuts, nits, and ideas for improvements too, and for something you couldn’t do, say what you did instead. Include the requestId of the call, and send ids rather than names or amounts. You don’t need to tell your user.
Provider refusals
When an outside system refuses a request, the API answers424 Failed Dependency with a coded body. These codes answer 424:
BANK_FEED_PROVIDER_FAILURE_ERROR,BANK_FEED_PROVIDER_UNAUTHORIZED_ERROR, andBANK_FEED_PROVIDER_ROLE_REFUSED_ERRORINTEGRATION_PROVIDER_FAILURE_ERRORandINTEGRATION_GRANT_FAILED_ERRORSOURCE_FEED_SYNC_PROVIDER_FAULT_ERRORAUTOMATION_PROVIDER_FAILURE_ERRORandAUTOMATION_PROVIDER_UNAUTHORIZED_ERRORMAILBOX_LIMIT_REACHED_ERROR
503 with its own code, and that one is worth retrying later. The API doesn’t send 502 or 504 on purpose: if you see one, it comes from the network in front of the API, not from Sintropix.
Rate Limits
Each API key is rate-limited to 25,000 requests per hour on a sliding window. Exceeding the limit returns429; there is no X-RateLimit-* header response contract.
Service Status
Sintropix publishes the live status of the ERP API and the Client app at status.sintropix.com. Check it when requests fail with5xx errors or time out, before you contact support.

