Trawl guides
04 · Webhooks

Results pushed to you, not polled.

Add an endpoint once and every job in the workspace reports back when it ends. The same endpoints warn you before your credits run out.

You'll need a workspace with Trawl enabled and an API key that can read and manage Trawl webhooks (trawl.webhook.read, trawl.webhook.manage); 01 · Foundations covers both. If you haven't run a job yet, do 02 · Your first extraction first.


1

The three events

Webhooks belong to the workspace: an endpoint receives the events it subscribes to from every job in it.

  • job.succeeded — a job finished and its result matches your JSON Schema. The result is in data.job.result.
  • job.failed — a job stopped without a result: the page did not load, it ran out of steps or time, or the result did not match your schema. The reason is in data.job.error. A cancelled job sends nothing.
  • credits.low — your balance dropped below 10% of your last top-up (at least 100 steps). Sent once, and again only after your next top-up. Section 4 has the details.

The webhook is a notification, not the record. The result also stays on the job (GET /v1/workspaces/:workspace_id/jobs/:id), so a missed delivery never loses data. The list of events, with a description and an example payload for each, is served by the API:

GET /v1/workspaces/:workspace_id/webhooks/event-types
curl https://api.trawl.productcraft.co/v1/workspaces/<workspace_id>/webhooks/event-types \
  -H 'authorization: Bearer pcft_live_...'

2

Add an endpoint

From the console (Trawl → Webhooks) or the API. Endpoints, signatures, tests, retries and replay work the same in every ProductCraft product.

POST /v1/workspaces/:workspace_id/webhooks/endpoints
curl -X POST https://api.trawl.productcraft.co/v1/workspaces/<workspace_id>/webhooks/endpoints \
  -H 'authorization: Bearer pcft_live_...' \
  -H 'idempotency-key: add-results-endpoint-1' \
  -H 'content-type: application/json' \
  -d '{
    "url":         "https://hooks.acme.com/webhooks/trawl",
    "event_types": ["job.succeeded", "job.failed"]
  }'

The answer carries the whsec_… signing secret exactly once. There is nothing to attach to a job: every job in the workspace reports to every endpoint subscribed to its event. An endpoint for results can leave out credits.low, and one for billing alerts can take only that.

Verifying the signature, Send test, automatic retries, auto-disable, the event log, replay and secret rotation are in the Webhooks guide, with Node code you can paste. Trawl expects a 2xx within 15 seconds; the result also stays on the job (GET /v1/workspaces/:workspace_id/jobs/:id), so a missed delivery never loses data.


3

What a job event looks like

Signed with Standard Webhooks like every ProductCraft event; the job is in data.job.

job.succeeded
{
  "id":           "evt_83cfc794-78e9-4102-96de-3a9a6f5bc31e",
  "type":         "job.succeeded",
  "created_at":   "2026-10-17T10:00:00.000Z",
  "workspace_id": "24fab978-7cd7-48ae-bce1-aba876b11957",
  "data": {
    "job": {
      "id":     "7c1e2a4b-5d3f-4e8a-9b6c-0d1e2f3a4b5c",
      "status": "succeeded",
      "result": { "title": "Example Domain", "price": null },
      "error":  null
    }
  }
}

Set up before 17 October 2026? Endpoints that existed then, or that are created through the older POST .../webhooks route, keep working as they did: they receive job.succeeded and job.failed only for the jobs that name them in webhook_id. Until 15 January 2027 they also get the old x-trawl-signature header plus x-trawl-event and x-trawl-event-id, and the body still carries the old top-level event, occurred_at and job fields: read type and data.job before then. x-trawl-delivery-attempt is no longer sent; dedupe on webhook-id. To receive every job without naming it, add a new endpoint; you can then stop sending webhook_id on job create. The Webhooks guide covers the old header and moving your verifier.


4

Hear about a low balance before jobs stop

New jobs are refused (402) when the balance reaches zero. credits.low gives you time to top up first.

credits.low
{
  "id":           "evt_1f0b9c2e-6a7d-4c3b-8e5f-2a1b0c9d8e7f",
  "type":         "credits.low",
  "created_at":   "2026-10-17T10:00:00.000Z",
  "workspace_id": "24fab978-7cd7-48ae-bce1-aba876b11957",
  "data": {
    "balance_steps":     840,
    "threshold_steps":   1000,
    "last_top_up_steps": 10000
  }
}

The line is 10% of your last top-up, and never under 100 steps. The event is sent once, by the job whose usage takes the balance under the line; it comes again only after your next top-up. The same answer is on the credits endpoint, for a dashboard banner of your own:

GET /v1/workspaces/:workspace_id/credits
curl https://api.trawl.productcraft.co/v1/workspaces/<workspace_id>/credits \
  -H 'authorization: Bearer pcft_live_...'

{
  "balance_steps":               840,
  "low_balance":                 true,
  "low_balance_threshold_steps": 1000,
  "entries": [ ... ]
}