"Organisations and roles"
Organisations own projects. Everyone who belongs to an organisation can reach its projects, with a role that decides what they can do.
Personal organisations
Every Tether account has a personal organisation. Projects you create land there unless you pick another organisation. If you used Tether before organisations existed, all of your projects were moved into your personal organisation automatically and nothing about how you use them has changed.
Personal organisations can't be deleted or left, but you can invite people to them like any other organisation.
Switching organisation
Open the menu under your name at the bottom of the sidebar. It lists every organisation you belong to and your role in each. Picking one changes which projects the Projects page shows and where new projects are created.
The CLI and API list projects from every organisation you belong to. Pass ?organisationId=<id> to GET /api/v1/projects to narrow the list, and organisationId in the body of POST /api/v1/projects to create a project somewhere other than your personal organisation.
Roles
| Viewer | Developer | Admin | Owner | |
|---|---|---|---|---|
| See projects, data, schema, logs, crons and usage | ✓ | ✓ | ✓ | ✓ |
| Run queries | ✓ | ✓ | ✓ | ✓ |
| See API keys, variable values, database exports and backup downloads | ✓ | ✓ | ✓ | |
| Edit data, run SQL and mutations | ✓ | ✓ | ✓ | |
| Deploy functions and schema, run crons | ✓ | ✓ | ✓ | |
| Manage crons, variables, backups, row-level security and database tokens | ✓ | ✓ | ✓ | |
| Create projects in the organisation | ✓ | ✓ | ✓ | |
| Manage environments, environment keys, publishable keys, domains and auth providers | ✓ | ✓ | ||
| Create, rotate and revoke scoped API keys | ✓ | ✓ | ||
| Manage bridges, rename, move and delete projects | ✓ | ✓ | ||
| Invite and remove members, change roles, view the audit log | ✓ | ✓ | ||
| Grant or remove the owner role, delete the organisation | ✓ |
Viewers see API keys and variable values as blank strings.
Every organisation keeps at least one owner: the last owner can't be demoted, removed or leave.
How checks work
Every request to /api/v1/projects/{id}/... is checked before it reaches the handler:
- People (dashboard, CLI sessions and OAuth app tokens) need a role in the organisation that owns the project. If you aren't a member the API answers
404 Project not found, so project ids don't leak. If your role is too low it answers403and says which role is needed. - Environment API keys (
tthr_dev_...,tthr_prod_...) keep full access to their own environment, exactly as before. - Scoped API keys (
tthr_sk_...) are limited by their scopes. See API keys. - Publishable keys (
tthr_pk_...) can still only call deployed functions from allowed origins.
OAuth app tokens are checked twice: the person who authorised the app needs the role, and the token needs the matching grant.
Inviting people
Admins and owners invite people from Organisation settings → Invites by email address and role. Only owners can invite another owner.
Each invite has a link that works once and expires after 14 days. It can only be accepted by someone signed in with the invited email address, once Strands Accounts has verified that address. Creating a new invite for the same address replaces the old one, and New link issues a fresh link (the old one stops working).
When the invite email is sent, the link only goes to the invited address. If this server can't send email, the dashboard shows the link after you create the invite: copy it and send it to the person yourself. Only owners can resend an owner invite.
When someone already in the organisation accepts another invite, they keep whichever role is higher.
Adding a known user directly
When you already know who someone is, for example you authorised an app on their behalf and have their user id from GET /api/v1/oauth/userinfo (the sub field), you can add them straight to an organisation without the invite email and acceptance step:
POST /api/v1/organisations/{id}/members
Content-Type: application/json
{ "userId": "...", "role": "admin", "email": "[email protected]", "name": "Sam" }
email and name are optional and only used for display until the user signs in. Admins can add members; only owners can grant the owner role, and a personal organisation takes no extra members. Adding is idempotent and only ever raises an existing member's role, never lowers it.
This is how a "set it up for them, hand it over later" flow works: create an organisation, add the user as an admin, put their project in it, and later promote them to owner (PATCH .../members/{userId}) and leave. Because a user id is derived from their Strands identity, the membership is valid even before they have signed in to Tether; they inherit it the moment they do.
Moving a project
Owners of a project's organisation can move it to another organisation where they are an admin or owner. Moving a project removes access for everyone in the old organisation, so admins can't do it:
POST /api/v1/projects/{id}/transfer
Content-Type: application/json
{ "organisationId": "..." }
The project's data, keys and settings are unchanged; only who can reach it changes. The move is recorded in the audit logs of both organisations.
API reference
All organisation routes need a signed-in person (dashboard or CLI session). API keys and OAuth app tokens can't manage organisations.
| Method | Path | Who |
|---|---|---|
GET |
/api/v1/organisations |
Anyone (creates your personal organisation on first call) |
POST |
/api/v1/organisations |
Anyone (you become the owner) |
GET |
/api/v1/organisations/{id} |
Members |
PATCH |
/api/v1/organisations/{id} |
Admins (rename) |
DELETE |
/api/v1/organisations/{id} |
Owners, once it has no projects |
GET |
/api/v1/organisations/{id}/members |
Members |
POST |
/api/v1/organisations/{id}/members |
Admins ({ "userId": "...", "role": "admin" }), not personal orgs |
PATCH |
/api/v1/organisations/{id}/members/{userId} |
Admins ({ "role": "developer" }) |
DELETE |
/api/v1/organisations/{id}/members/{userId} |
Admins, or yourself to leave |
GET |
/api/v1/organisations/{id}/invites |
Admins |
POST |
/api/v1/organisations/{id}/invites |
Admins ({ "email": "...", "role": "viewer" }) |
POST |
/api/v1/organisations/{id}/invites/{inviteId}/resend |
Admins |
DELETE |
/api/v1/organisations/{id}/invites/{inviteId} |
Admins |
GET |
/api/v1/invites/{token} |
Anyone signed in |
POST |
/api/v1/invites/{token}/accept |
The invited person |
GET |
/api/v1/projects/{id}/access |
Members (your role and permissions) |
POST |
/api/v1/projects/{id}/transfer |
Admins of both organisations |
Creating an invite returns the accept link:
{
"invite": { "id": "...", "email": "[email protected]", "role": "developer", "expiresAt": "..." },
"acceptUrl": "https://tetherdb.co.uk/invite/tthr_inv_...",
"emailSent": false
}