Callbacks

Send an HTTPS request when a scan, capture, survey, or permutation starts, finishes, or fails.

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" }
  }
}
EntryWhen it is sent
startThe job starts
successThe job completes
failThe job fails

Each entry is either a URL or a saved webhook:

FieldNotes
urlAbsolute URL. $job_id is replaced with the job id
methodPOST (default) or GET
callback_idId of a webhook. Do not also set url on the same entry
use_defaultsOn 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:

POST/v3/scans/{job_id}/callback

Replace the callback on a scan

PUT/v3/scans/{job_id}/callback/restart

Restart 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.

GET/v3/callback-deliveries

List deliveries

GET/v3/callback-deliveries/{delivery_id}

Get one delivery

POST/v3/callback-deliveries/{delivery_id}/retry

Retry 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).

FieldNotes
delivery_idId used to fetch or retry
statepending, delivered, failed, or canceled
eventEvent name, also sent as Efflux-Event
sourcekind, resource_id, and phase (start, success, fail, event, or digest)
webhook_idSet when the callback targeted a saved webhook
url, methodSet for an inline URL
payloadBody that was sent
attempt_count, attemptsWhat 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"