Webhooks support two delivery patterns, set with the notification_pattern field when the webhook is created:
result(default) — one delivery per job, fired when the job reaches a terminal state (success or failure).subscription— one delivery for every status change as the job moves through the pipeline.
notification_pattern is set on creation and is read-only afterwards. To change the pattern of an existing webhook, delete it and create a new one.
Setting the pattern
Pass notification_pattern in the create request:
curl -X POST https://api.selfdecode.com/service/health-analysis/b2b-integrations/user-webhook/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"job_type": "report_job",
"callback_url": "https://example.com/webhooks/reports",
"email": "[email protected]",
"notification_pattern": "subscription"
}'
| Field | Required | Notes |
|---|---|---|
job_type | Yes | Read-only after create. One webhook per (user, job_type). |
callback_url | Yes | Must be HTTPS. |
email | Yes | Receives a notice if delivery fails after all retries. |
notification_pattern | No | result or subscription. Defaults to result. Read-only after create. |
Comparison
result (default) | subscription | |
|---|---|---|
| Deliveries per job | 1, on terminal state | 1 per status change |
| Delivers intermediate states | No | Yes |
| Idempotency | Exactly-once (up to retry limit) | At-least-once per change |
| Typical use case | Replace polling for the final result | Real-time progress / pipeline tracking |
Result mode
Default behavior. The webhook fires once when the job reaches a terminal status. Once a delivery has succeeded, no further deliveries are sent for that job, even if the job is updated later.
Subscription mode
The webhook fires every time the job's status changes. The payload is always the current state of the job at delivery time, not the state that triggered the delivery — late retries always carry the freshest values.
A typical report_job will deliver in this order:
waiting_file_processing → file_processed → waiting_report_gen
→ report_generated → waiting_pdf → pdf_generated
A failure path delivers the matching failed_* status instead of advancing.
Status reference
The status field in each delivery comes from the job's status enum. Below are the values for the most common job types.
report_job, pdf_job, ancestry_job, and other PDF-style jobs
report_job, pdf_job, ancestry_job, and other PDF-style jobs| Status | Meaning |
|---|---|
init | Job created |
waiting_file_processing | Waiting on the genome file |
file_processed | Genome file ready |
waiting_report_gen | Report generation in progress |
report_generated | Report ready |
waiting_pdf | PDF generation in progress |
pdf_generated | PDF ready — terminal success |
failed_downloading_file | Terminal failure |
failed_uploading_file | Terminal failure |
failed_file_processing | Terminal failure |
failed_report_gen | Terminal failure |
failed_pdf | Terminal failure |
dna_kit_job
dna_kit_job| Status | Meaning |
|---|---|
shipped | Kit shipped to user |
registered | Kit activated |
received_by_lab | Sample received by lab |
analyzed_by_lab | Sample analyzed |
waiting_reanalysis | Low quality, awaiting reanalysis |
processing_dna_file | Genome file being created |
completed | Terminal success |
failed | Terminal failure |
cancelled | Terminal failure |
For other job types, the status field follows the same enum as report_job unless the OpenAPI schema indicates otherwise.
Payload
The payload shape is the same in both patterns: the job's serialized fields plus job_type. Subscription deliveries are distinguished only by the value of status.
Example mid-pipeline subscription delivery for a report_job:
{
"id": "8a4f…",
"user_id": "1c9d…",
"profile_id": "b210…",
"report_id": "37f1…",
"status": "report_generated",
"created_at": "2026-04-29T10:15:03Z",
"pdf_url": null,
"error": null,
"job_type": "report_job"
}
Headers, signing (X-Hub-Signature-256), retries, the failure email, the recover action, and the reset-secret action are all identical to the standard webhook flow — see the Webhooks Guide.
Handling subscription deliveries
- Match deliveries by
idto track a single job through its lifecycle. - Treat handlers as idempotent. The same status may arrive more than once on retry, and intermediate statuses can, in rare cases, arrive out of order.
- Treat the job as finished when
statusis one of the terminal values listed above (pdf_generated,completed, or anyfailed_*/cancelled).
