Skip to main content
Your API key proves which organization is calling. It does not say which person inside that organization the request is for. Records reads and writes are almost always for a person: someone looking at the records they own, a manager looking at a team. So a trusted server, such as your application’s backend, names that person on each request. Nexio then resolves that person’s authority from your own systems before it builds any query, and every response states the scope it was served at. On Records reads and writes, a header can only narrow what your key already reaches. What the person may reach comes from your own systems: your identity provider, your HR directory and your system of record’s security groups and business-unit access, and the access plane applies your rules to every read under the lit posture (see Access plane).

Acting-principal headers

These headers are asserted by a server you trust, never by a browser. The API sends no CORS headers, so it can only be called server to server.

The signed assertion

The assertion proves that the identity headers came from your server and were not changed on the way.
  • Format: v1.<unix timestamp in seconds>.<hex HMAC-SHA256>.
  • Signed bytes: acting_principal|acting_email|reserved|timestamp, joined with |. Trim each value. Lowercase the email. The third field is reserved: send an empty string. Use an empty string for a header you do not send. The timestamp is the same decimal string that appears in the header.
  • Key: a signing secret Nexio provisions for the server that asserts identity. It is not your API key.
  • Window: the timestamp must be within 5 minutes of Nexio’s clock, in either direction. Outside it the assertion is stale.
Nexio enables assertion verification for your organization when it provisions the signing secret. A missing or bad assertion is then refused with 403 assertion_invalid, and one outside the window with 403 assertion_stale.
The full status response is on Completeness and errors. Its scope block for this person reads:

Posture

Each organization has an access-plane posture. It decides where a person’s authority comes from. Send the acting principal on every Records request. Under shadow and lit, a request without it is refused with 403 identity_unmapped. A posture can be limited to named people. Your organization sets its posture with its own live API key or through a person it has delegated as an access administrator, and Nexio sets it only when you ask. Each change is written to the audit log. How the entitlement is derived from your own systems is on Access plane.

Scope kinds

The resolved scope decides which rows exist for this person. It appears as scope.kind in the scope block.

Selection

A selection narrows rows inside the scope. It never widens it. Nexio applies no default selection: a person-scoped caller that sends none is served everything they may open, and the response says so. me resolves to the person’s own verified codes. A person with none, asking for me, answers 403 scope_unavailable, never an empty list. A well-formed producer or client_manager code that matches none of the person’s rows answers either 200 with no rows or 403 scope_unavailable, depending on how the person’s access is bounded. A book code outside the person’s scope answers 403 scope_unavailable. A malformed value answers 400 invalid_request. mine and book ride outside the page cursor: resend them on every page, exactly as you resend the acting-principal headers. Whether producer and client_manager are fixed by the cursor or resent depends on the register; see What a cursor fixes.

The scope block

Every JSON response from a read under /api/v1/records ends with a scope block, except GET /records/actions, the /records/analyses routes and document content. GET /records/status carries its own, fuller scope block. The full list, beside the serving block, is Which responses carry each block. Graph reads carry no scope block either. The block looks like this:
Use selection to label what you show. A boundary read is not “my accounts”; it is every account this person may open.

Field classes

Some fields belong to a field class, and a role policy can deny a class. On a Records read that returns the field among others, a denied field is blanked: null on a nullable field, and the type’s empty value (0, "" or false) on the few fields that are not nullable. It stays in the shape, so your parser does not change. A run read is different: with an acting principal, a denied compensation key is removed from the run’s output (see Runs). A route whose whole answer is one denied class refuses instead, with 403 field_denied, because an all-null answer would read as a real zero. The field classes are fixed in code and are the same for every organization. Which classes a person may see follows from their security groups in your system of record.

Lens

X-Nexio-Records-Lens: principal:<id> shows another person’s data to a caller whose own scope is All or Platform. The response carries serving.lens with the target, their display name and the scope kind served. From any narrower scope the header is ignored. A lensed write answers 403 book_lens_read_only. A lens needs an acting principal: without one it answers 403 lens_caller_unattributed.

Refusal codes

Every refusal is distinct and none falls back to a wider scope. When a qualifying connection exists, GET /api/v1/records/status answers five of these refusals as data (200, with scope.refused set) so an application can explain them before the first read: identity_unmapped, identity_needs_review, identity_suspended, identity_stale and scope_unavailable. With no qualifying connection, it admits the caller as other governed routes do, and an identity refusal answers with its HTTP status. The other refusals in this table, including the assertion and lens refusals, answer with their HTTP status on /records/status as on every other route.

Next

Registers and pagination

Page through a scoped list.

Access plane

How each person’s access comes from your own systems.
Last modified on September 25, 2026