Webhook pranešimų gavimas
Webhook pranešimas jūsų sistemai praneša apie pakeitimą Sursoje, kai tik jis įvyksta: kortelė paskelbta, patikrinta ar
archyvuota, į klausimą neatsakyta. Sursa siunčia HTTPS POST su įvykiu jūsų užregistruotu adresu. Ši instrukcija
parodo, kaip sukurti gavėją, kuris veikia teisingai esant pakartojimams, pakitusiai tvarkai ir dublikatams.
Ką reiškia ir ką turi kiekvienas įvykis, žr. webhook pranešimų apžvalgoje ir API žinyno įvykių kataloge.
1. Užregistruokite galinį tašką
Administratorius registruoja galinius taškus Sursoje, skiltyje Administration → Integrations → Webhooks and API
(administravimas, integracijos, webhook pranešimai ir API), arba operacija
POST /v1/webhooks su raktu, turinčiu vaidmenį admin ir apimtį
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"]
}'Atsake pasirašymo paslaptis pateikiama lauke secret ir prasideda whsec_. Ji parodoma vieną kartą. Laikykite ją
kartu su savo gavėju, pavyzdžiui, aplinkos kintamajame SURSA_WEBHOOK_SECRET.
Adresas turi naudoti https ir būti nukreiptas į viešus IP adresus: privačių, grįžtamojo ryšio (loopback) ir kitų
rezervuotų tinklų adresai atmetami registruojant ir per kiekvieną pristatymą. Kad galėtumėte kurti savo kompiuteryje,
vietinį gavėją paskelbkite per tuneliavimo paslaugą, kuri suteikia jam viešą HTTPS adresą.
Bandomąjį įvykį bet kada išsiųskite operacija POST /v1/webhooks/{webhook_id}/test.
Atsakas parodo, ką atsakė jūsų gavėjas.
2. Kaip atrodo pristatymas
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}
| Antraštė | Reikšmė |
|---|---|
webhook-id | Įvykio ID. Tas pats per kiekvieną pakartojimą. Pagal jį atmeskite dublikatus. |
webhook-timestamp | Kada šis bandymas pasirašytas, Unix sekundėmis. |
webhook-signature | Parašas Standard Webhooks formatu. |
X-KB-Signature | Tas pats pristatymas, pasirašytas ankstesniu Sursos formatu. |
X-KB-Event | Įvykio tipas. |
X-KB-Attempt | Bandymo numeris, nuo 1. |
X-KB-Sequence | Šio pristatymo vieta galinio taško eilėje. |
Antraščių pavadinimuose didžiosios ir mažosios raidės nesiskiria; jūsų karkasas jas gali rodyti kaip X-Kb-Signature
arba x-kb-signature.
Turinys yra įvykis. Jo data priklauso nuo tipo. Galinis taškas su turinio režimu thin gauna įvykį be data; vietoj
to objektą nuskaitykite per API savo raktu.
3. Patikrinkite parašą
Prieš pasitikint kiekvienu pristatymu, patikrinkite jo parašą. Abu formatai pasirašo tikslius turinio baitus, todėl neapdorotą turinį nuskaitykite prieš bet kokią JSON analizę: iš naujo serializuotas JSON turi kitus baitus, ir patikra nepavyksta.
| Formatas | Pasirašoma eilutė | Raktas | Parašas |
|---|---|---|---|
Standard Webhooks (webhook-signature) | <webhook-id>.<webhook-timestamp>.<body> | Paslapties dalis po whsec_, iškoduota iš base64 | v1, + HMAC-SHA256 base64 forma |
Ankstesnis formatas (X-KB-Signature) | <t>.<body> | Visa paslapties eilutė kaip tekstas | v1= + HMAC-SHA256 šešioliktainė forma |
Pakanka patikrinti bet kurį iš jų. Rinkitės Standard Webhooks antraštę: ta pati patikra yra daugelyje paruoštų
bibliotekų. Paslapties rotacijos metu kiekvienoje antraštėje yra po vieną parašą kiekvienai galiojančiai paslapčiai
(webhook-signature – atskirti tarpais, X-KB-Signature – pasikartojantis v1=). Pristatymas galioja, jei sutampa
bet kuris iš jų.
Taip pat atmeskite laiko žymę, kuri nuo jūsų laikrodžio skiriasi daugiau nei 5 minutėmis. Tai neleidžia kam nors vėliau pakartotinai išsiųsti įrašyto pristatymo.
# 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' ' -f1Išbandykite parašo tikrinimą
Kol dar neprijungėte kodo prie tikrų pristatymų, paleiskite jį su šiomis reikšmėmis. Kai laikrodis nustatytas pagal laiko žymę, abi patikros turi pavykti, o pakeitus vieną turinio baitą – nepavykti.
| Įvestis | Reikšmė |
|---|---|
| Paslaptis | whsec_test_secret_0123456789abcdef |
webhook-id | evt_0123456789abcdef0123456789abcdef |
webhook-timestamp ir t | 1791194400 |
| Turinys | {"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. Atsakykite greitai, darbą atlikite vėliau
Sursa jūsų atsako laukia iki 10 sekundžių. Bet kokia 2xx būsena reiškia, kad pristatymas pavyko; bet kas kita,
įskaitant peradresavimą, baigusį laiko limitą ar nutrauktą ryšį, reiškia, kad jis nepavyko ir bus kartojamas.
Todėl gavėjas turėtų tik patikrinti parašą, įrašyti įvykį ir atsakyti. Tikrąjį darbą atlikite vėliau, iš savo eilės.
// 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);2xx atsakykite tik tada, kai įvykis saugiai išsaugotas. Jei pirmiau atsakysite, o paskui jūsų procesas nulūš,
įvykis jums bus prarastas, nes Sursa jį jau laiko pristatytu.
5. Pakartojimai
Nepavykęs pristatymas kartojamas vis ilgesnėmis pauzėmis: maždaug po 1 minutės, 5 minučių, 30 minučių, 2 valandų, 5 valandų, 10 valandų, 24 valandų ir dar 24 valandų – devyni bandymai per beveik tris dienas. Kiekviena pauzė gali skirtis iki 20 %, kad daugelio galinių taškų pakartojimai neatkeliautų tuo pačiu metu.
- Atsakas
429arba503suRetry-Afternukelia kitą bandymą bent iki to laiko, daugiausia 24 valandoms. Naudokite jį, kai jūsų sistema perkrauta arba vyksta techninė priežiūra. - Atsakas
410 Goneišjungia galinį tašką: siųskite jį tik tada, kai tuo adresu daugiau pristatymų nebenorite. - Po 10 nepavykusių bandymų iš eilės galinis taškas pristabdomas, o organizacijos administratoriams apie tai
pranešama. Įvykiai toliau kaupiami, o kai galinis taškas vėl įjungiamas administravimo sąsajoje arba operacija
POST /v1/webhooks/{webhook_id}/resume, jie pristatomi iš eilės. - Po paskutinio bandymo pristatymas pažymimas
exhausted. Jį galite išsiųsti dar kartą rankiniu būdu.
Galinio taško pristatymai su kiekvienu bandymu, jūsų atsako kodu ir jo trukme pateikiami operacijoje
GET /v1/webhooks/{webhook_id}/deliveries ir administravimo sąsajoje.
POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver išsiunčia
pristatymą dar kartą. Pakartotinis pristatymas turi tą patį webhook-id.
6. Tvarka ir dublikatai
- Tvarka. Pristatymai vienam galiniam taškui siunčiami griežtai vienas po kito pagal
sequencetvarką. Kol vienas pristatymas kartojamas, vėlesni laukia. Skirtingi galiniai taškai vienas kito nelaukia. - Dublikatai. Tas pats įvykis gali ateiti daugiau nei kartą, pavyzdžiui, kai jūsų atsakas dingo pakeliui atgal.
Išsaugokite kiekvieno apdoroto įvykio
webhook-id(turinyje tai taip patid) ir praleiskite jau matytą. - Mąstykite būsenomis. Kai pakeitimai susiję su tuo pačiu objektu, palyginkite
created_atarbasequencesu tuo, ką išsaugojote, ir ignoruokite įvykį, senesnį už jau turimą būseną. Jei abejojate, nuskaitykite dabartinį objektą per API: įvykis praneša, kad kas nors pasikeitė, o API parodo, koks jis dabar.
7. Suderinkite su įvykių juosta
Kiekvienas įvykis 30 dienų saugomas ir įvykių juostoje, nepriklausomai nuo to, ar jį prenumeravo koks nors galinis
taškas. Jei jūsų gavėjas neveikė ilgiau, nei apima pakartojimai, arba norite patikrinti, ar niekas nepraleista,
nuskaitykite juostą su raktu, turinčiu vaidmenį admin ir apimtį 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"Įvykis juostoje turi tą patį id ir formą kaip pristatyme, tik be pristatymo laukų sequence, payload ir test.
Kadangi jūsų gavėjas praleidžia jau matytus įvykius, suderinimą galite vykdyti kaip dažnai norite, pavyzdžiui, kartą
per valandą.
GET /v1/webhook-events/{event_id} nuskaito vieną įvykį pagal jo ID.
8. Pakeiskite paslaptį (rotacija)
POST /v1/webhooks/{webhook_id}/rotate-secret išduoda naują paslaptį,
o ankstesnė galioja persidengimo laikotarpiu – pagal numatytuosius nustatymus 24 valandas, daugiausia 7 dienas.
Persidengimo metu kiekvienas pristatymas pasirašomas abiem paslaptimis.
- Atlikite rotaciją ir savo gavėjuje išsaugokite naują paslaptį šalia senosios.
- Priimkite pristatymą, jei jo parašas sutampa su bet kuria iš paslapčių.
- Pasibaigus persidengimui, pašalinkite senąją paslaptį.
Jei senoji paslaptis nutekėjo, persidengimą nutraukite iš karto operacija
POST /v1/webhooks/{webhook_id}/revoke-previous-secret arba
paslaptį pakeiskite su "overlap_hours": 0.
Kontrolinis sąrašas
- Patikrinkite vieną iš parašų pagal neapdorotą turinį ir patikrinkite laiko žymę.
- Išsaugokite įvykį pagal
webhook-id, tada per 10 sekundžių atsakykite2xx. - Praleiskite dublikatus ir pasenusius įvykius; kai svarbu, nuskaitykite dabartinį objektą per API.
- Kai reikia, kad Sursa sulėtintų siuntimą, atsakykite
429arba503suRetry-After; niekada neatsakykite410netyčia. - Praleiskite nežinomus įvykių tipus ir laukus.
- Pagal tvarkaraštį suderinkite su įvykių juosta.