Webhooks

Subscribe to events, read the delivery format and verify the signature, plus retry behavior and delivery history.

Last updated 2026-10-23

Webhooks send an HTTP notification when a list, a search, enrichment, an import or a monitor changes. They are created and managed through the REST API, failures are retried, and every attempt can be inspected. This page covers subscribing, the request format, signature verification and retries.

Create a subscription

Send a POST /v1/webhooks:

{
  "url": "https://example.com/hooks/renewsell",
  "events": ["item.created", "enrichment.completed", "search.completed"]
}
  • url must be a public HTTP(S) address, not a private network or localhost, and at most 2048 characters.
  • events takes at least 1 and at most 19 values.
  • The response's secret is the signing secret, starts with whsec_, and is returned only this once; store it safely.
  • Manage subscriptions with GET /v1/webhooks, GET /v1/webhooks/{id}, PATCH /v1/webhooks/{id} and DELETE /v1/webhooks/{id}.

Delivery format

Each delivery is a POST with a JSON body:

{
  "id": "event_…",
  "object": "event",
  "type": "item.created",
  "data": {},
  "createdAt": "2026-10-23T08:30:00.000Z"
}

Headers:

HeaderContent
webhook-idEvent id, for de-duplication
webhook-timestampUnix timestamp in seconds
webhook-signaturev1, plus the signature
content-typeapplication/json

Event types

EventWhen it fires
target.createdA Target is created
target.updatedA Target is updated
target.deletedA Target is deleted
search.createdA search is created
search.updatedA draft search is edited
search.completedA search completes
search.canceledA search is canceled
search.failedA search fails
item.createdA result is added to a list
enrichment.completedAn enrichment column finishes one cell
import.createdAn import is created
import.completedAn import completes
import.deletedAn import is deleted
monitor.createdA monitor is created
monitor.updatedA monitor is updated
monitor.deletedA monitor is deleted
monitor.run.createdA monitor run starts
monitor.run.completedA monitor run completes
monitor.run.canceledA monitor run is canceled

Ids in event data, such as Target ids, are opaque strings. Do not rely on their prefix.

Verify the signature

Deliveries follow the Standard Webhooks scheme, so any Standard Webhooks library can verify them. To verify by hand:

  1. Build the signed string: <webhook-id header>.<webhook-timestamp header>.<raw body>.
  2. Take the secret returned at creation, drop the whsec_ prefix and base64-decode the rest. This is the HMAC key.
  3. Compute HMAC-SHA256 of the signed string and encode it as standard base64. Prefix it with v1,.
  4. Compare it with each space-separated value in webhook-signature, and process the request only when one matches.
SECRET="whsec_…"
WEBHOOK_ID="<webhook-id header>"
TIMESTAMP="<webhook-timestamp header>"
BODY="$(cat payload.json)"

KEY="$(printf '%s' "${SECRET#whsec_}" | base64 -d | xxd -p -c 256)"
printf '%s.%s.%s' "$WEBHOOK_ID" "$TIMESTAMP" "$BODY" \
  | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$KEY" -binary \
  | openssl base64 -A

With a library, pass the raw body and the three headers:

import { Webhook } from "standardwebhooks";

const wh = new Webhook(process.env.RENEWSELL_WEBHOOK_SECRET); // "whsec_…"
const event = wh.verify(rawBody, {
  "webhook-id": headers["webhook-id"],
  "webhook-timestamp": headers["webhook-timestamp"],
  "webhook-signature": headers["webhook-signature"],
});

The webhook-id header is the event id, and it is the same value used in the signed string. Also reject requests whose webhook-timestamp is more than a few minutes old.

NOTE

Verify before processing. Drop any request whose signature does not match instead of acting on its body.

Retries

  • A 2xx response is a success and is not retried.
  • A 429, a 5xx or a network error is retried. The delay starts at about 2 seconds and doubles each time, capped at one hour.
  • Any other 4xx is not retried; that delivery is marked failed.
  • Redirects are followed up to 5 times, and every new address is re-checked as a public address.
  • Events are picked up by a background sweep, so a delivery usually arrives within a few minutes.

Inspect deliveries

GET /v1/webhooks/{id}/attempts returns the time, status code, response headers and response body (bounded) of each attempt. Filter with eventType and successful. Each delivery keeps its last 10 attempts.

Related pages