REST API reference
Every endpoint of the Cheqq REST API, with the scope it needs, its parameters, errors and paging.
The basics
- Base URL:
https://cheqq.ai/api/platform/v1 - Authentication:
Authorization: Bearer cqk_…with an API key, or an access token from a connected app. - Requests:
GETandDELETEtake query parameters;POST,PUTandPATCHtake a JSON body (Content-Type: application/json). Ids in the path always win over the same name in the body. - Responses: JSON. Creating something answers
201, starting an App publish answers202, everything else200. - Who it acts as: you, in the key's workspace, with your role in each Wapp. Writes appear in each Wapp's history with "(API)" at the end, and can be undone there. An archived Wapp can be read but not changed.
Every operation here is also an MCP tool; its name is under each table.
Errors
Every error has the same shape:
{
"error": {
"code": "INSUFFICIENT_SCOPE",
"message": "This key isn't allowed to add and change records. Create a key with the \"records:write\" scope.",
"details": { "requiredScope": "records:write" }
}
}message is written to be shown to a person. details is null or an object
with more to go on.
| Status | Codes you'll see | What to do |
|---|---|---|
| 400 | VALIDATION_ERROR, INVALID_JSON, INVALID_FIELD, NOTHING_TO_CHANGE | Fix the request. VALIDATION_ERROR lists each problem in details, with details.issues naming where each one is (operations.0.font); INVALID_FIELD lists the fields you could have meant. |
| 401 | UNAUTHORIZED, INVALID_TOKEN | Send a valid key. |
| 403 | INSUFFICIENT_SCOPE, FORBIDDEN, WORKSPACE_ACCESS_LOST, ACCOUNT_SUSPENDED, NOT_YOUR_DECISION | The key, or you, may not do this. |
| 404 | NOT_FOUND and specific ones such as APP_NOT_FOUND | It doesn't exist in this workspace, or you can't see it. |
| 409 | DESTRUCTIVE_SCHEMA_CHANGE, DOCUMENT_VERSION_CONFLICT, WORKFLOW_CHANGED, WORKFLOW_DRAFT_CONFLICT, APP_ACCESS_WIDENING_UNCONFIRMED, AMBIGUOUS_WAPP | Something changed or needs confirming; the message says what. |
| 413 | FILE_TOO_LARGE, FILES_TOO_LARGE, ARTIFACT_FILE_TOO_LARGE | Send less at once. A document's HTML files are 2 MB each at most; move styles, scripts or data into their own files. |
| 422 | REQUEST_REJECTED | Cheqq understood the request but couldn't do it; the message says why. |
| 429 | RATE_LIMITED | Wait the Retry-After seconds, then retry. See Rate limits. |
A 401 carries a WWW-Authenticate header, and a 403 INSUFFICIENT_SCOPE
names the missing scope in it as well.
Paging
Lists that can be long page in one of two ways, and say so in their answer:
- Records and runs return
nextCursor. Pass it back ascursorto get the next page;nullmeans there are no more. - Documents take
page(from 1) andpageSize, and returntotal.
Rate-limit headers
Every answer after authentication carries:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997See Rate limits.
You
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /me | any | The key's workspace, your role, its scopes and its requests per minute. |
MCP: cheqq_whoami.
Wapps
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /wapps | structure:read | The Wapps installed in the workspace that you can open, most recently used first, with each one's install id, slug and your role. |
| GET | /wapps/{idOrSlug} | structure:read | One Wapp, by install id, Wapp id or slug, with its collections. |
| POST | /wapps | structure:write | Create an empty Wapp: name, and optionally description, icon. If you can already edit a Wapp of that name, you get it back with alreadyExisted: true; send allowDuplicate: true for a second one. |
| DELETE | /wapps/{idOrSlug} | structure:write | Delete a Wapp you made, in two steps (see below). |
A Wapp is named everywhere by its install id, its Wapp id or its slug (such
as content-studio). If two Wapps in the workspace share a slug, use the
install id.
Deleting a Wapp. The first DELETE deletes nothing: it answers
needsConfirmation: true with what goes with it (its records, collections
and automations, and how many other people lose it). Check with the person,
then send it again with { "confirmed": true }. The Wapp moves to Trash and
can be restored for 30 days with its records, automations and inbox
addresses; its Apps are deleted for good. If automations of yours outside the
Wapp still use it, the answer is 409 WAPP_DELETE_BLOCKED naming them in
details.workflows: send trashWorkflowIds with their ids to move them to
Trash with it.
MCP: cheqq_list_wapps, cheqq_get_wapp, cheqq_create_wapp,
cheqq_delete_wapp.
Collections and fields
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /collections?wapp= | structure:read | Collections with their fields, in one Wapp or in every Wapp. |
| POST | /collections | structure:write | Create a collection: wapp, name, slug, fields. |
| GET | /collections/{collectionId} | structure:read | One collection and every field in schemaDef. |
| PATCH | /collections/{collectionId} | structure:write | Rename it or change its slug: name, slug. |
| DELETE | /collections/{collectionId} | structure:write | Move it and its records to the Wapp's Trash. |
| POST | /collections/{collectionId}/fields | structure:write | Add a field: name, type, and what the type needs. |
| PATCH | /collections/{collectionId}/fields/{fieldKey} | structure:write | Change a field's settings: field, confirmDestructive. |
| DELETE | /collections/{collectionId}/fields/{fieldKey} | structure:write | Remove a field and its values. Needs ?confirmDestructive=true. |
Fields. A field's slug is its key: record values, filters and sorts use
it, and renaming the field never changes it. Where a path takes {fieldKey},
the field's label works too if only one field has it.
Field types: text, long_text, number, duration, checkbox,
date, url, email, select, multi-select, json, relation, file,
user, lookup, rollup, formula. Select fields take options (labels);
a relation takes targetCollectionSlug and mode (single or multiple);
a lookup takes relationFieldSlug and targetFieldSlug; rollups and
formulas take a formula.
Changes that lose data (retyping a field, making it required, removing
it) answer 409 DESTRUCTIVE_SCHEMA_CHANGE until you send
confirmDestructive: true. Every one can be undone from the Wapp's history.
curl -X POST https://cheqq.ai/api/platform/v1/collections/COLLECTION_ID/fields \
-H "Authorization: Bearer $CHEQQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Channel", "type": "select", "options": ["Blog", "LinkedIn", "Newsletter"] }'MCP: cheqq_list_collections, cheqq_create_collection,
cheqq_get_collection, cheqq_update_collection, cheqq_delete_collection,
cheqq_add_field, cheqq_update_field, cheqq_remove_field.
Views
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /collections/{collectionId}/views | structure:read | A collection's saved views, in order, with their filters, sorts, grouping and visible fields. |
| POST | /collections/{collectionId}/views | structure:write | Add a view for everyone: name, viewType (table, board, calendar, gallery, list…), config. |
| PATCH | /collections/{collectionId}/views/{viewId} | structure:write | Change a view's name, type, config, default flag or position. |
| DELETE | /collections/{collectionId}/views/{viewId} | structure:write | Delete a view. Its records are untouched; a collection keeps at least one view. |
config replaces the whole config, so read the view, change what you need
and send it all back. A locked view refuses changes to its name, type and
config unless you're an admin of the Wapp. MCP: cheqq_list_views,
cheqq_create_view, cheqq_update_view, cheqq_delete_view.
Dashboards
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /dashboards?wapp= | structure:read | Dashboards and their tiles, in one Wapp or every Wapp. Query: dashboardId for just one, detail=summary for each tile's id, kind and title only. |
| POST | /dashboards | structure:write | Add a dashboard to a Wapp: wapp, name, and optionally config.tiles. |
| PATCH | /dashboards/{dashboardId} | structure:write | Rename or move it, or replace its whole config. |
| PATCH | /dashboards/{dashboardId}/config | structure:write | Change some tiles and keep the rest: upsertTiles, removeTileIds. |
| DELETE | /dashboards/{dashboardId} | structure:write | Delete a dashboard. Its records are untouched. |
Each tile has a uuid id, a grid layout (x, y, w, h) and content
of kind chart, table or timeline. A tile's source is all of a collection's
records ({ "mode": "all" }), a saved view's ({ "mode": "view", "viewId" })
or a filter's ({ "mode": "filter", "filter" }, in the
filter language records use). Tiles are checked before
they're saved: a tile over a collection of another Wapp, or a filter on a
field the collection doesn't have, answers 422 naming the tile and the
field keys there are. Read an existing dashboard to copy the shape. MCP: cheqq_list_dashboards, cheqq_create_dashboard,
cheqq_update_dashboard, cheqq_update_dashboard_tiles,
cheqq_delete_dashboard.
Records
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /collections/{collectionId}/records | records:read | A page of records, newest first. Query: filter (a filter group as JSON, see below), sortBy (createdAt or data.<field key>), sortOrder (asc, desc), cursor, limit (up to 200, default 50). |
| GET | /collections/{collectionId}/records/{recordId} | records:read | One record. |
| POST | /collections/{collectionId}/records/count | records:read | How many records the collection has, or with filter how many match. |
| POST | /collections/{collectionId}/records/aggregate | records:read | Sums, averages, counts per option and more, without reading every record: widgets. |
| POST | /collections/{collectionId}/records | records:write | Add a record: data. |
| PATCH | /collections/{collectionId}/records/{recordId} | records:write | Change some fields of a record: data. Fields you leave out keep their values. |
| POST | /collections/{collectionId}/records/batch-create | records:write | Add up to 200 records: records (each its field values). All are created or none is. |
| POST | /collections/{collectionId}/records/batch-update | records:write | Set the same values on up to 200 records: recordIds, data. |
| DELETE | /collections/{collectionId}/records/{recordId} | records:delete | Move a record to the Wapp's Trash. |
| POST | /collections/{collectionId}/records/batch-delete | records:delete | Move up to 200 records to the Trash: recordIds. |
Writing values. data names fields by key or by label. A select takes
the option's label. A name no field answers to is refused with
400 INVALID_FIELD, listing the fields you could have meant. Automations that
run on new or changed records run for API writes as they do for yours.
Reading values. data is keyed by field key. A select value reads as
{ "id": "…", "label": "Live" } and a multi-select as a list of them, so you
can show the label and send either one back.
Filtering records
Listing, counting and dashboard tiles take one filter language, the one
saved views use: a group of rules joined by and (the default) or or,
where a rule can itself be a group.
{
"glue": "and",
"rules": [
{ "field": "status", "filter": "contains", "includes": ["Live"] },
{ "field": "amount", "filter": "greater", "value": 100 },
{ "glue": "or", "rules": [
{ "field": "title", "filter": "contains", "value": "launch" },
{ "field": "owner", "filter": "isEmpty" }
] }
]
}Rules name fields by key. Text takes contains, notContains, equal,
notEqual, beginsWith and endsWith; numbers and dates equal,
notEqual, greater, greaterOrEqual, less and lessOrEqual; any field
isEmpty and isNotEmpty. Select, relation and person fields use
contains or notContains with includes: option labels or ids, record ids
or member ids. A rule on a field the collection doesn't have answers 422
with the field keys it does have. On a GET, send the group as JSON in
?filter=. The older equality shorthand filter.<field key>=value still
works, but not together with filter.
Summaries. Each widget is
{ "id": "<a uuid you choose>", "aggregation": { "type": "sum", "sourceFieldId": "amount" } }.
Types: count, sum, avg, min, max, median, empty, unique,
earliest, latest, option-counts, group-by. Results come back keyed by
your widget id.
MCP: cheqq_list_records, cheqq_get_record, cheqq_count_records,
cheqq_aggregate_records, cheqq_create_record, cheqq_update_record,
cheqq_create_records, cheqq_update_records, cheqq_delete_record,
cheqq_delete_records.
Automations
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /workflows?wapp= | workflows:read | Your automations, most recently changed first: whether each is on, and how many steps and triggers it has. |
| GET | /workflows/{workflowId} | workflows:read | One automation: every step and trigger, and the values each trigger passes on. |
| PUT | /workflows/{workflowId}/definition | workflows:write | Replace its whole definition: definition, and optionally triggers, name, description, expectedUpdatedAt. |
| DELETE | /workflows/{workflowId} | workflows:write | Move it to the Trash. Its triggers stop. |
| GET | /workflow-actions | workflows:read | The actions a step can be built from: connected apps, saved API endpoints, and your Wapps' record actions. Query: q, wapp, source, limit. |
There's no endpoint to create an automation from scratch yet: build new ones
over MCP, or in Cheqq. See Automations.
MCP: cheqq_list_workflows, cheqq_get_workflow, cheqq_replace_workflow,
cheqq_delete_workflow, cheqq_list_workflow_actions.
Runs
| Method | Path | Scope | What it does |
|---|---|---|---|
| POST | /workflows/{workflowId}/runs | workflows:run | Start a run: mode (execute, test, dry-run), input, wait, timeoutMs (up to 60000). |
| GET | /workflows/{workflowId}/runs | workflows:read | An automation's runs, newest first. Query: status (active or failed), cursor, limit (up to 100, default 20). |
| GET | /runs/{runId} | workflows:read | One run: every step's output and errors, and, if it waits at an approval, who it asks and whether you may answer. Query: detail=summary leaves step outputs out and gives each one's size; step=<nodeId> returns one step. |
| POST | /runs/{runId}/cancel | workflows:run | Stop a run. What it already did stays done. |
| POST | /runs/{runId}/respond | workflows:approve | Answer a waiting run: approved, and optionally stepId, resumeData, stopAsking. |
MCP: cheqq_run_workflow, cheqq_list_runs, cheqq_get_run,
cheqq_stop_run, cheqq_respond_to_run.
Documents
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /documents | documents:read | Documents in the workspace, most recently opened first. Query: q, kind, scope (mine, shared, all), sort (viewed, updated, title), page, pageSize (up to 100, default 30). |
| GET | /documents/{documentId} | documents:read | A document, its currentVersionId and, for pages, documents, decks and designs, the text of its files. editor: "blocks" means it's written in blocks: use the block endpoints below. Query: versionId, content=false. |
| GET | /documents/{documentId}/files?path= | documents:read | One file whole, for a file that didn't come with the document (too large, or an image or font, which reads as base64). Query: path, versionId. |
| POST | /documents | documents:write | Create a document: format (page, document, deck, design), title, files (path, content, and encoding: "base64" for an image or font), summary. For a document written in blocks, send markdown and/or outline instead of files, and a page (font, width, pageSize, orientation, margins, pageNumbers) to start it with page settings of its own. |
| PATCH | /documents/{documentId} | documents:write | Save an edit as a new version: baseVersionId, summary, and files, deletePaths or title. |
| POST | /documents/{documentId}/patch | documents:write | Small edits without resending files: baseVersionId, summary, operations, path. |
| GET | /documents/{documentId}/blocks | documents:read | Read a document written in blocks; the outline includes its page settings. Query: mode (outline, blocks, section, tab, search, changes), blockIds (comma-separated), headingId, tabId, query, sinceRevision, cursor. |
| POST | /documents/{documentId}/blocks | documents:write | Change a document written in blocks: operations, summary, and baseRevision or a hash on each operation. The operations also add, rename, move, copy and delete its tabs, setPage changes its look, width, paper, orientation, margins and page numbers, colorWords colours words, and the table operations change a table's rows, columns, cell colours and widths in place. A stale one is 409 DOCUMENT_BLOCK_STALE. |
| POST | /documents/{documentId}/exports | documents:read | Make a file from a document: format (pdf or docx for a document, pptx or pptx-editable for a deck, png or jpg for a design), and tabId for one tab of a document written in blocks. A pending answer is asked again with its exportId. With documents:write, a document people are typing in is saved as a version first; with only documents:read, the file is of the last saved version. |
| GET | /documents/{documentId}/exports/{exportId} | documents:read | The finished file, from the downloadUrl a ready export gave you. |
| GET | /documents/{documentId}/versions | documents:read | Its version history, newest first. |
| POST | /documents/{documentId}/restore | documents:write | Bring back an earlier version as a new one: baseVersionId, restoreVersionId. |
| DELETE | /documents/{documentId} | documents:delete | Move a document you own to Trash, where you can restore it in Cheqq for 30 days. A published one's link stops working. |
See Documents and Apps for how versions
keep two people's edits apart. MCP: cheqq_list_documents,
cheqq_get_document, cheqq_read_document_file, cheqq_create_document,
cheqq_update_document, cheqq_patch_document,
cheqq_read_document_blocks, cheqq_edit_document_blocks,
cheqq_export_document, cheqq_list_document_versions, cheqq_restore_document_version,
cheqq_delete_document.
Apps
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /apps | apps:read | The Apps you made in the workspace: audience, whether they're live, their addresses and their App Builder link. |
| GET | /apps/{appId} | apps:read | One App: its versions, its newest deploy, and the data it may use. |
| GET | /apps/{appId}/deployments/{deploymentId} | apps:read | How a publish is going: building, deployed or failed. |
| GET | /apps/{appId}/files | apps:read | Every file in the App's source. |
| GET | /apps/{appId}/files/content?path= | apps:read | One file, or with offset and length a part of it, up to 1 MB at a time: content, its encoding (utf8 for text, base64 for an image or other binary file), the file's size in bytes, and nextOffset to read on from (null at the end). |
| PUT | /apps/{appId}/files | apps:write | Create or replace up to 50 files (2 MB in all): files (path, content, and encoding: "base64" for a binary file), label. Returns the checkpoint taken first. |
| DELETE | /apps/{appId}/files/content?path= | apps:write | Delete one file. Query: path, label. |
| POST | /apps/{appId}/dependencies | apps:write | Add or remove npm packages: add (name to version), remove. |
| GET | /apps/{appId}/checkpoints | apps:read | Snapshots of the source, newest first. |
| POST | /apps/{appId}/checkpoints/restore | apps:write | Put the source back as it was at a checkpoint: hash. |
| POST | /apps/{appId}/check | apps:write | Typecheck and build the draft without publishing. |
| POST | /apps/{appId}/verify | apps:write | Open the draft in a browser and report errors, what rendered and screenshots: path, viewport, steps. |
| POST | /apps/{appId}/publish | apps:publish | Start publishing the draft. Answers 202 with a deploymentId. |
| POST | /apps/{appId}/unpublish | apps:publish | Take the App offline. Everything is kept. |
| POST | /apps/{appId}/rollback | apps:publish | Put an earlier deployed version back live: versionNumber. |
Source files you can write are under src/, public/ and index.html; the
rest of the project is managed by Cheqq. See
Documents and Apps. MCP:
cheqq_list_apps, cheqq_get_app, cheqq_get_app_deployment,
cheqq_list_app_files, cheqq_read_app_file, cheqq_write_app_files,
cheqq_delete_app_file, cheqq_update_app_dependencies,
cheqq_list_app_checkpoints, cheqq_restore_app_checkpoint,
cheqq_check_app, cheqq_verify_app, cheqq_publish_app,
cheqq_unpublish_app, cheqq_rollback_app.