Skip to main content

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:
SourceTriggerPayload
Async-job webhookPass webhook_url in the body of an async endpointJob result envelope
Workflow outgoing_webhook blockAdd the block to a workflowWorkflow run envelope with results
Headers, signing, retry behavior, and verification are identical for both sources — only the payload shape differs.

Source 1: Async-job webhooks

All async enrichment endpoints accept an optional webhook_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

EndpointDescription
/find-email-asyncSingle email enrichment
/find-phone-asyncSingle phone enrichment
/find-email-bulk-asyncBulk email enrichment (up to 100 leads)
/find-phone-bulk-asyncBulk phone enrichment (up to 100 leads)
/people-intelligence-asyncPeople intelligence
/company-intelligence-asyncCompany intelligence
/research-agent-asyncResearch agent
/qa-agent-asyncQA agent evaluation

Request

Add the optional webhook_url parameter to your async request:
POST /find-email-async
{
  "lead": {
    "name": "John Doe",
    "company": "Acme Inc",
    "linkedin_url": "https://linkedin.com/in/johndoe"
  },
  "webhook_url": "https://your-server.com/webhooks/sixtyfour"
}
The async endpoint immediately returns a task_id:
{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending"
}

Payload — successful job

{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "task_type": "find_email",
  "result": {
    "name": "John Doe",
    "company": "Acme Inc",
    "email": [["john.doe@acme.com", "OK"]]
  }
}

Payload — failed job

{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "task_type": "find_email",
  "error": "Error message describing what went wrong"
}

Payload fields

FieldTypeDescription
task_idstringUnique identifier for the job.
statusstringEither "completed" or "failed".
task_typestringType of job (e.g., find_email, enrich_lead, find_phone_bulk).
resultobjectJob result data (only present when status is "completed").
errorstringError 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

FieldTypeDefaultDescription
urlstringrequiredDestination URL. Validated against SSRF rules — must be a public host.
headersobjectnoneOptional HTTP headers to include in the request. Header names are sanitized (CR/LF stripped).
timeout_secondsfloat10Per-attempt request timeout. Range 0 < x ≤ 300. Internally capped at 150s to fit the activity heartbeat window.
include_csv_download_linkbooleanfalseIf true, waits up to 120s for the previous block’s CSV result and includes a signed results_download_url in the payload.
The block also adds three columns to the workflow output dataset: webhook_status_code, webhook_response, and webhook_success.

Payload envelope

{
  "event_id": "f7c2a4e0-9b5d-4a1f-8d2c-1e3b5f7a9c0d",
  "event": "outgoing_webhook.completed",
  "status": "success",
  "workflow_id": "wf_abc123",
  "run_id": "run_xyz789",
  "organization_id": "org_456",
  "row_count": 95,
  "previous_block_id": "blk_2",
  "previous_block_name": "lead_enrichment",
  "previous_block_number": 2,
  "completed_at": "2026-04-22T20:00:00Z",
  "duration_ms": 1234,
  "attempt": 1,
  "results_download_url": "https://...signed-csv-url...",
  "results": [
    { "name": "John Doe", "email": "john@acme.com" }
  ]
}

Payload fields

FieldTypeDescription
event_idstring (UUID)Unique per delivery. Use as your dedupe key — same as the Sixtyfour-Event-Id header.
eventstringAlways outgoing_webhook.completed.
statusstringAlways success for a delivered webhook. Failure is signaled by HTTP status, not this field.
workflow_idstringThe workflow definition ID.
run_idstringThe specific run ID.
organization_idstringYour organization ID.
row_countintegerNumber of rows in the result.
previous_block_idstringID of the block immediately before the webhook block.
previous_block_namestringBlock type of the previous block (e.g. lead_enrichment).
previous_block_numberintegerSequence number of the previous block.
completed_atstring (ISO 8601 Z)When the webhook was sent.
duration_msintegerHow long the webhook block took.
attemptintegerDelivery attempt counter (starts at 1, increments on retry).
results_download_urlstring | nullSigned CSV download URL when include_csv_download_link=true. Expires per signing policy.
resultsarray | nullInline 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:
HeaderValue
Sixtyfour-Signaturet=<unix_seconds>,v1=<hex>[,v1=<hex>]
Sixtyfour-Event-IdUUID per delivery — use as your dedupe key
Sixtyfour-Event-TypeRouting hint (e.g., find_email, outgoing_webhook.completed)
Sixtyfour-Delivery-AttemptAttempt counter starting at 1; increments on each retry
Until you create a signing secret, deliveries are sent unsigned for backward compatibility.

Signing and verification

One signing secret per organization covers all outgoing webhook traffic — async-job webhooks and outgoing_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:
SettingValue
AttemptsUp to 5 retries
Backoff1s, 2s, 4s, 8s, 16s between attempts
Timeout10 seconds per attempt (async-job webhooks); configurable per outgoing_webhook block via timeout_seconds
If all retries fail, the webhook is marked as undelivered. The job or workflow itself remains successful and results can still be retrieved via the polling endpoints.

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_webhook block enforces this through its URL validation.
  • Match incoming deliveries against the task_id or run_id you 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
For async jobs:
GET /job-status/{task_id}
For workflow runs, see the status and download endpoints in Workflow Execution.