Webhook paziņojumu saņemšana
Webhook paziņojums informē jūsu sistēmu par izmaiņu Sursā, tiklīdz tā notiek: kartīte ir publicēta, pārbaudīta vai
arhivēta, uz jautājumu nav atbildes. Sursa nosūta HTTPS POST ar notikumu uz jūsu reģistrētu adresi. Šajā ceļvedī
tiek izveidots saņēmējs, kas darbojas pareizi arī atkārtojumu, mainītas secības un dublikātu gadījumā.
Ko katrs notikums nozīmē un satur, sk. webhook paziņojumu pārskatā un notikumu katalogā API rokasgrāmatā.
1. Reģistrējiet galapunktu
Administrators reģistrē galapunktus Sursā sadaļā Administration → Integrations → Webhooks and API (administrēšana,
integrācijas, webhook paziņojumi un API) vai ar POST /v1/webhooks un atslēgu
ar lomu admin un tvērumu webhooks:manage:
curl -X POST https://api.sursa.com/v1/webhooks \
-H "Authorization: Bearer $SURSA_ADMIN_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/sursa",
"description": "Sync verified cards to the help center",
"events": ["card.published", "card.updated", "card.verified", "card.archived"]
}'Atbildē parakstīšanas noslēpums ir laukā secret, un tas sākas ar whsec_. Tas tiek parādīts vienreiz.
Glabājiet to kopā ar savu saņēmēju, piemēram, vides mainīgajā SURSA_WEBHOOK_SECRET.
Adresei jāizmanto https un jāatrisinās uz publiskām IP adresēm: adreses privātos, atgriezeniskās cilpas (loopback)
un citos rezervētos tīklos tiek noraidītas gan reģistrējot, gan katrā piegādē. Lai izstrādātu savā datorā, padariet
lokālo saņēmēju pieejamu caur tunelēšanas pakalpojumu, kas tam piešķir publisku HTTPS adresi.
Testa notikumu jebkurā laikā var nosūtīt ar POST /v1/webhooks/{webhook_id}/test.
Atbilde parāda, ko atbildēja jūsu saņēmējs.
2. Kā izskatās piegāde
POST /sursa HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
webhook-id: evt_0123456789abcdef0123456789abcdef
webhook-timestamp: 1791194400
webhook-signature: v1,l1LLl/aEl4dQq7Geb383KbyNeZgs7VZpiw6iuoJgunI=
X-KB-Signature: t=1791194400,v1=82aa6b27378d89d7d880d17c3fe96268598443ae0e64d059c0c41e94e5d3ffbe
X-KB-Event-Id: evt_0123456789abcdef0123456789abcdef
X-KB-Event: card.verified
X-KB-Delivery: 99812
X-KB-Attempt: 1
X-KB-Sequence: 1042
{"id":"evt_0123456789abcdef0123456789abcdef","type":"card.verified","created_at":"2026-10-05T10:00:00Z","org_id":1,"api_version":"1.60.0","sequence":1042,"object":{"type":"card","id":"c1"},"payload":"full","data":{"card":{"id":"c1"}},"test":false}
| Galvene | Nozīme |
|---|---|
webhook-id | Notikuma ID. Tas pats katrā atkārtojumā. Izmantojiet to dublikātu atmešanai. |
webhook-timestamp | Kad šis mēģinājums parakstīts, Unix sekundēs. |
webhook-signature | Paraksts Standard Webhooks formātā. |
X-KB-Signature | Tā pati piegāde, parakstīta agrākajā Sursas formātā. |
X-KB-Event | Notikuma tips. |
X-KB-Attempt | Mēģinājuma numurs, sākot no 1. |
X-KB-Sequence | Šīs piegādes pozīcija galapunkta secībā. |
Galveņu nosaukumos lielie un mazie burti netiek šķiroti; jūsu ietvars tos var rādīt kā X-Kb-Signature vai
x-kb-signature.
Saturs ir notikums. Tā data ir atkarīgs no tipa. Galapunkts ar satura režīmu thin saņem notikumu bez data; tā
vietā nolasiet objektu caur API ar savu atslēgu.
3. Pārbaudiet parakstu
Pirms uzticaties piegādei, pārbaudiet tās parakstu. Abi formāti paraksta precīzus satura baitus, tāpēc nolasiet neapstrādāto saturu (raw body) pirms jebkādas JSON parsēšanas: atkārtota JSON serializēšana maina baitus, un paraksta pārbaude neizdodas.
| Formāts | Parakstītā virkne | Atslēga | Paraksts |
|---|---|---|---|
Standard Webhooks (webhook-signature) | <webhook-id>.<webhook-timestamp>.<body> | Noslēpuma daļa aiz whsec_, dekodēta no base64 | v1, + HMAC-SHA256 base64 formā |
Agrākais formāts (X-KB-Signature) | <t>.<body> | Visa noslēpuma virkne kā teksts | v1= + HMAC-SHA256 heksadecimālā formā |
Pietiek pārbaudīt vienu no abiem parakstiem. Dodiet priekšroku galvenei Standard Webhooks: tāda pati pārbaude ir
pieejama daudzās gatavās bibliotēkās. Noslēpuma rotācijas laikā katrā galvenē ir pa vienam parakstam katram derīgajam
noslēpumam (webhook-signature – atdalīti ar atstarpi, X-KB-Signature – atkārtots v1=). Piegāde ir derīga, ja
sakrīt jebkurš no tiem.
Noraidiet arī laika zīmogu, kas no jūsu pulksteņa atšķiras vairāk nekā par 5 minūtēm. Tas neļauj kādam vēlāk atkārtoti nosūtīt ierakstītu piegādi.
# Check a saved delivery by hand: body.json holds the raw body, the values come from its headers.
SECRET="whsec_…"; WEBHOOK_ID="evt_…"; TIMESTAMP="1791194400"
# Standard Webhooks: compare with the value after "v1," in webhook-signature
KEY=$(printf '%s' "${SECRET#whsec_}" | tr '_-' '/+')
while [ $(( ${#KEY} % 4 )) -ne 0 ]; do KEY="$KEY="; done
KEY_HEX=$(printf '%s' "$KEY" | openssl base64 -d -A | xxd -p | tr -d '\n')
{ printf '%s.%s.' "$WEBHOOK_ID" "$TIMESTAMP"; cat body.json; } \
| openssl dgst -sha256 -mac HMAC -macopt "hexkey:$KEY_HEX" -binary | openssl base64 -A
# Earlier format: compare with the value after "v1=" in X-KB-Signature
{ printf '%s.' "$TIMESTAMP"; cat body.json; } | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1Izmēģiniet paraksta pārbaudes kodu
Pirms pieslēdzat kodu reālām piegādēm, palaidiet to ar šīm vērtībām. Ja pulkstenis iestatīts uz laika zīmogu, abām pārbaudēm jāizdodas, bet, mainot vienu satura baitu, tām jāneizdodas.
| Ievade | Vērtība |
|---|---|
| Noslēpums | whsec_test_secret_0123456789abcdef |
webhook-id | evt_0123456789abcdef0123456789abcdef |
webhook-timestamp un t | 1791194400 |
| Saturs | {"id":"evt_0123456789abcdef0123456789abcdef","type":"card.verified","created_at":"2026-10-05T10:00:00Z","org_id":1,"data":{"card":{"id":"c1"}}} |
webhook-signature | v1,+xxWSXH6weQJ/MVg4+N78a1Dj4y/AQ4p94+PRNzpECg= |
X-KB-Signature | t=1791194400,v1=ce26a19cb63cd3ae620217bf7688e1df1044fa7d59d9ae148d215f0292b768dc |
4. Atbildiet ātri, darbu dariet pēc tam
Sursa gaida jūsu atbildi līdz 10 sekundēm. Jebkurš 2xx statuss nozīmē, ka piegāde izdevās; jebkas cits, arī
novirzīšana, noildze vai slēgts savienojums, nozīmē, ka tā neizdevās un tiks atkārtota.
Tāpēc saņēmējam jāpārbauda paraksts, jāsaglabā notikums un jāatbild – nekas vairāk. Īsto darbu dariet pēc tam no savas rindas.
// Node.js 20+, no framework. verifyStandard and verifyLegacy come from step 3.
import http from "node:http";
const SECRET = process.env.SURSA_WEBHOOK_SECRET;
http
.createServer(async (req, res) => {
const parts = [];
for await (const part of req) parts.push(part);
const body = Buffer.concat(parts); // the raw bytes, before any JSON parsing
const valid = req.headers["webhook-signature"]
? verifyStandard(SECRET, req.headers, body)
: verifyLegacy(SECRET, req.headers["x-kb-signature"], body);
if (!valid) {
res.writeHead(400).end();
return;
}
const event = JSON.parse(body);
await saveEventOnce(event); // insert into your table or queue, keyed by event.id; ignore a duplicate
res.writeHead(204).end();
})
.listen(3000);Atbildiet ar 2xx tikai pēc tam, kad notikums ir droši saglabāts. Ja vispirms atbildēsiet un tad process avarēs,
notikums jums būs zudis, jo Sursa to jau ir ieskaitījusi kā piegādātu.
5. Atkārtojumi
Neizdevusies piegāde tiek atkārtota ar pieaugošām pauzēm: pēc aptuveni 1 minūtes, 5 minūtēm, 30 minūtēm, 2 stundām, 5 stundām, 10 stundām, 24 stundām un 24 stundām – deviņi mēģinājumi gandrīz trīs dienu laikā. Katra pauze var atšķirties līdz 20 %, lai daudzu galapunktu atkārtojumi nepienāktu vienā brīdī.
- Atbilde
429vai503arRetry-Afterpārceļ nākamo mēģinājumu vismaz uz šo laiku, bet ne vēlāk kā par 24 stundām. Izmantojiet to, kad jūsu sistēma ir pārslogota vai notiek apkope. - Atbilde
410 Goneatspējo galapunktu: sūtiet to tikai tad, ja šajā adresē vairs nevēlaties saņemt piegādes. - Pēc 10 neveiksmīgiem mēģinājumiem pēc kārtas galapunkts tiek apturēts, un par to tiek informēti organizācijas
administratori. Notikumi turpina uzkrāties, un, kad galapunkts tiek atsākts administrēšanas saskarnē vai
ar
POST /v1/webhooks/{webhook_id}/resume, tie tiek piegādāti secībā. - Pēc pēdējā mēģinājuma piegāde tiek atzīmēta kā
exhausted. To var nosūtīt vēlreiz manuāli.
Galapunkta piegādes ar katru mēģinājumu, jūsu atbildes kodu un atbildes laiku uzskaita
GET /v1/webhooks/{webhook_id}/deliveries un administrēšanas
saskarne. POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver
nosūta vienu piegādi vēlreiz. Atkārtotai piegādei ir tas pats webhook-id.
6. Secība un dublikāti
- Secība. Piegādes vienam galapunktam notiek stingri cita pēc citas
sequencesecībā. Kamēr viena piegāde tiek atkārtota, vēlākās gaida. Dažādi galapunkti cits uz citu negaida. - Dublikāti. Viens un tas pats notikums var pienākt vairāk nekā vienu reizi, piemēram, ja jūsu atbilde pazuda
atpakaļceļā. Saglabājiet katra apstrādātā notikuma
webhook-id(tas ir arīidsaturā) un izlaidiet notikumu, kuru jau esat redzējuši. - Domājiet stāvokļos. Viena objekta izmaiņām salīdziniet
created_atvaisequencear saglabāto un ignorējiet notikumu, kas ir vecāks par jau zināmo stāvokli. Ja šaubāties, nolasiet pašreizējo objektu caur API: notikums pasaka, ka kaut kas mainījās, bet API pasaka, kāds tas ir tagad.
7. Saskaņojiet ar notikumu plūsmu
Katrs notikums 30 dienas tiek glabāts arī notikumu plūsmā neatkarīgi no tā, vai kāds galapunkts to ir abonējis.
Ja jūsu saņēmējs nedarbojās ilgāk, nekā aptver atkārtojumi, vai vēlaties pārliecināties, ka nekas nav palaists garām,
lasiet plūsmu ar atslēgu, kurai ir loma admin un
tvērums webhooks:manage:
curl -G https://api.sursa.com/v1/webhook-events \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "type=card.*" \
--data-urlencode "created_since=2026-10-20T00:00:00Z" \
--data-urlencode "limit=200"Notikumam plūsmā ir tas pats id un forma kā piegādē, tikai bez piegādes laukiem sequence, payload un test.
Tā kā jūsu saņēmējs izlaiž jau redzētus notikumus, saskaņošanu varat palaist tik bieži, cik vēlaties, piemēram,
reizi stundā.
GET /v1/webhook-events/{event_id} nolasa vienu notikumu pēc tā ID.
8. Nomainiet noslēpumu
POST /v1/webhooks/{webhook_id}/rotate-secret izsniedz jaunu noslēpumu
un saglabā iepriekšējo derīgu pārklāšanās periodā – pēc noklusējuma 24 stundas, ne ilgāk kā 7 dienas. Pārklāšanās
laikā katra piegāde tiek parakstīta ar abiem noslēpumiem.
- Veiciet rotāciju un saglabājiet jauno noslēpumu savā saņēmējā blakus vecajam.
- Pieņemiet piegādi, ja tās paraksts sakrīt ar jebkuru no noslēpumiem.
- Pēc pārklāšanās perioda noņemiet veco noslēpumu.
Ja vecais noslēpums ir noplūdis, izbeidziet pārklāšanos nekavējoties ar
POST /v1/webhooks/{webhook_id}/revoke-previous-secret vai
nomainiet noslēpumu ar "overlap_hours": 0.
Kontrolsaraksts
- Pārbaudiet vienu no parakstiem pēc neapstrādātā satura un pārbaudiet laika zīmogu.
- Saglabājiet notikumu ar atslēgu
webhook-id, tad 10 sekunžu laikā atbildiet ar2xx. - Izlaidiet dublikātus un novecojušus notikumus; ja tas ir svarīgi, nolasiet pašreizējo objektu caur API.
- Atbildiet ar
429vai503unRetry-After, ja vajag, lai Sursa samazina tempu; nekad neatbildiet ar410nejauši. - Izlaidiet notikumu tipus un laukus, kurus nepazīstat.
- Regulāri pēc grafika saskaņojiet datus ar notikumu plūsmu.