No Route Here Asks Who You Are Asking About
The public read interface has one property that decides most of its security: no route accepts an organisation identifier from the caller. The key carries it, so there is nothing for a client to get wrong or to change.
The most dangerous parameter an interface can accept is the one naming whose data you want.
A read interface serving many organisations has to answer two questions on every request: who is asking, and whose records they may see. Those can be one question or two, and choosing to make them one removes an entire class of failure.
The key is the organisation
A key is minted inside a workspace and belongs to it. Every request authenticated by that key is scoped to that workspace, and no route accepts an organisation identifier as a parameter — because there is nothing a caller could usefully supply.
Consider what the alternative costs. An interface accepting an organisation identifier must check on every route that the caller is entitled to the one they named, and a single route where that check is absent exposes everybody's data to anybody with a valid key. That is the most common serious defect in multi-organisation interfaces, and it is entirely avoided by not accepting the parameter.
A check you never have to write cannot be forgotten
The same reasoning appears elsewhere in this product — the supplier portal authorising by ownership rather than by permission, the file controller checking one thing and requiring the route to declare the rest. The pattern is to make the dangerous input unavailable rather than to validate it carefully everywhere, because "carefully everywhere" is a promise about every future route as well as every current one.
Read only, and visibly so
Every route in the interface is a read. There is no write verb anywhere in the group — not one that requires a special scope, not one behind an additional check. Writing is not restricted; it is absent.
That is worth stating plainly because "read only" is often a permission setting that can be changed, and here it is a property of what exists. An interface key that leaked cannot be used to alter anything, because there is nothing to call.
Four scopes, three of them narrow
| Scope | What it reaches |
|---|---|
| Inventory | Items, categories and warehouses. |
| Sales | Customers and invoices. |
| Procurement | Suppliers and purchase orders. |
| Read everything | An umbrella satisfying all three. |
The umbrella scope is described honestly in the documentation as convenient for a trusted internal integration and worth avoiding for a third party. That is the right advice to publish beside it, because the temptation with an umbrella scope is to use it for everything and the cost only appears when a key ends up somewhere it should not be.
A single route sits outside the resource scopes and requires only a valid key: the one that describes the key itself. It is what a client calls to confirm which organisation it is operating against and what it is entitled to, and it is the correct first call in any integration.
A narrow scope costs a decision once. An umbrella scope costs a decision every time the key moves.
The documentation and the routes come from one description
The published scope list is rendered from the same catalogue the interface is built around, rather than being maintained as a separate document. So the scopes described publicly and the scopes enforced on the routes cannot drift apart.
That matters more for an interface than almost anywhere else. Documentation is the contract, integrations are written against it by people you never speak to, and a documented scope that does not exist produces an integration that fails in production against a key its author configured exactly as instructed.
Public contract versus internal surface
There is a much larger interface behind this one, serving the product's own applications. It is explicitly not this: it is first-party, app-internal and undocumented, and it changes as the applications change.
Keeping the two separate is the discipline that makes a versioned public interface possible at all. A public surface is a promise that shapes stay stable; an internal one is a place where a screen and its data can evolve together. Merging them means either freezing internal development or breaking integrations, and both are worse than maintaining two.
For anybody building against this, the practical rule is short: if it is documented, it is a contract. If you found it by watching the product's own network traffic, it is not — and it will change without notice, because that is what the separation is for.
Beyond reading
The read surface is narrow, versioned and safe by construction. What integrators ask for next is more of it, and eventually the ability to write.
More read resources
Additional resources under the same scoping model — each one a scope, each one documented, each one carrying the organisation on the key.
A write surface
Writes as an explicit addition with their own scopes, their own idempotency requirements and their own rate limits, rather than by relaxing what exists.
Outbound events
Notification of a change rather than polling for one, which is what most integrations actually want from a read interface.
We publish scope, not dates.
Scope an integrationFive questions to ask about a multi-organisation interface
How is the organisation determined?
A good answer sounds like
From the credential.
What ours actually is
From the key. No route accepts an organisation identifier from the caller, so there is nothing to validate and nothing to tamper with.
Can a key write anything?
A good answer sounds like
A definite answer.
What ours actually is
No. Every route is a read. Writing is absent rather than restricted.
What scopes exist?
A good answer sounds like
A published list.
What ours actually is
Inventory, sales and procurement, plus an umbrella that satisfies all three and is documented as being for trusted internal use.
Is the documentation generated from the implementation?
A good answer sounds like
Yes.
What ours actually is
The published scope list renders from the same catalogue the interface is built around, so the two cannot drift.
Is everything you call documented?
A good answer sounds like
No, and here is the line.
What ours actually is
No. A much larger first-party interface serves the product's own applications and is deliberately undocumented and unversioned.
Our take
The decision worth copying here is not a feature, it is an omission. By refusing to accept an organisation identifier from the caller, the interface makes the most consequential authorisation check in a multi-organisation system into something that cannot be forgotten, because there is no place to write it. Everything else follows comfortably from that: a read-only surface, three narrow scopes and an honestly-labelled umbrella, and documentation rendered from the same description that enforces the routes. What it does not yet do is write, and that is the right order — a write surface deserves its own scopes, its own idempotency contract and its own limits rather than arriving as a relaxation of something built for reading.
What AWRA OpsHub does today
- A versioned, publicly documented read interface for a workspace's own data, authenticated by a key minted inside that workspace.
- The organisation carried by the key, with no route accepting an organisation identifier from the caller.
- Every route a read — writing is absent from the surface rather than restricted on it.
- Three narrow resource scopes covering stock, sales and purchasing, plus an umbrella scope documented as suited to trusted internal use.
- A single route requiring only a valid key, describing the key's own organisation and entitlements, as the correct first call in any integration.
- A rate limiter applied to the whole surface.
- Published documentation rendered from the same catalogue the interface is built around, so scopes cannot be documented without existing.
- A clear separation from the much larger first-party interface serving the product's own applications, which is deliberately undocumented and unversioned.
More we can add to your workspace
- Write operations, with their own scopes, their own idempotency requirements and their own limits.
- Additional read resources beyond stock, sales and purchasing — assets, people, projects and support each following the same scoping model.
- Outbound events, so an integration learns of a change rather than polling for one.
- Field selection on a response, so a client can ask for what it needs rather than filtering a full record.
- A per-key usage view, showing what a key has called and how often, inside the workspace that minted it.
- Cursor pagination stated as part of the contract, so a large collection can be walked with a stable guarantee.
Where we point you to a specialist
- We will not accept an organisation identifier from a caller on this surface. The check that a caller is entitled to the organisation they named is the one most likely to be omitted from exactly one route, and the reliable way to guarantee it everywhere is to make the parameter unavailable.
- We will not add writes by relaxing what exists. A write surface has different requirements — scopes, idempotency, limits, and a much more careful contract about partial success — and arriving at it by loosening a read interface would carry none of them.
- What is documented is a contract and what is not is not. The first-party interface serving our own applications changes as those applications change, and building against it is a decision to be broken; we would rather say so than let a version number imply a promise we are not making.
Outbound events are the piece most integrations actually want, because the majority of polling against a read interface exists only to discover that something changed.
Start with the narrow scope
The umbrella exists for convenience and it is the wrong default for anything leaving your organisation. Three narrow scopes cost one extra decision at setup and remove a whole category of regret.
Talk through the interfaceFrequently asked questions
How does the interface know which organisation to serve?
From the key. It is minted inside a workspace and belongs to it, and every request authenticated by it is scoped accordingly. No route accepts an organisation identifier from the caller, which means the check that a caller is entitled to the organisation they named does not need to exist — and therefore cannot be missing from one route.
Can a leaked key be used to change our data?
No, because there is nothing to call. Every route in the surface is a read, and writing is absent rather than restricted. That is a stronger statement than a read-only permission, which is a setting somebody could change.
Which scope should we grant?
The narrowest that covers what the integration needs — stock, sales or purchasing. The umbrella scope satisfies all three and is documented as suited to a trusted internal integration; for anything given to a third party, a narrow scope costs one extra decision at setup and bounds the consequences of the key ending up somewhere unexpected.
Where do I find the documentation?
It is published as part of the product, and it renders from the same catalogue the interface is built around rather than being maintained separately. That construction is deliberate: a documented scope that does not exist produces an integration that fails in production against a key its author configured exactly as instructed.
The product's own app calls endpoints I cannot find in the documentation. Can I use those?
You can, and they will break. Those belong to a first-party interface that serves the product's own applications and changes as they change — deliberately undocumented and unversioned. The line is simple: if it is documented, it is a contract; if you found it by watching network traffic, it is not.
Will there be a write interface?
It is on the list, as its own thing rather than as a relaxation of this one. Writes need their own scopes, their own idempotency contract and their own limits, and building them by loosening a read surface would carry none of those. In the meantime, the interface that already handles inbound integration calls is a different surface with a different arrangement.