Skip to main content

Payload shape

Every webhook is an HTTP POST with Content-Type: application/json and this body:
{
  "event": "workflow_run.completed",
  "timestamp": "2026-04-22T10:30:45Z",
  "data": {
    "workflow_run": {
      "id": 12345,
      "workflow_id": 67890,
      "status": "completed",
      "input": { "...": "the input the run was started with" },
      "output": { "...": "the workflow's final output" },
      "created_at": "2026-04-22T10:25:00Z",
      "updated_at": "2026-04-22T10:30:45Z"
    }
  }
}
FieldDescription
eventOne of workflow_run.completed or workflow_run.failed.
timestampWhen the event was dispatched, in ISO 8601 UTC.
data.workflow_run.idUnique ID of the workflow run. Use this for deduplication.
data.workflow_run.workflow_idThe workflow that produced this run. Use to filter if you only care about specific workflows.
data.workflow_run.statuscompleted or failed. Mirrors event but is convenient to switch on.
data.workflow_run.inputThe input payload the run was started with.
data.workflow_run.outputThe workflow’s final output. For failed runs this may include error details.
data.workflow_run.created_atWhen the run started (ISO 8601 UTC).
data.workflow_run.updated_atWhen the run reached its terminal state (ISO 8601 UTC).

Authentication

Champ applies the authentication configured on the destination’s REST API connection to every delivery:
  • BearerAuthorization: Bearer <token>
  • Basic — HTTP Basic credentials
  • Custom headers — applied as-is to every request
Configure this when you create the REST API connection used as the subscription’s Connection. See Add a REST API integration.
Champ does not currently sign webhook payloads — there is no HMAC or X-Signature header. Use bearer-token or basic auth on the destination connection to verify that a request actually came from Champ, and restrict your handler to that credential.

Retries

Failed deliveries retry automatically:
ParameterValue
Max attempts10
BackoffPolynomially increasing between attempts
SuccessAny HTTP status code in 200299
FailureAny non-2xx response, timeout, or error
Connect timeout10 seconds
Read timeout30 seconds
After 10 failed attempts, the event is marked failed and no further attempts are made. You can see which events failed and inspect the last response on the Webhooks page; there is no manual retry button today.

Handling events

Respond quickly

Return a 2xx response as soon as possible. Don’t do heavy work inside the request handler — enqueue the payload for background processing and acknowledge immediately. A slow handler risks hitting the 30-second read timeout and being retried as a failure.

Be idempotent

Because Champ retries until it gets a 2xx, the same payload can arrive more than once. Deduplicate on data.workflow_run.id plus event (a run could fire both completed and failed in rare recovery cases — treat them as distinct keys).

Switch on event type

app.post("/webhooks/champ", async (req, res) => {
  const { event, data } = req.body;
  const run = data.workflow_run;

  // Acknowledge fast; do the real work asynchronously.
  res.sendStatus(200);

  await queue.enqueue({ event, run });
});

Filter by workflow

Subscriptions are tenant-wide. If you only care about specific workflows, filter by data.workflow_run.workflow_id inside your handler rather than trying to scope the subscription itself.