Know the moment something changes
SapanBase posts a signed JSON event to your endpoint when an article is published or updated, a reader leaves feedback, or a support request comes in or moves.
X-SapanBase-Signature: 5d41402abc4b2a76… X-SapanBase-Timestamp: 1793709236 X-SapanBase-Event-Id: article.published:art_123:v3 { "id": "article.published:art_123:v3", "type": "article.published", "createdAt": "2026-11-03T09:14:00Z", "data": { "id": "art_123", "title": "Invite a teammate" } }
Five events, one shape
Every event has the same envelope: an id, its type, when it happened, and the object in data.
| Event | Sent when |
|---|---|
| article.published | An article goes live. |
| article.updated | A published article is republished with a new version. |
| article.feedback | A reader rates an article helpful or not helpful. |
| support_request.created | A new support request comes in. |
| support_request.updated | A support request changes status, assignee or reply count. |
Check it came from SapanBase
Each delivery is signed with HMAC-SHA256 over the timestamp and the raw body, using your webhook’s signing secret. Compare in constant time, and reject old timestamps to stop replays.
import { createHmac, timingSafeEqual } from 'node:crypto'; const ts = req.headers['x-sapanbase-timestamp']; const sig = req.headers['x-sapanbase-signature']; const expected = createHmac('sha256', secret) .update(`${ts}.${rawBody}`) .digest('hex'); // reject anything older than 5 minutes const age = Date.now() / 1000 - Number(ts); const fresh = Math.abs(age) < 300; const valid = fresh && sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
Built to arrive
Retried with backoff
A failed delivery is retried after 1 minute, 5 minutes, 30 minutes and 2 hours. Every attempt is re-signed with a fresh timestamp.
At least once
An event can arrive more than once. Dedupe on X-SapanBase-Event-Id and you process it exactly once.
10 second timeout
Return a 2xx within 10 seconds. Queue slow work and acknowledge first.
No redirects
Redirects are never followed. Point the webhook at the final HTTPS URL that returns 2xx.
Scoped per knowledge base
Limit article events to the knowledge bases you choose, or receive them from all of them.
A log of every delivery
See each attempt, its response code and any error in Settings, or list them from the API.
Webhook questions
Keep your systems in step.
Join the beta, add an endpoint and get your first signed event. Free for 14 days.
Private beta · Free for 14 days · New spots every week