Skip to content
StoryOS Docs
Search
Ctrl
K
Cancel
GitHub
Select theme
Dark
Light
Auto
Getting Started
What is StoryOS
Quickstart
Core concepts
Guides
Share a portal with a client
Creating a workspace
Migrating your data
Migrate from Linear
Removing a member, and GDPR
Keyboard shortcuts
Webhooks
Sources
Copying a record into another database
Sync with Google Calendar
Self-hosting
Overview
Configuration
Attachments (S3/MinIO)
Backup & upgrade
Concepts
Workspaces, spaces & databases
Databases & fields
Relations
Lookups & rollups
Formulas
Views
Automations & buttons
Validation rules
Access & roles
Data model reference
Mentions and notifications
Files & attachments
Record history
Personal space
Dashboards
Organising the sidebar
Tyron, the in-app assistant
Agent runs
Skills
Split-screen panels
Portal recipients
Use with AI (MCP)
Overview
Tools
Connect (Claude Code & Desktop)
Hosted MCP (HTTP + PAT)
OAuth connector
API
Overview
Authentication
Querying records
Conventions
Build an MCP server
API Reference
Overview
App
AppController_health
AppController_buildInfo
system
Liveness + database connectivity check
auth
Current authenticated user
Enabled auth providers (google appears only when configured)
workspaces
List workspaces I belong to
Create a workspace (creator becomes admin)
Workspace details
Update workspace (admin)
List spaces (guests: scoped spaces only)
Create a space
Deleted spaces in this workspace (admin)
Get or create the caller's personal space
Delete a space (creator on this space, or admin)
Rename/reorder a space
Restore a deleted space, its cascade-deleted databases, and their fields/records/views (admin)
List active members
Remove a member (admin)
Change a member role / guest scoping (admin)
List pending invites (admin)
Invite by email; guests require space_ids (admin)
Resend a pending invite; returns a fresh link (admin)
Revoke a pending invite (admin)
Accept an invite by token (must match your email)
Live Getting-Started state, derived from what actually exists (MN-213)
spaces
Folders in a space (MN-096)
Create a folder in a space
Delete a folder (its items fall back to the space root)
Rename / re-icon / reorder a folder
Presentational sidebar groups (#742 finding 04)
Create a sidebar group
Delete a sidebar group (its spaces fall back to ungrouped)
Rename / re-colour / reorder a sidebar group
billing
Plan, status, usage vs limits, and whether billing is configured
Create a Stripe Checkout session for a plan; returns a redirect URL
Create a Stripe Customer Portal session; returns a redirect URL
Start the 30-day Pro trial (no card, no Stripe subscription yet)
Stripe webhook receiver — signature-verified, unauthenticated by design
Current AI credit balance, auto-reload config, and card-on-file status
Create a one-time Checkout session to add credits; returns a redirect URL
Configure (or disable) auto-reload
access
List access grants (optionally for one user)
Grant a role on a space or database (upserts per scope)
Revoke a grant
referrals
This user’s referral link, code, and rewards summary
Attribute the current user as referred by a code (first-touch, one-time, best-effort)
action-gates
List this workspace's declared action-class gate policies
Declare a gate over an action class, scoped to workspace/space/database. Only classes the server enforces are accepted (422 lists them); today: delete_records
Remove a gate policy
Enable/disable a gate policy, or change its approver
fields
Convert a user field into a relation to the Members database. DRY RUN by default: reports matched/unresolvable counts, the per-role permission-neutrality proof, and what would be created. Applying keeps the original field (renamed) and parks anything unresolvable; nothing is dropped.
Convert a relation to the Members database back into a user field (the reverse). DRY RUN by default. Removes the relation and its Members-side inverse field; Members rows with no user id are parked in a text field.
Add a field (select types accept initial options)
Soft-delete a field (returns records_with_value)
Rename / reconfigure / reorder a field
What depends on this field — records carrying a value, plus views/automations/formulas referencing it (#681)
Convert field type within the compatibility matrix (dry_run supported)
Add a select option
Delete an option — 409 with usage count unless confirm: true
Rename / recolor / reorder an option (O(1), ids are stable)
My personal view override for this embedded collection
Set (or replace) my personal view override for this embedded collection
Clear my personal override for this embedded collection (falls back to the shared default)
Scan every readable database for a select that looks like its lifecycle (status) field, and say which databases already have a workflow field. Read-only.
Convert chosen selects to the Workflow field type through the existing per-field conversion. DRY RUN by default (dry_run: false to apply); needs creator on each database; per-item results, one refusal does not stop the rest.
databases
List databases (guests: scoped spaces only)
Create a database (auto: title field, system fields, default view)
Deleted databases in this workspace (admin)
Database with live fields and views (schema introspection)
Hard delete (creator on this database, or admin) — body.confirm must equal the name
Rename / re-icon (creator); moving between spaces stays member+
Restore a deleted database, and whatever fields/records/views were deleted with it (admin)
Duplicate a database — schema, or schema + records (#266)
records
List records (manual order, optional q= title search, cursor)
Create a record ({values} keyed by field api_name)
#230: match-or-create on a unique key. key_field must be a field marked unique (#229); values[key_field] is the match value.
Query records: filter AST + sorts + q + keyset cursor (the workhorse)
Count or aggregate records server-side (same filter AST as /query)
One aggregate value per group — a board/dashboard column's true total, in one query
Create up to 100 records atomically
Apply one values patch to up to 5000 records (partial failures reported)
#653 — undo a batch update using the `restorable` list its response reported
#694 — enqueue a durable bulk update/delete job (poll via GET .../batch-jobs/:id)
#694 — poll a bulk record job's status and progress
Soft-delete up to 5000 records
Restore up to 5000 records from trash
Soft-deleted records (30-day retention)
Resolve a record by its public per-database number (MN-087)
Single record, values keyed by api_name
Soft delete (restorable for 30 days)
Merge-update values (null clears a field)
Duplicate: clone values + description + single/m2m links (not owned collections)
Watch this record — get notified (inbox/email) on any change (#236)
Stop watching this record (#236)
List this record's watchers + whether I watch it (#236)
Atomic move: fractional reposition + optional value patch (kanban drop)
Restore from trash
Copy records into another database (map -> dry-run -> apply). dry_run (default true) returns the field mapping and any blocking fields without writing anything.
mentions
Records whose document mentions this one ("Mentioned in") — MN-205, paged (#512)
notifications
My notifications, newest first (filter by type; archived view)
Unread badge count
Mark one notification read
Mark everything read
Archive one notification (MN-073)
Restore an archived notification to the inbox
users
Set my avatar (multipart field "file", png/jpeg/webp ≤1MB)
Remove my avatar (falls back to initials)
Serve a user avatar (session required)
My preferences (defaults applied)
Update my preferences (deep-merged)
attachments
Attachments on a record
Upload a file (multipart field "file"; size-capped). `?field=<id>` puts it in an attachment field instead of the record bag (#391)
Download the file (authz-checked, streamed)
Image thumbnail (404 for non-images)
Delete an attachment (object removed best-effort)
relations
Every relation in the workspace — one entry per relation, both sides resolved (#448)
Create a relation — needs creator on BOTH databases
Relation config + comparable fields for the auto-link editor
Delete a relation, both its fields, and all links (confirm: true)
Set or clear a relation’s auto-link rules (MN-085)
Run auto-link now across existing records — returns a summary (MN-085)
Detect select↔relation drift for a parent record (MN-286): child records whose select-field label matches the parent’s title but aren’t linked here
Bulk-link every currently-drifted child record to the parent (MN-286)
Linked records for a relation field ({id, title} chips)
Replace all links for this record on this field
Add links (409 when one-to-many already linked)
Remove specific links
validation-rules
List this database's validation rules, each with how many stored records break it now
Declare a rule that REFUSES a record write when its condition is not met. Applies to every writer, admins included; no bypass.
Delete a rule
Change a rule's name, condition, message or enabled flag (the trigger is fixed)
The stored records that ALREADY break this rule (a rule only fires when a field it references changes, so existing violations persist; this is how they are seen)
buttons
Press a button field (editor+); actions run as the presser
automations
List rules
Create a rule (trigger + condition + actions)
Delete a rule
Update / enable / disable a rule
Run history (90-day retention, MN-264)
Dry-run a rule against one record
Rotate a webhook_received rule's token + secret — the old URL 404s immediately
The most recent payload a webhook_received rule received (for token mapping)
hooks
Inbound webhook receiver for a webhook_received automation rule
approvals
List approvals for this workspace, optionally filtered by status
Approve a pending approval — enqueues the gated action from its frozen snapshot (human-only)
Reject a pending approval — the gated action never runs (human-only)
webhooks
List webhooks (secrets are never returned)
Create a webhook — the signing secret is returned once, here only
Delete a webhook
Update a webhook (url / events / enabled)
Recent delivery attempts — status, code, error, retries
comments
Comments, newest first
Comment (guests included); mentions extracted server-side
Delete own comment (admins: any)
Edit own comment
activity
Record activity trail, newest first (cursor)
#674 — comments + references across a relation tree rooted at this record (e.g. Epic→Story→Task)
#240 — comments across every record in this database, newest first (cursor)
Workspace-wide activity + field changes, filterable by actor/entity/date range (admin)
record-versions
Record version history, newest first (cursor)
Per-field change history, newest first (cursor)
A single version, as a diff preview against the record's current values
Restore the record to a previously captured version
integrations
Integrations directory — registry metadata + per-integration connected status
GitHub config (token presence + repos + App connect state)
Save GitHub token, repos, webhook secret and/or state automation
Begin GitHub App OAuth connect (redirects to GitHub)
List the connected installation's repositories
Import/refresh Issues + PRs; auto-links PRs to issues by #N / branch refs
Disconnect GitHub — clears token, App installation and watched repos
Reviews sidebar: PRs in one bucket (needs_review/authored/participating)
PR detail: metadata, changed files (with patch), checks
Cached inline review comments for this PR
Post a new inline (file/line-anchored) review comment
Reply within an existing comment thread
React to a review comment
Poll GitHub for review comments and refresh the local cache
Approve / Request changes / Comment — submits a GitHub PR review
Code & reviews settings (defaulted)
Save Code & reviews settings
GitHub webhook receiver — HMAC-verified, unauthenticated by design
GitHub App OAuth callback — verifies state, captures installation id
Linear config (key presence + team keys)
Save Linear API key and/or team-key filter
Preview import counts per team — writes nothing
Import teams → spaces (Issues/Sprints/Projects), idempotent by Linear ID
Disconnect Linear — clears the stored API key and team-key filter
Slack config (token/webhook presence + default channel)
Save Slack bot token, webhook URL and/or default channel
Send a test message using the saved Slack config, to verify the connection
Disconnect Slack — clears the stored bot token, webhook and default channel
Create the Shopify product catalogue — databases, sources and relations in one click
Shopify product/collection webhook for one connection — HMAC-verified, unauthenticated by design
documents
Record description (BlockNote JSON; version 0 = never written)
Write the description — 409 with current version on conflict
Document version history, newest first (cursor)
A single document version, as a block-level diff preview against the current content
Restore the document to a previously captured version
Standalone documents in a space (MN-095)
Create a standalone document in a space
A standalone document (BlockNote content + version)
Delete a standalone document
Update title/icon/content — 409 on version conflict
Download the document as Markdown (#262)
Download the document as a PDF (#262 — rendered by the PDF sidecar, #794)
Move a document to a shared space (one-way out of Personal; notifies its mentions)
Copy a document into my personal space (independent fork, no sync)
connections
List connections (auth material is never returned)
Connect an api_key/smtp provider — runs a live health check before saving
The provider catalog — what can be connected, and how
Disconnect — hard-deletes the row, no tombstone
Re-run the provider health check against the stored credential
MN-264: manually close the circuit breaker before its cool-down elapses
Begin an OAuth2 connect (redirects to the provider)
OAuth2 callback — verifies state, exchanges the code, seals the tokens
Resend bounce/complaint webhook for one connection — signature-verified, unauthenticated by design
sources
List the sources syncing into this database
Configure a new source: provider + connection + field mapping + schedule
The source provider catalog — what can be synced, and its config shape
#341: list the YouTube channels a Google connection owns, for the channel picker
MN-262: preview a provider's field keys before creating a source (point-and-click mapping)
Stop syncing — leaves every record the source created intact
Reconfigure a source
Run one sync cycle immediately, ignoring the schedule gate
Recent sync runs for one source (fetched/created/updated/errors)
skills
List skills visible to the caller: their own, plus every shared one
Create a skill — shared with the workspace by default, whether a person or an agent (token, connected AI) creates it. An agent can also share it with named workspace members; making one public only raises an approval a person must give. A workspace admin can switch agent publishing off, after which an agent-authored skill is created personal
Starter scaffolds for the "new skill" flow (AC #2, not-from-scratch)
Read one skill
Delete a skill — owner-only
Edit a skill — owner-only, even if it's shared
Import a SKILL.md: returns a KEPT/DROPPED report first; pass create:true to write the skill
Export a skill as portable instructions (Markdown / Claude Skill SKILL.md / ChatGPT)
Run a skill manually; returns its step log (no model invoked yet)
public
A public skill, by its link token (portable fields only)
Public view definition + one page of records (link/public access only)
The built-in Business Pack gallery — public, pre-signup
One built-in pack — public, pre-signup preview
Public form definition (link/public access only)
Submit a public form → creates or (portal-scoped) edits a record (anonymous). Multipart with a "payload" JSON text part when the form has an attachment field.
Search candidate records for a public form relation field
Create a new linked record from a public form relation field
portal
List portal recipients for this workspace
Create a portal recipient — never creates a user, never touches billable seats
Revoke a recipient — every access path closes immediately, no cache/TTL
Issue a new token for a recipient, atomically invalidating the old one (#602)
Portal recipient activity — what a client saw and did, filterable by recipient/view (admin)
views
Create a saved view (config validated against live fields)
Create a view owned by me (private, never shared) over this database
Delete a view (409 on the last shared one)
Rename / reconfigure / reorder a view
Duplicate a view with its full config, placed next to the original
Set this view as the database's default (one default per database)
Publish a personal view to the shared database (one-way; see copy-to-personal)
Copy a shared view into my personal space (independent fork, no sync)
Deleted views on this database (editor+)
Restore a deleted view
Publish a read-only public link for this view, or update its allowlist (#264)
Revoke a view's public link — takes effect immediately (#264)
My personal filter override for this view (cleaned of dead field refs)
Set (or replace) my personal filter override for this view
Clear my personal filter override for this view
Views navigable in a space, for the sidebar tree (#347)
Create a space-level view — dashboards only (#306)
My own personal views across the workspace, for the Personal sidebar section (#551)
One view by id, with or without a database (#306)
Delete a space-level view (#383)
Update a view by id — name / config / placement (#306)
Move a database-level dashboard into its space (#306)
export
Download the database (or a view) as CSV
Download the whole workspace as a .zip (schema, records, relations, attachments)
tokens
My personal access tokens (prefix only — plaintext is never stored)
Create a PAT — the token is shown ONCE in this response
Revoke a token (immediate)
files
Upload an image for the editor (multipart "file"); returns { id, url }
Mint a signed, expiring download URL for a file (#201)
Revoke a file — kills its capability URL and any signed download URLs (#201)
Serve an uploaded editor image by id (capability URL, or access-checked under private-attachments mode)
Download a file via a signed, expiring URL (#201)
search
Search records by title + databases/spaces by name (grant-scoped)
Records across databases assigned to me or created by me (MN-049, #36)
Records the caller touched most recently (from activity)
import
Import CSV: fields "file", "mapping" (JSON), "dry_run" ("true"/"false")
google-calendar
List writable calendars for a Calendar connection
List database-to-calendar sync bindings
Bind a database and date fields to a Google Calendar
Push all current dated records to Google Calendar now
Remove a calendar binding (existing Google events remain)
runs
Monthly automation-run usage vs the plan allowance, with a pace projection
Every automation run in the workspace, newest first — rule runs today (source syncs pending #239)
Run detail: trigger context, per-action attempts/artifacts, approval linkage
Re-run one failed action from this run with its original frozen inputs
agents
Agents database summary, or { exists: false } if not provisioned
Provision the Agentic OS space + Agents/Runs/Agent Triggers databases (idempotent)
Bind an agent to a state on a database; returns the binding record
Run an agent manually; returns the Run record
Delegate a record to an agent — it runs with the record as context and posts progress back as a comment
Approve a run waiting for approval: apply the staged action
Reject a run waiting for approval: apply nothing, cancel it
A parked run's staged action and step log, or null if it isn't waiting
Field changes + activity events attributed to this agent, in a date range
Propose a plan from a plain-language goal; creates nothing
Build an approved plan through the ordinary CRUD services
tyron
The caller's own Tyron threads, most recent first (#359)
Start a thread, auto-named from its first message (#359)
One thread with its history (404 unless it is yours)
Delete a thread — does NOT undo what it did (#359)
Rename a thread
Send a message to Tyron and get what it did (#357)
Approve or decline Tyron's pending action (#358)
Build a workspace from one sentence (#363)
templates
Available starter templates
Install a template (packs create a space; database templates take space_id and may be renamed)
Remove exactly the sample records templates created
packs
Export a workspace slice as a pack manifest; creates nothing
Install a pack manifest; idempotent
Preview what installing a manifest would do; creates nothing
List tracked pack installs in this workspace
Uninstall a tracked pack install
List this workspace's marketplace submissions
Submit a pack manifest to the marketplace for review
The built-in Business Pack gallery
One built-in pack, manifest included
Browse published Community Marketplace packs
One published pack — manifest, changelog, versions
favorites
Current user's favorites in this workspace (resolved titles)
Star a record or database
Unstar
gdpr
Export everything held about this member (machine-readable JSON)
Erase/anonymize this member: wipe identity to a tombstone, destroy credentials, and remove workspace access. Comments and history are kept.
admin
Instance-wide counts: workspaces, users, records, plan mix, estimated MRR.
Every workspace on the instance: plan, seats, record count.
MN-194 — per-workspace cost and margin from real usage (hosted calls, storage, email; AI cost estimated pending MN-214r), plus blended margin per plan and the margin-floor flags.
#300/MN-216c — agent runs across every workspace: workspace, agent, status, run_class, trigger, started/finished. Read-only.
#300/MN-216c — kill switch: cancel a queued/running/waiting-approval run in any workspace. A status flip to Canceled only — no other side effects.
MN-220 — pack marketplace submissions awaiting (or having had) review
MN-220 — approve or reject a pending pack submission
#304 — set a workspace plan (comp/Enterprise grant); requires a reason; never touches live Stripe
#304 — set entitlement overrides (e.g. maxWorkspaces) for a workspace; requires a reason
#304 — clear a workspace's entitlement overrides; requires a reason
#304 — current plan + overrides + audit trail for a workspace
GitHub
Select theme
Dark
Light
Auto
Import/refresh Issues + PRs; auto-links PRs to issues by #N / branch refs
POST
/api/v1/workspaces/{ws}/integrations/github/sync
Responses
Section titled “Responses”
201
Section titled “201”