Public REST API
Automate compliance workflows, sync run data to external systems, and build custom dashboards or AI agents using scoped API keys and a standard REST interface.
Create an API key
Go to Settings → Integrations → API Keys and create a new key. Select only the scopes your integration requires.
Make a request
Include the key in the Authorization: Bearer header. The base URL is https://api.cadenio.com — there is no version prefix.
Handle the response
Responses are JSON with camelCase fields, matching what the Cadenio web app itself sends and receives. Errors include statusCode and error fields to branch on.
Authentication
All API requests must include a valid API key in the Authorization header using the Bearer scheme. Keys are prefixed with sk_live_ and are available to organizations on the Business plan or higher, under Settings → Integrations → API Keys.
Required header
AuthorizationstringrequiredMust be Bearer followed by your sk_live_ API key.
Content-TypestringoptionalRequired for POST and PATCH requests. Set to application/json.
curl https://api.cadenio.com/runs \
-H "Authorization: Bearer sk_live_a1b2c3..." \
-H "Content-Type: application/json"Scopes
Each API key carries a set of scopes that define exactly which operations it can perform, plus a resource mode that further restricts which templates or folders it can touch. Session-based (browser) requests are always permitted regardless of scope — enforcement applies only to API key requests.
| Scope | Description |
|---|---|
runs:read | Read run lists, run details, analytics, and exports |
runs:write | Update run title, task status/due-date/assignee, approvals |
runs:execute | Launch new runs from a template |
templates:read | Read templates, tasks, fields, rules, and versions |
templates:write | Create and edit templates, tasks, fields, rules, and phases |
templates:publish | Publish a template draft as a new version |
files:read | Download files, thumbnails, and check scan status |
files:write | Upload and delete files attached to run tasks |
data-sources:read | Read data sources, columns, rows, and relations |
data-sources:write | Create and update data sources, columns, and rows |
users:read | Read the organization member list |
webhooks:manage | Create, list, update, test, and delete webhook endpoints |
Resource mode
Beyond scopes, every key has a resourceMode: ALL (default, reaches any template/run in the org), SELECTED_TEMPLATES (restricted to a list of templates), or SELECTED_FOLDERS (restricted to every template inside the selected folders). The restriction applies to templates, their drafts, runs, and task execution — a key scoped to one template cannot read or modify others, even if the request otherwise looks valid.
Rate limits
Rate limits are applied per API key, independently of other keys or session users in the same organization. Read requests (GET) get a materially higher quota than write requests (POST/PATCH/DELETE), since listing and polling are far cheaper than mutations.
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 294
X-RateLimit-Reset: 1785005060HTTP/1.1 429 Too Many Requests
Retry-After: 47
{
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests",
"retryAfter": 47
}Error responses
Errors return a standard JSON body: statusCode (matches the HTTP status), error (a short, stable reason phrase such as "Forbidden" or "Not Found"), message (a human-readable string, or an array of strings for validation errors), timestamp, and path. There is no separate machine-readable error code for most errors — branch on statusCode and, where useful, on substrings of message.
| Status | error / message example |
|---|---|
| 400 | Bad RequestFailed input validation, or a business-rule conflict (e.g. completing a run with pending required tasks) |
| 401 | UnauthorizedMissing, malformed, or revoked API key ('Authentication required') |
| 401 | UnauthorizedEndpoint requires a browser session; API keys cannot access it (e.g. /api-keys itself) |
| 402 | Payment RequiredBody includes { code: "FEATURE_LOCKED", capability }. The org's plan does not include this feature |
| 403 | ForbiddenKey is missing the required scope for this action |
| 403 | ForbiddenKey's resource mode does not grant access to this template/folder |
| 404 | Not FoundResource does not exist, was deleted, or is not accessible from this org |
| 429 | Too Many RequestsRate limit exceeded. Check the Retry-After header for the retry delay in seconds |
| 500 | Internal Server ErrorUnexpected server error. Retry with backoff; contact support if it persists |
HTTP/1.1 403 Forbidden
{
"statusCode": 403,
"timestamp": "2026-07-24T16:43:10Z",
"path": "/runs",
"message": "API key missing required scope: runs:read",
"error": "Forbidden"
}Runs
A run is an execution instance of a template. It represents an in-progress or completed process with assigned tasks, deadlines, and a full audit trail. Runs have both a UUID id (used in every URL) and a short, human-friendly publicId used for display.
/runsruns:readReturns a paginated list of runs for the organization, newest first. Use query parameters to filter by status, template, or scheduled date.
Parameters
statusstringoptionalFilter by run status. One of: RUNNING, OVERDUE, COMPLETED, CANCELLED.
templateIdstringoptionalFilter runs launched from a specific template.
scheduledDatestringoptionalFilter by scheduled date (YYYY-MM-DD).
stalledForDaysintegeroptionalOnly active runs (RUNNING/OVERDUE) with no activity for at least this many days.
limitintegeroptionalItems per page. Default and max: 200.
curl -G https://api.cadenio.com/runs \
-H "Authorization: Bearer sk_live_..." \
-d status=RUNNING \
-d limit=20HTTP/1.1 200 OK
{
"data": [
{
"id": "3ed4dcf7-a102-4327-81ab-723b34d8a6b5",
"publicId": "r_3ytXrD6WA7",
"title": "Vendor Onboarding - ACME Corp",
"status": "RUNNING",
"templateId": "6795dfb5-15de-4f41-8a96-b83830526ca6",
"ownerUserId": "2bc947d9-114d-4c7f-9d18-6af9cfa2393c",
"scheduledDateLocal": "2026-07-24",
"createdAt": "2026-07-24T14:22:00Z",
"completedAt": null
}
],
"total": 1,
"hasMore": false
}
// id is the UUID you use in every other endpoint. publicId is a short,
// human-friendly identifier (only runs have one) meant for display in UI/PDFs./runsruns:executeCreates a new run from a published template. The run opens immediately in RUNNING status with all tasks generated from the template's published version. If your key's resourceMode is SELECTED_TEMPLATES or SELECTED_FOLDERS, templateId must be inside its allowed set.
Parameters
templateIdstringrequiredID of the template to launch. The template must be published.
titlestringoptionalCustom display name for this run. Defaults to the template's run-title pattern or the template name.
scheduledDateLocalstringoptionalScheduled date in YYYY-MM-DD format, in the org's timezone. Defaults to today.
ownerEmailstringoptionalEmail of the user to set as run owner. Defaults to the API key's creator.
variablesobjectoptionalKey-value map overriding the template's flow variables for this run.
curl -X POST https://api.cadenio.com/runs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"templateId": "6795dfb5-15de-4f41-8a96-b83830526ca6",
"title": "Vendor Onboarding - ACME Corp"
}'HTTP/1.1 201 Created
{
"id": "3ed4dcf7-a102-4327-81ab-723b34d8a6b5",
"publicId": "r_3ytXrD6WA7",
"title": "Vendor Onboarding - ACME Corp",
"status": "RUNNING",
"templateId": "6795dfb5-15de-4f41-8a96-b83830526ca6",
"templateVersionId": "fbc7dd41-334e-416b-8ddd-acb053aa0dd9",
"ownerUserId": "2bc947d9-114d-4c7f-9d18-6af9cfa2393c",
"createdAt": "2026-07-24T14:22:00Z"
}/runs/tasks/:taskId/statusruns:writeSets a task to PENDING or COMPLETED directly, bypassing form-field collection. For tasks with required fields, prefer the Execution flow below so field values are captured — completing a task this way does not submit any field values.
Parameters
statusstringrequiredNew task status.
PENDINGCOMPLETEDcurl -X PATCH \
https://api.cadenio.com/runs/tasks/22074d71-5767-48cf-ad21-88be0b52911c/status \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "status": "COMPLETED" }'HTTP/1.1 204 No Content/runs/tasks/:taskId/due-dateruns:writeSets or clears the per-task SLA deadline.
Parameters
dueAtdatetime | nullrequiredISO 8601 timestamp for the new deadline, or null to clear it.
dueAtHasTimebooleanoptionalWhether dueAt carries a specific time (true) or is a date-only deadline due at end of day (false).
curl -X PATCH \
https://api.cadenio.com/runs/tasks/22074d71-5767-48cf-ad21-88be0b52911c/due-date \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "dueAt": "2026-08-01T17:00:00Z", "dueAtHasTime": true }'HTTP/1.1 204 No Content/runs/tasks/:taskId/assigneeruns:writeReassigns a task to a different user or group. Pass both fields as null to unassign entirely.
Parameters
assigneeIdstring | nulloptionalUser ID to assign the task to. Pass null to unassign.
assigneeGroupIdstring | nulloptionalGroup ID to assign the task to instead of an individual user.
curl -X PATCH \
https://api.cadenio.com/runs/tasks/22074d71-5767-48cf-ad21-88be0b52911c/assignee \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "assigneeId": "2bc947d9-114d-4c7f-9d18-6af9cfa2393c" }'HTTP/1.1 204 No Content| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /runs/counts | runs:read | Run counts by status |
| GET | /runs/analytics | runs:read | Run analytics summary |
| GET | /runs/analytics/advanced | runs:read | Advanced run analytics |
| POST | /runs/analytics/filtered | runs:read | Analytics with a custom filter body |
| POST | /runs/analytics/advanced/filtered | runs:read | Advanced analytics with a custom filter body |
| GET | /runs/export/csv | runs:read | Export the run list as CSV |
| GET | /runs/analytics/export/pdf | runs:read | Export analytics as PDF |
| GET | /runs/analytics/export/csv | runs:read | Export analytics as CSV |
| POST | /runs/archive | runs:write | Bulk-archive runs by ID |
| GET | /runs/:id | runs:read | Get a run |
| GET | /runs/:id/summaries | runs:read | Get task/field summaries for a run |
| GET | /runs/:id/export/csv | runs:read | Export a single run as CSV |
| GET | /runs/:id/export/pdf | runs:read | Export a single run as PDF |
| GET | /runs/:id/dependencies | runs:read | Task dependency status for a run |
| GET | /runs/:id/activity | runs:read | Activity log for a run |
| GET | /runs/:id/variables | runs:read | Flow variable values for a run |
| PATCH | /runs/:id | runs:write | Rename a run |
| POST | /runs/:id/complete | runs:write | Complete a run (rejects if already terminal) |
| POST | /runs/:id/cancel | runs:write | Cancel a run |
| POST | /runs/:id/reopen | runs:write | Reopen a completed/cancelled run |
| POST | /runs/:id/migrate-to-latest | runs:write | Migrate a run to the template's latest version |
| POST | /runs/tasks/:taskId/approval | runs:write | Approve a task pending approval |
| POST | /runs/tasks/:taskId/approval/reject | runs:write | Reject a task's approval |
| GET | /runs/tasks/:taskId/approval-trail | runs:read | Approval history for a task |
| POST | /runs/tasks/:taskId/force-unblock | runs:write | Force-unblock a task stuck on a dependency |
Execution
This is the primitive to actually fill out a task's form and complete it — what an agentic AI or a custom integration should call to do real work in a run, rather than the coarse status-only PATCH above. The flow is always: open an execution entry for the task, submit one or more field values against it, then complete it.
/execution/entriesruns:writeStarts a fillable execution entry for a task. Most tasks allow only one open entry at a time; repeatable tasks can have several. Get runTaskId from a run's task list (GET /runs/:id).
Parameters
runTaskIdstringrequiredID of the run task to open an execution entry for.
curl -X POST https://api.cadenio.com/execution/entries \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "runTaskId": "22074d71-5767-48cf-ad21-88be0b52911c" }'HTTP/1.1 201 Created
{
"id": "4abc71a1-4c8d-4ac0-ae3d-4333f33ad886",
"runTaskId": "22074d71-5767-48cf-ad21-88be0b52911c",
"createdByUserId": "2bc947d9-114d-4c7f-9d18-6af9cfa2393c",
"createdAt": "2026-07-24T17:28:10Z",
"fieldValues": []
}/execution/field-valuesruns:writeWrites one field's value into an open execution entry. Call once per field, or use the batch variant below for multiple fields at once. Field IDs are stable per published version — fetch them from GET /templates/:id/published-fields.
Parameters
executionEntryIdstringrequiredID of the execution entry returned by POST /execution/entries.
runTaskFieldIdstringrequiredID of the field being filled. Get stable field IDs from GET /templates/:id/published-fields.
valueanyrequiredThe value to submit. Shape depends on the field type (string for text, ISO date for DATE, option key for DROPDOWN, etc.).
curl -X POST https://api.cadenio.com/execution/field-values \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"executionEntryId": "4abc71a1-4c8d-4ac0-ae3d-4333f33ad886",
"runTaskFieldId": "607ebeee-afd1-4834-8c9d-e5019e1373ad",
"value": "42"
}'HTTP/1.1 201 Created
{ "autoFilledFields": [] }
// autoFilledFields lists any other field the platform derived from this
// write (e.g. a lookup field populated from a linked data source row)./execution/entries/completeruns:writeValidates all required fields are filled, then marks the task COMPLETED. Rejects with 400 if a required field is still missing or a required approval is pending.
Parameters
executionEntryIdstringrequiredID of the execution entry to complete. Marks the underlying task COMPLETED.
idempotencyKeystringoptionalClient-generated UUID. Replaying the same key returns the original result instead of completing twice.
curl -X POST https://api.cadenio.com/execution/entries/complete \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "executionEntryId": "4abc71a1-4c8d-4ac0-ae3d-4333f33ad886" }'HTTP/1.1 204 No Content
// Completing the last required, visible task in a run auto-completes the
// run itself — no separate call to POST /runs/:id/complete is needed.| Method | Endpoint | Scope | Description |
|---|---|---|---|
| POST | /execution/field-values/batch | runs:write | Submit multiple field values in one call |
| POST | /execution/entries/reopen | runs:write | Reopen a completed execution entry |
| GET | /execution/tasks/:runTaskId | runs:read | List execution entries for a task (repeatable tasks can have several) |
| GET | /execution/field-values/:fieldValueId/history | runs:read | Get the edit history of a submitted field value |
Templates
Templates are process blueprints: phases, tasks, form fields, conditional logic rules, dependencies, and flow variables. Editing a template only ever touches its unpublished draft — publishing snapshots the draft into a new immutable version, which is what new runs are launched from.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /templates | templates:read | List templates |
| POST | /templates | templates:write | Create a template draft |
| GET | /templates/:id | templates:read | Get a template |
| PUT | /templates/:id | templates:write | Update a template's own settings |
| DELETE | /templates/:id | templates:write | Permanently delete a template. Blocked while RUNNING/OVERDUE runs exist. |
| GET | /templates/:id/runs | templates:read | List runs launched from this template |
| POST | /templates/:id/runs | runs:execute | Launch a run from this template (alias of POST /runs) |
| POST | /templates/:id/duplicate | templates:write | Duplicate a template |
| POST | /templates/:id/archive | templates:write | Archive a template |
| POST | /templates/:id/unarchive | templates:write | Unarchive a template |
| POST | /templates/:id/background-image | templates:write | Upload a background image (multipart/form-data) |
| GET | /templates/:id/published-fields | templates:read | List fields from the published version — the stable IDs to use with /execution/field-values |
| GET | /templates/:id/rules-sync-status | templates:read | Check background rule-sync progress after publishing with active runs |
| POST | /templates/:id/publish | templates:publish | Publish the draft as a new version |
| POST | /templates/:id/discard-draft | templates:write | Discard unpublished draft changes |
| GET | /templates/:id/versions | templates:read | List published versions |
| GET | /templates/:id/versions/:versionId | templates:read | Get a specific version snapshot |
| GET | /templates/:id/versions/draft-diff | templates:read | Diff the current draft against the last published version |
| GET | /templates/:id/versions/:versionId/diff | templates:read | Diff two published versions |
| POST | /templates/:id/versions/:versionId/restore | templates:write | Restore an older version into the draft |
| GET | /templates/:id/tasks | templates:read | List draft tasks |
| POST | /templates/:id/tasks | templates:write | Add a task to the draft |
| PUT | /templates/:id/tasks/:taskId | templates:write | Update a task |
| DELETE | /templates/:id/tasks/:taskId | templates:write | Delete a task |
| POST | /templates/:id/tasks/bulk-delete | templates:write | Delete multiple tasks |
| POST | /templates/:id/tasks/bulk-duplicate | templates:write | Duplicate multiple tasks |
| PATCH | /templates/:id/tasks/bulk-update | templates:write | Bulk-update multiple tasks |
| POST | /templates/:id/tasks/:taskId/fields | templates:write | Add a field to a task |
| PUT | /templates/:id/tasks/:taskId/fields/:fieldId | templates:write | Update a field |
| PATCH | /templates/:id/tasks/:taskId/fields/:fieldId/move | templates:write | Move a field to a different task |
| DELETE | /templates/:id/tasks/:taskId/fields/:fieldId | templates:write | Delete a field |
| POST | /templates/:id/tasks/:taskId/rules | templates:write | Add a conditional logic rule (show/hide/assign/set variable) |
| PUT | /templates/:id/tasks/:taskId/rules/:ruleId | templates:write | Update a logic rule |
| PATCH | /templates/:id/tasks/:taskId/rules/reorder | templates:write | Reorder logic rules |
| DELETE | /templates/:id/tasks/:taskId/rules/:ruleId | templates:write | Delete a logic rule |
| GET | /templates/:id/tasks/:taskId/dependencies | templates:read | List a task's dependencies |
| PUT | /templates/:id/tasks/:taskId/dependencies | templates:write | Set a task's dependencies |
| GET | /templates/:id/tasks/:taskId/dependency-tree | templates:read | Get the full dependency tree for a task |
| GET | /templates/:id/phases | templates:read | List phases |
| POST | /templates/:id/phases | templates:write | Create a phase |
| PUT | /templates/:id/phases/:phaseId | templates:write | Update a phase |
| DELETE | /templates/:id/phases/:phaseId | templates:write | Delete a phase |
| GET | /templates/:id/variables | templates:read | List flow variables |
| POST | /templates/:id/variables | templates:write | Create a flow variable |
| PUT | /templates/:id/variables/:variableId | templates:write | Update a flow variable |
| DELETE | /templates/:id/variables/:variableId | templates:write | Delete a flow variable |
Webhooks
Webhooks deliver real-time event notifications to your system. Every delivery is signed with HMAC-SHA256 using a single org-wide signing secret (not returned by this endpoint — see Settings → Integrations → Webhooks), so you can verify payloads genuinely came from Cadenio.
/webhookswebhooks:manageRegisters a new webhook endpoint. url must be HTTPS — plain HTTP and private/loopback/link-local addresses are rejected outright, and the URL is re-validated on every delivery attempt to close DNS-rebind windows.
Parameters
namestringrequiredDisplay name for this webhook.
urlstringrequiredHTTPS endpoint to deliver event payloads to. Plain HTTP and private/loopback/link-local addresses are rejected.
enabledEventsstring[]requiredEvents this webhook subscribes to.
run.startedrun.completedrun.cancelledrun.reopenedtask.completedtask.overdueapproval.requestedapproval.grantedapproval.rejectedenabledbooleanoptionalWhether the webhook is active. Default: true.
templateModestringoptionalScope deliveries to all flows or a selected subset of templates.
ALL_FLOWSSELECTED_TEMPLATEStemplateIdsstring[]optionalTemplate IDs to scope to, when templateMode is SELECTED_TEMPLATES.
descriptionstringoptionalOptional free-text note for your own reference.
curl -X POST https://api.cadenio.com/webhooks \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Sync to ERP",
"url": "https://your-system.com/hooks/cadenio",
"enabledEvents": ["run.completed", "task.overdue"]
}'POST https://your-system.com/hooks/cadenio
content-type: application/json
x-flow-timestamp: 1785005000000
x-flow-signature: 6f9b1c... (hex HMAC-SHA256)
{
"event": "run.completed",
"deliveryId": "9b1e2c3d-...",
"timestamp": "2026-07-24T16:05:00Z",
"orgId": "0c861a32-d927-47d7-a8f5-861a4adf28ed",
"data": {
"runId": "3ed4dcf7-a102-4327-81ab-723b34d8a6b5",
"templateId": "6795dfb5-15de-4f41-8a96-b83830526ca6"
}
}const crypto = require("crypto");
function isValid(req, secret) {
const timestamp = req.headers["x-flow-timestamp"];
const signature = req.headers["x-flow-signature"];
const body = JSON.stringify(req.body); // raw body, exactly as received
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
// The signing secret is a single org-wide value (WEBHOOK_SIGNING_SECRET),
// shared across all of your org's webhooks — not returned per-webhook by
// this endpoint. Find it under Settings → Integrations → Webhooks.| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /webhooks | webhooks:manage | List webhooks |
| GET | /webhooks/deliveries | webhooks:manage | List recent deliveries across all webhooks |
| GET | /webhooks/:id | webhooks:manage | Get a webhook |
| PATCH | /webhooks/:id | webhooks:manage | Update a webhook (URL is re-validated) |
| DELETE | /webhooks/:id | webhooks:manage | Delete a webhook |
| POST | /webhooks/:id/test | webhooks:manage | Send a test delivery |
| GET | /webhooks/:id/deliveries | webhooks:manage | List deliveries for one webhook |
Files
Upload and download files attached to run tasks. Direct uploads must be tied to a specific FILE_UPLOAD/SIGNATURE field's execution entry; large uploads can instead use a presigned upload-url + confirm flow.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| POST | /files/direct-upload | files:write | Upload a file (multipart/form-data) and attach it to a task's execution entry in one call |
| POST | /files/upload-url | files:write | Get a presigned upload URL for large files (step 1 of 2) |
| POST | /files/confirm | files:write | Confirm a presigned upload finished (step 2 of 2) |
| GET | /files/:id/download | files:read | Get a presigned download URL for a file |
| GET | /files/:id/thumbnail | files:read | Get a thumbnail URL for an image/video attachment |
| GET | /files/:id/scan-status | files:read | Check the antivirus scan status of an upload |
| POST | /files/bulk-download-zip | files:read | Download multiple files as a single ZIP |
| GET | /files | files:read | List files attached to a field/execution entry |
| DELETE | /files/:id | files:write | Delete a file |
| POST | /files/template-asset | files:write | Upload a template-level image asset (e.g. an IMAGE field's picture) |
| GET | /files/template-asset/download-url | files:read | Get a download URL for a template asset |
Data sources
Structured tables used to populate form fields (DATA_SOURCE / lookup fields) and drive conditional logic. Rows are made of typed cells; bulk row operations are atomic — a single invalid row rejects the whole batch.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /data-sources | data-sources:read | List data sources |
| POST | /data-sources | data-sources:write | Create a data source (name + column names) |
| GET | /data-sources/:id | data-sources:read | Get a data source and its columns |
| PATCH | /data-sources/:id | data-sources:write | Update a data source's name/description |
| DELETE | /data-sources/:id | data-sources:write | Delete a data source |
| POST | /data-sources/:id/columns | data-sources:write | Add a column. Types: TEXT, DATE, DATETIME, NUMBER, BOOLEAN, STATUS, RELATION |
| PATCH | /data-sources/:id/columns/:columnId | data-sources:write | Update a column (name, type, or config) |
| DELETE | /data-sources/:id/columns/:columnId | data-sources:write | Delete a column |
| PATCH | /data-sources/:id/columns/reorder | data-sources:write | Reorder columns |
| GET | /data-sources/:id/rows | data-sources:read | List rows (supports search, active-only, and column filters) |
| GET | /data-sources/:id/rows/:rowId | data-sources:read | Get a single row |
| POST | /data-sources/:id/rows | data-sources:write | Create a row |
| POST | /data-sources/:id/rows/bulk | data-sources:write | Bulk-create rows (up to the org's row limit) |
| PATCH | /data-sources/:id/rows/:rowId | data-sources:write | Update a row's cell values |
| POST | /data-sources/:id/rows/bulk-update | data-sources:write | Apply the same cell update to multiple rows atomically |
| DELETE | /data-sources/:id/rows/:rowId | data-sources:write | Delete a row |
| POST | /data-sources/:id/rows/bulk-delete | data-sources:write | Delete multiple rows atomically |
| GET | /data-sources/:id/rows/:rowId/impact | data-sources:read | See where a row is referenced (runs, other rows) |
| GET | /data-sources/:id/rows/:rowId/timeline | data-sources:read | Get a row's change history |
| GET | /data-sources/:id/rows/:rowId/relations | data-sources:read | List RELATION links to/from a row |
| POST | /data-sources/:id/relations | data-sources:write | Link two rows via a RELATION column |
| DELETE | /data-sources/:id/relations | data-sources:write | Remove a link between two rows |
| GET | /data-sources/:id/lookup | data-sources:read | Look up rows for a DATA_SOURCE-type template field |
Data source triggers
Automation triggers that fire when a data source row matches a condition (most commonly a DATE column reaching today) — the backbone of scheduled/recurring automations built on top of a data source.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /data-source-triggers | data-sources:read | List automation triggers |
| POST | /data-source-triggers | data-sources:write | Create a trigger (e.g. fire when a DATE column is reached) |
| GET | /data-source-triggers/:id | data-sources:read | Get a trigger |
| PATCH | /data-source-triggers/:id | data-sources:write | Update a trigger |
| DELETE | /data-source-triggers/:id | data-sources:write | Delete a trigger |
| GET | /data-source-triggers/:id/firings | data-sources:read | List past firings for a trigger |
| POST | /data-source-triggers/:id/dry-run | data-sources:read | Preview which rows would fire right now, without dispatching |
Saved views
Named, reusable run filter sets — the same filters available in the Runs UI, saved server-side so a dashboard or scheduled report can reference them by ID instead of re-encoding the filter logic.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /saved-views | runs:read | List saved views |
| POST | /saved-views | runs:read | Create a saved view (a stored run filter set) |
| GET | /saved-views/:id | runs:read | Get a saved view |
| PATCH | /saved-views/:id | runs:read | Update a saved view |
| DELETE | /saved-views/:id | runs:read | Delete a saved view |
| POST | /saved-views/preview | runs:read | Preview run counts for a filter set without saving it |
| GET | /saved-views/:id/runs | runs:read | List the runs matching a saved view |
Cross-organization template sharing via a public token: publish a share link, let another org preview and import your template as their own independent copy.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| POST | /templates/:templateId/shares | templates:write | Create a shareable link/token for a template |
| GET | /templates/:templateId/shares | templates:read | List shares for a template |
| PATCH | /shared-templates/:shareId | templates:write | Update a share |
| POST | /shared-templates/:shareId/refresh | templates:write | Rotate a share's token |
| DELETE | /shared-templates/:shareId | templates:write | Revoke a share |
| GET | /shared-templates/:token/preview | templates:read | Preview a shared template by its public token |
| POST | /shared-templates/:token/import | templates:write | Import a shared template into your org as a new template |
Portal
Customer-facing portal builder: pages made of content blocks (including live report widgets), access rules per user/group, and a published public view served at a slug.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /portals | templates:read | List portals |
| POST | /portals | templates:write | Create a portal |
| GET | /portals/me | templates:read | Get the portal(s) the caller can access |
| GET | /portals/:portalId | templates:read | Get a portal |
| PATCH | /portals/:portalId | templates:write | Update a portal |
| DELETE | /portals/:portalId | templates:write | Delete a portal |
| POST | /portals/:portalId/publish | templates:write | Publish a portal |
| POST | /portals/:portalId/unpublish | templates:write | Unpublish a portal |
| GET | /portals/by-slug/:slug/view | templates:read | Get a published portal's content by its public slug |
| GET | /portals/:portalId/pages | templates:read | List a portal's pages |
| POST | /portals/:portalId/pages | templates:write | Create a page |
| GET | /portals/:portalId/pages/:pageId | templates:read | Get a page |
| PATCH | /portals/:portalId/pages/:pageId | templates:write | Update a page |
| DELETE | /portals/:portalId/pages/:pageId | templates:write | Delete a page |
| PUT | /portals/:portalId/pages/:pageId/blocks | templates:write | Replace a page's content blocks |
| POST | /portals/:portalId/pages/:pageId/publish-changes | templates:write | Publish a single page's pending changes |
| GET | /portals/:portalId/access-rules | templates:read | List access rules |
| POST | /portals/:portalId/access-rules | templates:write | Grant a user/group access to the portal |
| DELETE | /portals/:portalId/access-rules/:ruleId | templates:write | Revoke an access rule |
| GET | /portals/report-presets | templates:read | List saved report presets |
| POST | /portals/report-presets | templates:write | Save a report preset |
| DELETE | /portals/report-presets/:presetId | templates:write | Delete a report preset |
Users
Read the organization member list. Use member IDs to assign runs and tasks via the Runs API.
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /users | users:read | List organization members |
API key management
API keys are created and revoked from Settings → Integrations → API Keys. Each key has a name, a set of scopes, an optional expiry date, and a resource mode (all templates/folders, or a selected subset). Only organization owners and privileged admins can manage keys. The full key value is shown only once, at creation.
Endpoints
/api-keysList active API keys/api-keysCreate a new API key/api-keys/:idRevoke an API keyCreate parameters
namestringrequiredDisplay name for this key.
scopesstring[]requiredPermission scopes granted to this key. See the Scopes reference.
resourceModestringoptionalWhich templates/folders this key can reach. Default: ALL.
ALLSELECTED_TEMPLATESSELECTED_FOLDERSscopedTemplateIdsstring[]optionalTemplate IDs accessible to this key when resourceMode is SELECTED_TEMPLATES.
scopedFolderIdsstring[]optionalFolder IDs accessible to this key (and every template inside them) when resourceMode is SELECTED_FOLDERS.
expiresAtdatetimeoptionalISO 8601 timestamp after which the key is automatically rejected. Default: never expires.
curl -X POST https://api.cadenio.com/api-keys \
-H "Cookie: flow_session=...; flow_csrf=..." \
-H "x-cadenio-csrf: ..." \
-H "Content-Type: application/json" \
-d '{
"name": "ERP Sync Integration",
"scopes": ["runs:read", "runs:execute"],
"resourceMode": "ALL"
}'HTTP/1.1 201 Created
{
"id": "1105c74c-bc73-4d7c-b9b0-c88ca1824a5f",
"name": "ERP Sync Integration",
"keyPrefix": "sk_live_...93f7",
"scopes": ["runs:read", "runs:execute"],
"resourceMode": "ALL",
"scopedTemplateIds": [],
"scopedFolderIds": [],
"status": "ACTIVE",
"expiresAt": null,
"createdAt": "2026-07-24T16:41:11Z",
"plainKey": "sk_live_beda794d400a159f4214c69965412267bacfb9eafc8893f7"
}
// plainKey is shown only in this response, store it securely.API keys, scoped permissions, webhooks, and programmatic access to runs, templates, and data sources are available on the Business and Enterprise plans. Talk to us to enable it for your organization.