Skip to main content
Instead of polling, pass webhook_url on submit and the completed payload is POSTed to it, signed. Omit webhook_url and your account’s default endpoint is used, if one is set (Dashboard → Webhooks); omit it with no default set and nothing is delivered — poll instead.
The endpoint is resolved when the batch is accepted, so changing your default does not retarget a batch already submitted. Results always remain fetchable via GET, so a failed delivery never loses them.
The delivery body is the same SignalsResponse the GET endpoint returns. Deliveries are signed, retried with backoff, and dead-lettered on exhaustion.

Verifying the signature

Every delivery carries an X-TruthFactor-Signature header. Its value is the HMAC-SHA256 of the exact raw request-body bytes, keyed by your account’s webhook signing secret, lowercase hex-encoded and prefixed sha256=:
Recompute the same value over the body you received and compare the two in constant time.
Verify against the raw bytes before you parse or re-serialise the JSON — a re-serialised body will not reproduce the signature.

Test vector

Check your implementation against this before going live:

Managing deliveries

Dashboard → Webhooks is where you set the default endpoint, reveal or rotate the signing secret, and read the delivery log — every attempt for every batch, its response status, when the next retry is due, and which deliveries dead-lettered. A batch you’ve fixed the receiver for can be re-sent from there; the replay is recorded as a further attempt and erases none of the failed ones.
Revealing the secret mints one if your account has none yet, so you can wire verification up before your first delivery. Rotating takes effect immediately — a signature computed with the old secret stops verifying.