> ## Documentation Index
> Fetch the complete documentation index at: https://qodex.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Generic webhook

> Send Qodex run-completion events to any HTTPS endpoint so another system can route, alert, or store the result.

# Generic webhook

Use a generic webhook when you want Qodex run results to flow into your own system.

Common uses include sending results to Microsoft Teams, Discord, PagerDuty, a CI service, an internal dashboard, or a small relay that creates tickets.

## Webhook options

Qodex can send outbound webhooks in two places:

| Option                              | When it fires                           | Best for                                 |
| ----------------------------------- | --------------------------------------- | ---------------------------------------- |
| Schedule webhook                    | After a scheduled run finishes.         | Team notifications and recurring checks. |
| `callback_url` on a trigger request | After a webhook-triggered run finishes. | CI jobs that need a completion callback. |

Both fire once when the run completes.

<Warning>
  Qodex does not retry failed webhook deliveries today. Make your endpoint idempotent, return a 2xx response quickly, and use the run id to fetch details later if needed.
</Warning>

## Schedule webhook

Add a webhook URL to a schedule in **Schedules > Notifications**.

If the URL is not a Slack webhook URL, Qodex sends a generic JSON payload:

```json theme={null}
{
  "event": "test_run_completed",
  "projectName": "Acme Staging",
  "projectSlug": "acme-staging",
  "testRunId": "tr_...",
  "policy": { "id": "pol_...", "name": "Nightly regression" },
  "passed": false,
  "summary": { "total": 42, "passed": 39, "failed": 3 },
  "failedScenarios": [
    { "name": "Cancel order", "status": "fail" }
  ],
  "environment": "staging",
  "durationMs": 86420,
  "runUrl": "https://agents.qodex.ai/p/acme-staging/test-runs/tr_...",
  "timestamp": 1764979286420
}
```

Fields that do not apply to a run are sent as `null` or empty arrays, so consumers can rely on a stable shape.

## Trigger callback URL

When you trigger a run from CI, include `callback_url` in the request body.

```bash theme={null}
curl -X POST https://agents.qodex.ai/api/projects/acme-staging/webhooks/trigger \
  -H "Authorization: Bearer qk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "environment": "staging",
    "tags": ["smoke"],
    "callback_url": "https://ci.example.com/hooks/qodex/abc123"
  }'
```

Qodex responds immediately with a running test id. When the run finishes, Qodex posts a compact callback:

```json theme={null}
{
  "testRunId": "tr_...",
  "status": "passed",
  "total": 42,
  "passed": 42,
  "failed": 0,
  "url": "https://agents.qodex.ai/p/acme-staging/test-runs/tr_..."
}
```

## Securing your endpoint

Outbound payload signing is not currently implemented.

Protect the endpoint with one or more of these controls:

* A long random path token.
* A network allowlist.
* A relay that validates the request before forwarding it.
* Idempotency keyed by `testRunId`.

## Troubleshooting

If your endpoint does not receive a payload:

* Confirm the URL is reachable from the Qodex deployment.
* Confirm the endpoint returns a 2xx response.
* Check whether the schedule's notification rule allows sending for that run.
* Check server logs for webhook delivery failures.

## Next steps

<CardGroup cols={2}>
  <Card title="Run tests via webhook" icon="webhook" href="/run-tests-via-webhook">
    Trigger a run and pass a completion callback.
  </Card>

  <Card title="Run tests on a schedule" icon="clock" href="/run-tests-on-schedule">
    Add a webhook URL to a recurring policy.
  </Card>

  <Card title="Slack" icon="message-square" href="/integrations-slack">
    Use the Slack-formatted version of the same dispatcher.
  </Card>

  <Card title="Integrations" icon="plug" href="/integrations">
    Return to all integrations.
  </Card>
</CardGroup>
