Skip to content

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 401 response with the code invalid_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.