Events & Activity Event search, activity polling, WebSocket realtime.
Events capture every action in the system — file operations, membership changes, comments, AI activity, billing, workflow, and more. Use the event search endpoints to query the log, activity polling for efficient change detection, and WebSocket for real-time delivery.
Events Search
Search and filter the event log. Events capture every action in the system — file operations, membership changes, comments, AI activity, billing, workflow, and more.
Search Events
/current/events/search/
Search and filter events with comprehensive filtering options. Uses offset-based pagination.
Auth: Required (JWT). Subject to global rate limiting; see the rate-limit section in the main reference.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| user_id | string | Conditional | — | Filter by user profile ID. One of user_id, org_id, workspace_id, share_id, or parent_event_id is required. |
| org_id | string | Conditional | — | Filter by organization profile ID |
| workspace_id | string | Conditional | — | Filter by workspace profile ID |
| share_id | string | Conditional | — | Filter by share profile ID |
| parent_event_id | string | Conditional | — | Filter by parent event ID for serial/batch events. Cannot combine with filters other than acknowledged, limit, offset. |
| event | string | No | — | Filter by specific event name (e.g., workspace_storage_file_added). Max 100 characters. |
| category | string | No | — | Filter by event category. See Event Categories. |
| subcategory | string | No | — | Filter by event subcategory. See Event Subcategories. |
| calling_user_id | string | No | — | Filter by the user who triggered the event (19-digit numeric ID) |
| object_id | string | No | — | Filter by related object ID (file, folder, etc.) |
| acknowledged | string | No | — | Filter by acknowledgment status: "true" or "false" |
| visibility | string | No | All non-internal | "external_audit_log" or "external" |
| created-min | string | No | — | Lower bound for event creation time. Accepts ISO 8601 (e.g., 2025-12-01T06:00:00Z) or YYYY-MM-DD HH:MM:SS |
| created-max | string | No | — | Upper bound for event creation time. Same format as created-min; must be > created-min |
| limit | integer | No | 100 |
Maximum number of results (1–250) |
| offset | integer | No | 0 |
Number of results to skip for pagination |
| output | string | No | — | Select the response shape. Comma-separated tokens (e.g. terse, standard, full). See the "Compact Responses" section below for the three detail levels and the fields returned at each level. |
Profile filter priority: If multiple profile filters are supplied, priority is: user_id > org_id > workspace_id > share_id. Only the highest-priority filter is applied.
Example Request
curl -X GET "https://api.fast.io/current/events/search/?workspace_id=1234567890123456789&category=workspace&subcategory=storage&limit=50" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"events": [
{
"event_id": "abc123xyz789def456ghi789jkl01",
"created": "2025-01-20 10:30:45 UTC",
"acknowledged": false,
"event": "workspace_storage_file_added",
"category": "workspace",
"sub_category": "storage",
"object_id": "def456ghi789jkl012mno345pqr67",
"calling_user": "9876543210987654321",
"calling_user_name": "Jane Smith",
"org_id": "1111111111111111111",
"workspace_id": "1234567890123456789",
"filename": "quarterly_report.pdf",
"file_size": 2485760
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| events | array | Array of event objects |
| events[].event_id | string | Unique event identifier (alphanumeric OpaqueId) |
| events[].created | string | Event timestamp (Y-m-d H:i:s UTC) |
| events[].acknowledged | boolean | Whether the current user has acknowledged this event |
| events[].event | string | Event name identifier (e.g., workspace_storage_file_added) |
| events[].category | string | Event category name |
| events[].sub_category | string | Event subcategory name |
| events[].object_id | string | Related object OpaqueId (if applicable) |
| events[].calling_user | string | 19-digit numeric ID of the triggering user |
| events[].calling_user_name | string | Display name of the triggering user |
| events[].org_id | string | Organization ID context (if applicable) |
| events[].workspace_id | string | Workspace ID context (if applicable) |
| events[].share_id | string | Share ID context (if applicable) |
| events[].user_id | string | Target user ID for user-specific events (if applicable) |
Additional event-specific fields (e.g., filename, file_size, member_name) vary by event type.
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | No profile filter or parent_event_id provided |
1605 (Invalid Input) | 400 | created-min is greater than created-max |
1605 (Invalid Input) | 400 | parent_event_id combined with disallowed filters |
1680 (Access Denied) | 403 | Token scope does not include the requested profile |
1600 (Query Error) | 500 | Internal error during event search |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT token |
1651 (Invalid Request Type) | 400 | Wrong HTTP method (only GET accepted) |
Notes: Results may be slightly delayed due to caching. OAuth scoped tokens enforce entity-level access: events are filtered to only entities within the token's scope. Events the user cannot access are automatically excluded from results.
Summarize Events (AI)
/current/events/search/summarize/
Search events and generate an AI-powered natural language summary. Accepts all parameters from /events/search/ plus user_context.
Auth: Required (JWT). Subject to global rate limiting; shares the events search rate limit bucket.
Additional Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| user_context | string | No | "" |
Focus guidance for the AI summary (e.g., "Focus on uploads"). Max 64 chars; letters, numbers, spaces, . , ! ? ' - only. |
All other parameters are identical to Search Events.
Example Request
curl -X GET "https://api.fast.io/current/events/search/summarize/?workspace_id=1234567890123456789&user_context=Focus%20on%20file%20uploads&limit=100" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"summary": {
"text": "@[user:9876543210987654321:Jane Smith] uploaded 12 files...",
"metrics": {
"total_events": 50,
"unique_actors": 5,
"date_range": {
"start": "2025-01-01 00:00:00 UTC",
"end": "2025-01-20 10:30:45 UTC"
},
"categories": {
"storage": 30,
"members": 20
}
}
},
"events": [ ... ]
}
Response Fields (additional to events search)
| Field | Type | Description |
|---|---|---|
| summary | object|null | AI-generated summary, or null if no events or generation failed |
| summary.text | string | Natural language summary with @[type:ID:name] mention pills |
| summary.metrics.total_events | integer | Total events summarized |
| summary.metrics.unique_actors | integer | Distinct users who triggered events |
| summary.metrics.date_range.start | string | Earliest event timestamp (Y-m-d H:i:s UTC) |
| summary.metrics.date_range.end | string | Most recent event timestamp (Y-m-d H:i:s UTC) |
| summary.metrics.categories | object | Map of category names to event counts |
Summary Mention Pill Formats
| Entity | Format | Example |
|---|---|---|
| User | @[user:USER_ID:Display Name] | @[user:9876543210987654321:Jane Smith] |
| File | @[file:FILE_ID:filename.ext] | @[file:abc123xyz789def456ghi789jkl01:report.pdf] |
| Folder | @[folder:FOLDER_ID:foldername] | @[folder:def456ghi789jkl012mno345pqr67:Projects] |
| Workspace | @[workspace:WS_ID:name] | @[workspace:1234567890123456789:Engineering] |
| Share | @[share:SHARE_ID:name] | @[share:5555555555555555555:Client Files] |
Notes: Summary generation failures are non-fatal:
summaryisnullbut events are still returned. Requires a billable organization for AI token billing (resolved from profile context).
Event Details
/current/event/{event_id}/details/
Get full details for a single event.
Auth: Required (JWT). Default rate limiting. No credit consumption.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {event_id} | string | Yes | Alphanumeric OpaqueId of the event |
Example Request
curl -X GET "https://api.fast.io/current/event/abc123xyz789def456ghi789jkl01/details/" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"event": {
"event_id": "abc123xyz789def456ghi789jkl01",
"created": "2025-01-20 10:30:45 UTC",
"acknowledged": false,
"event": "workspace_storage_file_added",
"category": "workspace",
"sub_category": "storage",
"object_id": "def456ghi789jkl012mno345pqr67",
"calling_user": "9876543210987654321",
"calling_user_name": "Jane Smith",
"org_id": "1111111111111111111",
"workspace_id": "1234567890123456789",
"filename": "quarterly_report.pdf",
"file_size": 2485760
}
}
Access Rules
| Condition | Access |
|---|---|
User is the calling_user | Granted |
User is the event_user (target) | Granted |
Event has targeted permission and user is neither target nor caller | Denied |
Event is internal visibility | Always denied |
| User has appropriate profile-level permissions | Granted based on permission level |
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | Event ID missing, empty, or not a valid OpaqueId |
1609 (Not Found) | 404 | No event exists with the provided ID |
1605 (Invalid Input) | 400 | Event has internal visibility |
1605 (Invalid Input) | 400 | User lacks permission (targeted event) |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT token |
1651 (Invalid Request Type) | 400 | Wrong HTTP method (only GET accepted) |
Acknowledge Event
/current/event/{event_id}/ack/
Acknowledge (mark as read) an event for the current user. Idempotent.
Auth: Required (JWT). Default rate limiting.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {event_id} | string | Yes | Alphanumeric OpaqueId of the event to acknowledge |
Example Request
curl -X POST "https://api.fast.io/current/event/abc123xyz789def456ghi789jkl01/ack/" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true
}
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | Event ID missing or invalid |
1609 (Not Found) | 404 | Event not found |
1605 (Invalid Input) | 400 | Event has internal visibility |
1605 (Invalid Input) | 400 | User lacks permission (targeted event) |
1664 (Datastore Error) | 500 | Failed to persist the acknowledgment |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT token |
Note: Acknowledgment is per-user. Acknowledging for one user does not affect others. Same access rules as event details apply.
Compact Responses (output=)
Every endpoint that returns event objects (search, details) accepts an optional output query parameter that selects the response shape. A single detail-level token may be combined with modifier tokens; specifying two detail levels (e.g. ?output=terse,standard) returns HTTP 400. When output= is omitted, responses are full and byte-for-byte unchanged.
| Level | Fields returned on each event (cumulative) |
|---|---|
terse | event_id, event, category, object_id, created |
standard | terse + sub_category, calling_user, org_id, workspace_id, user_id, share_id, acknowledged, template (containing description + params), severity, visibility, notification |
full | standard + required_params, requires_parent_node, permission |
Use terse for activity feed tickers and unread-count polling — it carries the event identity (event_id), name (event), category, target object, and a timestamp (created), which is the minimum a feed row needs to render without a follow-up fetch. Use standard for the most common event list/detail views — it adds subcategory, every profile-link id (calling user, owning org/workspace/share), the acknowledgment flag, the template object (which carries the human-readable description and any template params), and the render-hint enums: severity (drives feed-row color/icon), visibility (distinguishes the Activity, Audit-Log, and internal tabs), and notification (drives bell/notification rendering). Use full (or omit the parameter) for audit-log exports and event schema introspection. Unknown tokens are silently ignored. Add the markdown modifier (e.g. ?output=standard,markdown) to receive the response as GitHub-flavored Markdown (Content-Type: text/markdown; charset=UTF-8) instead of JSON — see the cross-cutting ?output= reference for the full contract.
Event Categories
| Category | API Value | Description |
|---|---|---|
| Upload | upload | File upload operations |
| User | user | User account events |
| Organization | org | Organization events |
| Workspace | workspace | Workspace operations |
| Share | share | Share operations |
| AI | ai | AI/ML operations |
| Invitation | invitation | Invitation events |
email | Email-related events | |
| Billing | billing | Billing and subscription events |
| Metadata | metadata | Metadata operations |
| Domain | domain | Custom domain events |
| Apps | apps | Application/integration events |
| Workflow | workflow | Workflow events (task lists, tasks, and workflow-run activity) |
Event Subcategories
| Subcategory | API Value | Description |
|---|---|---|
| Storage | storage | File and folder operations |
| Comments | comments | Comment activity |
| Members | members | Membership changes |
| Lifecycle | lifecycle | Create, update, delete, archive events |
| Settings | settings | Configuration changes |
| Security | security | Security-related events |
| Authentication | authentication | Login and auth events |
| AI | ai | AI processing events |
| Invitations | invitations | Invitation management |
| Billing | billing | Subscription and payment |
| Assets | assets | Asset (avatar, branding) updates |
| Upload | upload | Upload events |
| Transfer | transfer | Ownership transfer events |
| Import/Export | import_export | Import/export operations |
| Quick Share | quickshare | Quick share events |
| Metadata | metadata | Metadata operations |
| Workflow | workflow | Workflow events |
Event Visibility Levels
| Visibility | API Value | Description |
|---|---|---|
| Internal | internal | System events. Never accessible via API. |
| Audit Log | external_audit_log | Audit/compliance events. Targeted permission checks bypassed for admins. |
| External | external | Standard user-facing events. |
Default (no visibility parameter): returns both external_audit_log and external events, excludes internal.
Event Permission Levels
| Permission | Description |
|---|---|
member | Any member of the profile can view |
admin | Only admins of the profile can view |
targeted | Only the target user or the calling user can view |
When querying with visibility=external_audit_log, targeted permission checks are bypassed.
Event Names Reference
Workspace Storage
workspace_storage_file_added— File uploadedworkspace_storage_file_deleted— File trashedworkspace_storage_file_moved— File movedworkspace_storage_file_copied— File copiedworkspace_storage_file_updated— File metadata updatedworkspace_storage_file_restored— File restored from trashworkspace_storage_file_version_restored— File version restoredworkspace_storage_folder_created— Folder createdworkspace_storage_folder_deleted— Folder trashedworkspace_storage_folder_moved— Folder movedworkspace_storage_download_token_created— Download token issuedworkspace_storage_zip_downloaded— ZIP download completedworkspace_storage_link_added— Link added
Share Storage
share_storage_file_added— File uploadedshare_storage_file_deleted— File trashedshare_storage_file_moved— File movedshare_storage_file_copied— File copiedshare_storage_file_updated— File metadata updatedshare_storage_file_restored— File restoredshare_storage_folder_created— Folder createdshare_storage_folder_deleted— Folder trashedshare_storage_folder_moved— Folder movedshare_storage_download_token_created— Download token issuedshare_storage_zip_downloaded— ZIP download completed
Comments
comment_created— Comment createdcomment_updated— Comment updatedcomment_deleted— Comment deletedcomment_mentioned— User mentioned in comment (targeted permission)comment_replied— Reply to a commentcomment_reaction— Reaction added
Membership
added_member_to_org/removed_member_from_org— Org membershipadded_member_to_workspace/removed_member_from_workspace— Workspace membershipadded_member_to_share/removed_member_from_share— Share membershipmembership_updated— Permission changes
Workspace Lifecycle
workspace_created/workspace_updated/workspace_deletedworkspace_archived/workspace_unarchived
Share Lifecycle
share_created/share_updated/share_deletedshare_archived/share_unarchivedshare_imported_to_workspace— Share imported into workspace
File Share Lifecycle
Durable single-file File Share events. Category share, external visibility, member permission. Anchored to the owning workspace; the affected File Share id travels in the event data as file_share_id.
file_share_created— A durable File Share was createdfile_share_updated— A File Share's settings (title / access tier / password) were updatedfile_share_content_updated— The shared file's content was replaced (external edit / write-back)file_share_deleted— A File Share was deletedfile_share_access_granted— A per-user grant (view / download / edit) was added or raisedfile_share_access_revoked— A per-user grant was revoked
AI
ai_chat_created/ai_chat_updated/ai_chat_deleted— AI agent conversation lifecycleai_chat_new_message— New message in an AI agent conversationai_chat_published— AI agent conversation published (chat publish is currently disabled platform-wide —capabilities.can_publish_agent_chatisfalse; fires only for chats published before the disable)node_ai_summary_created— AI summary generated for a fileworkspace_ai_share_created— AI share created in workspace
Metadata
metadata_kv_update/metadata_kv_delete/metadata_kv_extractmetadata_template_update/metadata_template_delete/metadata_template_selectmetadata_view_update/metadata_view_delete
Quick Shares (deprecated — see File Share Lifecycle)
QuickShare creation is deprecated in favor of the durable File Share; these events fire only for the draining QuickShare population. New single-file sharing emits the file_share_* events above.
workspace_quickshare_created/workspace_quickshare_updated/workspace_quickshare_deletedworkspace_quickshare_file_downloaded/workspace_quickshare_file_previewed
Invitations
invitation_email_sent/invitation_accepted/invitation_declined
User
user_created/user_updated/user_deleteduser_email_reset/user_asset_updated
Organization
org_created/org_updated/org_closed
Billing
subscription_created— fires when a new subscription is initiatedsubscription_cancel_scheduled— fires when a customer schedules cancellation; the subscription remains active untilcancel_atsubscription_cancelled— fires when the subscription is actually terminated by the payment provider (atcancel_at)billing_free_trial_ended
Workflow
task_list_created/task_list_updated/task_list_deletedtask_created/task_updated/task_deletedtask_status_changed/task_assigned/task_completedtask_moved— fires when a task is moved between liststasks_reordered— fires when tasks are reordered within a listtask_lists_reordered— fires when task lists are reordered
Event Search Examples
Recent comments in a workspace
GET /current/events/search/?workspace_id={id}&subcategory=comments
File uploads to a share in a date range
GET /current/events/search/?share_id={id}&event=share_storage_file_added&created-min=2025-12-01T06:00:00Z
Membership changes in an org
GET /current/events/search/?org_id={id}&subcategory=members
AI activity in a workspace
GET /current/events/search/?workspace_id={id}&category=ai
Unacknowledged events for a user
GET /current/events/search/?user_id={id}&acknowledged=false
Audit log events only
GET /current/events/search/?workspace_id={id}&visibility=external_audit_log&limit=100
Child events of a batch operation
GET /current/events/search/?parent_event_id=abc123xyz789def456ghi789jkl01&limit=100
Workflow activity in a workspace
GET /current/events/search/?workspace_id={id}&category=workflow
Activity Polling
Long-poll endpoints for efficient change detection. The server holds the connection open and returns immediately when something changes, avoiding expensive resource polling.
Poll User Activity
/current/activity/poll/
Poll for activity updates on the current user's profile.
Auth: Required (JWT). Subject to global rate limiting; see the rate-limit section in the main reference. No credit consumption.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| wait | integer | No | 0 |
Long-poll timeout in seconds (0–95). Server holds connection open until update or timeout. |
| lastactivity | string | No | Current time | Only return activity newer than this timestamp. Micro-precision datetime (e.g., 2025-01-20 10:30:45.123456 UTC). |
| updated | any | No | — | If present, only return activity fields updated since lastactivity |
| fields | string | No | All fields | Comma-delimited activity field names to check. Max 30 fields. Supports ID qualifier via colon (e.g., storage:12345). |
Example Request
curl -X GET "https://api.fast.io/current/activity/poll/?wait=30&lastactivity=2025-01-20%2010:30:45.123456" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK — activity found)
{
"result": true,
"results": 3,
"activity": {
"storage": "2025-01-20 10:30:45.123456 UTC",
"members": "2025-01-20 09:15:22.654321 UTC",
"settings": "2025-01-19 14:00:00.000000 UTC"
},
"lastactivity": "2025-01-20 10:30:45.123456 UTC"
}
Response (200 OK — no activity)
{
"result": true,
"results": 0,
"activity": []
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| results | integer | Number of activity fields returned |
| activity | object | Map of activity field names to micro-precision UTC timestamps |
| lastactivity | string | Most recent timestamp; pass as lastactivity in next poll |
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | Invalid profile ID format |
1605 (Invalid Input) | 400 | User lacks permissions for the specified profile |
1605 (Invalid Input) | 400 | Invalid field names or more than 30 fields |
1665 (Object Init Failed) | 500 | Internal error |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT token |
Poll Profile Activity
/current/activity/poll/{profile_id}/
Poll for activity updates on a specific workspace, share, org, or File Share.
Auth: Required (JWT). Same rate limits and parameters as Poll User Activity.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {profile_id} | string | Yes | 19-digit numeric profile ID (org, workspace, share, or File Share). For upload progress, use your user ID. |
Access Requirements
| Profile Type | Permission Required |
|---|---|
| User (self) | Authenticated |
| Organization | PERM_VIEW on the org |
| Workspace | PERM_VIEW on the workspace |
| Share | Share view permissions + multiplayer enabled |
| File Share | The same access decision as the File Share's public read surface (access tier + password + named grant). A signed-in recipient granted view/download/edit receives a recipient-scoped feed (comment activity plus a bare content/lifecycle nudge — never the owner's internal activity); an anonymous anyone-with-link visitor cannot poll. |
Example Request
curl -X GET "https://api.fast.io/current/activity/poll/1234567890123456789/?wait=30&fields=storage,members&updated=1&lastactivity=2025-01-20%2010:30:45.123456" \
-H "Authorization: Bearer {jwt_token}"
Response format is identical to Poll User Activity.
Polling Workflow
- Make initial poll request (no
lastactivityparameter) - Receive response with
activityfields andlastactivitytimestamp - Process changes by fetching updated resources based on activity field names
- Make next poll with
lastactivityfrom previous response - Repeat — server returns immediately on change, or after
waitseconds timeout
Activity Key Patterns
| Key Pattern | What Changed |
|---|---|
storage:{fileId} | File added, updated, or removed |
preview:{fileId} | File preview/thumbnail is ready |
metadata:{fileId} | File's extracted metadata fields were written (use to refresh a single row during a template extraction) |
ai_chat:{chatId} | AI chat message updated |
comments:{nodeId} | Comment added or updated |
member:{userId} | Membership changed |
Anti-Patterns
- Do NOT loop on resource detail endpoints to wait for previews or processing.
- Instead, poll on the workspace/share and watch for the relevant activity key.
- For uploads, use your user ID as the
profile_idsince upload progress is tied to the user, not a workspace.
WebSocket (Real-Time)
Optional real-time delivery (~300ms latency vs ~1s for polling). Sends both activity messages (field names for change detection) and enriched event messages (full event details) via WebSocket. Backwards compatible — existing clients continue to work without changes.
WebSocket Auth
/current/websocket/auth/{profile_id}
Generate a WebSocket authentication JWT for a specific profile. User, organization, workspace, and File Share tokens are valid for 24 hours. Share and workflow tokens use a shorter TTL — always check the expires_in field on every response and refresh before it expires. A File Share realtime channel is gated by the same access decision as its public read surface (access tier + password + named grant), the same requirement as its activity poll. A signed-in recipient granted view/download/edit can mint a token and receives a recipient-scoped feed — comment activity plus a bare content/lifecycle nudge, never the owner's internal activity; an anonymous anyone-with-link visitor cannot mint a realtime token.
Auth: Required (JWT). No credit consumption.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {profile_id} | string | Yes | 19-digit numeric ID of the user, org, workspace, share, file share, or workflow to subscribe to |
Example Request
curl -X GET "https://api.fast.io/current/websocket/auth/1234567890123456789" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"expires_in": 86400,
"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| expires_in | integer | Effective token lifetime in seconds (86400 = 24 hours for user/org/workspace/file-share; shorter for share and workflow) |
| auth_token | string | Signed JWT with websocket scope, bound to the requested profile |
Access Requirements
| Profile Type | Permission Required |
|---|---|
| User (self) | None beyond authentication |
| Organization | PERM_VIEW on the org |
| Workspace | PERM_VIEW on the workspace |
| Share | canViewShareDetails |
| File Share | The same access decision as the File Share's public read surface (access tier + password + named grant), the same gate as its activity poll. A signed-in view/download/edit recipient mints a recipient-scoped token (comment activity plus a bare content/lifecycle nudge only); an anonymous anyone-with-link visitor cannot mint one. |
| Workflow | Workflow OBSERVE standing — workspace view (or a workflow-scoped viewer/participant/admin grant) for workspace-visibility workflows; workspace member-or-above (or a workflow-scoped participant/admin grant — a viewer grant alone is NOT sufficient at these visibilities) for private/participants_only workflows |
Token Lifetime
The default expires_in for User, Organization, Workspace, and File Share tokens is 86400 (24 hours). Share and Workflow tokens are shorter-lived — always inspect the expires_in field on the response and refresh the token before it expires. Both channels use a short TTL because the recipient's standing can change during a session, and the token freezes that standing at mint time: a workflow's OBSERVE standing can change (a grant is revoked, the workflow's visibility tightens, or the caller is removed from the parent workspace), and a share guest can be removed or have their access level downgraded. The short TTL bounds how long an open connection can keep delivering events under a now-stale authorization; on reconnect the freshly minted token reflects the current standing. See the Workflow Orchestration reference for the workflow-specific realtime contract.
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | No profile ID provided or invalid format |
1605 (Invalid Input) | 400 | Profile type unsupported, not found, or user lacks permissions |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT, or internal JWT generation failure |
WebSocket Connection
Connect to: wss://{host}/api/websocket/?{auth_token}
Where {auth_token} is the JWT returned from the auth endpoint above — it is the entire query string (no token= key, no other query parameters).
Message Types
The server pushes two types of JSON messages:
activity Messages
Indicate which resource categories changed. Use these to know what to re-fetch:
{
"response": "activity",
"activity": ["storage:2abc...", "preview:2abc..."]
}
The activity array contains the same activity key patterns as the polling endpoint.
event Messages
Sent alongside activity messages when structured event data is available. Provide full event details for immediate UI updates without a follow-up API call:
{
"result": true,
"response": "event",
"time": "2026-03-22 14:30:45.123456 UTC",
"timestamp": "1711123456.1234",
"event": "workspace_storage_file_added",
"category": "workspace",
"sub_category": "storage",
"object_id": "abc123def456ghi789jkl012mno34",
"calling_user": "1234567890123456789",
"activity_field": "storage",
"data": {
"name": "report.pdf",
"parent_node_id": "xyz789...",
"size": 1048576
}
}
event Message Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | Always true for event messages |
| response | string | Always "event" for this message type |
| time | string | Server send time (Y-m-d H:i:s.uuuuuu UTC, e.g. "2026-03-22 14:30:45.123456 UTC"). Added when the message is dispatched. |
| timestamp | string | Event trigger time as a microtime float string (e.g., "1711123456.1234"). |
| event | string | Event name identifier (e.g., workspace_storage_file_added) |
| category | string | Event category (e.g., workspace, share) |
| sub_category | string | Event subcategory (e.g., storage, members) |
| object_id | string | Affected object OpaqueId (file, folder, etc.) |
| calling_user | string | 19-digit numeric ID of the user who triggered the event |
| activity_field | string | Corresponding activity field name (e.g., storage) |
| data | object | Event-specific details; shape varies by event type |
Backwards Compatibility
activity messages are sent for every change a recipient is permitted to observe. event messages are supplementary — sent alongside activity messages when structured event data is available. Existing clients need no changes. Event payloads are kept under ~4KB.
Permission gating: Enriched event messages are only sent for member-level events. Admin and targeted events receive only the activity message.
Per-recipient scoping (share channels): On a share channel, each outgoing activity/event frame is scoped to the receiving guest's share access before it is delivered. A guest receives only the changes their access level permits them to observe — frames they may not see are suppressed, and content detail (file names, node identifiers, enriched data) is collapsed to a bare category or dropped for guests with restricted file visibility. Members and all non-share channels (user / organization / workspace / workflow) are unaffected and receive the full frame. Do not assume a share guest will observe every change on the channel, or that a delivered activity frame will always carry an enriched event companion.
Workflow Channel — invalidation-nudge only
Workflow profiles use the same wss:// endpoint and frame shape, but the workflow runtime events are administrator-level, so the workflow channel ONLY emits activity messages — never enriched event messages. The frame's activity array carries identifiers like details (workflow lifecycle changed) or steps:{step_occurrence_id} (a step occurrence transitioned); the client refetches GET /workflows/{workflow_id}/state/ (or the targeted step endpoint) as authoritative state. WebSocket delivery on the workflow channel is best-effort and not durable — for a transactional, gap-free record of workflow state changes use the audit-event log (GET /workflows/{workflow_id}/audit/events/). The full contract — connection flow, the activity-field set, reconnect behavior, mid-session authorization changes — lives in the Workflow Orchestration reference.
Fallback
If the WebSocket connection drops, fall back to long-polling (GET /current/activity/poll/{profile_id}/). Activity polling returns field names and timestamps. To retrieve full event details after reconnection, use GET /current/events/search/ with a created-min filter.
Workflow profiles do not currently support the activity-poll fallback. The /current/activity/poll/{profile_id}/ endpoint only services User / Organization / Workspace / Share / File Share profiles. For workflow channels, on reconnect refetch GET /workflows/{workflow_id}/state/ (and any scoped step / obligation endpoint the UI was tracking) — that surface is authoritative and is what the realtime channel's nudges tell the client to re-read. For a transactional, gap-free record of workflow state changes, use the audit-event log (GET /workflows/{workflow_id}/audit/events/).
Realtime Auth (Collaborative Rooms)
Separate from WebSocket activity channels, these endpoints provide authentication for collaborative editing rooms.
Generate Realtime Token
/current/realtime/auth/{room_id}
Generate a realtime JWT for a workspace or share collaborative room. Tokens are valid for 24 hours.
Auth: Required (JWT). Subject to global rate limiting; see the rate-limit section in the main reference. No credit consumption.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {room_id} | string | Yes | 19-digit numeric ID of the workspace or share to join |
Example Request
curl -X GET "https://api.fast.io/current/realtime/auth/1234567890123456789" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"expires_in": 86400,
"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Access Requirements
| Profile Type | Permission Required |
|---|---|
| Workspace | At least PERM_VIEW |
| Share | canViewShareDetails + multiplayer enabled |
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | Missing room ID |
1605 (Invalid Input) | 400 | Room ID is not numeric |
1605 (Invalid Input) | 400 | Room ID does not correspond to a workspace or share |
1680 (Access Denied) | 403 | User lacks permissions on the room |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT, or internal JWT generation failure |
Note: Only workspace and share profile types are accepted as room IDs.
Generate Realtime Note Token
/current/realtime/note-auth/{profile_id}/{note_id}
Generate a realtime token for collaborative editing of a single Note. The token is bound to the calling user, the note's workspace, and the note itself, and carries the caller's edit/view standing for the note. Tokens are valid for 900 seconds (15 minutes); refresh before expiry by calling the endpoint again, which re-resolves your current standing on the note.
Auth: Required (JWT). Subject to global rate limiting; see the rate-limit section in the main reference. No credit consumption.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| {profile_id} | string | Yes | 19-digit numeric ID of the workspace the note lives in |
| {note_id} | string | Yes | ID of the Note to edit |
Example Request
curl -X GET "https://api.fast.io/current/realtime/note-auth/{profile_id}/{note_id}" \
-H "Authorization: Bearer {jwt_token}"
Response (200 OK)
{
"result": true,
"expires_in": 900,
"auth_token": "{realtime_note_token}"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| expires_in | integer | Token lifetime in seconds (900 = 15 minutes) |
| auth_token | string | Signed realtime-note token, bound to the user, workspace, and note |
Access Requirements
The token's granted capabilities are frozen at mint time from your current permission on the workspace:
| Workspace Permission | Granted Capability |
|---|---|
| Edit (or higher) | Read and edit the note |
| View | Read the note only |
| Below View | Denied |
Because the capabilities are frozen for the token's lifetime, a permission change made after a token is issued takes effect on the next token refresh (at most ~15 minutes later).
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1605 (Invalid Input) | 400 | Missing or invalid note ID, or the node is not a note |
1609 (Not Found) | 404 | No such note exists, or the note is in the trash |
1680 (Access Denied) | 403 | You lack permission on the workspace |
1650 (Authentication Invalid) | 401 | Missing or invalid JWT, or internal token generation failure |
Validate Realtime Token
/current/realtime/auth/validate/
Validate a realtime JWT and extract the room ID. Intended for backend services to verify tokens.
Auth: Bearer token in Authorization header (the realtime JWT to validate, not a user JWT).
Example Request
curl -X GET "https://api.fast.io/current/realtime/auth/validate/" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Response (200 OK)
{
"result": true,
"room_id": "1234567890123456789"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| room_id | string | The workspace or share profile ID the token is bound to |
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1650 (Authentication Invalid) | 401 | Missing Authorization header |
1605 (Invalid Input) | 400 | Malformed Authorization header |
1605 (Invalid Input) | 400 | Authorization header does not use Bearer scheme |
1605 (Invalid Input) | 400 | Bearer keyword present but no token follows |
1605 (Invalid Input) | 400 | Token is not valid JWT format |
1680 (Access Denied) | 403 | Token signature verification or expiration check failed |
1654 (Internal Error) | 500 | Token payload is malformed or missing required fields |
1605 (Invalid Input) | 400 | Token scope is not realtime |
Notes: Only validates tokens with
realtimescope. WebSocket-scoped tokens are rejected. Validation is performed using the JWT alone.
Validate Realtime Note Token
/current/realtime/note-auth/validate/
Validate a realtime-note token (minted by GET /current/realtime/note-auth/{profile_id}/{note_id}) and read back the note, workspace, and permission it is bound to. Intended for the collaborative-editing backend to confirm a token on connect.
Auth: Bearer token in Authorization header (the realtime-note token to validate, not a user JWT).
Example Request
curl -X GET "https://api.fast.io/current/realtime/note-auth/validate/" \
-H "Authorization: Bearer {realtime_note_token}"
Response (200 OK)
{
"result": true,
"profile": "1234567890123456789",
"node": "n5mno-pqrst-uvwxy-z1234-abcde-fghi",
"perm": "edit"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| result | boolean | true on success |
| profile | string | The workspace profile ID the token is bound to |
| node | string | The Note node ID the token is bound to |
| perm | string | The frozen permission: "edit" (read and edit) or "view" (read only) |
Error Responses
| Error Code | HTTP Status | Description |
|---|---|---|
1650 (Authentication Invalid) | 401 | Missing Authorization header, or the token is invalid, expired, wrong-scope, wrong-audience, or malformed |
↑ Back to topNotes: Only validates tokens with the
realtime-notescope; any other token is rejected. Validation is performed using the token alone — signature, expiry, scope, audience, and the perm/capability binding are all checked.