1. Connect an endpoint
In Settings → Webhooks, add your public HTTPS receiver. Copy the generated signing secret when it is shown, then copy the webhook ID.
2. Select destinations
Pass webhook_ids to choose endpoints for a run. An empty array disables delivery. Omitting it on a workflow run uses the published selection; omitting it on a direct action sends no webhook.
curl --request POST "https://api.uselongrun.app/v1/pdf/html-to-pdf" \
--header "Authorization: Bearer ${API_KEY}" \
--header "Content-Type: application/json" \
--data "$(jq -n --arg WEBHOOK_ID "${WEBHOOK_ID}" '{
"inputs": {
"html": "<h1>Hello</h1>"
},
"webhook_ids": [
$WEBHOOK_ID
]
}')"{
"inputs": {
"html": "<h1>No webhook</h1>"
},
"webhook_ids": []
}3. Verify and acknowledge
Verify X-LongRun-Signature using HMAC-SHA256 over event_id.timestamp. followed by the exact request body bytes. The signature is v1= plus a hexadecimal digest. Use X-LongRun-Event-Id and X-LongRun-Timestamp, reject timestamps over five minutes from your clock, and compare signatures in constant time. In the Node.js example, rawBody must be the original Buffer from the HTTP request, headers must use lowercase keys, and secret is the signing secret from Settings. Reject the request if this returns false; only then parse its JSON.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody, headers, secret) {
const eventId = headers['x-longrun-event-id'];
const timestamp = headers['x-longrun-timestamp'];
const signature = headers['x-longrun-signature'];
if (!Buffer.isBuffer(rawBody) || typeof eventId !== 'string' ||
!/^[a-zA-Z0-9_-]+$/.test(eventId) ||
!Number.isSafeInteger(Number(timestamp)) ||
Math.abs(Date.now() / 1000 - Number(timestamp)) > 300 ||
typeof signature !== 'string' || !/^v1=[a-f0-9]{64}$/.test(signature)) return false;
const expected = 'v1=' + createHmac('sha256', secret)
.update(eventId + '.' + Number(timestamp) + '.')
.update(rawBody).digest('hex');
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}4. Handle retries
Return 2xx promptly and deduplicate by event ID. Initial deliveries allow up to eight attempts. HTTP 408, 429, 5xx and transient delivery failures retry with exponential delays; other rejected HTTP responses fail without automatic retries. A manual retry adds another eight-attempt allowance. A delivery failure does not change the run result. View delivery history in Settings → Webhooks.
5. Check delivery
Submit a sample, then open Settings → Webhooks to inspect its delivery history. Use the returned run id below to check the run independently. Successful processing and successful webhook delivery are separate outcomes.
curl --request GET "https://api.uselongrun.app/v1/runs/${RUN_ID}" \
--header "Authorization: Bearer ${API_KEY}"