Workspaces and API keys
Authenticate every call with one key, and know exactly what that key may read and write.
One Bearer header authenticates everything. The key names its workspace, so no request ever carries a tenant parameter, and the key's roles decide what it may touch. A workspace holds your objects, records, files and people; in the SDK and the API it is called a tenant.
The Authorization header
Send the key as a Bearer token on every request:
curl https://api.standards.new/v1/records/contacts \
-H "Authorization: Bearer stndrds_your_api_key"Keys are read from the Authorization header only. A key in a cookie or query string is ignored.
Two refusals cover authentication and authorization:
| Status | Code | Meaning |
|---|---|---|
401 | none | Invalid, expired, or revoked API key. One message for all three cases. |
403 | SCHEMA_FORBIDDEN | The key is valid but its roles do not grant the action. The message never names the object or the action. |
Creating keys
POST /api-keys creates a key. The caller needs api-keys:create, which the built-in Owner role holds.
curl -X POST https://api.standards.new/v1/api-keys \
-H "Authorization: Bearer stndrds_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "status-page", "roleId": "role-uuid", "expiresAt": "2027-01-01T00:00:00Z" }'The plaintext secret is returned once, in this response. Store it in a secrets manager. Afterwards the API exposes the key's metadata only (name, prefix, creation date, last use).
What a key may do is decided at creation:
- Without
roleId, the key inherits every role of the actor that created it. Create a key from an Owner and you get an Owner key. - With
roleId, the key holds that role and nothing else. This is the shape for automations: one dedicated role per integration, granting only the objects and actions it touches. - The
permissionsarray in the body is accepted and ignored. Keys are role-driven only. standards keys createhas no role option. A CLI-created key inherits the roles of the key you ran it with. Give it a narrower role from the People area of the app if it needs less.
Personal keys
A key is either a workspace key or a personal key. Passing userProfileId makes it personal, and it may name only your own profile:
- Only a signed-in user can create a personal key. An API key or an agent owns no profile, so the request is refused with
403SCHEMA_FORBIDDEN. - A personal key acts with its owner's roles, and only its owner can revoke it. No colleague and no administrator can withdraw it.
A workspace key names no profile and is governed by the api-keys permission alone.
Permissions
A permission grants a set of actions on one target, within one of two scopes. On the wire:
{ "scope": "object", "target": "contacts", "actions": ["read", "update"] }In prose, this documentation writes resource:action, so architect:update means the update action on the architect system resource.
objectscope is business data. The target is an object name, or*for every object.systemscope is the platform itself. The target is one of the thirteen resources below, or*for all of them.
Actions
| Action | Grants |
|---|---|
read | Fetching data. |
create | Creating records or resources. |
update | Modifying records or resources. |
delete | Soft-deleting and restoring. |
manage | Administrative operations, such as purging records for good. |
observe | Read-only visibility on agent session timelines. Only meaningful on the session resource. |
Actions are independent, not tiers: manage does not imply read, and delete does not imply update. * in an actions list means the five CRUD actions and never observe.
System resources
| Resource | Controls |
|---|---|
people | User profiles, invitations, roles and permissions. people:read unlocks the list_workspace_users MCP tool. |
workspace | Workspace settings, including reading the schema and listing schema sources. |
architect | Changing the schema. architect:update syncs a schema source; architect:delete removes one. |
documents | Documents, folders and drives. |
api-keys | Creating, listing and revoking API keys. |
connectors | Connected accounts and outbound MCP servers. |
env-vars | Environment variables for agents. |
session | Agent sessions. Pairs with observe. |
files, views, forms, feature-flags and audit each control the resource their name says.
Record routes check an object-scope permission on the object they touch: read to list, search and get, create to create, update to update and attach documents, delete to delete and restore, manage to purge. Every other route checks the matching CRUD action on its own system resource.
Built-in roles
Every workspace starts with three roles you will meet:
| Role | Object access | System access |
|---|---|---|
owner | All actions on all objects. | All actions on all resources. |
member | All actions on all objects. | read on people and workspace; read, create, update, delete on connectors, files and documents. |
agent_default | read, create, update, delete on all objects. | read, create, update on documents and files; read on env-vars; observe on session. |
A Member cannot change the schema, mint keys or administer people. Those stay with Owner unless a custom role grants them. Built-in roles cannot be edited or deleted.
Only an actor that already holds Owner can grant the Owner role. Custom roles, and their assignment to keys and people, are managed from the People area of the app.
Expiry and revocation
- Expiry:
expiresAtis optional. An expired key is refused like an invalid one. - Revocation:
DELETE /api-keys/:id, orstandards keys revoke <id> --yes. The next request with that key gets a401. - The last owner is protected: revoking the only usable Owner credential the workspace has left is refused with
400SCHEMA_VALIDATION_FAILED,Cannot revoke the last owner role. Assign another owner first. - Auditing: each key records when it was last used, so stale keys are easy to spot.
Keys are server-side secrets
Never commit a key or ship it in browser code. The SDK refuses to run with an API key in a browser. Rotate a key you suspect has leaked: create the replacement, switch, then revoke the old one.