Webhookit
Saat allekirjoitettuja tapahtumailmoituksia, kun dokumentteja indeksoidaan, toimitukset epäonnistuvat tai päätepisteiden tila muuttuu. Vahvistus, yritykset uudelleen ja testaus.
Webhookit lähettävät tapahtumailmoitukset järjestelmiisi HTTPS POST -pyynnöillä, joten voit reagoida muutoksiin ilman pollausta. Rekisteröi päätepiste työtilan asetuksista: URL-osoitteen on käytettävä HTTPS:ää, ja jokainen työtila voi rekisteröidä enintään 10 päätepistettä. Luonnin yhteydessä saat allekirjoitusavaimen (etuliitteellä whsec_, Standard Webhooks -formaatti) täsmälleen kerran; sitä ei voi hakea myöhemmin, joten kopioi se salaisuuksien tallennuspaikkaasi heti.
Jokainen toimitus on JSON-runko, jossa on sama kirjekuori:
{
"event": "documents.indexed",
"timestamp": "2026-07-23T09:14:07.000Z",
"tenantId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"sequence": 42,
"data": { "count": 12 }
}Sisällöt ovat tarkoituksellisesti kevyitä: vain tunnisteita, lukumääriä ja aikaleimoja. Käsittele webhookia signaalina siitä, että jotain on muuttunut, ja hae nykyinen tila autentikoidun API:n kautta. Dokumenttien nimiä ja sisältöä ei koskaan näy webhook-sisällössä.
sequence on päätepistekohtainen laskuri, tiheä tämän päätepisteen omassa virrassa: peräkkäiset tähän päätepisteeseen toimitetut tapahtumat kantavat peräkkäisiä numeroita, joten puuttuva numero tarkoittaa toimitusta, jota palvelusi ei koskaan vastaanottanut. Toimituksen JÄRJESTYS ei ole taattu, joten käytä järjestystä (ei saapumisjärjestystä) tapahtumien järjestämiseen. Kaksi huomautusta: uudelleenlähetykset saapuvat tarkoituksellisesti järjestysnumeron ulkopuolelle (kiinni jäänyt tapahtuma säilyttää alkuperäisen, vanhemman järjestysnumeronsa), joten poista duplikaatit webhook-id:n perusteella äläkä koskaan hylkää toimitusta vain siksi, että sen järjestysnumero on alle korkeimman merkitsemäsi arvon; ja aukko voi tarkoittaa myös sitä, että puuttuva tapahtuma on vielä yrittämässä uudelleen tai odottamassa uudelleenlähetettävässä tilassa, joten käsittele aukot merkintänä "tarkista toimitusloki" eikä todisteena menetyksestä.
Tapahtumakatalogi
Voit tilata päätepisteen mille tahansa alla olevista tapahtumatyypeistä. Suunnitelluiksi merkityt tyypit voidaan jo valita, mutta niille ei vielä lähetetä mitään ja niiden sisällön muoto ei ole lopullinen; se julkaistaan tässä, kun tapahtuma otetaan käyttöön.
| Tapahtuma | Tila | Sisältö (data) |
|---|---|---|
documents.indexed | Käytössä | Dokumentit tulivat haettaviksi. Aggregoitu työtilakohtaisesti: korkeintaan yksi tapahtuma aggregointiaikavälillä, sisältäen lukumäärän. |
documents.failed | Käytössä | Dokumenttien käsittely epäonnistui lopullisesti. Aggregoitu työtilakohtaisesti: korkeintaan yksi tapahtuma aggregointiaikavälillä, sisältäen lukumäärän. |
sync.completed | Suunniteltu | Connector-synkronointiajo valmistui. Sisällön muoto ei ole lopullinen. |
sync.failed | Suunniteltu | Connector-synkronointiajo epäonnistui. Sisällön muoto ei ole lopullinen. |
ingestion.completed | Suunniteltu | Ingestioajo valmistui. Sisällön muoto ei ole lopullinen. |
ingestion.failed | Suunniteltu | Ingestioajo epäonnistui. Sisällön muoto ei ole lopullinen. |
audit.recorded | Käytössä | Työtilan audit-lokiin lisättiin merkintöjä. Aggregoitu työtilakohtaisesti aikavälin yli: lukumäärä ja aikaväli, jolta hakea, mutta ei itse merkintöjä. |
endpoint.disabled | Käytössä | Webhook-päätepiste poistettiin käytöstä: automaattisesti jatkuvien toimitusvirheiden tai 410 Gone -tilakoodin jälkeen tai ylläpitäjän toimesta. Toimitetaan työtilan muille päätepisteille. |
delivery.failing | Käytössä | Toimitukset webhook-päätepisteeseen epäonnistuvat: lähetetään kerran virheikkunan aikana, 30 minuuttia ensimmäisen epäonnistuneen yrityksen jälkeen, ja toimitetaan työtilan muille päätepisteille. |
endpoint.enabled | Käytössä | Poistettu käytöstä ollut webhook-päätepiste otettiin takaisin käyttöön. Sulkee tapahtuman endpoint.disabled avaaman häiriön; toimitetaan työtilan muille päätepisteille. |
delivery.recovered | Käytössä | Toimitus onnistui päätepisteessä, jolle delivery.failing oli lähetetty. Sulkee kyseisen häiriön; toimitetaan työtilan muille päätepisteille. |
webhook.ping | Käytössä | Suunnattu testitapahtuma, jonka kojelauta lähettää testitoiminnolla täsmälleen yhdelle päätepisteelle. Ei voi tilata; data on aina tyhjä. |
Esimerkkiobjektit data käytössä oleville tapahtumille:
// documents.indexed
{ "count": 12 }
// documents.failed
{ "count": 2 }
// audit.recorded
{
"count": 34,
"windowStart": "2026-07-23T09:05:00.000Z",
"windowEnd": "2026-07-23T09:10:00.000Z"
}
// endpoint.disabled
{
"endpointId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"reason": "sustained_failure",
"disabledAt": "2026-07-23T09:14:07.000Z"
}
// delivery.failing
{
"endpointId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"failingSince": "2026-07-23T09:14:07.000Z"
}
// endpoint.enabled
{
"endpointId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"enabledAt": "2026-07-24T08:02:51.000Z"
}
// delivery.recovered
{
"endpointId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"failingSince": "2026-07-23T09:14:07.000Z",
"recoveredAt": "2026-07-23T11:40:12.000Z"
}
// webhook.ping
{}Operatiiviset tapahtumat (delivery.failing, delivery.recovered, endpoint.disabled, endpoint.enabled) raportoivat muiden päätepisteiden tilasta: päätepiste, josta tapahtuma kertoo, on aina suljettu pois kyseisen tapahtuman toimituksesta, koska sen sinne lähettäminen olisi taattua häiriötä.
Jokainen käytössä oleva tapahtuma on kuvattu myös OpenAPI-dokumentissa osoitteessa /api/openapi.json, kohdassa webhooks: koko JSON-skeema rungolle ja kolmelle allekirjoitusotsakkeelle, joten voit generoida vastaanottajatyypit kopioimisen sijaan. Skeemaa noudatetaan myös meidän puolellamme: sellaista sisältöä, joka ei vastaa sitä, ei koskaan lähetetä.
Audit-lokin syöttäminen SIEM-järjestelmään
audit.recorded on push-puoli SIEM-syötettä, eikä se tarkoituksellisesti sisällä merkintöjä: audit-merkintä nimeää henkilön, hänen osoitteensa ja sen, mihin hän koski, kun taas webhook-sisältö tallennetaan toimituslokiin ja lähetetään URL-osoitteeseen, jota hallitset ja joka voi sijaita missä tahansa. Tapahtuma kertoo, että aikaväli sulkeutui ja sisälsi merkintöjä; haet merkinnät autentikoidun API:n kautta avaimella, jolla on audit:read-oikeus.
Jokaisen tapahtuman yhteydessä hae lokia windowStart:llä startDate:na ja windowEnd:lla endDate:nä, sivuilla osoittimen mukaan, kunnes se palaa tyhjänä. Haun alkuraja on inklusiivinen ja aikavälin raja ei ole, joten sivu voi toistaa merkinnän täsmälleen tuossa hetkessä; poista duplikaatit merkinnän tunnisteen perusteella, jota tarvitset joka tapauksessa, koska toimitus tapahtuu vähintään kerran.
Katalogipäätepiste listaa kaikki toimet, joita loki voi tallentaa, sekä kategorian, johon kukin kuuluu, ja version, joka muuttuu, kun sanasto muuttuu. Lue se kerran, vertaa versiota myöhemmissä luvuissa ja käsittele toimintoa, joka puuttuu siitä, tuntemattomana eikä virheellisenä: loki on vain lisäys ja säilyttää kirjoitushetken oikeinkirjoituksen.
Aikavälit ovat peräkkäisiä niin kauan kuin pysyt tilattuna: jokainen alkaa siitä, mihin viimeksi lähettämäsi tapahtuma päättyi, joten viiveellä suoritettu lähetys tekee seuraavasta aikavälistä pidemmän sen sijaan, että menettäisi välissä tapahtuneet asiat. Aikaväli, jossa ei ole merkintöjä, ei lähetä mitään.
Toimitusten varmentaminen
Jokainen toimitus on allekirjoitettu Standard Webhooks -määrityksen mukaisesti. Varmista aina allekirjoitus ennen kuin luotat pyyntöön: päätepisteesi URL-osoite on kenen tahansa internetissä olevan saavutettavissa.
Jokainen pyyntö sisältää kolme otsaketta:
| Otsake | Arvo |
|---|---|
webhook-id | Viestin tunniste. Sama jokaisella saman tapahtuman uudelleenyrittämisellä, uudelleenlähetyksellä ja toistolla; poista duplikaatit sen perusteella. |
webhook-timestamp | Unix-aikaleima sekunteina lähetyshetkellä. |
webhook-signature | Yksi tai useampi allekirjoitus, välilyönnein eroteltuna, kukin muodossa v1,{base64}. |
Varmistaaksesi:
- Rekonstruoi allekirjoitettu sisältö muodossa
{webhook-id}.{webhook-timestamp}.{raw body}. Käytä raakaa pyynnön runkoa täsmälleen sellaisena kuin se vastaanotettiin, ennen kuin JSON-parsintaa. - Laske HMAC-SHA256 tästä merkkijonosta. Avain on base64-dekoodattu osa salaisuudesta
whsec_-etuliitteen jälkeen (Standard Webhooksin avainjohdannainen, jonka viiteluokat toteuttavat). - Koodaa HMAC base64:ksi ja vertaa sitä jokaiseen
v1,-allekirjoitukseen otsakkeessa käyttäen vakioaikaista vertailua. Toimitus on aito, jos yksikin vastaa. - Hylkää toimitukset, joiden
webhook-timestamperoaa nykyisestä ajastasi yli 5 minuuttia kumpaan tahansa suuntaan. Tämä rajoittaa kaapattujen pyyntöjen toistoa.
Otsake voi sisältää useamman kuin yhden allekirjoituksen: kun salaisuuden kiertoikkuna on avoinna, toimitukset allekirjoitetaan sekä uudella että edellisellä salaisuudella (v1,NEW_SIG v1,OLD_SIG), joten varmennus onnistuu riippumatta siitä, mihin salaisuuteen palvelusi on siirtynyt.
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 5 * 60;
/**
* @param {string} secret - The whsec_ signing secret from endpoint creation.
* @param {Record<string, string>} headers - Lowercased request headers.
* @param {string} rawBody - The raw request body, unparsed.
*/
export function verifyWebhook(secret, headers, rawBody) {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatureHeader = headers["webhook-signature"];
if (!id || !timestamp || !signatureHeader) return false;
const skew = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (!Number.isFinite(skew) || skew > TOLERANCE_SECONDS) return false;
const key = Buffer.from(secret.slice("whsec_".length), "base64");
const expected = createHmac("sha256", key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest();
return signatureHeader.split(" ").some((entry) => {
const comma = entry.indexOf(",");
if (comma === -1 || entry.slice(0, comma) !== "v1") return false;
const received = Buffer.from(entry.slice(comma + 1), "base64");
return received.length === expected.length && timingSafeEqual(received, expected);
});
}Koska formaatti noudattaa Standard Webhooks -määritystä, avoimen lähdekoodin varmennuskirjastot muille kielille toimivat sellaisenaan; välitä niille salaisuus ja kolme otsaketta.
Uudelleenyrittämiset ja virheet
Päätepisteelläsi on 10 sekuntia aikaa vastata, yhteyden muodostus mukaan lukien. Vastaus, jonka tila on 2xx, lasketaan toimitetuksi; kaikki muu, mukaan lukien aikakatkaisu tai uudelleenohjaus (toimitukset eivät koskaan seuraa uudelleenohjauksia), lasketaan virheeksi ja yritetään uudelleen. Ainoa poikkeus on 410 Gone: se kertoo, että reitti poistettiin tarkoituksella, joten kyseistä toimitusta ei yritetä uudelleen ja päätepiste poistetaan käytöstä välittömästi, lähettäen endpoint.disabled-tapahtuman (syy gone) työtilan muille päätepisteille ja sähköpostin jokaiselle omistajalle ja ylläpitäjälle. 410 vastauksena Lähetä testi -toimintoon tai manuaaliseen uudelleenlähetykseen epäonnistuu vain kyseinen toimitus.
Vastaa 2xx heti, kun olet hyväksynyt tapahtuman kestävästi, ja tee raskas käsittely asynkronisesti.
Epäonnistunut toimitus yritetään uudelleen seuraavan aikataulun mukaisesti:
| Yritys | Viive edellisen epäonnistumisen jälkeen |
|---|---|
| 1 | välittömästi |
| 2 | 5 sekuntia |
| 3 | 5 minuuttia |
| 4 | 30 minuuttia |
| 5 | 2 tuntia |
| 6 | 5 tuntia |
| 7 | 10 tuntia |
| 8 | 10 tuntia |
Tämä on 8 yritystä noin 27,5 tunnin aikana, joten koko päivän kestävä katkos palvelusi puolella ei menetä tapahtumia. Jokainen viive sisältää jopa 20 % satunnaista hajontaa kumpaankin suuntaan, mikä estää synkronoidut uudelleenyrittämisryöpyt palautuvaa päätepistettä vastaan. Jos päätepisteesi palauttaa Retry-After-otsakkeen, pyydettyä viivettä kunnioitetaan rajoissa: se rajataan aikataulun mukaisen viiveen ja kaksinkertaisen aikataulun mukaisen viiveen väliin. Vastaukset, joiden tila on 429, ja aikakatkaistut yritykset yritetään uudelleen aikaisintaan 60 sekunnin kuluttua, riippumatta siitä, kuinka aikaisin aikataulun paikka osuu.
Automaattinen poistaminen käytöstä
Päätepiste, joka jatkaa epäonnistumista, poistetaan lopulta käytöstä sen sijaan, että sitä pommitettaisiin ikuisesti:
- Kun toimitukset ovat epäonnistuneet 30 minuutin ajan,
delivery.failing-tapahtuma käynnistyy kerran (toimitetaan työtilan muille päätepisteille) ja jokainen työtilan omistaja ja ylläpitäjä saa ilmoituksen sovelluksessa. Tämä on varoitus; lyhyt häiriö, jonka onnistunut toimitus sulkee 30 minuutin kuluessa, ei aiheuta mitään. - Kun virheikkuna jatkuu, varoitus eskaloituu: 3 päivän ja uudelleen 4,5 päivän kuluttua jokainen omistaja ja ylläpitäjä saa ilmoituksen sovelluksessa ja sähköpostin, jossa kerrotaan aika, jonka jälkeen päätepiste poistetaan käytöstä, jos toimitukset epäonnistuvat edelleen. Jokainen varoitus tavoittaa jokaisen henkilön kerran virheikkunaa kohden.
- Onnistuneesti toimitettu tapahtuma nollaa virheikkunan. Testitapahtuma ei: se todistaa, että päätepiste vastaa, ei sitä, että se käsittelee tapahtumia. Jos varoitus oli jo lähetetty,
delivery.recovered-tapahtuma käynnistyy ja omistajat ja ylläpitäjät saavat ilmoituksen sovelluksessa, että päätepiste on palautunut. - 5 päivän jatkuvien epäonnistumisten jälkeen päätepiste poistetaan käytöstä:
endpoint.disabled-tapahtuma käynnistyy (taas muille päätepisteille), ja jokaiselle työtilan omistajalle ja ylläpitäjälle lähetetään sähköposti.
Poistaminen käytöstä vaatii epäonnistuneen toimituksen lopullisen varoituksen jälkeen. Jos mitään ei ollut lähetetty päätepisteelle siihen mennessä, kun lopullinen varoitus annettiin, seuraava epäonnistuminen aiheuttaa uuden lopullisen varoituksen, ja päätepiste poistetaan käytöstä vain, jos toimitukset epäonnistuvat edelleen 12 tunnin kuluttua.
Päätepisteen poistaminen käytöstä itse käynnistää endpoint.disabled-tapahtuman syyllä manual työtilan muille päätepisteille. Poistettu käytöstä oleva päätepiste ei vastaanota enää toimituksia, eikä sen Lähetä testi- ja uudelleenlähetystoiminnot ole käytettävissä. Kun vastaanottimesi on taas toimintakunnossa, ota päätepiste uudelleen käyttöön työtilan asetuksista (klikkaa sen tilamerkkiä): uudelleen ottaminen käyttöön tyhjentää virhehistorian, joten päätepiste aloittaa uuden 5 päivän ikkunan, ja endpoint.enabled-tapahtuma käynnistyy työtilan muille päätepisteille. Tapahtumat, jotka tapahtuvat, kun päätepiste on poistettu käytöstä, tallennetaan sen toimituslokiin hylätty-tilalla sen sijaan, että niitä lähetettäisiin. Kun olet ottanut päätepisteen uudelleen käyttöön, käytä Lähetä testi -toimintoa vahvistaaksesi, että päätepiste on saavutettavissa, ja sitten Toista epäonnistuneet + hylätyt saadaksesi kiinni kaikesta, mitä katkos maksoi, yhdellä toiminnolla.
Manuaalinen uudelleenlähetys ja testaus
Toimitusloki työtilan asetuksissa näyttää jokaisen toimitusyrityksen tilakoodin ja vastauksen kanssa. Sieltä käsin:
- Lähetä uudelleen lähettää alkuperäisen tapahtuman aiemmasta toimituksesta (sama
webhook-id, sama JSON-sisältö) yhtenä yrityksenä. Se ei mene uudelleenyrittämisaikatauluun eikä koskaan lasketa automaattisen poiston perusteeksi, joten sitä on turvallista käyttää epävakaan vastaanottimen vianetsinnässä. Uudelleenlähetys sisältää alkuperäisenwebhook-id:n, joten vastaanotin, joka on jo käsitellyt tapahtuman ennen virhevastauksen antamista, käsittelee sitä samana viestinä. - Toista epäonnistuneet + hylätyt toistaa massana jokaisen päätepisteen lopullisesti epäonnistuneen ja hylätyn toimituksen, vanhimmasta alkaen (toimitukset, jotka ovat vielä automaattisessa uudelleenyrittämisaikataulussa, jätetään pois, joten toisto ei koskaan voi duplikoida uudelleenyrittämistä, joka olisi muuten onnistunut). Toistetut toimitukset käyttävät täyttä uudelleenyrittämisaikataulua ja sisältävät alkuperäisen
webhook-id:n: palvelullesi toisto on sama viesti uudelleen, joten idempotenssikäsittelywebhook-id:n perusteella tekee kiinniottamisesta turvallista riippumatta siitä, saapuiko alkuperäinen koskaan. Tapahtuma, jonka uudelleenlähetys tai aikaisempi toisto on jo toimittanut, ohitetaan, samoin kuin sellainen, jota vielä toimitetaan. Valitse, kuinka pitkälle taaksepäin haluat mennä (viimeiset 24 tuntia, viimeiset 7 päivää tai kaikki säilytetyt), ja valintaikkuna näyttää etukäteen, kuinka monta tapahtumaa kyseinen alue lähettää ennen aloittamista; suuret alueet sivutetaan automaattisesti, ja edistyminen näytetään niiden edetessä. Toistot saapuvat järjestysnumeron ulkopuolisessa järjestyksessä; järjestä kiinniotetut tapahtumat sisällönsequence:n mukaan. - Lähetä testi toimittaa allekirjoitetun
webhook.ping-tapahtuman tyhjällädata-objektilla täsmälleen kyseiselle päätepisteelle, riippumatta sen tapahtumatilauksista, ja näyttää tuloksen (tilakoodin tai syyn epäonnistumiseen) heti, kun yritys päättyy. Käytä sitä saavutettavuuden vahvistamiseen ja allekirjoitusvarmennuksen testaamiseen päästä päähän. Testitapahtuma ei avaa, edistä tai nollaa virheikkunaa.
Parhaat käytännöt
- Poista duplikaatit
webhook-id:n perusteella. Automaattiset uudelleenyrittämiset, uudelleenlähetykset ja toistot käyttävät samaa tunnistetta, joten käsiteltyjen tunnisteiden tallentaminen antaa sinulle täsmälleen kerran -käsittelyn vähintään kerran -toimituksen päälle. - Älä koskaan käsittele sisältöä nykyisenä tilana. Sisällöt ovat kevyitä ja voivat saapua myöhässä; käytä tapahtumaa laukaisimena ja lue nykyinen tila API:sta.
- Älä luota järjestykseen. Uudelleenyrittämiset ja rinnakkainen toimitus tarkoittavat, että tapahtumat voivat saapua väärässä järjestyksessä.
- Vastaa 2xx ennen raskasta työtä. Jonoita tapahtuma ja käsittele se asynkronisesti; käsittelijä, joka tekee työnsä suoraan, voi ylittää 10 sekunnin aikarajan ja tulla yritetyksi uudelleen, mikä muuttaa yhden tapahtuman useiksi duplikaattiyrityksiksi.
- Kierrätä salaisuuksia siirtymäikkunan kanssa. Kierrätys työtilan asetuksista pitää edellisen salaisuuden voimassa valitsemasi ikkunan ajan, ja toimitukset allekirjoitetaan molemmilla salaisuuksilla sen aikana, joten palvelujesi liikkuva käyttöönotto ei koskaan menetä toimitusta. Päätepiste säilyttää yhden edellisen salaisuuden, joten toista kierrätystä siirtymäikkunan kanssa ei hyväksytä ennen kuin ensimmäinen ikkuna on päättynyt; kierrätys ilman siirtymäikkunaa hyväksytään aina ja mitätöi kaikki vanhat salaisuudet välittömästi, mikä on tie vuotaneelle salaisuudelle.