API Reference¶
Audience: Developers · Tags:
api,reference
SnapLink is an early-access, lightweight integration-automation (iPaaS) platform. This is the complete reference for its REST API: Trigger → Mapping/Logic → Action flows, connectors, executions, and the AI-assisted Snap Studio flow builder.
Base URL: https://api.snaplink.cloudsolutionaccelerators.com/api/v1 for every endpoint below, except GET /health and GET /health/ready, which live at the service root with no /api/v1 prefix and no authentication.
Headers on every authenticated request:
Authorization: Bearer <token>
Content-Type: application/json
A token is issued by POST /auth/signup or POST /auth/login (see Auth). There is no separate API-key mechanism — the bearer token is the only credential the API accepts.
The envelope — read this before you write a client¶
Every SnapLink response body has a top-level data field on success. Most endpoint groups also wrap it with ok: true. Two groups do not.
| Groups | Success shape |
|---|---|
/auth, /workspaces, /flows, /drafts, /connectors, /connections, /executions, /runs, /monitoring, /webhooks, /health, /health/ready |
{ "ok": true, "data": { ... } } |
/marketplace, /flow-designer (including every /flow-designer/studio/* route) |
{ "data": { ... } } — no ok key at all |
This is a real, current quirk of the API, not a typo in this document. /marketplace and /flow-designer predate the ok convention being applied consistently, and no ok: true was retrofitted onto their success responses.
Practical rule for every client you write: don't branch on response.ok (the JSON field) to decide whether a call succeeded — it won't be there on roughly a third of the API. Branch on the HTTP status code (2xx = success), then always read the payload from data. On any non-2xx status, the body is uniformly { "ok": false, "error": { "code", "message", "details"? } } regardless of which group the endpoint belongs to — error responses are consistent across the entire API even where success responses aren't.
// Success — /flows (has ok)
{ "ok": true, "data": { "flows": [] } }
// Success — /marketplace (no ok)
{ "data": { "connectors": [] } }
// Error — identical shape everywhere, always has ok:false
{ "ok": false, "error": { "code": "FLOW_NOT_FOUND", "message": "Flow not found." } }
Endpoint map¶
Tables below list every endpoint. Curl examples for the most-used ones follow each table. Snap Studio's five endpoints (/flow-designer/studio/*) are summarized here and covered in full depth, with worked examples, in Studio API. Webhook ingress (POST /webhooks/:flowId/:secret) is summarized here and covered in full depth in Webhooks.
Health (unversioned, no auth)¶
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Liveness probe |
| GET | /health/ready |
Readiness probe (checks the database when running on Postgres) |
curl https://api.snaplink.cloudsolutionaccelerators.com/health
{ "ok": true, "data": { "status": "ok", "service": "snaplink-backend", "version": "0.1.0", "uptimeSeconds": 41823, "timestamp": "2026-07-02T14:03:11.000Z" } }
curl https://api.snaplink.cloudsolutionaccelerators.com/health/ready
{ "ok": true, "data": { "ready": true, "driver": "postgres", "database": "ok" } }
503 with { "ok": false, "error": { "code": "NOT_READY", "message": "Database is not reachable." } }. In memory driver mode (no database configured) it always returns { "ready": true, "driver": "memory", "database": "not-applicable" }.
Auth¶
| Method | Path | Purpose |
|---|---|---|
| POST | /auth/signup |
Create an account, returns a bearer token |
| POST | /auth/login |
Log in, returns a bearer token |
| GET | /auth/session |
Current user + workspace memberships (Bearer required) |
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","password":"correct-horse-battery"}'
{ "ok": true, "data": { "token": "$TOKEN", "user": { "id": "usr_8c1f0a", "email": "jane@example.com" } } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","password":"correct-horse-battery"}'
{ "ok": true, "data": { "token": "$TOKEN", "user": { "id": "usr_8c1f0a", "email": "jane@example.com" } } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/auth/session -H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"user": { "id": "usr_8c1f0a", "email": "jane@example.com" },
"workspaces": [
{ "workspace": { "id": "ws_51ac9d", "name": "Jane's Team" }, "role": "owner" }
]
}
}
Signup fails 400 INVALID_EMAIL if the email has no @, 400 WEAK_PASSWORD if the password is under 8 characters, and 409 EMAIL_TAKEN if the account already exists. Login fails 401 INVALID_CREDENTIALS on any mismatch (no distinction between "no such user" and "wrong password").
Workspaces¶
Bearer required for every route below.
| Method | Path | Purpose |
|---|---|---|
| GET | /workspaces |
Workspaces the caller belongs to |
| POST | /workspaces |
Create a workspace (caller becomes owner) |
| GET | /workspaces/:id |
One workspace + caller's role |
| GET | /workspaces/:id/members |
List members |
| POST | /workspaces/:id/members |
Add a member (owner/admin only) |
| DELETE | /workspaces/:id/members/:userId |
Remove a member (owner/admin only) |
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Jane'"'"'s Team"}'
{ "ok": true, "data": { "workspace": { "id": "ws_51ac9d", "name": "Jane's Team", "ownerId": "usr_8c1f0a", "createdAt": "2026-07-02T14:00:00.000Z" }, "role": "owner" } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "workspaces": [ { "workspace": { "id": "ws_51ac9d", "name": "Jane's Team", "ownerId": "usr_8c1f0a", "createdAt": "2026-07-02T14:00:00.000Z" }, "role": "owner" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces/ws_51ac9d -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "workspace": { "id": "ws_51ac9d", "name": "Jane's Team", "ownerId": "usr_8c1f0a", "createdAt": "2026-07-02T14:00:00.000Z" }, "role": "owner" } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces/ws_51ac9d/members -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "members": [ { "id": "mem_1a2b3c", "workspaceId": "ws_51ac9d", "userId": "usr_8c1f0a", "role": "owner", "createdAt": "2026-07-02T14:00:00.000Z" } ] } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces/ws_51ac9d/members \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"userId":"usr_44d1c8","role":"member"}'
{ "ok": true, "data": { "id": "mem_7e0b2f", "workspaceId": "ws_51ac9d", "userId": "usr_44d1c8", "role": "member", "createdAt": "2026-07-02T14:05:00.000Z" } }
curl -X DELETE https://api.snaplink.cloudsolutionaccelerators.com/api/v1/workspaces/ws_51ac9d/members/usr_44d1c8 \
-H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "removed": true } }
Adding or removing a member as a caller whose own role is member returns 403 FORBIDDEN. Any operation on a workspace the caller does not belong to — including one that doesn't exist — returns 404 WORKSPACE_NOT_FOUND, never 403 (no existence leak).
Flows & drafts¶
Bearer required; every route is workspace-scoped.
| Method | Path | Purpose |
|---|---|---|
| GET | /flows?workspaceId=&includeArchived= |
List flows |
| POST | /flows |
Create a flow |
| GET | /flows/:id |
Flow detail |
| GET | /flows/:id/versions |
List a flow's published versions |
| POST | /flows/:id/drafts |
Create a draft (definition) |
| GET | /flows/:id/webhook |
Get-or-create the flow's webhook endpoint |
| POST | /flows/:id/webhook/rotate |
Rotate the webhook secret |
| POST | /flows/:id/archive |
Archive a flow |
| PUT | /drafts/:id |
Update a draft's definition |
| POST | /drafts/:id/promote |
Promote a draft to a new active version |
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"workspaceId":"ws_51ac9d","name":"Lead alert","description":"Notify sales on new lead"}'
{
"ok": true,
"data": {
"id": "flow_51ac9d", "workspaceId": "ws_51ac9d", "name": "Lead alert",
"description": "Notify sales on new lead", "status": "draft",
"activeVersionId": null, "createdBy": "usr_8c1f0a",
"createdAt": "2026-07-02T14:10:00.000Z", "updatedAt": "2026-07-02T14:10:00.000Z", "archivedAt": null
}
}
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows?workspaceId=ws_51ac9d&includeArchived=false" \
-H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "flows": [ { "id": "flow_51ac9d", "workspaceId": "ws_51ac9d", "name": "Lead alert", "status": "active", "activeVersionId": "flowver_9d2a1b", "description": "Notify sales on new lead", "createdBy": "usr_8c1f0a", "createdAt": "2026-07-02T14:10:00.000Z", "updatedAt": "2026-07-02T14:12:00.000Z", "archivedAt": null } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "flow_51ac9d", "workspaceId": "ws_51ac9d", "name": "Lead alert", "status": "active", "activeVersionId": "flowver_9d2a1b", "description": "Notify sales on new lead", "createdBy": "usr_8c1f0a", "createdAt": "2026-07-02T14:10:00.000Z", "updatedAt": "2026-07-02T14:12:00.000Z", "archivedAt": null } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d/versions -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "versions": [ { "id": "flowver_9d2a1b", "flowId": "flow_51ac9d", "versionNumber": 1, "definition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [] }, "checksum": "a1b2c3...", "createdBy": { "kind": "user", "id": "usr_8c1f0a" }, "createdAt": "2026-07-02T14:12:00.000Z" } ] } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d/drafts \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"definition":{"trigger":{"key":"trigger","connectorKey":"webhook","triggerType":"webhook"},"actions":[{"key":"notify","connectorKey":"slack","actionType":"send_message","input":{"channel":"C0000000","text":"New lead!"}}]}}'
{ "ok": true, "data": { "id": "draft_7e0b2f", "flowId": "flow_51ac9d", "workspaceId": "ws_51ac9d", "definition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [ { "key": "notify", "connectorKey": "slack", "actionType": "send_message", "input": { "channel": "C0000000", "text": "New lead!" } } ] }, "source": "human", "status": "proposed", "createdBy": { "kind": "user", "id": "usr_8c1f0a" }, "createdAt": "2026-07-02T14:13:00.000Z", "updatedAt": "2026-07-02T14:13:00.000Z" } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d/webhook -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "flowId": "flow_51ac9d", "secret": "9f3a...48hex...c2", "path": "/api/v1/webhooks/flow_51ac9d/9f3a...48hex...c2" } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d/webhook/rotate \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"graceSeconds":3600}'
{ "ok": true, "data": { "flowId": "flow_51ac9d", "secret": "b7e1...48hex...09", "secretVersion": 2, "path": "/api/v1/webhooks/flow_51ac9d/b7e1...48hex...09", "previousSecretExpiresAt": "2026-07-02T15:13:00.000Z" } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flows/flow_51ac9d/archive -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "flow_51ac9d", "workspaceId": "ws_51ac9d", "name": "Lead alert", "status": "archived", "activeVersionId": "flowver_9d2a1b", "description": "Notify sales on new lead", "createdBy": "usr_8c1f0a", "createdAt": "2026-07-02T14:10:00.000Z", "updatedAt": "2026-07-02T15:20:00.000Z", "archivedAt": "2026-07-02T15:20:00.000Z" } }
curl -X PUT https://api.snaplink.cloudsolutionaccelerators.com/api/v1/drafts/draft_7e0b2f \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"definition":{"trigger":{"key":"trigger","connectorKey":"webhook","triggerType":"webhook"},"actions":[{"key":"notify","connectorKey":"slack","actionType":"send_message","input":{"channel":"C0000000","text":"New lead — updated copy"}}]}}'
{ "ok": true, "data": { "id": "draft_7e0b2f", "flowId": "flow_51ac9d", "status": "proposed", "definition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [ { "key": "notify", "connectorKey": "slack", "actionType": "send_message", "input": { "channel": "C0000000", "text": "New lead — updated copy" } } ] }, "workspaceId": "ws_51ac9d", "source": "human", "createdBy": { "kind": "user", "id": "usr_8c1f0a" }, "createdAt": "2026-07-02T14:13:00.000Z", "updatedAt": "2026-07-02T14:20:00.000Z" } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/drafts/draft_7e0b2f/promote -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "flow": { "id": "flow_51ac9d", "status": "active", "activeVersionId": "flowver_2b7c40", "workspaceId": "ws_51ac9d", "name": "Lead alert", "description": "Notify sales on new lead", "createdBy": "usr_8c1f0a", "createdAt": "2026-07-02T14:10:00.000Z", "updatedAt": "2026-07-02T14:21:00.000Z", "archivedAt": null }, "version": { "id": "flowver_2b7c40", "flowId": "flow_51ac9d", "versionNumber": 2, "definition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [] }, "checksum": "d4e5f6...", "createdBy": { "kind": "user", "id": "usr_8c1f0a" }, "createdAt": "2026-07-02T14:21:00.000Z" } } }
Connectors & connections¶
Bearer required. The connector registry (/connectors) is global; connections (/connections) are workspace-scoped and never echo credential values back.
| Method | Path | Purpose |
|---|---|---|
| GET | /connectors |
List registered connector definitions |
| GET | /connectors/:key |
One connector definition |
| GET | /connectors/:key/versions |
Version history of a connector definition |
| GET | /connections?workspaceId= |
List connections in a workspace |
| POST | /connections |
Create a connection (optionally attach a credential) |
| GET | /connections/:id |
One connection |
| PUT | /connections/:id |
Rename a connection |
| DELETE | /connections/:id |
Remove a connection |
| POST | /connections/:id/validate |
Actively re-check connection health |
| GET | /connections/:id/health |
Last known connection health |
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connectors -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "connectors": [ { "id": "condef_1", "key": "slack", "version": "1.0.0", "displayName": "Slack", "authType": "oauth", "status": "active", "manifest": { "key": "slack", "version": "1.0.0", "displayName": "Slack", "category": "communication", "authType": "oauth", "capabilities": ["send_message"], "triggers": [], "actions": [] }, "createdAt": "2026-06-01T00:00:00.000Z", "updatedAt": "2026-06-01T00:00:00.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connectors/slack -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "condef_1", "key": "slack", "version": "1.0.0", "displayName": "Slack", "authType": "oauth", "status": "active", "manifest": { "key": "slack", "version": "1.0.0", "displayName": "Slack", "category": "communication", "authType": "oauth", "capabilities": ["send_message"], "triggers": [], "actions": [] }, "createdAt": "2026-06-01T00:00:00.000Z", "updatedAt": "2026-06-01T00:00:00.000Z" } }
:key that no connector defines returns 404 CONNECTOR_NOT_FOUND.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connectors/slack/versions -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "versions": [ { "id": "condef_1", "key": "slack", "version": "1.0.0", "displayName": "Slack", "authType": "oauth", "status": "active", "manifest": { "...": "..." }, "createdAt": "2026-06-01T00:00:00.000Z", "updatedAt": "2026-06-01T00:00:00.000Z" } ] } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"workspaceId":"ws_51ac9d","connectorDefinitionId":"condef_1","name":"#sales-alerts","credential":{"credentialType":"oauth_access","secret":"xoxb-REDACTED"}}'
{ "ok": true, "data": { "id": "conn_3a90ee", "workspaceId": "ws_51ac9d", "connectorDefinitionId": "condef_1", "name": "#sales-alerts", "status": "active", "credentialRef": "cred_ref_9f21", "createdAt": "2026-07-02T14:30:00.000Z", "updatedAt": "2026-07-02T14:30:00.000Z" } }
credentialRef is a non-secret pointer — the secret value you sent is never returned by any endpoint.
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "connections": [ { "id": "conn_3a90ee", "workspaceId": "ws_51ac9d", "connectorDefinitionId": "condef_1", "name": "#sales-alerts", "status": "active", "credentialRef": "cred_ref_9f21", "createdAt": "2026-07-02T14:30:00.000Z", "updatedAt": "2026-07-02T14:30:00.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections/conn_3a90ee -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "conn_3a90ee", "workspaceId": "ws_51ac9d", "connectorDefinitionId": "condef_1", "name": "#sales-alerts", "status": "active", "credentialRef": "cred_ref_9f21", "createdAt": "2026-07-02T14:30:00.000Z", "updatedAt": "2026-07-02T14:30:00.000Z" } }
curl -X PUT https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections/conn_3a90ee \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"#sales-alerts-renamed"}'
{ "ok": true, "data": { "id": "conn_3a90ee", "name": "#sales-alerts-renamed", "workspaceId": "ws_51ac9d", "connectorDefinitionId": "condef_1", "status": "active", "credentialRef": "cred_ref_9f21", "createdAt": "2026-07-02T14:30:00.000Z", "updatedAt": "2026-07-02T14:35:00.000Z" } }
curl -X DELETE https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections/conn_3a90ee -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "removed": true } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections/conn_3a90ee/validate -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "health_1", "connectionId": "conn_3a90ee", "status": "healthy", "lastCheckAt": "2026-07-02T14:36:00.000Z", "lastSuccessAt": "2026-07-02T14:36:00.000Z", "lastFailureAt": null, "failureReason": null } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/connections/conn_3a90ee/health -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "health_1", "connectionId": "conn_3a90ee", "status": "healthy", "lastCheckAt": "2026-07-02T14:36:00.000Z", "lastSuccessAt": "2026-07-02T14:36:00.000Z", "lastFailureAt": null, "failureReason": null } }
Executions¶
Bearer required. Creates and drives a single run of a flow immediately (inline, synchronous with respect to the HTTP call).
| Method | Path | Purpose |
|---|---|---|
| POST | /executions |
Run a flow now |
| GET | /executions?workspaceId= |
List runs in a workspace |
| GET | /executions/:id |
Run + steps + retries |
| GET | /executions/:id/events |
Run's event log |
| GET | /executions/:id/audit |
Run's audit log |
| POST | /executions/:id/cancel |
Cancel a run |
| POST | /executions/:id/retry |
Re-run as a new run |
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"flowId":"flow_51ac9d","triggerType":"manual"}'
{ "ok": true, "data": { "id": "run_44d1c8", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "status": "succeeded", "triggerType": "manual", "attempts": 1, "startedAt": "2026-07-02T14:40:00.000Z", "completedAt": "2026-07-02T14:40:01.000Z", "failureReason": null, "createdAt": "2026-07-02T14:40:00.000Z" } }
triggerType defaults to manual when omitted; it accepts manual, webhook, schedule, or test.
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "runs": [ { "id": "run_44d1c8", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "status": "succeeded", "triggerType": "manual", "attempts": 1, "startedAt": "2026-07-02T14:40:00.000Z", "completedAt": "2026-07-02T14:40:01.000Z", "failureReason": null, "createdAt": "2026-07-02T14:40:00.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions/run_44d1c8 -H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"run": { "id": "run_44d1c8", "status": "succeeded", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "triggerType": "manual", "attempts": 1, "startedAt": "2026-07-02T14:40:00.000Z", "completedAt": "2026-07-02T14:40:01.000Z", "failureReason": null, "createdAt": "2026-07-02T14:40:00.000Z" },
"steps": [ { "id": "step_1", "executionRunId": "run_44d1c8", "stepNumber": 1, "stepType": "action", "connectorKey": "slack", "actionType": "send_message", "status": "succeeded", "attempt": 1, "startedAt": "2026-07-02T14:40:00.400Z", "completedAt": "2026-07-02T14:40:00.900Z", "errorCode": null, "failureReason": null } ],
"retries": []
}
}
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions/run_44d1c8/events -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "events": [ { "id": "evt_1", "executionRunId": "run_44d1c8", "workspaceId": "ws_51ac9d", "eventType": "run.started", "payload": {}, "createdAt": "2026-07-02T14:40:00.000Z" }, { "id": "evt_2", "executionRunId": "run_44d1c8", "workspaceId": "ws_51ac9d", "eventType": "run.succeeded", "payload": {}, "createdAt": "2026-07-02T14:40:01.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions/run_44d1c8/audit -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "audit": [ { "id": "aud_1", "executionRunId": "run_44d1c8", "workspaceId": "ws_51ac9d", "auditType": "run.created", "details": { "triggerType": "manual" }, "createdAt": "2026-07-02T14:40:00.000Z" } ] } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions/run_44d1c8/cancel -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "run_44d1c8", "status": "cancelled", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "triggerType": "manual", "attempts": 1, "startedAt": "2026-07-02T14:40:00.000Z", "completedAt": "2026-07-02T14:40:02.000Z", "failureReason": null, "createdAt": "2026-07-02T14:40:00.000Z" } }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/executions/run_44d1c8/retry -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "id": "run_9a02f1", "status": "succeeded", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "triggerType": "manual", "attempts": 1, "startedAt": "2026-07-02T14:45:00.000Z", "completedAt": "2026-07-02T14:45:01.000Z", "failureReason": null, "createdAt": "2026-07-02T14:45:00.000Z" } }
run_9a02f1 above, distinct from run_44d1c8) — it never mutates the original.
Runs (read-only history)¶
Bearer required. /runs is the paginated, filterable read model over the same underlying data /executions writes; use it for history views and dashboards.
| Method | Path | Purpose |
|---|---|---|
| GET | /runs?workspaceId=&flowId=&status=&from=&to=&connector=&errorCode=&limit=&offset= |
Paginated, filtered run history |
| GET | /runs/:id |
Run detail (run + steps + retries + REST/webhook invocations) |
| GET | /runs/:id/timeline |
Reconstructed chronological timeline |
| GET | /runs/:id/events |
Run's event log |
| GET | /runs/:id/audit |
Run's audit log |
| GET | /runs/:id/retries |
Run's retry attempts |
See Pagination and Filtering below for the query parameters. Full worked example:
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs?workspaceId=ws_51ac9d&status=failed&limit=20&offset=0" \
-H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"items": [
{
"runId": "run_2f88ab", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowName": "Lead alert",
"status": "failed", "triggerType": "webhook",
"startedAt": "2026-07-02T13:10:00.000Z", "completedAt": "2026-07-02T13:10:02.000Z",
"durationMs": 2000, "retryCount": 1, "stepCount": 1, "createdAt": "2026-07-02T13:10:00.000Z"
}
],
"total": 1,
"limit": 20,
"offset": 0
}
}
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs/run_2f88ab -H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"run": { "id": "run_2f88ab", "status": "failed", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowVersionId": "flowver_2b7c40", "triggerType": "webhook", "attempts": 2, "startedAt": "2026-07-02T13:10:00.000Z", "completedAt": "2026-07-02T13:10:02.000Z", "failureReason": "slack.send_message: auth", "createdAt": "2026-07-02T13:10:00.000Z" },
"steps": [ { "id": "step_9", "executionRunId": "run_2f88ab", "stepNumber": 1, "stepType": "action", "connectorKey": "slack", "actionType": "send_message", "status": "failed", "attempt": 2, "startedAt": "2026-07-02T13:10:01.500Z", "completedAt": "2026-07-02T13:10:02.000Z", "errorCode": "auth", "failureReason": "Invalid or expired token" } ],
"retries": [ { "id": "retry_1", "executionRunId": "run_2f88ab", "executionStepId": "step_9", "attemptNumber": 2, "strategy": "exponential", "notBefore": "2026-07-02T13:10:01.000Z", "startedAt": "2026-07-02T13:10:01.500Z", "completedAt": "2026-07-02T13:10:02.000Z", "status": "failed" } ],
"restInvocations": [],
"webhookInvocations": [ { "id": "wh_1", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "endpointId": "endpoint_1", "method": "POST", "contentType": "application/json", "requestSizeBytes": 214, "status": "accepted", "rejectionReason": null, "executionRunId": "run_2f88ab", "createdAt": "2026-07-02T13:10:00.000Z" } ]
}
}
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs/run_2f88ab/timeline -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "timeline": [ { "at": "2026-07-02T13:10:00.000Z", "kind": "event", "type": "run.started", "label": "Run started", "detail": {} }, { "at": "2026-07-02T13:10:02.000Z", "kind": "step", "type": "step.failed", "label": "slack.send_message failed", "detail": { "errorCode": "auth" } } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs/run_2f88ab/events -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "events": [ { "id": "evt_9", "executionRunId": "run_2f88ab", "workspaceId": "ws_51ac9d", "eventType": "run.failed", "payload": {}, "createdAt": "2026-07-02T13:10:02.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs/run_2f88ab/audit -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "audit": [ { "id": "aud_9", "executionRunId": "run_2f88ab", "workspaceId": "ws_51ac9d", "auditType": "run.failed", "details": { "errorCode": "auth" }, "createdAt": "2026-07-02T13:10:02.000Z" } ] } }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs/run_2f88ab/retries -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "retries": [ { "id": "retry_1", "executionRunId": "run_2f88ab", "executionStepId": "step_9", "attemptNumber": 2, "strategy": "exponential", "notBefore": "2026-07-02T13:10:01.000Z", "startedAt": "2026-07-02T13:10:01.500Z", "completedAt": "2026-07-02T13:10:02.000Z", "status": "failed" } ] } }
GET /runs returns 400 VALIDATION_ERROR if status is present but isn't one of queued, running, succeeded, failed, cancelled, retry_pending, retry_running, retry_exhausted.
Monitoring¶
Bearer required, workspace-scoped via ?workspaceId=. Every route accepts the same filter query params as /runs (flowId, status, from, to, connector, errorCode) where relevant.
| Method | Path | Purpose |
|---|---|---|
| GET | /monitoring/summary |
Aggregate run counts + success/failure/retry rates + duration stats |
| GET | /monitoring/failures |
Failures grouped by error code |
| GET | /monitoring/retries |
Retry metrics |
| GET | /monitoring/durations |
Duration distribution (avg/min/max/p95) |
| GET | /monitoring/flows |
Per-flow run stats |
| GET | /monitoring/webhooks |
Webhook invocation log (accepted + rejected) |
| GET | /monitoring/rest |
REST action invocation log |
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/summary?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"workspaceId": "ws_51ac9d", "totalRuns": 128, "successfulRuns": 119, "failedRuns": 6,
"retryExhaustedRuns": 1, "cancelledRuns": 2, "inProgressRuns": 0, "retriedRuns": 8,
"successRate": 0.93, "failureRate": 0.05, "retryRate": 0.06,
"duration": { "count": 128, "avgMs": 340, "minMs": 90, "maxMs": 2100, "p95Ms": 900, "smallSample": false }
}
}
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/failures?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "failures": [ { "errorCode": "auth", "occurrences": 4, "affectedFlows": 1, "firstSeen": "2026-06-20T10:00:00.000Z", "lastSeen": "2026-07-02T13:10:02.000Z" } ] } }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/retries?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "count": 8, "avgMs": 1500, "minMs": 500, "maxMs": 4200, "p95Ms": 3800, "smallSample": false } }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/durations?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "count": 128, "avgMs": 340, "minMs": 90, "maxMs": 2100, "p95Ms": 900, "smallSample": false } }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/flows?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": [ { "flowId": "flow_51ac9d", "flowName": "Lead alert", "totalRuns": 128, "successfulRuns": 119, "failedRuns": 6, "retriedRuns": 8, "successRate": 0.93, "retryRate": 0.06 } ] }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/webhooks?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "invocations": [ { "id": "wh_1", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "endpointId": "endpoint_1", "method": "POST", "contentType": "application/json", "requestSizeBytes": 214, "status": "accepted", "rejectionReason": null, "executionRunId": "run_2f88ab", "createdAt": "2026-07-02T13:10:00.000Z" } ] } }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/monitoring/rest?workspaceId=ws_51ac9d" -H "Authorization: Bearer $TOKEN"
{ "ok": true, "data": { "invocations": [ { "id": "rest_1", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "url": "https://api.example.com/status", "method": "GET", "statusCode": 200, "createdAt": "2026-07-02T13:12:00.000Z" } ] } }
Marketplace¶
Bearer required. Envelope is { "data": ... } only — no ok key on success (see The envelope). Browse/search/analytics routes are session-only; install and lifecycle routes are workspace-scoped and require membership.
| Method | Path | Purpose |
|---|---|---|
| GET | /marketplace/connectors?q= |
Browse (or search, if q given) all connectors |
| GET | /marketplace/categories |
Categories with connector counts |
| GET | /marketplace/search?q= |
Free-text search |
| GET | /marketplace/connectors/:key |
One connector's marketplace listing |
| POST | /marketplace/installed |
Install a connector into a workspace |
| GET | /marketplace/installed/:workspaceId |
List a workspace's installed connectors |
| POST | /marketplace/installed/transition |
Advance a connector's lifecycle state |
| GET | /marketplace/analytics |
Usage analytics for every connector |
| GET | /marketplace/analytics/:key |
Usage analytics for one connector |
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/connectors?q=slack" -H "Authorization: Bearer $TOKEN"
{ "data": [ { "key": "slack", "displayName": "Slack", "vendor": "Slack Technologies", "category": "communication", "authType": "oauth", "logoUrl": null, "docsUrl": null, "version": "1.0.0", "status": "available", "capabilities": ["send_message"], "capabilityDetail": ["send_message"] } ] }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/categories -H "Authorization: Bearer $TOKEN"
{ "data": [ { "category": "communication", "count": 2 }, { "category": "crm", "count": 1 } ] }
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/search?q=hub" -H "Authorization: Bearer $TOKEN"
{ "data": [ { "key": "hubspot", "displayName": "HubSpot", "vendor": "HubSpot", "category": "crm", "authType": "oauth", "logoUrl": null, "docsUrl": null, "version": "1.0.0", "status": "available", "capabilities": ["create_contact"], "capabilityDetail": ["create_contact"] } ] }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/connectors/slack -H "Authorization: Bearer $TOKEN"
{ "data": { "key": "slack", "displayName": "Slack", "vendor": "Slack Technologies", "category": "communication", "authType": "oauth", "logoUrl": null, "docsUrl": null, "version": "1.0.0", "status": "available", "capabilities": ["send_message"], "capabilityDetail": ["send_message"] } }
:key with no listing returns 404 CONNECTOR_NOT_FOUND.
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/installed \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"workspaceId":"ws_51ac9d","connectorKey":"slack"}'
{ "data": { "id": "inst_1a2b", "workspaceId": "ws_51ac9d", "connectorKey": "slack", "state": "installed", "installedAt": "2026-07-02T14:50:00.000Z", "updatedAt": "2026-07-02T14:50:00.000Z" } }
409 ALREADY_INSTALLED.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/installed/ws_51ac9d -H "Authorization: Bearer $TOKEN"
{ "data": [ { "id": "inst_1a2b", "workspaceId": "ws_51ac9d", "connectorKey": "slack", "state": "installed", "installedAt": "2026-07-02T14:50:00.000Z", "updatedAt": "2026-07-02T14:50:00.000Z" } ] }
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/installed/transition \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"workspaceId":"ws_51ac9d","connectorKey":"slack","action":"activate"}'
{ "data": { "id": "inst_1a2b", "workspaceId": "ws_51ac9d", "connectorKey": "slack", "state": "active", "installedAt": "2026-07-02T14:50:00.000Z", "updatedAt": "2026-07-02T14:52:00.000Z" } }
action is one of configure, certify, activate, disable, deprecate; each maps to a lifecycle-state transition (configured, certified, active, disabled, deprecated). Transitioning a connector that was never installed returns 404 NOT_INSTALLED.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/analytics -H "Authorization: Bearer $TOKEN"
{ "data": [ { "connector": "slack", "installs": 1, "runs": 128, "successes": 119, "failures": 9, "successRate": 0.93, "failureRate": 0.07, "latencyMs": 210, "topActions": ["send_message"] } ] }
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/marketplace/analytics/slack -H "Authorization: Bearer $TOKEN"
{ "data": { "connector": "slack", "installs": 1, "runs": 128, "successes": 119, "failures": 9, "successRate": 0.93, "failureRate": 0.07, "latencyMs": 210, "topActions": ["send_message"] } }
Flow designer¶
Bearer required. Envelope is { "data": ... } only — no ok key on success, same as Marketplace.
| Method | Path | Purpose |
|---|---|---|
| GET | /flow-designer/templates?category= |
List (or filter) the 7 built-in flow templates |
| GET | /flow-designer/templates/:id |
One template |
| POST | /flow-designer/draft |
Legacy rule-based drafter — prompt → draft flow (always draft-only) |
| POST | /flow-designer/validate |
Design-time validation of a flow definition |
| POST | /flow-designer/explain |
Plain-English explanation of a flow definition |
| POST | /flow-designer/snap |
Snap Pad: one-click real send (REST POST or email) |
| GET | /flow-designer/debug/:runId |
Read-only debug report for a run |
| POST | /flow-designer/studio/plan |
Snap Studio — prompt → editable plan |
| POST | /flow-designer/studio/check |
Snap Studio — validate a (possibly edited) plan |
| POST | /flow-designer/studio/approve |
Snap Studio — save an approved plan as an active flow |
| POST | /flow-designer/studio/test-run |
Snap Studio — run the saved flow and explain the result |
| GET | /flow-designer/studio/runs/:runId/explain |
Snap Studio — re-fetch a run's plain-English explanation |
The five studio/* routes are Snap Studio, SnapLink's guided AI flow builder. They're covered in full — request/response bodies, the plan schema, error shapes, and an end-to-end scripted walkthrough — in Studio API.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/templates -H "Authorization: Bearer $TOKEN"
{
"data": [
{ "id": "webhook-to-slack", "title": "Webhook → Slack Message", "description": "When a webhook fires, post a message to a Slack channel.", "category": "notifications", "requiredConnectors": ["slack"], "flowDefinition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [ { "key": "notify", "connectorKey": "slack", "actionType": "send_message", "input": { "channel": "C0000000", "text": "New event received" } } ] } }
]
}
webhook-to-slack, webhook-to-teams, webhook-to-hubspot, hubspot-lead-to-slack, hubspot-to-teams, rest-to-slack, rest-to-teams — spanning categories notifications, crm, and sales.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/templates/webhook-to-slack -H "Authorization: Bearer $TOKEN"
{ "data": { "id": "webhook-to-slack", "title": "Webhook → Slack Message", "description": "When a webhook fires, post a message to a Slack channel.", "category": "notifications", "requiredConnectors": ["slack"], "flowDefinition": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [ { "key": "notify", "connectorKey": "slack", "actionType": "send_message", "input": { "channel": "C0000000", "text": "New event received" } } ] } } }
:id returns 404 TEMPLATE_NOT_FOUND.
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/draft \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"prompt":"When a webhook fires, post to Slack"}'
{
"data": {
"draftFlow": { "trigger": { "key": "trigger", "connectorKey": "webhook", "triggerType": "webhook" }, "actions": [ { "key": "notify", "connectorKey": "slack", "actionType": "send_message", "input": { "channel": "C0000000", "text": "New event received" } } ] },
"rationale": "Matched the 'webhook-to-slack' template based on keywords in your prompt.",
"matchedTemplateId": "webhook-to-slack",
"explanation": "When a webhook trigger fires, this flow will Slack: send message.",
"activated": false
}
}
activated is always false — this endpoint (and Snap Studio) never activates a flow; you must separately promote/approve it. This is the legacy rule-based drafter — Snap Studio (/flow-designer/studio/*) is the current, richer flow-authoring surface.
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/validate \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"workspaceId":"ws_51ac9d","definition":{"trigger":{"key":"trigger","connectorKey":"webhook","triggerType":"webhook"},"actions":[{"key":"notify","connectorKey":"slack","actionType":"send_message","input":{}}]}}'
{ "data": { "valid": false, "errors": [ { "code": "schema_mismatch", "message": "Missing required input 'channel' for 'send_message'.", "location": "notify" } ] } }
errors[].code is one of invalid_structure, unsupported_trigger, missing_connector, missing_capability, missing_credential, schema_mismatch, duplicate_key, orphan_node, cycle — a design-time taxonomy distinct from the top-level error.code values in Error responses.
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/explain \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"definition":{"trigger":{"key":"trigger","connectorKey":"webhook","triggerType":"webhook"},"actions":[{"key":"notify","connectorKey":"slack","actionType":"send_message","input":{"channel":"C0000000","text":"hi"}}]}}'
{
"data": {
"summary": "When a webhook trigger fires, this flow will slack: send message.",
"executionPath": ["When a webhook trigger fires", "Slack: send message"],
"connectorsUsed": ["slack"],
"requiredCredentials": ["Slack (oauth)"],
"potentialFailurePoints": ["Slack send message could fail (auth, rate limit, or upstream error) — the engine will retry per policy."]
}
}
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/snap \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"text":"Ping from SnapLink","destination":"https://webhook.site/abc-123","title":"Test ping"}'
{ "data": { "runId": "run_c02f19", "status": "succeeded", "flowId": "flow_snap01", "workspaceId": "ws_51ac9d", "destination": "https://webhook.site/abc-123", "channel": "rest" } }
destination is either an http(s):// URL (→ channel: "rest", delivered as a REST POST) or an email address (→ channel: "email"). This is a real, immediate send through the execution engine — not a simulation — reusing a single internal "Snap Pad" flow per workspace. Empty text returns 400 EMPTY_SNAP; a destination that's neither a URL nor an email returns 400 INVALID_DESTINATION.
curl https://api.snaplink.cloudsolutionaccelerators.com/api/v1/flow-designer/debug/run_c02f19 -H "Authorization: Bearer $TOKEN"
{
"data": {
"runId": "run_c02f19", "status": "succeeded", "attempts": 1,
"timeline": [ { "at": "2026-07-02T15:00:00.000Z", "kind": "event", "type": "run.started", "label": "Run started", "detail": {} } ],
"steps": [ { "id": "step_1", "executionRunId": "run_c02f19", "stepNumber": 1, "stepType": "action", "connectorKey": "rest_sdk", "actionType": "request", "status": "succeeded", "attempt": 1, "startedAt": "2026-07-02T15:00:00.100Z", "completedAt": "2026-07-02T15:00:00.400Z", "errorCode": null, "failureReason": null } ],
"retries": [],
"connectorInvocations": [ { "stepNumber": 1, "connectorKey": "rest_sdk", "capability": "request", "status": "succeeded", "attempt": 1, "errorCode": null } ],
"failureCause": null,
"suggestedFix": null
}
}
Webhooks (public ingress, no auth)¶
| Method | Path | Purpose |
|---|---|---|
| POST | /webhooks/:flowId/:secret |
Trigger a flow — the secret in the URL path IS the authorization |
curl -X POST https://api.snaplink.cloudsolutionaccelerators.com/api/v1/webhooks/flow_51ac9d/9f3a...48hex...c2 \
-H "Content-Type: application/json" -d '{"anything":"you want"}'
{ "ok": true, "data": { "runId": "run_7c11de", "status": "queued" } }
Full detail — getting your URL, secret rotation and grace windows, the 1MB body cap, the no-storage policy, and rate limiting — is in Webhooks.
Request / response worked example¶
A typical read: paginated run history for a workspace.
curl "https://api.snaplink.cloudsolutionaccelerators.com/api/v1/runs?workspaceId=ws_51ac9d&limit=2&offset=0" \
-H "Authorization: Bearer $TOKEN"
{
"ok": true,
"data": {
"items": [
{ "runId": "run_9a02f1", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowName": "Lead alert", "status": "succeeded", "triggerType": "manual", "startedAt": "2026-07-02T14:45:00.000Z", "completedAt": "2026-07-02T14:45:01.000Z", "durationMs": 1000, "retryCount": 0, "stepCount": 1, "createdAt": "2026-07-02T14:45:00.000Z" },
{ "runId": "run_44d1c8", "workspaceId": "ws_51ac9d", "flowId": "flow_51ac9d", "flowName": "Lead alert", "status": "succeeded", "triggerType": "manual", "startedAt": "2026-07-02T14:40:00.000Z", "completedAt": "2026-07-02T14:40:01.000Z", "durationMs": 1000, "retryCount": 0, "stepCount": 1, "createdAt": "2026-07-02T14:40:00.000Z" }
],
"total": 42,
"limit": 2,
"offset": 0
}
}
offset=2; stop once items.length < limit or offset + items.length >= total.
Pagination¶
GET /runs is the only cursor-free, offset-paginated list endpoint. It accepts:
limit— page size. Defaults to 20, capped at 100. Non-numeric or out-of-range values are clamped, not rejected.offset— number of items to skip. Defaults to 0.
The response always includes total (the full matching count, independent of the page) alongside items, limit, and offset. There is no cursor/token-based pagination — offset/limit is the only mechanism the API supports.
Every other list endpoint (/flows, /connections, /marketplace/connectors, etc.) returns its full result set in one response; none of them currently paginate.
Filtering¶
GET /runs and every /monitoring/* route accept the same filter query parameters:
| Param | Type | Notes |
|---|---|---|
workspaceId |
string | Required |
flowId |
string | Optional |
status |
one of queued, running, succeeded, failed, cancelled, retry_pending, retry_running, retry_exhausted |
Optional; 400 VALIDATION_ERROR if it's anything else |
from / to |
ISO 8601 timestamps | Optional; bounds on createdAt |
connector |
string | Optional; matches runs whose steps invoked this connector key |
errorCode |
string | Optional; matches runs whose steps failed with this code (see the taxonomy in Error responses) |
/marketplace/connectors, /marketplace/search accept a single q free-text query param.
Rate limits¶
Webhook ingress (POST /webhooks/:flowId/:secret) is rate-limited per IP, per endpoint, and per workspace; a tripped limit returns 429 RATE_LIMITED with error.details.retryAfterSeconds. See Rate limiting for limits and backoff guidance, and Webhooks for the full ingress contract.
Error responses¶
Every error response, from every endpoint with no exception, has this exact shape:
{ "ok": false, "error": { "code": "FLOW_NOT_FOUND", "message": "Flow not found.", "details": null } }
details is optional and varies by code — often zod validation issues for VALIDATION_ERROR, or { retryAfterSeconds } for RATE_LIMITED.
| HTTP | error.code |
Where |
|---|---|---|
| 400 | VALIDATION_ERROR |
Any endpoint — bad request body/query |
| 400 | INVALID_EMAIL |
POST /auth/signup |
| 400 | WEAK_PASSWORD |
POST /auth/signup — password under 8 characters |
| 400 | STUDIO_PLAN_MALFORMED |
Studio check/approve — plan fails schema/whitelist validation |
| 400 | STUDIO_PLAN_INVALID |
Studio approve — plan has unresolved problems; carries error.details.problems |
| 401 | UNAUTHENTICATED |
Any Bearer-protected endpoint — missing/invalid token |
| 401 | INVALID_CREDENTIALS |
POST /auth/login — bad email/password |
| 403 | FORBIDDEN |
Workspace member routes — caller's role is insufficient |
| 404 | WORKSPACE_NOT_FOUND |
Any workspace-scoped route — no such workspace, or caller isn't a member |
| 404 | FLOW_NOT_FOUND |
Flow routes |
| 404 | DRAFT_NOT_FOUND |
Draft routes |
| 404 | RUN_NOT_FOUND |
Execution/run routes |
| 404 | STEP_NOT_FOUND |
Execution step lookups |
| 404 | RETRY_NOT_FOUND |
Retry attempt lookups |
| 404 | CONNECTOR_NOT_FOUND |
Connector registry / marketplace routes |
| 404 | CONNECTION_NOT_FOUND |
Connection routes |
| 404 | HEALTH_NOT_FOUND |
Connection health routes |
| 404 | TEMPLATE_NOT_FOUND |
Flow template routes |
| 409 | EMAIL_TAKEN |
POST /auth/signup — duplicate account |
| 429 | RATE_LIMITED |
Webhook ingress — carries error.details.retryAfterSeconds |
| 503 | NOT_READY |
GET /health/ready only |
Cross-workspace access — a real ID that exists but belongs to a workspace you're not a member of — returns the resource's ordinary 404 *_NOT_FOUND code, never 403. This is deliberate: it avoids confirming that a resource exists to a caller who shouldn't be able to see it.
A few endpoints throw additional, narrowly-scoped codes worth knowing if you integrate against them directly: webhook ingress returns 404 WEBHOOK_NOT_FOUND (not FLOW_NOT_FOUND) for an unknown flow or bad secret, and 409 FLOW_NOT_ACTIVE if the target flow isn't active (see Webhooks); POST /flow-designer/snap returns 400 EMPTY_SNAP / 400 INVALID_DESTINATION; marketplace install/lifecycle routes return 409 ALREADY_INSTALLED, 404 NOT_INSTALLED, 409 NOT_CERTIFIABLE, and 422 CERTIFICATION_FAILED. Requests to routes that don't exist at all get a generic 404 NOT_FOUND; truly unexpected server errors get 500 INTERNAL_ERROR.
Run/step failure taxonomy. Separately from the HTTP error.code above, a failed execution step carries an errorCode drawn from a fixed connector-failure taxonomy: auth, rate_limit, timeout, upstream_5xx, bad_request, blocked, unknown. This is the same value GET /runs?errorCode= filters on, and what GET /flow-designer/debug/:runId uses to suggest a fix.
SDK examples (login → list runs)¶
Every example below reads the token/data the same way regardless of which envelope shape the endpoint uses: check the HTTP status for success, then read .data (or ["data"]) directly — never assume an ok field is present in the body.
cURL
BASE="https://api.snaplink.cloudsolutionaccelerators.com/api/v1"
TOKEN=$(curl -s -X POST "$BASE/auth/login" -H 'Content-Type: application/json' \
-d '{"email":"jane@example.com","password":"correct-horse-battery"}' | jq -r .data.token)
curl -s "$BASE/runs?workspaceId=$WS" -H "Authorization: Bearer $TOKEN" | jq .data
JavaScript / TypeScript
const BASE = "https://api.snaplink.cloudsolutionaccelerators.com/api/v1";
async function login(email: string, password: string) {
const res = await fetch(`${BASE}/auth/login`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email, password }),
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message); // error shape is always { ok:false, error }
return body.data.token as string; // success shape here has ok:true, but we only read .data
}
async function listRuns(token: string, workspaceId: string) {
const res = await fetch(`${BASE}/runs?workspaceId=${workspaceId}`, {
headers: { Authorization: `Bearer ${token}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
return body.data; // { items, total, limit, offset }
}
const token = await login("jane@example.com", "correct-horse-battery");
const runs = await listRuns(token, "ws_51ac9d");
Python
import requests
BASE = "https://api.snaplink.cloudsolutionaccelerators.com/api/v1"
def login(email, password):
res = requests.post(f"{BASE}/auth/login", json={"email": email, "password": password})
body = res.json()
if not res.ok:
raise RuntimeError(body["error"]["message"])
return body["data"]["token"]
def list_runs(token, workspace_id):
res = requests.get(f"{BASE}/runs", params={"workspaceId": workspace_id},
headers={"Authorization": f"Bearer {token}"})
body = res.json()
if not res.ok:
raise RuntimeError(body["error"]["message"])
return body["data"]
token = login("jane@example.com", "correct-horse-battery")
runs = list_runs(token, "ws_51ac9d")
C#
using var http = new HttpClient();
var loginRes = await http.PostAsJsonAsync($"{BASE}/auth/login", new { email, password });
var loginBody = await loginRes.Content.ReadFromJsonAsync<JsonElement>();
if (!loginRes.IsSuccessStatusCode)
throw new Exception(loginBody.GetProperty("error").GetProperty("message").GetString());
var token = loginBody.GetProperty("data").GetProperty("token").GetString();
http.DefaultRequestHeaders.Authorization = new("Bearer", token);
var runsRes = await http.GetAsync($"{BASE}/runs?workspaceId={ws}");
var runsBody = await runsRes.Content.ReadFromJsonAsync<JsonElement>();
if (!runsRes.IsSuccessStatusCode)
throw new Exception(runsBody.GetProperty("error").GetProperty("message").GetString());
var data = runsBody.GetProperty("data");
PowerShell
$loginRes = Invoke-RestMethod "$BASE/auth/login" -Method Post -ContentType 'application/json' `
-Body (@{ email = $Email; password = $Password } | ConvertTo-Json) -SkipHttpErrorCheck -StatusCodeVariable loginStatus
if ($loginStatus -ge 400) { throw $loginRes.error.message }
$token = $loginRes.data.token
$runsRes = Invoke-RestMethod "$BASE/runs?workspaceId=$Ws" -Headers @{ Authorization = "Bearer $token" } `
-SkipHttpErrorCheck -StatusCodeVariable runsStatus
if ($runsStatus -ge 400) { throw $runsRes.error.message }
$data = $runsRes.data
Postman / collection guide¶
Import the endpoints above as a collection: set a baseUrl variable, a token variable populated from POST /auth/login's data.token, and an Authorization: Bearer {{token}} header at the collection level. An exportable OpenAPI spec is Planned — none exists yet, so don't link to one.
Related: Studio API · Webhooks · Rate limiting · Creating flows