API integration guide
Everything below is the same surface the product's own screens use. An integration signs in with a token, and the platform applies the same licence, permission and company checks it applies to a person.
1. Create a token
In the app, go to Settings → API Tokens and create one. You see the secret once; it is stored only as a SHA-256 hash, so it cannot be recovered. If it is lost, revoke it and create another.
- Format.
nxs_followed by 32 characters. The first 8 stay visible as a prefix, so an administrator can tell two tokens apart without seeing either secret. - Scopes. A token carries an explicit list.
tool:<id>grants one capability;*grants everything the person who created it can do. A token never exceeds that person's permissions. Scopes are enforced on MCP today; enforcement on the REST API is rolling out. - Rate limit. Per token, 60 calls a minute by default; an administrator can raise it for a busy integration. Like scopes, the limit is enforced on MCP and rolling out on REST.
- Revocation. Immediate, from the same screen. Every call updates
last_used_at, so an unused token is easy to spot before you remove it.
2. Call the REST API
Each app serves its capabilities as JSON under /api/<module>/… on your own company address. Sign in
with a bearer token:
curl https://yourcompany.tarleaks.com/api/hr/employees \
-H "Authorization: Bearer nxs_your_token_here"
The company comes from the address, so there is no company id to pass and no way to reach another company's data with your token.
Sending a body. Send JSON with Content-Type: application/json (curl -d sends a form type
unless you add that header). Where a body is optional, send no body (or {}) for the defaults. A body the
server cannot read is refused and the action does not run: not valid JSON, or a field of the wrong type, answers
400 with a key such as error.request.invalid_json or error.request.body_field and the
field's name; a non-JSON Content-Type answers 415 error.request.not_json. It is never
read as "no body".
3. Or connect an AI tool over MCP
Each app also speaks the Model Context Protocol at /api/<module>/mcp, with one gateway covering
all of them. Point Claude, an IDE or an agent framework at it and your ERP data becomes readable and actionable, with
the same permission check on every tool and an audit row for every call. More than 3,000+ tools come from one shared
catalogue, so an app's MCP list cannot drift from what the app does.
Ask for a shape, not a page
List tools accept a _shape object, so you can aggregate on the server 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 all the rows, not the visible page. Every response also carries a meta block
with the true row count, the column names and their types; read it rather than counting the rows you can see.
4. Subscribe to events instead of polling
Business 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 instead of asking again and again whether anything changed.
5. What you get for free
- Company isolation. Checked at the gateway and in every service, and each company's records sit in a separate database.
- The same permissions as the screens. An integration cannot do anything the person who created its token could not do.
- An audit trail. Every call is attributed to the token and the person behind it, and tracked records keep old and new values, which makes an integration debuggable and a compliance question answerable.
- Licence checks. An app your plan does not include answers 402, not 404, so the reason is clear.
Where the rest of the documentation lives
The full API reference for each app ships inside the product, generated from the same catalogue the Copilot uses. The documentation shows the same capabilities from the other end: what each person does on screen, step by step.