Webhooks

Get notified when an async task completes — preferred for Make / Zapier / n8n / Clay.

Async callbacks task.completed api_key in query (legacy)
Callbacks
Notes
  • Webhooks are optional. If you don’t use them, poll GET /task/{process_id}/status.
  • Enable by passing webhook_url in the original async POST request body.
  • When your endpoint returns 2xx, the event is acknowledged. Non-2xx triggers retries.
  1. Send any async request (Company / Contact / Apollo / etc.)
  2. Include webhook_url in the body
  3. We POST a JSON event when the task completes
  4. You fetch the result using result_url (or /task/{id}/data)
{
  "items": ["ibm", "microsoft"],
  "max": 100,
  "webhook_url": "https://yourapp.com/webhooks/scrupp"
}
The rest of the body depends on the endpoint. Only webhook_url is common.
HTTP 200 OK
Return 2xx fast. Process async on your side.
Don’t do heavy work inside the webhook handler. Store the payload, respond 200, then fetch/process results in background.

Event payload

Sent to your webhook_url when a task completes.
task.completed
{
  "event": "task.completed",
  "process_id": 6666,
  "status": "completed",
  "result_url": "https://api.scrupp.com/api/v1/task/6666/data",
  "meta": {
    "endpoint": "/company/linkedin",
    "external_id": "row_9481",
    "source": "zapier"
  }
}
Always treat meta as optional. It can contain integration-specific values.
GET /task/6666/data?api_key=YOUR_API_KEY
Prefer result_url from the payload if provided. Otherwise build it from process_id.
{
  "event": "task.completed",
  "process_id": 6666,
  "status": "failed",
  "error": "Message (optional)"
}

Retries

If your endpoint is temporarily unavailable, we retry delivery.
Delivery
  • 2xx = acknowledged
  • Non-2xx / timeout = retry with backoff
  • Make sure your webhook handler responds within a few seconds
Best practice
Store the payload → respond 200 → fetch result_url and process in background.

Signature verification

Recommended to verify the webhook origin (HMAC).
HMAC
X-Scrupp-Signature: sha256=<hex>
X-Scrupp-Timestamp: 1735471800
Signature is computed from timestamp + raw body using your shared secret.
base = timestamp + "." + raw_body
expected = HMAC_SHA256(secret, base)
compare expected to signature (constant-time)
Where to find your webhook secret
Your webhook signature/secret is the first API key listed on your settings page.
Replay protection
Reject requests with timestamp older than e.g. 5 minutes.

Examples

Plug webhooks into common automation tools.
Integrations
Make
  1. Custom webhook → copy URL
  2. Pass it as webhook_url in POST
  3. On webhook event → HTTP GET result_url
  4. Map items → Sheets/CRM
Zapier
  1. Trigger: Catch Hook
  2. Use Scrupp async POST with webhook_url
  3. On webhook → GET result_url
  4. Looping → create records
n8n / Clay
  1. Create webhook endpoint
  2. Pass webhook_url
  3. Fetch /task/{id}/data
  4. Store results / enrich further