API integration guide
Everything below is the same surface the product's own screens use. There is no separate "integration API" to fall behind — an integration authenticates as a token, and the platform applies the identical licence, permission and tenant checks it applies to a person.
1. Mint a token
In the app, go to Settings → API Tokens and create one. You are shown the secret once; it is stored only as a SHA-256 hash, so it cannot be recovered afterwards — if it is lost, revoke it and mint another.
- Format.
nxs_followed by 32 characters. The first 8 are kept in clear as a display prefix, so an administrator can tell two tokens apart in the list without ever seeing either secret. - Scopes. A token carries an explicit list.
tool:<id>grants one capability;*grants everything the minting user could do. A token can never exceed the permissions of the person who created it. - Rate limit. Per token, defaulting to 60 calls a minute; an administrator can raise it for a high-volume integration.
- Revocation. Immediate, from the same screen. Every call stamps
last_used_at, so an unused token is easy to spot before you remove it.
2. Call the REST API
Every module serves its full capability as JSON under /api/<module>/… on your
own tenant hostname. Authenticate with a bearer token:
curl https://yourcompany.tarleaks.com/api/hr/employees \
-H "Authorization: Bearer nxs_your_token_here"
The tenant is resolved from the hostname, so there is no tenant id to pass and no way to reach another company's data with your token.
3. Or connect an AI tool over MCP
Every module also speaks the Model Context Protocol at
/api/<module>/mcp, with one aggregate endpoint covering all of them. Point Claude,
an IDE or an agent framework at it and the ERP becomes readable and actionable — with the same
per-tool permission checks, and an audit row for every call.
The tool list is generated from one shared catalogue, so a module's MCP surface cannot drift from what the module actually does.
Ask for a shape, not a page
List tools accept a _shape object so you can aggregate server-side instead of paging
thousands of rows and counting them yourself:
{ "_shape": {
"group_by": "department",
"measures": ["count", "avg:base_salary"],
"where": { "status": "active" },
"sort": "count:desc"
} }
Grouping and filtering run over the whole population, not the visible page. Every response also
carries a meta block giving the true row count, the column names and their types — read
that rather than counting the rows you can see.
4. Subscribe to events instead of polling
Domain events — a hire, a payroll run posted, a certificate issued, a ticket answered, a campaign result — are published on a message bus. Integrations subscribe and react, rather than asking repeatedly whether anything changed.
5. What you get for free
- Tenant isolation. Enforced at the gateway, in every service, and again at the database — each tenant's data lives in its own database.
- The same permissions as the UI. An integration cannot do something the person who minted its token could not do.
- A full audit trail. Every call is attributed to the token and the person behind it, with old → new values recorded, which is what makes an integration debuggable and a compliance question answerable.
- Licence gating. A module your plan does not include answers 402, not 404 — so the reason is unambiguous.
Where the rest of the documentation lives
Per-module API references are generated from the live routes of your own installation, so they always match the version you are running. The role guides show the same capabilities from the other end — what each person does on screen, step by step.
Talk to us about API access