Webhooks
Motta signerte varsler om hendelser når dokumenter blir indeksert, leveranser mislykkes eller endepunkter endrer tilstand. Verifisering, forsøk på nytt og testing.
Webhooks sender hendelsesvarsler til systemene dine som HTTPS POST-forespørsler, slik at du kan reagere på endringer uten å måtte polle. Registrer et endepunkt fra arbeidsområdets innstillinger: URL-en må bruke HTTPS, og hvert arbeidsområde kan registrere opptil 10 endepunkter. Ved opprettelse mottar du en signeringshemmelighet (prefikset whsec_, Standard Webhooks-format) nøyaktig én gang; den kan aldri hentes igjen etterpå, så kopier den til hemmelighetslageret ditt med en gang.
Hver leveranse er en JSON-kropp med samme konvolutt:
{
"event": "documents.indexed",
"timestamp": "2026-07-23T09:14:07.000Z",
"tenantId": "0198f2a4-6c1e-7d30-b6a1-2f9d54c08a11",
"sequence": 42,
"data": { "count": 12 }
}Nyttelastene er bevisst tynne: kun ID-er, tellinger og tidsstempler. Behandle en webhook som et signal om at noe har endret seg, og hent deretter gjeldende tilstand via den autentiserte API-en. Dokumentnavn og innhold vises aldri i en webhook-nyttelast.
sequence er en per-endepunkt-teller, tett for denne endepunktets egen strøm: påfølgende hendelser levert til dette endepunktet har påfølgende nummer, så et manglende nummer betyr en leveranse tjenesten din aldri mottok. LeveringsREKKEFØLGE er ikke garantert, så bruk sekvensen (ikke ankomstrekkefølge) for å sortere hendelser. To forbehold: replays kommer utenfor sekvensrekkefølge med vilje (en innhentet hendelse beholder sitt opprinnelige, eldre sekvensnummer), så fjern duplikater på webhook-id og kast aldri en leveranse bare fordi sekvensen er under høyvannsmerket ditt; og et gap kan også bety at den manglende hendelsen fortsatt prøver på nytt eller venter i en tilstand som kan spilles av, så behandle gap som «sjekk leveringsloggen», ikke bevis på tap.
Hendelseskatalog
Abonner et endepunkt på en hvilken som helst kombinasjon av hendelsestypene nedenfor. Typer merket planlagt kan allerede velges, men ingenting utløses for dem ennå, og nyttelastformen er ikke endelig; den publiseres her når hendelsen blir aktiv.
| Hendelse | Status | Nyttelast (data) |
|---|---|---|
documents.indexed | Aktiv | Dokumenter ble søkbare. Aggregeres per arbeidsområde: maks én hendelse per aggregeringsvindu, med en telling. |
documents.failed | Aktiv | Dokumenter mislyktes terminalt i behandlingen. Aggregeres per arbeidsområde: maks én hendelse per aggregeringsvindu, med en telling. |
sync.completed | Planlagt | En synkroniseringskjøring for kobling ble fullført. Nyttelastform er ikke endelig. |
sync.failed | Planlagt | En synkroniseringskjøring for kobling mislyktes. Nyttelastform er ikke endelig. |
ingestion.completed | Planlagt | En inntakskjøring ble fullført. Nyttelastform er ikke endelig. |
ingestion.failed | Planlagt | En inntakskjøring mislyktes. Nyttelastform er ikke endelig. |
audit.recorded | Aktiv | Arbeidsområdets revisjonsspor fikk nye oppføringer. Aggregeres per arbeidsområde over et vindu: en telling og vinduet å hente fra, aldri oppføringene selv. |
endpoint.disabled | Aktiv | Et webhook-endepunkt ble deaktivert: automatisk etter vedvarende leveringsfeil eller en 410 Gone, eller av en administrator. Leveres til arbeidsområdets andre endepunkter. |
delivery.failing | Aktiv | Leveranser til et webhook-endepunkt mislykkes: utløses én gang per feilvindu, 30 minutter etter første mislykkede forsøk, og leveres til arbeidsområdets andre endepunkter. |
endpoint.enabled | Aktiv | Et deaktivert webhook-endepunkt ble slått på igjen. Lukker hendelsen endpoint.disabled åpnet; leveres til arbeidsområdets andre endepunkter. |
delivery.recovered | Aktiv | En leveranse lyktes på et endepunkt som delivery.failing ble utløst for. Lukker den hendelsen; leveres til arbeidsområdets andre endepunkter. |
webhook.ping | Aktiv | Rettet testhendelse sendt av dashbordets send-test-handling til nøyaktig ett endepunkt. Aldri abonnerbar; data er alltid tom. |
Eksempel-data-objekter for de aktive hendelsene:
// 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
{}De operasjonelle hendelsene (delivery.failing, delivery.recovered, endpoint.disabled, endpoint.enabled) rapporterer om helsen til andre endepunkter: endepunktet en hendelse gjelder er alltid ekskludert fra leveransen av den hendelsen, siden levering dit ville være garantert støy.
Hver aktive hendelse er også beskrevet i OpenAPI-dokumentet på /api/openapi.json, under webhooks: hele JSON-skjemaet for kroppen og de tre signaturhodene, slik at du kan generere mottakertypene i stedet for å kopiere eksemplene ovenfor. Skjemaet håndheves også på vår side: en nyttelast som ikke samsvarer med det sendes aldri.
Å mate et revisjonsspor til et SIEM
audit.recorded er push-delen av en SIEM-mating, og den er bevisst ikke oppføringene: en revisjonsoppføring navngir en person, adressen deres og hva de berørte, og en webhook-nyttelast lagres i leveringsloggen og sendes til en URL du kontrollerer, som kan løses hvor som helst. Hendelsen forteller deg at et vindu ble lukket med oppføringer i det; du henter oppføringene over den autentiserte API-en med en nøkkel som har audit:read-omfanget.
For hver hendelse søker du i sporet med windowStart som startDate og windowEnd som endDate, og blar gjennom siden til markøren kommer tilbake som null. Søkets startgrense er inklusiv og vinduets er ikke, så en side kan gjenta oppføringen på nøyaktig det tidspunktet; fjern duplikater på oppførings-ID, som du trenger uansett fordi levering er minst én gang.
Katalogendepunktet lister opp hver handling sporet kan registrere, med kategorien hver tilhører og en versjon som endres når vokabularet gjør det. Les det én gang, sammenlign versjonen ved senere lesinger, og behandle en handling som mangler fra det som ukjent i stedet for ugyldig: sporet er kun tilføyelse og beholder stavemåten hver oppføring ble skrevet med.
Vinduene er sammenhengende så lenge du forblir abonnert: hvert starter der det siste hendelsen du mottok sluttet, så en forsinket gjennomgang gjør det neste vinduet bredere i stedet for å miste det som skjedde imellom. Et vindu uten oppføringer sender ingenting.
Bekreftelse av leveranser
Hver leveranse er signert i henhold til Standard Webhooks-spesifikasjonen. Bekreft alltid signaturen før du stoler på en forespørsel: endepunktets URL er tilgjengelig for hvem som helst på internett.
Hver forespørsel har tre hoder:
| Hode | Verdi |
|---|---|
webhook-id | Meldings-ID. Identisk ved hvert nytt forsøk, gjenutsendelse og replay av samme hendelse; fjern duplikater på det. |
webhook-timestamp | Unix-tidsstempel i sekunder ved sendingstidspunkt. |
webhook-signature | Én eller flere signaturer, adskilt med mellomrom, hver på formen v1,{base64}. |
For å bekrefte:
- Rekonstruer det signerte innholdet som
{webhook-id}.{webhook-timestamp}.{raw body}. Bruk de rå forespørselskroppsbyttene nøyaktig som mottatt, før noen JSON-tolking. - Beregn HMAC-SHA256 over den strengen. Nøkkelen er base64-dekodede delen av hemmeligheten etter
whsec_-prefikset (Standard Webhooks-nøkkelavledning, som er det referansebibliotekene implementerer). - Base64-kod HMAC og sammenlign den med hver
v1,-signatur i hodet ved hjelp av en sammenligning med konstant tid. Leveransen er autentisk hvis noen av dem stemmer. - Avvis leveranser der
webhook-timestamper mer enn 5 minutter fra gjeldende tid, i begge retninger. Dette begrenser replay av fangede forespørsler.
Hodet kan inneholde mer enn én signatur: mens et hemmelighetsrotasjons-vindu er åpent, signeres leveranser med både den nye og den forrige hemmeligheten (v1,NEW_SIG v1,OLD_SIG), så bekreftelsen fortsetter å lykkes uavhengig av hvilken hemmelighet tjenesten din har rullet til.
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);
});
}Fordi formatet følger Standard Webhooks-spesifikasjonen, fungerer åpen kildekode-bekreftelsesbiblioteker for andre språk som de er; send dem hemmeligheten og de tre hodene.
Nytt forsøk og feil
Endepunktet ditt har 10 sekunder på å svare, inkludert oppkobling. Et svar med 2xx-status teller som levert; alt annet, inkludert tidsavbrudd eller videresending (leveranser følger aldri videresendinger), teller som en feil og forsøkes på nytt. Det ene unntaket er 410 Gone: det forteller oss at ruten ble fjernet med vilje, så den leveransen forsøkes ikke på nytt, og endepunktet deaktiveres umiddelbart, med en endpoint.disabled-hendelse (årsak gone) til arbeidsområdets andre endepunkter og en e-post til alle eiere og administratorer. En 410 som svar på Send test eller en manuell gjenutsendelse mislykkes bare den leveransen.
Svar 2xx så snart du har akseptert hendelsen varig, og gjør det tunge arbeidet asynkront.
En mislykket leveranse forsøkes på nytt etter denne planen:
| Forsøk | Forsinkelse etter forrige feil |
|---|---|
| 1 | umiddelbart |
| 2 | 5 sekunder |
| 3 | 5 minutter |
| 4 | 30 minutter |
| 5 | 2 timer |
| 6 | 5 timer |
| 7 | 10 timer |
| 8 | 10 timer |
Det er 8 forsøk over omtrent 27,5 timer, så en heldags driftsstans på din side mister ikke hendelser. Hver forsinkelse har opptil 20 % tilfeldig jitter i begge retninger, noe som forhindrer synkroniserte forsøksbølger mot et gjenopprettet endepunkt. Hvis endepunktet ditt returnerer en Retry-After-hode, blir den forespurte forsinkelsen respektert innenfor grenser: den klemmes mellom den planlagte forsinkelsen og dobbelt så lang planlagt forsinkelse. Svar med status 429 og tidsavbrutte forsøk forsøkes ikke på nytt før etter 60 sekunder, uavhengig av hvor tidlig planlagte tidsluken faller.
Automatisk deaktivering
Et endepunkt som fortsetter å mislykkes, blir til slutt deaktivert i stedet for å bli bombardert for alltid:
- Når leveranser har mislyktes i 30 minutter, utløses en
delivery.failing-hendelse én gang (leveres til arbeidsområdets andre endepunkter), og hver eier og administrator av arbeidsområdet får en varsling i appen. Dette er tidlig varsel; en kortvarig feil som en suksess lukker innen de 30 minuttene utløser ingenting. - Etter hvert som feilvinduet fortsetter, eskalerer varslingen: etter 3 dager og igjen etter 4,5 dager får hver eier og administrator en varsling i appen og en e-post som oppgir tidspunktet etter hvilket endepunktet blir deaktivert hvis leveranser fortsatt mislykkes. Hver varsling når hver person én gang per feilvindu.
- En vellykket levert hendelse tilbakestiller feilvinduet. En testhendelse gjør det ikke: den beviser at endepunktet svarer, ikke at det behandler hendelser. Hvis en varsling allerede var sendt ut, utløses en
delivery.recovered-hendelse, og eiere og administratorer får en varsling i appen om at endepunktet er gjenopprettet. - Etter 5 dager med påfølgende feil, blir endepunktet deaktivert: en
endpoint.disabled-hendelse utløses (igjen til andre endepunkter), og hver eier og administrator av arbeidsområdet får en e-post.
Deaktiveringen krever en mislykket leveranse etter det siste varslet. Hvis ingenting ble sendt til endepunktet innen varslet tidspunkt, utløser neste feil en ny siste varsling i stedet, og endepunktet blir deaktivert bare hvis leveranser fortsatt mislykkes 12 timer senere.
Å slå av et endepunkt selv utløser endpoint.disabled med årsak manual til arbeidsområdets andre endepunkter. Et deaktivert endepunkt mottar ingen flere leveranser, og send-test- og gjenutsendelseshandlingene er blokkert. Når mottakeren din er frisk igjen, aktiver endepunktet på nytt fra arbeidsområdets innstillinger (klikk på statusmerket): å aktivere på nytt tømmer feilhistorikken, så endepunktet starter et nytt 5-dagers vindu, og en endpoint.enabled-hendelse utløses til arbeidsområdets andre endepunkter. Hendelser som oppstår mens et endepunkt er deaktivert, registreres i leveringsloggen med statusen droppet i stedet for å bli sendt. Etter reaktivering, bruk Send test for å bekrefte at endepunktet er tilgjengelig, og Replay mislykkede + droppede for å ta igjen alt driftsstansen kostet i én handling.
Manuell gjenutsendelse og testing
Leveringsloggen i arbeidsområdets innstillinger viser hvert leveringsforsøk med statuskode og svar. Derfra:
- Gjenutsend leverer den opprinnelige hendelsen fra en tidligere leveranse (samme
webhook-id, samme JSON-innhold) som ett forsøk. Den går ikke inn i forsøksplanen og teller aldri mot automatisk deaktivering, så det er trygt å bruke mens du feilsøker en ustabil mottaker. Gjenutsendelsen har det opprinneligewebhook-id, så en mottaker som allerede behandlet hendelsen før den svarte med en feil, behandler den som samme melding. - Replay mislykkede + droppede bulk-spiller av hver terminalt mislykket og droppet leveranse for endepunktet, eldste først (leveranser som fortsatt er på automatisk forsøksplan er ekskludert, så en replay kan aldri duplisere et forsøk som ville lyktes uansett). Gjenavspilte leveranser bruker full forsøksplan og har det opprinnelige
webhook-id: for tjenesten din er en replay samme melding igjen, så idempotenshåndtering påwebhook-idgjør innhenting trygt, enten den opprinnelige leveransen kom frem eller ikke. En hendelse som en gjenutsendelse eller en tidligere replay allerede leverte, hoppes over, og det samme gjør en som fortsatt leveres. Velg hvor langt tilbake du vil gå (de siste 24 timene, de siste 7 dagene eller alt som er bevart), og dialogboksen viser forhåndsvisning av hvor mange hendelser det området vil sende før du starter; store områder blar gjennom automatisk, med fremdrift vist underveis. Replays kommer utenfor sekvensrekkefølge; sorter de innhentede hendelsene etter nyttelastenssequence. - Send test leverer en signert
webhook.ping-hendelse med et tomtdata-objekt til nøyaktig det endepunktet, uavhengig av hendelsesabonnementene, og viser utfallet (statuskoden, eller hvorfor det mislyktes) så snart forsøket er ferdig. Bruk det for å bekrefte tilgjengelighet og for å teste signaturbekreftelsen fra ende til ende. En testhendelse åpner, fremskynder eller tilbakestiller aldri feilvinduet.
Beste praksis
- Fjern duplikater på
webhook-id. Automatiske forsøk på nytt, gjenutsendelser og replays bruker samme ID, så å lagre behandlede ID-er gir deg nøyaktig én gangs behandling på toppen av minst én gangs levering. - Behandle aldri en nyttelast som gjeldende tilstand. Nyttelaster er tynne og kan komme sent; bruk hendelsen som en utløser og les gjeldende tilstand fra API-en.
- Ikke stol på rekkefølge. Forsøk på nytt og parallell levering betyr at hendelser kan komme i feil rekkefølge.
- Svar 2xx før tungt arbeid. Sett hendelsen i kø og behandle den asynkront; en håndterer som gjør arbeidet direkte risikerer å treffe 10-sekunders tidsavbruddet og bli forsøkt på nytt, noe som gjør én hendelse til flere dupliserte forsøk.
- Roter hemmeligheter med et grace-vindu. Rotasjon fra arbeidsområdets innstillinger beholder den forrige hemmeligheten gyldig i et vindu du velger, og leveranser signeres med begge hemmelighetene i løpet av det, så en rullende utrulling av tjenestene dine mister aldri en leveranse. Et endepunkt har én tidligere hemmelighet, så en andre rotasjon med grace-vindu avvises til det første vinduet er avsluttet; en rotasjon uten grace-vindu aksepteres alltid og tilbakekaller alle gamle hemmeligheter umiddelbart, noe som er veien å gå ved en lekket hemmelighet.