Getting Started
Team Data API
Manage team data collections for pages with Team App storage. Includes CRUD operations and team file management.
Collection names must start with a lowercase letter and contain only lowercase letters, numbers, and underscores (regex: `^[a-z][a-z0-9_]*$`, max 100 characters). Examples: tasks, user_scores. Names starting with underscores or containing uppercase letters will return a 400 error.
Endpoints
/api/pages/:id/team-data
List all collections
/api/pages/:id/team-data/:collection
List records in a collection
/api/pages/:id/team-data/:collection/count
Count records (with optional groupBy)
/api/pages/:id/team-data/:collection
Create a new record
/api/pages/:id/team-data/:collection/:recordId
Get a single record
/api/pages/:id/team-data/:collection/:recordId
Update a record
/api/pages/:id/team-data/:collection/:recordId
Delete a record
Team File Endpoints
For file uploads and downloads within a team. Use these instead of the Page Assets API — team files support role-based permissions (member+ can upload, creator or admin+ can delete). In client-side code, use TeamData.uploadFile() etc. instead of calling these directly.
/api/pages/:id/team-files
Upload a file (member+)
/api/pages/:id/team-files
List files (viewer+)
/api/pages/:id/team-files/:fileId?metadata=true
Get file metadata (viewer+)
/api/pages/:id/team-files/:fileId
Download a file (viewer+)
/api/pages/:id/team-files/:fileId
Delete a file (creator or admin+)
GET /api/pages/:id/team-data
List all collections available for a page. Requires team-data:read scope. Use this to discover what collections exist before querying them.
Request
curl -H "Authorization: Bearer vm_your_token_here" \ https://visimade.com/api/pages/123/team-data
Response
{
"collections": [
{
"name": "tasks",
"recordCount": 18,
"lastUpdated": "2024-01-15T10:30:00Z"
},
{
"name": "stages",
"recordCount": 8,
"lastUpdated": "2024-01-14T15:20:00Z"
}
]
}GET /api/pages/:id/team-data/:collection
List records in a team data collection. Requires team-data:read scope.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
where | JSON string | Filter by data fields, e.g., {"status":"active"} |
orderBy | string | Sort field: created_at or updated_at |
order | string | asc or desc (default) |
limit | number | Max records to return (default 50, max 100) |
offset | number | Number of records to skip for pagination |
mine | boolean | Only return records created by the authenticated user |
before | number | Return records with ID less than this value (cursor pagination) |
after | number | Return records with ID greater than this value (cursor pagination) |
Example
curl -H "Authorization: Bearer vm_your_token_here" \ "https://visimade.com/api/pages/123/team-data/tasks?where=%7B%22status%22%3A%22active%22%7D&limit=10"
Response
{
"records": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"collection": "tasks",
"data": { "title": "Complete project", "status": "active", "priority": "high" },
"createdBy": { "id": 42, "username": "johndoe" },
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"total": 25, "limit": 10, "offset": 0, "hasMore": true
}Cursor-Based Pagination
For real-time collections like chat messages, use before and after instead of offset. Offset-based pagination can skip or duplicate records when new data is inserted. Cursors anchor to a specific record ID, so results are always consistent.
# Get the 20 most recent messages curl -H "Authorization: Bearer ..." \ "https://visimade.com/api/pages/123/team-data/messages?limit=20" # Load older messages (use the smallest ID from previous results) curl -H "Authorization: Bearer ..." \ "https://visimade.com/api/pages/123/team-data/messages?limit=20&before=456" # Poll for new messages (use the largest ID you already have) curl -H "Authorization: Bearer ..." \ "https://visimade.com/api/pages/123/team-data/messages?after=500&order=asc"
The response includes hasMore: true/false to indicate if more records exist beyond the current page. When using cursors, offset is ignored.
GET /api/pages/:id/team-data/:collection/count
Count records in a collection, optionally grouped by a data field. Requires team-data:read scope. Use this instead of fetching all records when you only need counts (e.g., reply counts, vote tallies).
Query Parameters
| Parameter | Type | Description |
|---|---|---|
where | JSON string | Filter by data fields, e.g., {"status":"active"} |
mine | boolean | Only count records created by the authenticated user |
groupBy | string | Group counts by this data field name |
values | string | Comma-separated list of values to limit groupBy results (max 1000) |
Simple Count
curl -H "Authorization: Bearer vm_your_token_here" \
"https://visimade.com/api/pages/123/team-data/tasks/count?where=%7B%22status%22%3A%22active%22%7D"
// Response:
{ "count": 42 }Grouped Count (countBy)
Get counts grouped by a data field — perfect for reply counts, vote tallies, category stats, etc. This replaces N separate API calls with a single request.
// Get reply counts for all messages in one request
curl -H "Authorization: Bearer vm_your_token_here" \
"https://visimade.com/api/pages/123/team-data/replies/count?groupBy=parentId"
// Response:
{ "counts": { "msg-1": 5, "msg-2": 12, "msg-3": 0 } }
// Limit to specific parent IDs
curl -H "Authorization: Bearer vm_your_token_here" \
"https://visimade.com/api/pages/123/team-data/replies/count?groupBy=parentId&values=msg-1,msg-2"POST /api/pages/:id/team-data/:collection
Create a new record in a collection. Requires team-data:write scope.
Request Body
{
"data": { "title": "New task", "status": "pending", "priority": "medium" }
}Example
curl -X POST \
-H "Authorization: Bearer vm_your_token_here" \
-H "Content-Type: application/json" \
-d '{"data": {"title": "New task", "status": "pending"}}' \
https://visimade.com/api/pages/123/team-data/tasksResponse
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"collection": "tasks",
"data": { "title": "New task", "status": "pending" },
"createdBy": { "id": 42, "username": "johndoe" },
"createdAt": "2024-01-15T11:00:00Z",
"updatedAt": "2024-01-15T11:00:00Z"
}PATCH /api/pages/:id/team-data/:collection/:recordId
Update an existing record. Data is merged with existing values. Requires team-data:write scope. You can only update records you created, unless you are a team admin.
Example
curl -X PATCH \
-H "Authorization: Bearer vm_your_token_here" \
-H "Content-Type: application/json" \
-d '{"data": {"status": "completed"}}' \
https://visimade.com/api/pages/123/team-data/tasks/550e8400-e29b-41d4-a716-446655440000DELETE /api/pages/:id/team-data/:collection/:recordId
Delete a record. Requires team-data:write scope. You can only delete records you created, unless you are a team admin.
curl -X DELETE \ -H "Authorization: Bearer vm_your_token_here" \ https://visimade.com/api/pages/123/team-data/tasks/550e8400-e29b-41d4-a716-446655440000
Batch Operations
Execute up to 100 create, update, and delete operations in a single request. The entire batch runs in one database transaction (all-or-nothing) and counts as a single rate limit hit.
/api/pages/:id/team-data/:collection/batch
Execute batch operations (member+ for creates, owner/admin for others' records)
Request Body
{
"operations": [
{ "op": "create", "data": { "title": "New item" } },
{ "op": "update", "id": "uuid-1", "data": { "order": 1 } },
{ "op": "update", "id": "uuid-2", "data": { "order": 2 } },
{ "op": "delete", "id": "uuid-3" }
]
}Response
{
"results": [
{ "op": "create", "success": true, "id": "uuid-new", "data": { "title": "New item" } },
{ "op": "update", "success": true, "id": "uuid-1" },
{ "op": "update", "success": true, "id": "uuid-2" },
{ "op": "delete", "success": true, "id": "uuid-3" }
]
}Update = Shallow Merge (same as PATCH)
The update operation merges the provided data with the existing record's data. Only the fields you include are overwritten — fields you omit are preserved. For example, if a record has {"title": "Hello", "order": 3} and you send{"data": {"order": 1}}, the result is {"title": "Hello", "order": 1}. However, if you send a field with null, it will be set to null. This is a shallow merge — nested objects are fully replaced, not deep-merged.
Rules: Maximum 100 operations per batch. All operations run atomically — if any operation fails (e.g., record not found, permission denied), the entire batch is rolled back. Schema validation is applied to each create/update. Requires team-data:write scope.
Example (curl)
curl -X POST \\
-H "Authorization: Bearer vm_your_token_here" \\
-H "Content-Type: application/json" \\
-d '{"operations": [
{"op": "update", "id": "uuid-1", "data": {"order": 0}},
{"op": "update", "id": "uuid-2", "data": {"order": 1}},
{"op": "update", "id": "uuid-3", "data": {"order": 2}}
]}' \\
https://visimade.com/api/pages/933/team-data/items/batchOn this page
- Endpoints
- Team File Endpoints
- GET - List Collections
- GET - List Records
- GET - Count Records
- POST - Create Record
- PATCH - Update Record
- DELETE - Delete Record
- Batch Operations