Docs

Webhooks

Use callbackUrl for one job. Use dashboard or REST account endpoints when you need HMAC signatures (Zapier REST Hooks, n8n Trigger). Verify signed POSTs against the raw body — do not parse and re-serialize JSON.

Two different delivery paths. Per-job callbackUrl is HTTPS-only and unsigned. Account endpoints (Dashboard → Webhooks or /v1/webhooks) are HMAC-signed. Do not treat callbackUrl as a signed dashboard webhook.

Per-job callbackUrl (unsigned)

Optional https URL on a generating request (pdf, convert, tools, …). RelayPDF POSTs that job’s result when it finishes. The body is not HMAC-signed. http and private IPs are rejected (url_not_allowed). Failed validation is not billed.

Account endpoints (HMAC)

Register HTTPS URLs in /dashboard/webhooks or over the API. Those POSTs include RelayPDF-Event and RelayPDF-Signature (t=<unix>,v1=<hex HMAC of {t}.{raw_body}). Secret is the signing secret shown once at create — not the API key. Cap 25 endpoints per account.

REST CRUD

Same bearer key as every other write. Not billed. GET never returns secret (secretPrefix only). POST returns secret once. DELETE unsubscribes. events is optional on create (defaults to all).

MethodPathNotes
GET/v1/webhooksList id, url, events, secretPrefix, enabled, createdAt. Secret is never listed.
POST/v1/webhooks{ "url": "https://…", "events": ["job.completed"] }. events optional. 201 with secret once. HTTPS only. Cap 25.
DELETE/v1/webhooks/:idUnsubscribe. 404 if missing or another account’s id.
Create endpoint
curl https://api.relaypdf.com/v1/webhooks \
  -H "Authorization: Bearer pdf_live_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hooks","events":["job.completed"]}'

Events

job.completed, job.failed, wallet.topup, wallet.auto_reload, wallet.auto_reload_failed, wallet.payment_required. Filter with events on create; omit to receive all.

Clients

Node client.webhooks.list/create/delete, Python client.webhooks.list/create/delete, CLI relaypdf webhooks list|create|delete, MCP webhooks_list / webhooks_create / webhooks_delete. If a published package is missing the methods, call REST until you upgrade.

Verify in Node

Secret is the webhook signing secret, not the API key.

verifyWebhook
import { verifyWebhook } from "@relaypdf/sdk";

const ok = await verifyWebhook(secret, rawBody, request.headers.get("RelayPDF-Signature") ?? "");