Workflow API
Start a workflow from your own backend, follow its runs and read the data tables it uses. For example, when a subscription payment fails, your server can start the workflow that opens a proactive conversation with that customer.
Before you start
| Allow API start | Turn it on in the workflow's trigger, under Automation, then Workflows. A workflow without it answers 403 with the code start_not_allowed. |
|---|---|
| Scopes | workflows:write to start a run, workflows:read to read runs, tables:read and tables:write for data tables. |
| Retries are safe | Send an Idempotency-Key with every start. One key starts at most one run of a workflow, however many times you retry. |
Start a workflow
POST
/workflows/{id}/runsStarts one run for a contact or a conversation. The workflow's audience, frequency caps and consent rules still apply.
| Body field | Type | Description |
|---|---|---|
| subject.type | string, required | contact or conversation. |
| subject.external_id | string | The user ID you pass to identify. Send this or subject.id. |
| params | object | Values the workflow can read in its steps and messages, up to 50 keys. |
curl -X POST "$BASE/workflows/wf_payment_failed/runs" \
-H "Authorization: Bearer $GRIPZ_API_KEY" \
-H "Idempotency-Key: 9b2e41c7-5d0a-4f3e-8c61-2a7f0e4d1b58" \
-H "Content-Type: application/json" \
-d '{
"subject": { "type": "contact", "external_id": "usr_4821" },
"params": { "invoice": "INV-2041", "reason": "card_declined" }
}'What comes back
{
"id": "wfr_3Kd81Q",
"object": "workflow_run",
"workflow_id": "wf_payment_failed",
"status": "started",
"subject": { "type": "contact", "id": "ct_9d3m" },
"created_at": "2026-10-02T10:42:11Z"
}| started | The run is queued. Follow it with the runs endpoint below. |
|---|---|
| skipped | Nothing ran, and reason says why: audience, frequency_cap, consent or workflow_paused. A skip is not an error, so do not retry it. |
| failed | The run could not start. The error names the problem, for example subject_not_found, and carries a request ID you can quote to support. |
Runs and data tables
Read what a run did, step by step, and keep the tables your workflows look up in sync with your own systems.
| GET | /workflow_runs/{id} | One run with its status and the result of each step. |
|---|---|---|
| GET | /workflow_runs | Runs of one workflow, newest first. Filter by workflow_id and status. |
| GET | /data_tables/{id}/rows | Rows of a data table, for example office hours or escalation contacts. |
| POST | /data_tables/{id}/rows | Add or update rows. Columns are typed, and a row that does not match is rejected with the column named. |
Verify requests from your workflows
When an HTTP step in a workflow calls your server, the request is signed exactly like a webhook delivery: an HMAC-SHA256 signature over the request ID, the timestamp and the raw body, made with the workflow's signing secret. Reject anything older than five minutes.
| gripz-webhook-id | Unique per request. Use it to ignore repeats. |
|---|---|
| gripz-webhook-timestamp | Seconds since the epoch, when the request was signed. |
| gripz-webhook-signature | The signature to compare in constant time. |