What a callback is
A callback is an HTTP request Efflux makes when a job changes state. The same object is accepted on scans, captures, surveys, permutation checks, schedules, and tasks.
{
"callback": {
"start": { "url": "https://example.com/started", "method": "POST" },
"success": { "url": "https://example.com/done/$job_id", "method": "POST" },
"fail": { "callback_id": "whook_abc123" }
}
}| Entry | When it is sent |
|---|---|
start | The job starts |
success | The job completes |
fail | The job fails |
Each entry is either a URL or a saved webhook:
| Field | Notes |
|---|---|
url | Absolute URL. $job_id is replaced with the job id |
method | POST (default) or GET |
callback_id | Id of a webhook. Do not also set url on the same entry |
use_defaults | On the callback object, not on a phase. false skips saved defaults. Omit it to follow preferences |
Callback requests include an efflux-job-id header. When the entry points at a webhook, the delivery is signed. See Webhooks.
Saved defaults
When preferences set callbacks.apply to when_absent, job creation copies a saved phase into any phase the request left empty. Scans, captures, surveys, and permutation checks do this. Tasks do not.
A phase you set wins. The response marks that phase with source request. A phase copied from preferences has source preference.
{ "callback": { "use_defaults": false } }That body copies nothing, including when you send no phases. Omit callback entirely to follow preferences.
A saved webhook that is missing or inactive is skipped for that phase. The job is still created. GET /preferences lists the problem in issues. A webhook you name on the request itself is rejected, and the job is not created.
A schedule stores the callback you put on its target. It does not freeze the preference copy. Each run fills empty phases from the preferences at that moment. If the schedule itself names a callback_id that was deleted or deactivated, that run is not created. The schedule keeps the id.
After you create it
The object you get back adds delivery state on each entry: delivery_id, attempts (time, code, raw, error), and complete.
Scans can replace or restart that configuration after create:
/v3/scans/{job_id}/callbackReplace the callback on a scan
/v3/scans/{job_id}/callback/restartRestart callback delivery
Those two routes return the callback object.
Delivery history
Every outbound callback, inline URL or saved webhook, is a delivery you can list and retry.
/v3/callback-deliveriesList deliveries
/v3/callback-deliveries/{delivery_id}Get one delivery
/v3/callback-deliveries/{delivery_id}/retryRetry a failed delivery
Filters on the list: state, webhook_id, inline (deliveries that used a URL instead of a saved webhook), and event. Page size defaults to 20 (max 200).
| Field | Notes |
|---|---|
delivery_id | Id used to fetch or retry |
state | pending, delivered, failed, or canceled |
event | Event name, also sent as Efflux-Event |
source | kind, resource_id, and phase (start, success, fail, event, or digest) |
webhook_id | Set when the callback targeted a saved webhook |
url, method | Set for an inline URL |
payload | Body that was sent |
attempt_count, attempts | What happened on each try |
Retry is accepted only when state is failed.
curl -sS "https://api.efflux.io/v3/callback-deliveries?state=failed&limit=20" \
-H "Authorization: Bearer $EFFLUX_TOKEN"