> Part of the Fast.io API Reference. Overview: https://api.fast.io/current/llms/ # Events, Activity & Realtime Base URL: `https://api.fast.io/current/` Auth: All endpoints require `Authorization: Bearer {jwt_token}` unless noted. Response format: JSON (standard envelope with `result`, `status`, and data fields). --- ## 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. --- ### `GET /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 | Constraints | Description | |-----------|------|----------|---------|-------------|-------------| | `user_id` | string | Conditional | - | 19-digit numeric ID | 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 | - | 19-digit numeric ID | Filter by organization profile ID | | `workspace_id` | string | Conditional | - | 19-digit numeric ID | Filter by workspace profile ID | | `share_id` | string | Conditional | - | 19-digit numeric ID | Filter by share profile ID | | `parent_event_id` | string | Conditional | - | Alphanumeric OpaqueId | Filter by parent event ID for serial/batch events. Cannot combine with filters other than `acknowledged`, `limit`, `offset`. | | `event` | string | No | - | Max 100 characters | Filter by specific event name (e.g., `workspace_storage_file_added`) | | `category` | string | No | - | See Event Categories | Filter by event category | | `subcategory` | string | No | - | See Event Subcategories | Filter by event subcategory | | `calling_user_id` | string | No | - | 19-digit numeric ID | Filter by the user who triggered the event | | `object_id` | string | No | - | Alphanumeric OpaqueId | Filter by related object ID (file, folder, etc.) | | `acknowledged` | string | No | - | `"true"` or `"false"` | Filter by acknowledgment status | | `visibility` | string | No | All non-internal | `"external_audit_log"` or `"external"` | Filter by event visibility level | | `created-min` | string | No | - | Accepts ISO 8601 (e.g., `2025-12-01T06:00:00Z`) or `YYYY-MM-DD HH:MM:SS` format | Lower bound for event creation time | | `created-max` | string | No | - | Same format as `created-min`; must be > `created-min` | Upper bound for event creation time | | `limit` | integer | No | `100` | 1-250 | Maximum number of results | | `offset` | integer | No | `0` | 0+ | Number of results to skip for pagination | | `output` | string | No | - | Comma-separated tokens (e.g. `terse`, `standard`, `full`) | Select the response shape. See "Compact Responses" below for the three detail levels and which event fields appear in each. | **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. **curl Example:** ```bash 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):** ```json { "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 ("Event profile was missing.") | | `1605 (Invalid Input)` | 400 | `created-min` is greater than `created-max` | | `1605 (Invalid Input)` | 400 | `parent_event_id` combined with disallowed filters | | `1605 (Invalid Input)` | 400 | Invalid datetime format for `created-min` or `created-max` | | `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. --- ### `GET /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 | Constraints | Description | |-----------|------|----------|---------|-------------|-------------| | `user_context` | string | No | `""` | Max 64 chars; letters, numbers, spaces, `. , ! ? ' -` only | Focus guidance for the AI summary (e.g., `"Focus on uploads"`) | All other parameters are identical to `GET /current/events/search/`. **curl Example:** ```bash 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):** ```json { "result": true, "summary": { "text": "@[user:9876543210987654321:Jane Smith] uploaded 12 files to the project folder, including quarterly reports and design assets. @[user:5555555555555555555:John Doe] added 3 new members to the workspace.", "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 or 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]` | **Error Responses:** All errors from `/events/search/` apply. Summary generation failures are non-fatal: `summary` is `null` but events are still returned. **Notes:** - Requires a billable organization for AI token billing (resolved from profile context). - AI token consumption is billed to the associated organization. --- ### `GET /current/event/{event_id}/details/` Get full details for a single event. **Auth:** Required (JWT). Default rate limiting. **Path Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `{event_id}` | string | Yes | Alphanumeric OpaqueId of the event | **curl Example:** ```bash curl -X GET "https://api.fast.io/current/event/abc123xyz789def456ghi789jkl01/details/" \ -H "Authorization: Bearer {jwt_token}" ``` **Response (200 OK):** ```json { "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 } } ``` **Response Fields:** | Field | Type | Description | |-------|------|-------------| | `result` | boolean | `true` on success | | `event` | object | Full event object (same fields as event search results) | **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) | --- ### `POST /current/event/{event_id}/ack/` Acknowledge (mark as read) an event for the current user. Idempotent: acknowledging an already-acknowledged event succeeds silently. **Auth:** Required (JWT). Default rate limiting. **Path Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `{event_id}` | string | Yes | Alphanumeric OpaqueId of the event to acknowledge | **curl Example:** ```bash curl -X POST "https://api.fast.io/current/event/abc123xyz789def456ghi789jkl01/ack/" \ -H "Authorization: Bearer {jwt_token}" ``` **Response (200 OK):** ```json { "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 | **Notes:** - 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 (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 in `llms.txt` 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` | 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, worklogs, approvals, todos) | --- ## 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 uploaded - `workspace_storage_file_deleted` -- File trashed - `workspace_storage_file_moved` -- File moved - `workspace_storage_file_copied` -- File copied - `workspace_storage_file_updated` -- File metadata updated - `workspace_storage_file_restored` -- File restored from trash - `workspace_storage_file_version_restored` -- File version restored - `workspace_storage_folder_created` -- Folder created - `workspace_storage_folder_deleted` -- Folder trashed - `workspace_storage_folder_moved` -- Folder moved - `workspace_storage_download_token_created` -- Download token issued - `workspace_storage_zip_downloaded` -- ZIP download completed - `workspace_storage_link_added` -- Link added ### Share Storage - `share_storage_file_added` -- File uploaded - `share_storage_file_deleted` -- File trashed - `share_storage_file_moved` -- File moved - `share_storage_file_copied` -- File copied - `share_storage_file_updated` -- File metadata updated - `share_storage_file_restored` -- File restored - `share_storage_folder_created` -- Folder created - `share_storage_folder_deleted` -- Folder trashed - `share_storage_folder_moved` -- Folder moved - `share_storage_download_token_created` -- Download token issued - `share_storage_zip_downloaded` -- ZIP download completed ### Comments - `comment_created` -- Comment created - `comment_updated` -- Comment updated - `comment_deleted` -- Comment deleted - `comment_mentioned` -- User mentioned in comment (targeted permission) - `comment_replied` -- Reply to a comment - `comment_reaction` -- Reaction added ### Membership - `added_member_to_org` / `removed_member_from_org` -- Org membership - `added_member_to_workspace` / `removed_member_from_workspace` -- Workspace membership - `added_member_to_share` / `removed_member_from_share` -- Share membership - `membership_updated` -- Permission changes ### Workspace Lifecycle - `workspace_created` / `workspace_updated` / `workspace_deleted` - `workspace_archived` / `workspace_unarchived` ### Share Lifecycle - `share_created` / `share_updated` / `share_deleted` - `share_archived` / `share_unarchived` - `share_imported_to_workspace` -- Share imported into workspace ### AI - `ai_chat_created` / `ai_chat_updated` / `ai_chat_deleted` -- Chat lifecycle - `ai_chat_new_message` -- New AI chat message - `ai_chat_published` -- Chat published - `node_ai_summary_created` -- AI summary generated for a file - `workspace_ai_share_created` -- AI share created in workspace ### Metadata - `metadata_kv_update` / `metadata_kv_delete` / `metadata_kv_extract` - `metadata_template_update` / `metadata_template_delete` / `metadata_template_select` - `metadata_view_update` / `metadata_view_delete` ### Quick Shares - `workspace_quickshare_created` / `workspace_quickshare_updated` / `workspace_quickshare_deleted` - `workspace_quickshare_file_downloaded` / `workspace_quickshare_file_previewed` ### Invitations - `invitation_email_sent` / `invitation_accepted` / `invitation_declined` ### User - `user_created` / `user_updated` / `user_deleted` - `user_email_reset` / `user_asset_updated` ### Organization - `org_created` / `org_updated` / `org_closed` - `org_transfer_token_created` / `org_transfer_completed` ### Billing - `subscription_created` — fires when a new subscription is initiated - `subscription_cancel_scheduled` — fires when a customer schedules cancellation; the subscription remains active until `cancel_at` - `subscription_cancelled` — fires when the subscription is actually terminated by the payment provider (at `cancel_at`) - `billing_free_trial_ended` ### Workflow - `task_list_created` / `task_list_updated` / `task_list_deleted` - `task_created` / `task_updated` / `task_deleted` - `task_status_changed` / `task_assigned` / `task_completed` - `worklog_entry_created` - `worklog_interjection_created` / `worklog_interjection_acknowledged` - `approval_requested` / `approval_approved` / `approval_rejected` - `todo_created` / `todo_toggled` / `todo_deleted` / `todo_updated` --- ## 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. --- ### `GET /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. **Query Parameters:** | Parameter | Type | Required | Default | Constraints | Description | |-----------|------|----------|---------|-------------|-------------| | `wait` | integer | No | `0` | 0-95 | Long-poll timeout in seconds. Server holds connection open until update or timeout. | | `lastactivity` | string | No | Current time | Micro-precision datetime (e.g., `2025-01-20 10:30:45.123456 UTC`) | Only return activity newer than this timestamp | | `updated` | any | No | - | Any value = enabled | If present, only return activity fields updated since `lastactivity` | | `fields` | string | No | All fields | Comma-delimited; max 30 fields | Activity field names to check. Supports ID qualifier via colon (e.g., `storage:12345`). | **curl Example:** ```bash 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):** ```json { "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):** ```json { "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 | --- ### `GET /current/activity/poll/{profile_id}/` Poll for activity updates on a specific workspace, share, or org. **Auth:** Required (JWT). Same rate limits and parameters as `GET /current/activity/poll/`. **Path Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `{profile_id}` | string | Yes | 19-digit numeric profile ID (org, workspace, or 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 (multiplayer status is automatically determined based on share configuration -- not directly togglable via API) | **curl Example:** ```bash 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 `GET /current/activity/poll/`. --- ### Polling Workflow 1. Make initial poll request (no `lastactivity` parameter) 2. Receive response with `activity` fields and `lastactivity` timestamp 3. Process changes by fetching updated resources based on activity field names 4. Make next poll with `lastactivity` from previous response 5. Repeat -- server returns immediately on change, or after `wait` seconds 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_id` since 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. --- ### `GET /current/websocket/auth/{profile_id}` Generate a WebSocket authentication JWT for a specific profile. Tokens are valid for 24 hours. **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, or share to subscribe to | **curl Example:** ```bash curl -X GET "https://api.fast.io/current/websocket/auth/1234567890123456789" \ -H "Authorization: Bearer {jwt_token}" ``` **Response (200 OK):** ```json { "result": true, "expires_in": 86400, "auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` **Response Fields:** | Field | Type | Description | |-------|------|-------------| | `result` | boolean | `true` on success | | `expires_in` | integer | Token lifetime in seconds (86400 = 24 hours) | | `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` | **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/?token={auth_token}` Where `{auth_token}` is the JWT returned from the auth endpoint above. ### WebSocket 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: ```json { "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: ```json { "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:** `result` (boolean, always true), `response` (always `"event"`), `time` (server send time, `YYYY-MM-DD HH:MM:SS.ffffff UTC`, e.g. `"2026-03-22 14:30:45.123456 UTC"`), `timestamp` (event trigger time as microtime float string, e.g. `"1711123456.1234"`), `event` (event name), `category`, `sub_category`, `object_id` (affected object OpaqueId), `calling_user` (actor's 19-digit ID), `activity_field` (corresponding activity field name), `data` (event-specific details, shape varies by event type). **Backwards compatible:** `activity` messages are always sent. `event` messages are supplementary. Existing clients need no changes. Payload kept under ~4KB. **Permission gating:** Enriched `event` messages are only sent for member-level events. Admin and targeted events receive only the `activity` message. ### WebSocket 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. --- ## Realtime Auth (Collaborative Rooms) Separate from WebSocket activity channels, these endpoints provide authentication for collaborative editing rooms. --- ### `GET /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 | **curl Example:** ```bash curl -X GET "https://api.fast.io/current/realtime/auth/1234567890123456789" \ -H "Authorization: Bearer {jwt_token}" ``` **Response (200 OK):** ```json { "result": true, "expires_in": 86400, "auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` **Response Fields:** | Field | Type | Description | |-------|------|-------------| | `result` | boolean | `true` on success | | `expires_in` | integer | Token lifetime in seconds (86400 = 24 hours) | | `auth_token` | string | Signed JWT with `realtime` scope, bound to the requested room | **Access Requirements:** | Profile Type | Permission Required | |--------------|-------------------| | Workspace | At least `PERM_VIEW` | | Share | `canViewShareDetails` + multiplayer enabled (multiplayer status is automatically determined based on share configuration -- not directly togglable via API) | **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 | **Notes:** - Only workspace and share profile types are accepted as room IDs. --- ### `GET /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). **curl Example:** ```bash curl -X GET "https://api.fast.io/current/realtime/auth/validate/" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` **Response (200 OK):** ```json { "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 `realtime` scope. WebSocket-scoped tokens are rejected. - Validation is performed using the JWT alone.