Use Case
Sixtyfour POSTs to your URL when work completes — so you can react in real time instead of polling. Outgoing webhooks come from two sources, both delivered through the same signed, retried HTTP pipeline:| Source | Trigger | Payload |
|---|---|---|
| Async-job webhook | Pass webhook_url in the body of an async endpoint | Job result envelope |
Workflow outgoing_webhook block | Add the block to a workflow | Workflow run envelope with results |
Source 1: Async-job webhooks
All async enrichment endpoints accept an optionalwebhook_url parameter. When the job finishes, Sixtyfour POSTs the result to that URL instead of requiring you to poll /job-status/{task_id}.
Supported endpoints
| Endpoint | Description |
|---|---|
/find-email-async | Single email enrichment |
/find-phone-async | Single phone enrichment |
/find-email-bulk-async | Bulk email enrichment (up to 100 leads) |
/find-phone-bulk-async | Bulk phone enrichment (up to 100 leads) |
/people-intelligence-async | People intelligence |
/company-intelligence-async | Company intelligence |
/research-agent-async | Research agent |
/qa-agent-async | QA agent evaluation |
Request
Add the optionalwebhook_url parameter to your async request:
task_id:
Payload — successful job
Payload — failed job
Payload fields
| Field | Type | Description |
|---|---|---|
task_id | string | Unique identifier for the job. |
status | string | Either "completed" or "failed". |
task_type | string | Type of job (e.g., find_email, enrich_lead, find_phone_bulk). |
result | object | Job result data (only present when status is "completed"). |
error | string | Error message (only present when status is "failed"). |
Source 2: Workflow outgoing_webhook block
Add an outgoing_webhook block to a workflow to POST the full run result to an external URL when the workflow completes. One request per workflow run, not per row.
Block specs
| Field | Type | Default | Description |
|---|---|---|---|
url | string | required | Destination URL. Validated against SSRF rules — must be a public host. |
headers | object | none | Optional HTTP headers to include in the request. Header names are sanitized (CR/LF stripped). |
timeout_seconds | float | 10 | Per-attempt request timeout. Range 0 < x ≤ 300. Internally capped at 150s to fit the activity heartbeat window. |
include_csv_download_link | boolean | false | If true, waits up to 120s for the previous block’s CSV result and includes a signed results_download_url in the payload. |
webhook_status_code, webhook_response, and webhook_success.
Payload envelope
Payload fields
| Field | Type | Description |
|---|---|---|
event_id | string (UUID) | Unique per delivery. Use as your dedupe key — same as the Sixtyfour-Event-Id header. |
event | string | Always outgoing_webhook.completed. |
status | string | Always success for a delivered webhook. Failure is signaled by HTTP status, not this field. |
workflow_id | string | The workflow definition ID. |
run_id | string | The specific run ID. |
organization_id | string | Your organization ID. |
row_count | integer | Number of rows in the result. |
previous_block_id | string | ID of the block immediately before the webhook block. |
previous_block_name | string | Block type of the previous block (e.g. lead_enrichment). |
previous_block_number | integer | Sequence number of the previous block. |
completed_at | string (ISO 8601 Z) | When the webhook was sent. |
duration_ms | integer | How long the webhook block took. |
attempt | integer | Delivery attempt counter (starts at 1, increments on retry). |
results_download_url | string | null | Signed CSV download URL when include_csv_download_link=true. Expires per signing policy. |
results | array | null | Inline result rows. Present when the result is small enough to embed; otherwise null and results_download_url carries the data. |
Shared delivery infrastructure
Everything below applies to both sources above.Headers
When your org has a signing secret configured, every delivery includes:| Header | Value |
|---|---|
Sixtyfour-Signature | t=<unix_seconds>,v1=<hex>[,v1=<hex>] |
Sixtyfour-Event-Id | UUID per delivery — use as your dedupe key |
Sixtyfour-Event-Type | Routing hint (e.g., find_email, outgoing_webhook.completed) |
Sixtyfour-Delivery-Attempt | Attempt counter starting at 1; increments on each retry |
Signing and verification
One signing secret per organization covers all outgoing webhook traffic — async-job webhooks andoutgoing_webhook blocks alike. Generate it in the dashboard at Settings → API Keys → Webhooks.
See Signing Secrets & Verification for the full HMAC-SHA256 verification algorithm, working Python (Flask) and Node.js (Express) code samples, rotation behavior, and fail-closed semantics.
Retry behavior
If your endpoint is unavailable or returns a non-2xx status code, we retry delivery with exponential backoff:| Setting | Value |
|---|---|
| Attempts | Up to 5 retries |
| Backoff | 1s, 2s, 4s, 8s, 16s between attempts |
| Timeout | 10 seconds per attempt (async-job webhooks); configurable per outgoing_webhook block via timeout_seconds |
Best practices
- Return a 2xx status code within 10 seconds. Process the payload asynchronously if needed — returning non-2xx triggers retries even for events you intend to ignore.
- Dedupe with
Sixtyfour-Event-Id. Retries can cause the same event to arrive more than once, so treat the event ID as your idempotency key. - Use HTTPS endpoints for payload security. The
outgoing_webhookblock enforces this through its URL validation. - Match incoming deliveries against the
task_idorrun_idyou initiated and drop unexpected payloads silently with a 2xx response.
Fallback: polling
Webhooks are optional. You can always poll for results if:- Your infrastructure doesn’t support inbound webhooks
- Webhook delivery fails after all retries
- You need to retrieve results at a later time