Open dashboard

Guides

Webhooks

Receive new signal events at your endpoint the moment they happen — no polling. Configure once in Settings; VeilStrat POSTs outbound with your webhook auth key.

Overview

There is no customer POST /webhooks API. Firehose is outbound only: we POST to your HTTPS URL when a subscribed signal type is written. Delivery is forward-only from the moment you save.

Recommended pattern: webhook + dossier

Use the firehose as a ping (company.id + signalId), then enrich with GET /companies/{id}. Avoid polling large searches.

Set up a webhook

Endpoint URL

HTTPS in production. Locally you may use http://127.0.0.1:8787/… or an ngrok URL.

Authentication key

Generate or paste in Settings → Webhooks. We send Authorization: Bearer <key> on every POST.

Signal types

Select at least one public type (hiring, funding, …).

Test endpoint

Send test must return 2xx within 10s before save. Re-test when URL or key changes.

Owner + Pro only

Only team owners on an active Pro plan can configure webhooks.

Event types

Hiring

hiring
New hiring / role signals from job ingest.

Funding

funding
New funding round signals from Fundup ingest.

Funding + AI

funding_ai
Funding paired with AI hiring activity.

Website AI

web
Website AI activity signals.

Tool adoption

tool
Tooling adoption signals.

Hiring velocity

velocity
Hiring velocity / acceleration signals.

Unsubscribed types are never delivered. Subscribe only to what your handler supports.

Headers & delivery

Headers
POST /your-path HTTP/1.1
Authorization: Bearer <your-webhook-auth-key>
Content-Type: application/json
Accept: application/json

Success

Return 2xx within 10 seconds.

Retries

6 attempts · backoff 1m → 5m → 15m → 1h → 4h

Concurrency

Max 5 concurrent POSTs per team

Queue cap

100 undelivered pending — excess may dead-letter

REST budgets

Firehose does not consume request/record quotas

Payload

POST body: application/json
{
  "eventId": "wh_<signalId>_created_<unix>",
  "type": "hiring",
  "action": "created",
  "occurredAt": "2026-08-20T09:15:00Z",
  "signalId": "<uuid>",
  "company": {
    "id": "<uuid>",
    "name": "Example Co",
    "domain": "example.com",
    "logo": null
  },
  "signal": {
    "label": "Hiring AI SDR roles",
    "confidence": 75,
    "jobTitle": "AI SDR"
  }
}

Field reference

FieldTypeDescription
eventIdstringStable id for dedupe; reused on retries
typestringPublic signal slug (hiring, funding, …)
actionstringUsually created (sometimes updated)
occurredAtstringISO timestamp of the event
signalIdstringUUID of the signal row
companyobjectid, name, domain, logo — use id for dossier
signalobjectType-specific fields (label, confidence, …)

Verifying requests

Compare Authorization: Bearer to your saved webhook auth key using a constant-time compare. Reject missing or wrong values with non-2xx so we retry (or stop after the attempt budget).

Dedupe on eventId — handlers must be idempotent.

Local testing

Receiver
node scripts/firehose-webhook-receiver.mjs \
  --port 8787 \
  --host 127.0.0.1 \
  --secret 'your-webhook-auth-key' \
  --capture-file /tmp/veilstrat-webhook-last.json

Settings Send test works without Inngest. Live delivery after Save requires the Inngest Dev Server locally.

Best practices

  • Return 2xx quickly; do heavy work asynchronously.
  • Store and rotate webhook keys like production secrets.
  • Missed history is not self-serve — contact support for manual replay.
  • Continue with All endpoints and Rate limits.
Webhooks — Pro API — VeilStrat | VeilStrat