Authentication and scopes
Sending the key
Every request carries the key as a bearer token:
Authorization: Bearer <your key>
There is no other accepted form — no query parameter, no custom header, no cookie. The key is shown once, when it is created. It is not recoverable afterwards; if it is lost, a new one is issued.
What a key is bound to
A key belongs to exactly one organization, called its owner. That binding is fixed for the life of the key: it cannot be moved to another organization, and a key cannot be made to act for two.
Everything the key can reach is owned by that organization. There is no shared or public pool of resources, so a resource belonging to another organization is refused whether you reach for it by id, by list, or through a related record.
The two scope sets
| Set | Grants | Applies to |
|---|---|---|
read_types |
list and fetch | GET doors |
operate_types |
change | PATCH, enrol, exit, attest, status |
Operating implies reading. A type in operate_types does not need repeating in read_types; the
readable set is the union of the two.
Which endpoints need which:
- Read scope —
GET /v1/resources(list),GET /v1/resources/:id,GET /v1/resources/search, and the per-resource reads:/events,/advancement,/members,/containers,/capabilities,/requirements,/ports,/ports/:portId/legal-targets. - Operate scope —
PATCH /v1/resources/:id,POST /v1/resources/:id/members,POST /v1/resources/:id/exit,POST /v1/resources/:id/move,POST /v1/resources/:id/attestations,PATCH /v1/resources/:id/status, theenrollInto/moveOf/moveFromfilters of search, andPOST/DELETE /v1/resource-interactions— operate on the side whose port points out (the side making the choice), read on the side it points to. bind_systems— the external systems your key may bind identifiers under:POST /v1/aliases/bindandPOST /v1/identity-claims/redeem.
A third list, find_or_create_types, governs POST /v1/resources/find-or-create only. It is separate on
purpose: being able to change a bid is not the same as being able to bring one into existence.
The general-reference lists — types, statuses, lifecycles, units and so on — are not type-scoped. Any
valid key may read them. A by-id read of one of them (a type, a lifecycle, its graph, its transitions) answers 404
for anything the key's own list would not show.
POST /v1/ingest also authenticates an API key. Its contract is not yet part of this pack.
Changing scopes
You cannot change your own scopes. An administrator at the owning organization does it, through a
surface your key cannot reach. Ask them; do not build a retry around a 403.
Every scope change is recorded on the ledger, with the complete before and after. So is the creation of the key and its revocation. If you need to know why a call that worked last week fails today, that record is the answer, and your administrator can read it.
Revocation
A key is revoked, not deleted. Once revoked it stops authenticating immediately and permanently; there is no un-revoke. Everything it wrote stays on the ledger and stays attributed to it.
Keys do not expire on their own. A key is valid until somebody revokes it — so treat it like a password that never rotates itself, and ask for a new one if you suspect it has leaked.
Rate limit
300 requests per minute per key by default. The budget is counted per credential, so another integration cannot spend yours and you cannot spend theirs. ReSync may set a different limit for your key — for a large integration, ask your administrator; it is not something a key can change for itself. Whatever your key's limit is, every response says so:
x-ratelimit-limit: 300
x-ratelimit-remaining: 297
x-ratelimit-reset: 59
The window is fixed, not rolling: it starts with your first request and lasts one minute; when it ends, the whole
budget is back. x-ratelimit-reset is the seconds left in the current window.
When you exhaust the budget the answer is 429, with retry-after (seconds left in the window) beside the same
headers. Captured on a key whose own limit is 3, at its fourth request:
x-ratelimit-limit: 3
x-ratelimit-remaining: 0
x-ratelimit-reset: 60
retry-after: 60
From rate-limited-429.json — status 429:
{
"error": "rate_limited",
"message": "rate limit exceeded — 3 requests per 1 minute",
"retryAfterSeconds": 60
}
message reads "…
What a key cannot do yet
Hold a live stream. GET /v1/live — the live-update stream ReSync's web app and kiosk stations use — refuses
an integration key. (Kiosk station credentials are a separate plane, not covered by this pack.) Poll instead (events.md).
From live-key-not-supported.json — status 403:
{
"error": "live_key_not_supported",
"message": "Live updates are available to sessions and kiosk station credentials only; poll the events read with ?after= instead"
}
Request ids
Every response carries x-request-id.
If you send one, it is echoed back, so you can use your own correlation id end to end:
curl -s -H "Authorization: Bearer $TOKEN" -H "x-request-id: order-sync-8842" "$BASE/v1/resources/13813"
Ids are sanitised: letters, digits, ., _, : and - survive, everything else is stripped, and the
result is truncated to 64 characters. If you send nothing, one is generated for you.
Quote it when you report a problem. It is how a specific request of yours is found in the server logs.