Sharing and orgs
Grant a role on a session to a person, an organisation or a link; list what is shared with you; manage org membership.
A share grants a role on one session to a user, to every member of an org, or to whoever presents a link token. The session owner manages shares; anyone can create an org and invite people into it.
principal_type | principal_id | Who gets access |
|---|---|---|
user | The user's UUID | That account, on every device. |
org | The org's UUID | Every current member of the org. Only an org member can share a session into it. |
link | — (must be omitted) | Any authenticated principal who presents the token. |
role is viewer (default), editor or owner. expires_at is optional and must be in the future; an expired share is ignored everywhere. Sharing with the session's own owner is 400 — The owner already has full access.
Share a session
curl -X POST https://ai.codai.ro/v1/sessions/5b3e…/shares \
-H "Authorization: Bearer $CODAI_API_KEY" -H "Content-Type: application/json" \
-d '{ "principal_type": "user", "principal_id": "7d21…-uuid", "role": "editor" }'{
"id": "e4a9…", "session_id": "5b3e…", "principal_type": "user", "principal_id": "7d21…",
"role": "editor", "has_token": false, "expires_at": null,
"created_by_user_id": "…", "created_at": "2026-09-23T10:00:00.000Z"
}Unknown user → 404 not_found (User not found.). A non-UUID principal_id → 400 (principal_id must be a user uuid.).
A link token grants the share's role to any authenticated codai user who presents it. Treat it like a password: set expires_at, keep the role at viewer unless you need more, and delete the share when done.
Manage shares
| Method | Path | Min role | Response |
|---|---|---|---|
GET | /v1/sessions/:id/shares | owner | { shares: Share[] } — never includes tokens, only has_token. |
POST | /v1/sessions/:id/shares | owner | 201 Share (+ token once for link). |
DELETE | /v1/sessions/:id/shares/:shareId | owner | { deleted: true, id }; unknown → 404 (Share not found.). |
Deleting a share revokes access immediately for everyone it covered — including anyone currently connected via a link token, whose next request is 403 not_a_member.
What is shared with me
curl "https://ai.codai.ro/v1/sessions/shared-with-me" -H "Authorization: Bearer $CODAI_API_KEY"{ "sessions": [ { "id": "5b3e…", "session_key": "…", "owner_user_id": "…", "title": "Fix the flaky test", "created_at": "…", "last_event_at": "…", "last_seq": 42, "executor_device_id": "1c2f…", "lease_expires_at": "…", "e2e": false, "archived": false, "role": "editor", "share_id": "e4a9…" } ] }Lists sessions shared with you directly or through an org (up to 200; ?archived=1 includes archived ones). Link-share access is exercised per request and does not appear in any list — a viewer who arrived by link has to keep the token. GET /v1/sessions (with x-codai-device or ?v=2) returns your own sessions first, then the shared ones, each with your role.
Your effective role on a session is the highest across every share that matches you — a viewer link plus an editor user share makes you an editor.
Organisations
An org is a named group of users. Sharing a session with an org shares it with everyone in it, now and later.
On the wire the Org object is camelCase — { id, name, ownerUserId, createdAt } — unlike every other object on this surface. This is part of v1 and will not be renamed.
| Method | Path | Who | Request | Response |
|---|---|---|---|---|
POST | /v1/orgs | any user | { "name": string 1..200 } | 201 { id, name, ownerUserId, createdAt, role: "owner" } |
GET | /v1/orgs | any user | — | { orgs: [{ id, name, ownerUserId, createdAt, role }] } — orgs you belong to, with your role |
GET | /v1/orgs/:id/members | org member | — | { org_id, members: [{ user_id, role, created_at, email }] } |
POST | /v1/orgs/:id/members | org owner or admin | { "user_id": uuid } or { "email": string } (exactly one), role? default member | 201 { org_id, user_id, role } — an upsert, so re-posting changes the role |
DELETE | /v1/orgs/:id/members/:userId | org owner or admin | — | { deleted: true, org_id, user_id } |
Membership roles are owner · admin · member. Only the org owner can grant owner (403 — Only the org owner can grant the owner role.) and the owner cannot be removed (403 — The org owner cannot be removed.). Adding someone who has no codai account is 404 (User not found.); a non-member reading the list is 403.
# create an org and add a teammate by email
ORG=$(curl -s -X POST https://ai.codai.ro/v1/orgs \
-H "Authorization: Bearer $CODAI_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "Platform team" }' | jq -r .id)
curl -X POST "https://ai.codai.ro/v1/orgs/$ORG/members" \
-H "Authorization: Bearer $CODAI_API_KEY" -H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "role": "admin" }'Every share and org mutation writes an audit row (share_add, share_remove, org:create, org:member_add, org:member_remove), so the owner can always reconstruct who had access when.