Skip to content

REST API

The SessionFS API server exposes a REST API for session management, auditing, sync, and settings.

  • Cloud: https://api.sessionfs.dev
  • Self-hosted: Your deployment URL

All endpoints (except signup) require a Bearer token:

Authorization: Bearer sk_sfs_...

Two key kinds:

  • User keys — created via POST /api/v1/auth/keys. Tied to a single user, inherit all of that user's permissions. Legacy keys are back-filled to scopes=["*"].
  • Service keys (v0.10.10+) — created via POST /api/v1/orgs/{org_id}/service-keys. Org-scoped, expirable, and restricted to an enumerated scopes list (e.g. ["handoffs:write", "agent_runs:write"]). Deny-by-default: a service key only reaches a route handler that explicitly opted in via require_scope(...). The recommended credential for cloud agents (Bedrock, Vertex), CI runners (GitHub Actions, GitLab MR), and integration partners.

Structured 401/403 error codes: api_key_revoked, api_key_expired, service_key_not_allowed, insufficient_scope (with required + current arrays), cross_org_denied, service_key_project_required, service_key_project_not_registered, service_key_project_ambiguous.

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/auth/signup | None | Create account | | GET | /api/v1/auth/me | Bearer | Current user profile | | POST | /api/v1/auth/keys | Bearer | Create user API key | | GET | /api/v1/auth/keys | Bearer | List user API keys | | DELETE | /api/v1/auth/keys/{key_id} | Bearer | Delete a user API key | | GET | /api/v1/auth/verify/{token} | None | Verify email address |

Org-scoped, scope-restricted API keys for cloud agents, CI runners, and integration partners. Org admin role + Team+ tier required for mutations. Raw key returned exactly once on create + rotate; the list/detail endpoints only return key_prefix.

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/orgs/{org_id}/service-keys | Bearer (org admin) | Create a service key (body: name, scopes[], optional expires_at, project_ids[]) | | GET | /api/v1/orgs/{org_id}/service-keys | Bearer (org member) | List service keys for the org | | DELETE | /api/v1/orgs/{org_id}/service-keys/{id} | Bearer (org admin) | Revoke a service key (body: optional revoke_reason) | | POST | /api/v1/orgs/{org_id}/service-keys/{id}/rotate | Bearer (org admin) | Issue a new raw secret for an existing key |

Available scopes (the * wildcard is reserved for legacy user/admin keys; service keys must enumerate explicitly):

| Scope | Status | Routes opted in | |-------|--------|-----------------| | handoffs:read, handoffs:write | ✅ live (v0.10.10) | Handoff create/claim/revoke/decline + comments + events | | agent_runs:write | ✅ live (v0.10.10) | POST /agent-runs, POST /agent-runs/{id}/complete | | tickets:read, tickets:write | ✅ live (v0.10.18) | Ticket list/get/comments/review-state + start/complete/comment | | knowledge:read, knowledge:write | ✅ live (v0.10.19) | GET /entries, GET /entries/{id}, POST /entries/add, PUT /entries/{id} (dismiss/update/refresh/promote/supersede) | | personas:read, personas:write | ✅ live (v0.10.20) | Persona list/get + create/update/delete | | agent_runs:read | ✅ live (v0.10.21) | GET /agent-runs, GET /agent-runs/{run_id} | | sessions:read, rules:read, rules:write, retrieval_audit:read, admin:* | Reserved | Not yet opted in on any route |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/sessions | Bearer | List sessions (paginated) | | GET | /api/v1/sessions/{id} | Bearer | Get session detail | | PUT | /api/v1/sessions/{id}/sync | Bearer | Push session (upload archive) | | GET | /api/v1/sessions/{id}/sync | Bearer | Pull session (download archive) | | GET | /api/v1/sessions/{id}/messages | Bearer | Get paginated messages | | GET | /api/v1/sessions/{id}/summary | Bearer | Get session summary | | POST | /api/v1/sessions/{id}/summary | Bearer | Generate session summary | | POST | /api/v1/sessions | Bearer | Upload/create a session | | DELETE | /api/v1/sessions/{id} | Bearer | Soft-delete a session | | PUT | /api/v1/sessions/{id}/alias | Bearer | Set session alias | | DELETE | /api/v1/sessions/{id}/alias | Bearer | Clear session alias | | POST | /api/v1/sessions/{id}/share | Bearer | Create share link | | DELETE | /api/v1/sessions/{id}/share/{link_id} | Bearer | Revoke share link | | GET | /api/v1/sessions/share/{token} | None | Access shared session (public) | | POST | /api/v1/sessions/share/{token} | None | Access password-protected share link | | GET | /api/v1/sessions/search | Bearer | Full-text search |

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/sessions/{id}/audit | Bearer | Run LLM Judge audit | | GET | /api/v1/sessions/{id}/audit | Bearer | Get latest audit report | | GET | /api/v1/sessions/{id}/audits | Bearer | Audit history | | GET | /api/v1/sessions/{id}/audit/status | Bearer | Check background audit status |

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/handoffs | Bearer | Create handoff | | GET | /api/v1/handoffs/{id} | Bearer | Get handoff details | | POST | /api/v1/handoffs/{id}/claim | Bearer | Claim handoff (copies session) | | GET | /api/v1/handoffs/inbox | Bearer | Handoffs received | | GET | /api/v1/handoffs/sent | Bearer | Handoffs sent | | GET | /api/v1/handoffs/{id}/summary | None | Get handoff session summary |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/sync/settings | Bearer | Get autosync settings (mode, debounce_seconds, max_member_bytes — tier-aware per-file cap; CLI v0.10.27+ reads this to avoid a hardcoded fallback) | | PUT | /api/v1/sync/settings | Bearer | Update autosync mode (requires autosync feature if not "off"); response echoes the same shape as GET including max_member_bytes | | GET | /api/v1/sync/watchlist | Bearer | Get watched sessions | | POST | /api/v1/sync/watch/{id} | Bearer | Add session to watchlist | | DELETE | /api/v1/sync/watch/{id} | Bearer | Remove session from watchlist | | PUT | /api/v1/sync/watch/{id}/{status} | Bearer | Update watch status (pending/queued/synced/failed) | | GET | /api/v1/sync/status | Bearer | Sync status overview (counts, storage usage) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/settings/judge | Bearer | Get judge settings | | PUT | /api/v1/settings/judge | Bearer | Save judge settings | | DELETE | /api/v1/settings/judge | Bearer | Clear judge settings | | GET | /api/v1/settings/judge/models | Bearer | Discover models from custom endpoint | | GET | /api/v1/settings/audit-trigger | Bearer | Get auto-audit trigger | | PUT | /api/v1/settings/audit-trigger | Bearer | Set auto-audit trigger | | GET | /api/v1/settings/github | Bearer | GitHub installation settings | | PUT | /api/v1/settings/github | Bearer | Update GitHub settings | | GET | /api/v1/settings/gitlab | Bearer | GitLab integration settings | | PUT | /api/v1/settings/gitlab | Bearer | Update GitLab settings | | DELETE | /api/v1/settings/gitlab | Bearer | Remove GitLab integration |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/projects/ | Bearer | List projects the user has access to | | POST | /api/v1/projects/ | Bearer | Create project context (requires project_context feature) | | GET | /api/v1/projects/{remote} | Bearer | Get project context by git remote | | PUT | /api/v1/projects/{remote}/context | Bearer | Update context document | | DELETE | /api/v1/projects/{project_id} | Bearer | Delete project (owner or admin only) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/projects/{id}/entries | Bearer | List knowledge entries. Query params: type, pending, search, limit | | POST | /api/v1/projects/{id}/entries/add | Bearer | Create a knowledge entry (types: decision, pattern, discovery, convention, bug, dependency) | | PUT | /api/v1/projects/{id}/entries/{entry_id} | Bearer | Dismiss or un-dismiss a knowledge entry | | POST | /api/v1/projects/{id}/compile | Bearer | Compile pending entries into project context (optional LLM config in body) | | GET | /api/v1/projects/{id}/compilations | Bearer | List compilation history. Query param: limit | | GET | /api/v1/projects/{id}/health | Bearer | Knowledge health stats (total/pending/compiled/dismissed entries, staleness) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/projects/{id}/pages | Bearer | List all wiki pages for a project | | GET | /api/v1/projects/{id}/pages/{slug} | Bearer | Get a wiki page with backlinks | | PUT | /api/v1/projects/{id}/pages/{slug} | Bearer | Create or update a wiki page (requires project_context feature) | | DELETE | /api/v1/projects/{id}/pages/{slug} | Bearer | Delete a wiki page (requires project_context feature) | | POST | /api/v1/projects/{id}/pages/{slug}/regenerate | Bearer | Regenerate an auto-generated concept page from latest entries | | GET | /api/v1/projects/{id}/links/{target_type}/{target_id} | Bearer | Get backlinks for a target | | PUT | /api/v1/projects/{id}/settings | Bearer | Update project settings (e.g. auto_narrative toggle) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/projects/{id}/tickets | Bearer (tickets:read) | List tickets. Query params: status, assigned_to, kind | | POST | /api/v1/projects/{id}/tickets | Bearer (tickets:write) | Create a ticket (body: title, description, acceptance_criteria, priority, kind, parent_ticket_id, depends_on) | | GET | /api/v1/projects/{id}/tickets/{tid} | Bearer (tickets:read) | Get a ticket with dependencies, dependents, and recent comments | | PUT | /api/v1/projects/{id}/tickets/{tid} | Bearer (tickets:write) | Partial mutation for title / description / priority / acceptance_criteria / context_refs / file_refs / depends_on. Status transitions remain FSM-only. Authz: creator OR project admin. Optional lease_epoch for optimistic concurrency (409 + structured envelope on stale; last-write-wins when omitted; lease_epoch alone rejected with 400 — it's a fence, not a mutation). Side effect: every successful update auto-posts ONE author_persona='system' diff comment + writes per-field rows to the ticket_edits audit table (no-op writes don't pollute the audit). depends_on updates run same-project + cycle + dedup validation before wipe-and-reinsert. (v0.10.28) | | POST | /api/v1/projects/{id}/tickets/{tid}/start | Bearer (tickets:write) | Atomic claim. Increments and returns lease_epoch, creates a server-side retrieval_audit_id, returns compiled persona + ticket context | | POST | /api/v1/projects/{id}/tickets/{tid}/complete | Bearer (tickets:write) | in_progressreview. Pass lease_epoch to reject stale workers with 409 | | POST | /api/v1/projects/{id}/tickets/{tid}/resolve | Bearer (tickets:write) | reviewdone. Atomic with rowcount-1 guard | | POST | /api/v1/projects/{id}/tickets/{tid}/close | Bearer (tickets:write) | Issue terminator (rejects kind='task' with 400) | | POST | /api/v1/projects/{id}/tickets/{tid}/approve | Bearer (tickets:write) | Move suggestedopen so an agent-source ticket can be started | | POST | /api/v1/projects/{id}/tickets/{tid}/escalate | Bearer (tickets:write) | Raise priority and append a non-idempotent audit comment | | POST | /api/v1/projects/{id}/tickets/{tid}/comments | Bearer (tickets:write) | Append a comment to the ticket thread | | GET | /api/v1/projects/{id}/tickets/{tid}/comments | Bearer (tickets:read) | Paginated comment thread (query: since, since_id, limit) | | GET | /api/v1/projects/{id}/tickets/{tid}/review-state | Bearer (tickets:read) | Derived review state — open/closed findings, last verdict, severity counts |

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/org | Bearer | Create organization (Team tier or above required) | | GET | /api/v1/org | Bearer | Get org info, member list, and current user role | | POST | /api/v1/org/invite | Bearer | Invite a member by email (admin only). Sends invite email best-effort (v0.10.22). UPSERTs over stale (org_id, email) rows (declined / expired / orphan-accepted) since v0.10.28 — regenerates id to invalidate stale acceptance links and preserves created_at as the audit signal. | | POST | /api/v1/org/invite/{invite_id}/accept | Bearer | Accept an org invite | | POST | /api/v1/org/invite/{invite_id}/decline | Bearer | Decline a pending invite (recipient only, optional decline_reason) — v0.10.22 | | GET | /api/v1/org/invites | Bearer | List pending invites (admin only) | | GET | /api/v1/org/invites/me | Bearer | List pending invites addressed to the caller (v0.10.22) | | DELETE | /api/v1/org/invites/{invite_id} | Bearer | Revoke a pending invite (admin only) | | POST | /api/v1/orgs/{org_id}/invites/{invite_id}/resend | Bearer | Resend an invite email (admin only) — v0.10.22 | | POST | /api/v1/orgs/{org_id}/invite | Bearer | Org-scoped invite path (admin only). Same UPSERT-over-stale semantics as /api/v1/org/invite since v0.10.28. | | PUT | /api/v1/org/members/{user_id}/role | Bearer | Change a member's role (admin only) | | DELETE | /api/v1/org/members/{user_id} | Bearer | Remove a member from the org (admin only) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | POST | /api/v1/admin/users/{user_id}/api-keys | Bearer (admin) | Mint a user-kind ApiKey on behalf of any active user as a lost-key recovery path. Raw key returned exactly once; audit row via _log_action(action="mint_api_key_on_behalf", details={key_id, name}). Guards: 404 unknown user, 403 inactive user (no backdoor for disabled accounts), 403 non-admin caller. Service keys are NOT minted here — they remain at /api/v1/orgs/{org_id}/service-keys per v0.10.10. (v0.10.28) | | POST | /api/v1/admin/projects/{project_id}/restore-from-compilation | Bearer (admin) | Restore project.context_document from a prior ContextCompilation.context_after; restore compiled_at on participating entries. Body: {compilation_id: int, dry_run: bool = true}. Single atomic transaction. Audit-logged. (v0.10.13) |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /api/v1/billing/status | Bearer | Current subscription status, tier, storage usage | | POST | /api/v1/billing/checkout | Bearer | Start a SessionFS Cloud plan checkout (body: tier, seats) | | POST | /api/v1/billing/portal | Bearer | Open the SessionFS Cloud subscription page |

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /health | None | Health check |

After deployment, interactive API docs are available at:

  • Swagger UI: https://your-domain/api/docs
  • ReDoc: https://your-domain/api/redoc