Use Case
Receive HTTP notifications when async jobs complete instead of polling. This is useful for production workflows where you need to know when a job is complete without polling the API.
All async endpoints support optional webhook notifications. Instead of polling /job-status/{task_id} to check if your job is complete, you can provide a webhook_url and receive an HTTP POST request when the job finishes.
Supported endpoints
The following async endpoints support webhooks:
| 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) |
/enrich-lead-async | Lead enrichment |
/enrich-company-async | Company enrichment |
/research-agent-async | Research agent |
/qa-agent-async | QA agent evaluation |
Usage
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"
}
Webhook payload
When your job completes, we send a POST request to your webhook URL with the following JSON 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"]]
}
}
Failed job
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"task_type": "find_email",
"error": "Error message describing what went wrong"
}
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"). |
Retry behavior
If your webhook endpoint is unavailable or returns a non-2xx status code, we retry delivery with exponential backoff:
- Attempts: Up to 5 retries
- Backoff: 1s, 2s, 4s, 8s, 16s between attempts
- Timeout: 10 seconds per attempt
If all retries fail, the webhook is marked as undelivered. The job itself remains successful and results can still be retrieved via /job-status/{task_id}.
Best practices
-
Return 2xx quickly: Your webhook endpoint should return a 2xx status code within 10 seconds. Process the payload asynchronously if needed.
-
Idempotency: Design your webhook handler to be idempotent. While rare, you may receive duplicate deliveries.
-
Use HTTPS: We recommend using HTTPS URLs for webhook endpoints to ensure payload security.
-
Validate task_id: Store the
task_id from your initial request and validate it matches the webhook payload.
Example: Receiving webhooks
Node.js (Express)
app.post('/webhooks/sixtyfour', express.json(), (req, res) => {
const { task_id, status, task_type, result, error } = req.body;
if (status === 'completed') {
console.log(`Job ${task_id} completed:`, result);
// Process the result
} else {
console.error(`Job ${task_id} failed:`, error);
// Handle the error
}
res.status(200).send('OK');
});
Python (Flask)
@app.route('/webhooks/sixtyfour', methods=['POST'])
def handle_webhook():
data = request.json
task_id = data['task_id']
status = data['status']
if status == 'completed':
result = data['result']
# Process the result
else:
error = data['error']
# Handle the error
return 'OK', 200
Fallback: Polling
Webhooks are optional. You can always fall back to polling /job-status/{task_id} if:
- Your infrastructure doesn’t support incoming webhooks
- Webhook delivery fails
- You need to retrieve results at a later time
GET /job-status/{task_id}