Webhooks and callbacks¶
Rig workflows can be started from outside the application in two ways, and the result of a run is collected by polling.
| API trigger | Inbound webhook trigger | |
|---|---|---|
| Path | POST /{client_id}/workflows/{workflow_id}/triggers/api |
POST /api/webhooks/{webhook_path} |
| Authentication | API token | HMAC-SHA256 signature |
| Runs with the permissions of | The token's owner | The workflow's creator |
| Typical caller | Your own service or script | A third-party system that can sign requests |
Completion callbacks
Rig does not send an outbound callback when a run finishes. Poll the run for its result, as described in Polling for the result.
API trigger¶
curl -X POST https://app.rig.so/jaffleshop/workflows/WORKFLOW_ID/triggers/api \
-H "Authorization: Bearer rig_mcp_jaffleshop_EXAMPLE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-export-2030-01-31" \
-d '{"input_data": {"region": "north"}}'
The token needs the workflows.trigger scope for this workflow. See
Authentication.
Request body
| Field | Type | Description |
|---|---|---|
input_data |
object | Input for the run. Validated against the workflow's trigger input schema, if it defines one. |
Response 202 Accepted for a new run, 200 OK when an idempotency key replays an earlier run.
{
"execution_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"status": "running",
"trigger_type": "api",
"poll_url": "/jaffleshop/workflows/WORKFLOW_ID/runs/aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
"started_at": "2030-01-31T09:00:00+00:00"
}
status is one of queued, running, completed or failed. poll_url is a path relative
to the base URL. A replayed response also carries "replay": true and, if that run has
completed, its result.
Idempotency¶
Send an Idempotency-Key header to make a trigger safe to retry. Repeating a request with the
same key and the same input_data returns the original run instead of starting a new one.
Reusing a key with different input_data within 24 hours of the original run is rejected with
idempotency_key_body_mismatch. After 24 hours, and on a workflow configured to allow
concurrent runs, the input is not compared and the key replays its original run. A key stays
bound to its run, so use a new key for each new request. A workflow can be configured to require the header.
Concurrency¶
By default a workflow accepts one triggered run at a time. A trigger that arrives while a run
is in progress receives 409 with the code concurrent_in_flight and the id of the running
execution. A workflow can be configured to allow one run per distinct input, or to allow
concurrent runs.
Errors¶
Errors carry a machine-readable code at detail.error.
| Status | Code | Meaning |
|---|---|---|
| 400 | malformed_request |
The body is not valid JSON. |
| 400 | invalid_input_schema |
input_data is missing required fields or has fields of the wrong type. The response lists them. |
| 400 | idempotency_key_required |
The workflow requires an Idempotency-Key header. |
| 400 | idempotency_key_body_mismatch |
The key was already used with different input. |
| 401 | unauthorized |
The token is missing, unknown or revoked. |
| 403 | token_scope_mismatch |
The token is not scoped to trigger this workflow. |
| 403 | forbidden |
The token's owner is not permitted to run this workflow. |
| 404 | workflow_not_found |
No such workflow in this workspace. Also returned when the token belongs to a different workspace. |
| 409 | concurrent_in_flight |
A run is already in progress. |
| 423 | WORKSPACE_PAUSED |
The workspace is paused. This code is reported at detail.error_code. |
Polling for the result¶
curl https://app.rig.so/jaffleshop/workflows/WORKFLOW_ID/runs/EXECUTION_ID \
-H "Authorization: Bearer rig_mcp_jaffleshop_EXAMPLE"
A token-authenticated caller receives these fields:
| Field | Description |
|---|---|
id |
The execution id. |
workflow_id |
The workflow. |
status |
queued, running, completed or failed. |
trigger_type |
api, webhook or another trigger type. |
started_at, completed_at |
Timestamps. |
final_context |
The run's result, once status is completed. Before that it contains only the run's input. |
error_message |
Set when the run failed. |
A run that is still running after 30 minutes is marked failed.
Inbound webhook trigger¶
A workflow whose trigger type is webhook has its own endpoint path and signing secret. The URL does not contain a workspace identifier; the path identifies the workflow.
POST https://app.rig.so/api/webhooks/{webhook_path}
X-Rig-Signature: t=<unix timestamp>,v1=<hex signature>
Content-Type: application/json
{"data": {"region": "north"}, "metadata": {"source": "billing-system"}}
data becomes the run's input. metadata is optional and is recorded with the run. The
Idempotency-Key header works as it does for the API trigger, comparing data only: a repeat
with the same key and data but different metadata replays the original run. The response has the same shape
as the API trigger's, with "trigger_type": "webhook".
Signing a request¶
The signature is an HMAC-SHA256 of the timestamp, a full stop and the raw request body, keyed with the signing secret and hex-encoded.
import hashlib, hmac, json, time
import urllib.request
secret = "whsec_EXAMPLE" # the workflow's signing secret
body = json.dumps({"data": {"region": "north"}}).encode()
t = int(time.time())
signature = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
urllib.request.urlopen(urllib.request.Request(
"https://app.rig.so/api/webhooks/WEBHOOK_PATH",
data=body,
headers={"X-Rig-Signature": f"t={t},v1={signature}", "Content-Type": "application/json"},
))
Rules the receiver applies:
- The timestamp must be within 5 minutes of the server's clock.
- The body must be at most 1 MB. A larger body receives
413. - Sign the exact bytes you send. Re-serialising the JSON after signing changes the signature.
- Any authentication failure (unknown path, bad signature, stale timestamp, malformed header)
receives the same
401response with the codeinvalid_webhook_request, so the response does not reveal which check failed.
Signing secrets¶
Create or rotate the secret from the workflow's webhook settings in the application, or with
POST /{client_id}/workflows/{workflow_id}/schedule/webhook-secret
(Preview, editor role or above). The secret is returned once. After a rotation the previous
secret remains valid for 5 minutes so that callers can switch over.
Other inbound webhooks¶
| Endpoint | Purpose | Signature |
|---|---|---|
POST /{client_id}/fde/context/dbt-cloud-webhook |
Receives dbt Cloud's job run completed notification and refreshes the workspace's dbt models. See Data models. | dbt Cloud's webhook signature: an HMAC-SHA256 of the body in the Authorization header. |
POST /{client_id}/fde/context/pr-event |
Preview. Receives pull request events from a repository so that the context layer can follow model changes. | X-Rig-Signature, as above. |