Skip to content

Integration guides

Webhooks

Updated

Push delivery for async enrichment results. Use when you already run a public HTTPS receiver and prefer a push model.

Introduction

Webhooks deliver async enrichment results to a public HTTPS URL you operate. Use them when you already operate a public HTTPS receiver and prefer a push model.

For most use cases, polling is faster to integrate and equally cost-effective. Same endpoints, same data, same enrichment cost. See the Polling guide to compare both side by side.

How it works

Async endpoints work in the background so your application doesn't have to wait. The API accepts your request immediately, processes it, and delivers the result to your server as soon as it's ready.

This is what happens step by step:

  1. You send a request. Call any async endpoint (e.g. POST /v2/fetch/persons/live).
  2. The API confirms instantly. You get back a webhookId that uniquely identifies this request. Use it to match incoming callbacks back to your original request.
  3. Processing happens in the background. The API fetches and prepares the data for you.
  4. The result is delivered to you. As soon as the data is ready, the API sends a POST request to your webhook URL with the full JSON payload.

The delivery POST to your webhook URL does not count toward the per-minute rate limit. The request that creates the async job does count. See Rate limits & credits for the full rate-limit rules.

Async endpoints

All of these endpoints deliver results via webhook:

Endpoint
Profiles
Person Profile LivePOST /v2/fetch/persons/live
Company Profile LivePOST /v2/fetch/companies/live
Contact
Email FinderPOST /v2/contact/email

1. Configure your webhook URL

Set a single HTTPS URL at workspace level so all async results are delivered automatically. No need to include webhookUrl in every request.

  1. Go to Settings > Webhooks
  2. Enter your HTTPS endpoint URL
  3. Click Save
  4. Click Test to send a test payload and verify connectivity

Per-request webhook URL override (optional)

Include a webhookUrl field in your request body to override the delivery target for a single request. This is the fastest way to test locally with a tunnel like ngrok:

Bash

Local tunnel

ngrok http 3000

Then use the forwarding URL in your request:

JSON

Request body

{
  "url": "https://social.com/in/janedoe",
  "webhookUrl": "https://a1b2c3d4.ngrok-free.app/webhooks/reversecontact"
}

If no webhook URL is available (neither in the request body nor in workspace settings), the API returns 422 immediately:

JSON

422 WEBHOOK_URL_REQUIRED

{
  "success": false,
  "data": null,
  "error": {
    "code": "WEBHOOK_URL_REQUIRED",
    "message": "A webhook URL is required to receive results. Either provide a \"webhookUrl\" in the request body, or configure a default webhook URL in your workspace settings."
  }
}

No credits are consumed. Configure a default URL in Settings > Webhooks or include webhookUrl in your request body.

2. Set up a receiver

A webhook receiver is a standard POST endpoint that accepts JSON and returns 200. That's it.

const express = require("express");
const app = express();

app.use(express.json());

app.post("/webhooks/reversecontact", (req, res) => {
  const event = req.body;
  console.log("Webhook received:", event.webhookId);

  if (event.data) {
    // Process the result, e.g. from POST /v2/fetch/persons/live
    console.log("Profile:", event.data.firstName, event.data.lastName);
  }

  // Always respond with 200 to acknowledge receipt
  res.status(200).json({ received: true });
});

app.listen(3000, () => console.log("Listening on port 3000"));

Webhook payload

Error callback

When something goes wrong, you receive a callback with an errorCode inside data describing the issue. The original input fields are echoed back alongside the error code:

JSON

Error callback

{
  "webhookId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "errorCode": "..."
}

Result callback

When the job completes successfully, the callback carries the requested data in data:

JSON

Result callback

{
  "webhookId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "data": {
    "...": "endpoint-specific result payload"
  }
}

Enrichment error codes

These codes describe the enrichment outcome and arrive as data.errorCode in the callback:

CodeDescription
invalid-requestThe request input is malformed or doesn't match the expected format
data-not-foundNo matching result was found
person-not-foundThe person profile doesn't exist
company-not-foundThe company profile doesn't exist
email-not-foundNo email could be resolved for this person
fetch-data-errorThe API failed while fetching data. Safe to retry
result-unavailableThe enrichment completed but the result was lost on our side. Retry the job. If the request was charged, contact support to get the credit back.

Delivery error codes

These codes mean the enrichment was fetched successfully but the result could not be pushed to your webhook URL. The job is reported as succeeded, the result is still available, and the failed push is named by a deliveryStatus field (set to one of the codes below) on the poll and check_task responses.

CodeBilledDescription
webhook-url-invalidYesYour webhook returned a 4xx response
webhook-url-erroredYesYour webhook returned a 5xx or a network error
webhook-url-timeoutYesYour webhook did not respond in time
webhook-url-unreachableYesThe webhook URL could not be reached from production

Security best practices

  • Use HTTPS. The API rejects plain HTTP URLs for webhook delivery.
  • Validate the payload shape. Every callback contains webhookId + data. Check for errorCode inside data to distinguish errors from results. Ignore anything that doesn't match.
  • Verify the webhookId. Store the webhookId from the initial response and check it against incoming callbacks. This is your correlation and validation key.
  • Respond quickly. Return a 200 status code promptly. If you need to do heavy processing, acknowledge receipt first and process asynchronously.

Dashboard monitoring

The Webhook Events page in your dashboard gives you full visibility into every webhook delivery:

  • Status distribution. A summary showing succeeded, errored, and in-progress events at a glance.
  • Event log. Each row displays the timestamp, webhookId, status, credits consumed, credits refunded, and error code (if any).
  • Filters. Narrow down events by status, error code, or webhookId to quickly find specific deliveries.

Go to production

Before going live, make sure your webhook integration is solid:

  • Deduplicate on webhookId. In rare cases, a callback may be delivered more than once.
  • Log the webhookId. Include it in your application logs to trace requests end-to-end.
  • Monitor your credits. Credits are deducted when the request is accepted, before the result is delivered. Refundable errors are automatically refunded. See Rate limits & credits for details.

For the full hardening checklist, see Production checklist.

Troubleshooting

Not receiving webhooks

  • Ensure your endpoint is publicly accessible from the internet (not just localhost)
  • If you omitted webhookUrl from the request, verify that a workspace default URL is configured in Settings > Webhooks
  • Verify it accepts POST requests with a Content-Type: application/json body
  • Check your server/firewall logs for incoming requests

Timeout errors

  • Your webhook endpoint must respond within 10 seconds
  • If processing takes longer, return 200 immediately and handle the data asynchronously

Receiving an error or not-found callback instead of data

  • This is expected. The API sends a callback with an errorCode in data when the result is not available (see Error codes)
  • Verify the URL does not require authentication or return redirects

Duplicate deliveries

  • Use the webhookId to deduplicate on your side

Transient errors

  • fetch-data-error is usually transient and safe to retry after a short delay
  • result-unavailable means the enrichment completed but the result was lost on our side. Retry the job. If the request was charged, contact support to get the credit back