ReferenceAPI

Workflows

Workflows API methods, requests, and responses for RawTree Cloud and RawTree BYOC.

Workflows API

This API manages SQL workflows in RawTree Cloud and RawTree BYOC, where enabled. RawTree executes the SQL. The service manages schedules, runs, and result delivery.

Workflows run SQL on demand or on a schedule. They send read-query results to HTTP, table, or Slack sinks. See the workflow guide for SQL behavior and delivery guarantees.

All workflow endpoints require organization and cluster query parameters, using their names, and an admin API key, a user session bearer token, or an OAuth token with full_access. Admin API keys can read and manage workflows only in their bound organization and cluster; other API key permissions, including custom database roles, are not supported. Organization members can read workflows, runs, logs, and metrics; organization administrators can create, run, update, and delete workflows, and cancel runs.

Workflows belong to the organization and execute with organization credentials. Expiring or revoking the API key used to create a workflow prevents further API access with that key but does not stop the workflow. Pause or delete the workflow to stop future scheduled executions.

A disabled workflow service returns 503.

GET /v1/workflows

List workflows in the selected organization and cluster.

{ "workflows": [] }

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—

Request:

# List workflows in an organization and cluster.
curl -X GET "https://api.rawtree.com/v1/workflows?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 200.

{
  "workflows": [
    {
      "id": "11111111-1111-4111-8111-111111111111",
      "name": "event-count",
      "query": {
        "database": "analytics",
        "sql": "SELECT count() AS total FROM events"
      },
      "schedule": null,
      "sinks": [],
      "revision": 1,
      "created_at": "2026-11-09T10:00:00Z",
      "updated_at": "2026-11-09T10:00:00Z"
    }
  ]
}

Errors: 403, 503. See API errors.

POST /v1/workflows

Create a workflow. Returns 201 with the saved workflow, including its id, revision, created_at, updated_at, and sink metadata.

{
  "name": "high-volume-customers",
  "description": "Customers with more than 100 events",
  "query": {
    "database": "default",
    "sql": "SELECT customer_id, count() AS total FROM events GROUP BY customer_id HAVING total > 100"
  },
  "schedule": {
    "cron": "*/5 * * * *",
    "enabled": true
  },
  "sinks": []
}

The required query object contains database and sql. Responses use the same shape. Top-level database and sql fields are rejected.

schedule controls automatic executions. Set it to null for a manual-only workflow. When omitted, it defaults to running every second: {"cron": "* * * * * *", "enabled": true}. Within schedule, cron is required and enabled defaults to true. sinks defaults to an empty list.

cron uses UTC. It accepts five fields (minute hour day-of-month month day-of-week) or six fields with second first. Each field accepts *, a number, a range such as 9-17, a step such as */15 or 5/10, or a comma-separated list.

Day of week uses 0–7; 0 and 7 mean Sunday. If both day fields are restricted, a run requires both to match. Names, shortcuts such as @hourly, and ?, L, or # return 422. The workflow service normalizes spaces and limits the normalized expression to 1,024 characters. See schedule a workflow for examples and missed-run behavior.

Each cluster supports up to 100 workflows, including paused workflows. Names are trimmed and lowercased and must be unique in the cluster. The optional description is trimmed, accepts up to 1,000 characters, and is null when omitted or blank.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—
namebodystringYes—
descriptionbodystring or nullNoOptional free-form text. Surrounding whitespace is trimmed and blank values are stored as null.
querybodyWorkflowQueryYes—
schedulebodynull or WorkflowScheduleNo—
sinksbodyarray of SinkInputNo—

Request:

# Create a scheduled SQL workflow.
curl -X POST "https://api.rawtree.com/v1/workflows?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "event-count",
  "query": {
    "database": "analytics",
    "sql": "SELECT count() AS total FROM events"
  },
  "schedule": null,
  "sinks": []
}'

Expected response: HTTP 201.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "name": "event-count",
  "query": {
    "database": "analytics",
    "sql": "SELECT count() AS total FROM events"
  },
  "schedule": null,
  "sinks": [],
  "revision": 1,
  "created_at": "2026-11-09T10:00:00Z",
  "updated_at": "2026-11-09T10:00:00Z"
}

Errors: 400, 403, 409, 422, 503. See API errors.

GET /v1/workflows/{workflow_id}

Get a workflow and its schedule state. HTTP sink responses include settings.url and settings.header_names. The URL is null if its encrypted configuration cannot be read; the workflow and sink metadata remain available for repair. Header values are write-only and are never returned. schedule is null for manual-only workflows. Otherwise it contains cron, enabled, and next_run_at, the next scheduled evaluation time in RFC 3339 format. next_run_at is null while paused or when no future time is available. A successful create or update can also return null if schedule metadata could not be refreshed.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—

Request:

# Get a workflow and its sink configuration.
curl -X GET "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 200.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "name": "event-count",
  "query": {
    "database": "analytics",
    "sql": "SELECT count() AS total FROM events"
  },
  "schedule": null,
  "sinks": [],
  "revision": 1,
  "created_at": "2026-11-09T10:00:00Z",
  "updated_at": "2026-11-09T10:00:00Z"
}

Errors: 403, 404, 503. See API errors.

PATCH /v1/workflows/{workflow_id}

Update the supplied fields and return the saved workflow. Omitted fields retain their existing values. Omitting query preserves the saved query. Within query, omitted database or sql fields retain their values; for example, {"query":{"sql":"SELECT 1"}} changes only the SQL. Within schedule, omitted fields retain their values: {"schedule": {"enabled": false}} pauses automatic runs and {"schedule": {"enabled": true}} resumes them and keeps the cron. Set schedule to null for manual-only execution. To schedule it again, supply a cron; enabled then defaults to true. Pausing does not prevent explicit runs. Set description to null or blank text to clear it.

{ "schedule": { "cron": "*/10 * * * * *", "enabled": false } }

Supplying sinks replaces the full list. Preserve existing sink IDs when editing; omit id for new sinks. An empty list removes every sink. Each sink has a type and a typed settings object: HTTP settings accept url and headers; table settings require database and table; Slack settings require integration_id and exactly one of channel_id or channel_name. HTTP responses expose settings.url, settings.url_configured, and settings.header_names, never header values. Slack responses expose settings.integration_id, settings.channel_id, and settings.channel_name. Flattened fields are rejected. See sink configuration for HTTP credentials and table sinks, and Post results to Slack for connecting a Slack workspace.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—
namebodystring or nullNo—
descriptionbodystring or nullNoOmit to preserve the description; null or blank text clears it.
querybodynull or UpdateWorkflowQueryNo—
schedulebodynull or UpdateWorkflowScheduleNo—
sinksbodyarray or nullNo—

Request:

# Update a workflow, including its schedule and sinks.
curl -X PATCH "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "schedule": {
    "cron": "*/5 * * * *",
    "enabled": true
  }
}'

Expected response: HTTP 200.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "name": "event-count",
  "query": {
    "database": "analytics",
    "sql": "SELECT count() AS total FROM events"
  },
  "schedule": {
    "cron": "*/5 * * * *",
    "enabled": true
  },
  "sinks": [],
  "revision": 2,
  "created_at": "2026-11-09T10:00:00Z",
  "updated_at": "2026-11-09T10:00:00Z"
}

Errors: 400, 403, 404, 409, 422, 503. See API errors.

DELETE /v1/workflows/{workflow_id}

Delete the workflow and its schedule. Returns 204 with no response body.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—

Request:

# Delete a workflow and its schedule.
curl -X DELETE "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 204.

The response body is empty.

Errors: 403, 404, 503. See API errors.

POST /v1/workflows/{workflow_id}/sinks

Add one sink without resending the others. The body is a sink as in the sinks list, without id; the new sink goes last. Returns 201 with the saved sink. A workflow holds up to five sinks.

{ "type": "table", "settings": { "database": "analytics", "table": "alerts" } }

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—

Request:

# Add a sink to a workflow.
curl -X POST "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/sinks?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "table",
  "settings": {
    "database": "analytics",
    "table": "event_counts"
  }
}'

Expected response: HTTP 201.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "type": "table",
  "settings": {
    "database": "analytics",
    "table": "event_counts"
  }
}

Errors: 400, 403, 404, 409, 422, 503. See API errors.

PATCH /v1/workflows/{workflow_id}/sinks/{sink_id}

Change one sink and return it. Send the settings to change; omitted settings keep their stored values. HTTP headers work as in a PATCH of sinks: the map lists every header the sink keeps, null keeps a header's stored value, and omitted headers are removed. type is optional and must match the sink's type; to change the type, delete the sink and add a new one.

This keeps Authorization, adds X-Region, and removes any other header:

{ "settings": { "headers": { "Authorization": null, "X-Region": "eu" } } }

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—
typebodynull or SinkTypeNo—
settingsbodyHttpSinkSettingsInput or TableSinkSettingsPatch or SlackSinkSettingsPatchYes—

Request:

# Change one sink of a workflow; omitted settings keep their stored values.
curl -X PATCH "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/sinks/11111111-1111-4111-8111-111111111111?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "settings": {
    "table": "event_counts_archive"
  }
}'

Expected response: HTTP 200.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "type": "table",
  "settings": {
    "database": "analytics",
    "table": "event_counts_archive"
  }
}

Errors: 400, 403, 404, 409, 422, 503. See API errors.

DELETE /v1/workflows/{workflow_id}/sinks/{sink_id}

Remove one sink. Returns 204 with no response body.

Sink changes through these routes stop queued and active runs of the previous definition, as a PATCH of sinks does. Each route changes only its own sink, so other sinks stay as saved. A sink PATCH returns 409 if the workflow changes while it is applied.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—

Request:

# Remove one sink from a workflow.
curl -X DELETE "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/sinks/11111111-1111-4111-8111-111111111111?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 204.

The response body is empty.

Errors: 403, 404, 409, 503. See API errors.

POST /v1/workflows/{workflow_id}/runs

Start an execution using the saved definition without changing its schedule. Requires an organization administrator or admin API key. No request body is required. Returns 202 with id, workflow_id, query_id, and source: "manual". The optional Idempotency-Key header accepts 1–128 visible ASCII characters without spaces. Reusing a key recovers the same execution while Temporal retains it. See explicit runs for revision checks, overlap, and delivery semantics.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
Idempotency-Keyheaderstring or nullNoOptional retry key, 1–128 visible ASCII characters without spaces. Scoped to this workflow; deduplication lasts while Temporal retains the execution.

Request:

# Execute a saved workflow once, independently of its schedule.
curl -X POST "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/runs?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 202.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "workflow_id": "11111111-1111-4111-8111-111111111111",
  "query_id": "workflow-docs-run",
  "source": "manual"
}

Errors: 400, 401, 403, 404, 503. See API errors.

POST /v1/workflows/{workflow_id}/runs/{run_id}/cancel

Request cancellation of one manual or scheduled execution. Requires an organization administrator or admin API key, with the same organization and cluster query parameters as the other workflow endpoints. No body is required. Returns 202 with an empty body once cancellation is accepted.

curl -X POST \
  "$RAWTREE_URL/v1/workflows/$WORKFLOW_ID/runs/$RUN_ID/cancel?organization=$ORGANIZATION&cluster=$CLUSTER" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Cancellation is asynchronous and requires a worker to process it. Use the runs list to inspect the eventual status. It preserves execution history, other concurrent runs, and future scheduled executions. It does not roll back completed writes or recall deliveries already handed off to sinks. Query cleanup can take time, especially when a database replica is unavailable.

Repeating cancellation is safe: a pending request or an already canceled run returns 202. A run that has otherwise finished returns 409. Unknown runs, runs belonging to another workflow, and deleted workflows return 404. Because run lookup uses Temporal visibility, a newly started run may briefly return 404; retry once it appears in the runs list. A 503 means acceptance could not be confirmed; retry cancellation for the same run.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Request:

# Request cancellation of one manual or scheduled run without changing its schedule.
# No body is required. Acceptance is asynchronous and does not undo completed writes.
# Recently started runs may not yet be visible. Repeating a request is safe;
# already canceled runs return 202 and other finished runs return 409.
curl -X POST "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/runs/11111111-1111-4111-8111-111111111111/cancel?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 202.

The response body is empty.

Errors: 400, 401, 403, 404, 409, 503. See API errors.

GET /v1/workflows/{workflow_id}/runs

List manual and scheduled executions retained by Temporal for this workflow. limit defaults to 20 and accepts 1–100. This is a per-page limit, not a total history limit. Pass next_cursor as cursor to request another page for the same workflow. The page size may change between requests. next_cursor: null means there are no more pages; an empty page with a cursor can still be continued.

{
  "runs": [
    {
      "id": "01a10ffc-b4f7-7871-859c-6353f93d875f",
      "workflow_id": "d668a6c1-1904-4a27-b113-ef54b5435483",
      "query_id": "workflow:d668a6c1-1904-4a27-b113-ef54b5435483:01a10ffc-b4f7-7871-859c-6353f93d875f",
      "source": "manual",
      "status": "running",
      "started_at": "2026-10-06T10:32:00Z",
      "finished_at": null,
      "deliveries": [
        {
          "sink_id": "5b0f2f0e-7c8e-4d4b-9a2b-6f1d0c3e8a71",
          "status": "delivering"
        }
      ]
    }
  ],
  "next_cursor": null
}

id is the Temporal run ID and matches the ID returned by POST. query_id is the RawTree query ID for the run, in the form workflow:{workflow_id}:{run_id}. Search system.query_log for this ID to inspect the query when it has executed. source is manual or scheduled. status is running, completed, failed, canceled, terminated, continued_as_new, timed_out, or paused. Timestamps use RFC 3339 in UTC; finished_at is null until the execution closes.

Active runs appear first by descending start time, then finished runs by descending finish time. Temporal visibility is eventually consistent: recent starts and status changes may appear after a delay. Pagination reflects live history, so refresh from the first page to see current state. Runs remain available after pausing or removing a schedule, until Temporal expires their history. Deleting the saved workflow makes its runs endpoint return 404.

Sinks receive rows asynchronously, and delivery to a sink is retried for up to an hour. A run stays running until every sink it sent rows to reports how delivery ended. It is completed only when every sink received its rows, and failed if a sink rejected them or kept failing for an hour. If a sink's outcome is still unknown when the 65-minute delivery confirmation window closes, the run fails: the rows may have reached the sink, but the service could not confirm it. Cancelling a run that is waiting for its sinks closes it as canceled; rows already handed off may still be delivered.

deliveries lists each sink the run sent rows to, ordered by sink ID, and is empty when the run sent none. Each status is delivering, delivered, failed, or delivery_unknown. These statuses describe this run's delivery, not the sink's configuration. Inspect the workflow logs for SQL outcomes and each delivery attempt. Invalid limits or cursors return 400; an unavailable execution service returns 503.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Request:

# List manual and scheduled executions retained by Temporal.
# Active executions come first, then finished executions by descending finish
# time. Visibility is eventually consistent. A run stays `running` until every
# sink it handed rows to reports its delivery, and fails if any delivery
# failed or is unconfirmed after 65 minutes. `deliveries` shows each sink's
# progress; per-attempt details are in logs.
curl -X GET "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/runs?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 200.

{
  "runs": [],
  "next_cursor": null
}

Errors: 400, 401, 403, 404, 503. See API errors.

GET /v1/workflows/{workflow_id}/logs

List execution and delivery history. Optional from (inclusive) and to (exclusive) are Unix milliseconds and default to the last 24 hours. Ranges can cover up to seven days. limit defaults to 100 and accepts 1–200.

The response contains logs, from, to, and next_cursor. Each log includes event_type (for example, workflow.evaluated) and workflow_revision. Delivery records identify the sink with sink_id and sink_type. Pass the returned from, to, and next_cursor as cursor to fetch older logs within the same window. History is best-effort observability data.

Use an API key, a permitted workload token, or a user bearer token. Database-role keys support only the operations listed in Authentication.

Parameters:

FieldLocationTypeRequiredNotes
organizationquerystringYes—
clusterquerystringYes—
fromqueryinteger or nullNoInclusive Unix milliseconds. Defaults to the last 24 hours.
toqueryinteger or nullNoExclusive Unix milliseconds.
cursorquerystring or nullNo—
limitqueryinteger or nullNo—

Request:

# List workflow execution and sink delivery logs.
curl -X GET "https://api.rawtree.com/v1/workflows/11111111-1111-4111-8111-111111111111/logs?organization=team_alpha&cluster=production" \
  -H "Authorization: Bearer $RAWTREE_API_KEY"

Expected response: HTTP 200.

{
  "logs": [],
  "from": 1794214800000,
  "to": 1794218400000
}

Errors: 400, 403, 404, 503. See API errors.

Sink delivery metrics

Read sink delivery metrics through GET /v1/metrics. Each observation contains the organization, cluster, workflow (rawtree.workflow.id), and sink (rawtree.workflow.sink.id) identities.

MetricMeaningUnit
rawtree.workflow.sink.errorsTerminal delivery failures; retry attempts are excluded{error}
rawtree.workflow.sink.written_rowsRows in successful sink deliveries, including HTTP sinks{row}

These are monotonic delta sums. Use aggregation=sum to add deliveries within each bucket. Do not use function=increase, which requires cumulative counters. Filter by workflow ID and group by sink ID:

curl -X GET -G "https://api.rawtree.com/v1/metrics" \
  -H "Authorization: Bearer $RAWTREE_SESSION_TOKEN" \
  --data-urlencode "organization=$RAWTREE_ORGANIZATION" \
  --data-urlencode "cluster=$RAWTREE_CLUSTER" \
  --data-urlencode 'metric=rawtree.workflow.sink.errors,rawtree.workflow.sink.written_rows' \
  --data-urlencode "filters={\"rawtree.workflow.id\":\"$WORKFLOW_ID\"}" \
  --data-urlencode 'aggregation=sum' \
  --data-urlencode 'granularity_seconds=60' \
  --data-urlencode 'group_by=rawtree.workflow.sink.id' \
  --data-urlencode 'window_seconds=3600'

Metric export is buffered and best effort; it does not block sink delivery. History starts when the deployment begins emitting these metrics. Existing logs are not backfilled into metrics. Workflow logs remain available for individual attempts, failure details, and links to runs. The sink metrics endpoint /v1/workflows/{workflow_id}/sinks/metrics has been removed.