Integrationer og drift

Webhooks i drift: stol på afsenderen uden at stole på leveringen

En webhook kan få appen til at reagere på en betaling, booking eller statusændring med det samme. Men det samme event kan komme flere gange, komme sent eller ramme appen, mens den er nede. En driftssikker webhook kontrollerer derfor afsenderen, gemmer hændelsen sikkert og kan behandle den igen uden dobbelte handlinger.

Hvad er en webhook?

En webhook er et HTTP-kald fra ét system til et endpoint i et andet system, når en bestemt hændelse sker. I stedet for at jeres app spørger betalingsudbyderen hvert minut, kan udbyderen eksempelvis sende besked, når en betaling lykkes eller fejler.

Betaling

Udbyderen melder, at en betaling eller refundering har skiftet status.

Booking

Et eksternt system sender oprettelse, ændring eller annullering.

Automatisering

CRM, mail- eller dokumenttjenesten melder, at et trin er færdigt.

Det er praktisk, men endpointet er samtidig en offentlig indgang til appen. Et gyldigt JSON-format beviser hverken, hvem der sendte data, eller at hændelsen kun bliver leveret én gang. Begge dele skal håndteres eksplicit.

Kortlæg virkningen før teknikken

Start med at beskrive, hvad hver hændelse kan ændre. En webhook, der blot gemmer en leveringsstatus, har en anden risiko end en webhook, der frigiver en ordre, opretter en reservation eller giver adgang til et produkt.

HændelseForretningsvirkningStabil nøgleHvis den mangler eller gentages
Betaling gennemførtOrdre frigivesEvent-id og betalings-idOrdren står fast eller frigives to gange
Booking ændretDato og kapacitet opdateresEvent-id, booking-id og versionForkert dato eller overskrevet ændring
Dokument færdigtFil bliver synligJob-id og dokument-idManglende eller forkert dokumentstatus

Notér også endpoint, miljø, leverandør, secret-ejer, forventede eventtyper, dataklassifikation og hvem der reagerer på fejl. Det gør det muligt at afgrænse både rettigheder, logs og genbehandling.

Kontrollér signaturen før payloaden bruges

Brug leverandørens dokumenterede signaturmetode og officielle bibliotek, når det findes. En delt webhook-secret ligger kun på afsenderens og modtagerens servere. Modtageren beregner den forventede signatur over den modtagne request og sammenligner den sikkert med signaturen i headeren. En hemmelig tekst i URL'en er ikke en god erstatning: URL'er kan ende i logs, browserhistorik og supportudtræk.

  1. Bevar den oprindelige body. Nogle leverandører, blandt andre Stripe, kræver den rå request-body. Hvis et framework først parser JSON, ændrer mellemrum eller genopbygger indholdet, kan signaturkontrollen fejle.
  2. Brug endpointets egen secret. Test og produktion skal ikke dele secret, og flere endpoints kan have hver deres værdi.
  3. Sammenlign på en sikker måde. Ved egen HMAC-kontrol bør sammenligningen være timing-sikker. GitHub anbefaler eksempelvis en constant-time-funktion frem for almindelig lighedskontrol.
  4. Kontrollér eventuel tidsgrænse. Hvis leverandørens signatur indeholder et tidsstempel, kan en rimelig tolerance mindske risikoen for genafspilning. Serverens ur skal være korrekt.
  5. Afvis før behandling. Manglende eller ugyldig signatur må ikke oprette data, sende mails eller lægge arbejde i den normale behandlingskø.
IP-lister er højst et ekstra lag. Leverandørens adresser kan ændre sig, og netværksopsætningen kan skjule den oprindelige afsender. Signaturkontrol bør følge leverandørens dokumentation og være den primære bekræftelse, når den understøttes.

Kvittér hurtigt – behandl sikkert bagefter

Leverandøren venter normalt kun en begrænset tid på et HTTP-svar. GitHub kræver eksempelvis et 2xx-svar inden for 10 sekunder, mens Stripe siger, at endpointet skal svare hurtigt før kompleks logik. Den konkrete grænse afhænger af leverandøren.

Et robust modtageflow

  1. 1. Modtag: Begræns requeststørrelse, læs nødvendige headers og bevar raw body.
  2. 2. Bekræft: Validér signatur og eventuel tidsgrænse med korrekt secret til miljøet.
  3. 3. Registrér: Gem event-id, type, modtaget tidspunkt og behandlingsstatus atomisk.
  4. 4. Overdrag: Læg en beskyttet reference på en holdbar kø, hvis behandlingen ikke er helt kort og sikker.
  5. 5. Kvittér: Returnér den statuskode, leverandøren forventer, når hændelsen er sikkert modtaget.
  6. 6. Behandl: En worker udfører forretningshandlingen idempotent og registrerer resultatet.

Et 2xx-svar bør betyde, at I har accepteret ansvaret for hændelsen – ikke nødvendigvis at hele forretningshandlingen er færdig. Hvis serveren svarer succes, før hændelsen er gemt holdbart, kan et nedbrud i det lille mellemrum gøre eventet usynligt. Hvis den omvendt venter på mails, rapporter og eksterne API-kald, øges risikoen for timeout og leverandørens genforsøg.

Dubletter er normal drift – ikke en særfejl

Webhook-leverandører kan gensende en hændelse, når svaret mangler, forbindelsen brydes eller en operatør vælger redelivery. Stripe dokumenterer også, at samme event kan modtages mere end én gang. Behandlingen skal derfor kunne se en gentagelse uden at skabe en ekstra refundering, booking, mail eller lagerbevægelse.

  • Gem event-id med en entydig regel. En almindelig “find og opret” i to separate trin kan stadig skabe dubletter under samtidighed.
  • Knyt id'et til leverandør og endpoint. Et kort id er ikke nødvendigvis globalt unikt på tværs af alle integrationer og miljøer.
  • Beskyt selve forretningshandlingen. Event-id forhindrer samme levering, men en leverandør kan i nogle tilfælde udsende to forskellige events om samme objekt. Brug derfor også en relevant forretningsnøgle eller tilstandsregel.
  • Markér status tydeligt. Skeln mellem modtaget, i behandling, gennemført, ignoreret og permanent fejl. Ellers kan en dublet af et tidligere fejlende event blive afvist uden genopretning.

Idempotens betyder ikke, at alle eventtyper gør det samme hver gang. Det betyder, at gentagen behandling af den samme logiske hændelse ikke giver en ekstra skadelig virkning. Den konkrete regel skal passe til betaling, booking, dokument eller den anden forretningshandling.

Events kan komme i forkert rækkefølge

Netværk, retries og parallel behandling kan få hændelser til at ankomme eller blive færdige i en anden rækkefølge end den, de blev skabt i. En gammel “opdateret”-hændelse må ikke nødvendigvis overskrive en nyere “annulleret”-status.

  • Brug leverandørens version, sequence eller hændelsestid, hvis feltets betydning og garanti er dokumenteret.
  • Modellér lovlige statusskift. “Betalt” bør ikke blindt gå tilbage til “afventer”, fordi et ældre event kommer sent.
  • Hent den aktuelle tilstand fra leverandørens API ved kritiske eller tvetydige events, hvis integrationens vilkår og rate limits tillader det.
  • Serialisér behandling pr. forretningsobjekt, når rækkefølgen er afgørende, frem for at blokere alle kunders events i én kø.

Payloaden er stadig ubetroet input efter en gyldig signatur: den kan være gammel, uventet eller fra en ny eventversion. Kontrollér eventtype, version, nødvendige felter og den tilladte forretningsændring før skrivning.

Planlæg genbehandling og afstemning

Leverandørens retries er nyttige, men de er ikke jeres driftsplan. Retryperiode, intervaller og mulighed for manuel redelivery varierer. Dokumentér derfor, hvad I selv gør, når endpointet var nede, en secret var forkert, eller en kodefejl gjorde alle events ugyldige.

  1. Bevar en sikker modtagelsespost. Gem det minimum, der kræves for at finde og genbehandle hændelsen. Krypter og begræns adgang efter dataenes følsomhed.
  2. Parkér permanente fejl. Ugyldigt format eller ukendt eventtype skal ikke prøve for evigt. Gør fejlen synlig med event-id og en sikker årsagskategori.
  3. Genkør gennem samme idempotente vej. En særskilt admin-knap, der omgår kontrollerne, bliver hurtigt den farlige vej i produktion.
  4. Afstem mod kilden. En planlagt kontrol kan sammenligne kritiske betalinger, bookinger eller jobs med leverandørens aktuelle status og finde hændelser, der aldrig kom frem.
Slet ikke fejlhistorik uden en politik. Modtagne payloads kan indeholde persondata, men for kort opbevaring kan gøre fejlsøgning og afstemning umulig. Vælg nødvendige felter, adgang, slettefrist og eventuel maskering ud fra formål og risiko – ikke “gem alt for en sikkerheds skyld”.

Overvåg forretningsflowet – ikke kun endpointet

Et endpoint kan svare 200 på alle requests, mens workerens kø vokser, events bliver ignoreret eller betalinger aldrig knyttes til ordrer. Mål derfor både modtagelse, behandling og den forventede forretningsvirkning.

Modtagelse
Antal pr. type, signaturfejl, svartid, ikke-2xx og pludseligt ophør.
Kø og behandling
Ventetid, gennemførte, dubletter, retries og parkerede fejl.
Forretning
Betaling uden ordre, booking med statusforskel eller job uden resultat.
Sporbarhed
Event-id og intern korrelations-id uden secrets eller unødvendig persondata.

En alarm skal have en modtager og en lille runbook: kontrollér leverandørstatus, endpointets fejlrate, køens alder, seneste vellykkede event, ændringer i secrets og om en sikker genbehandling er nødvendig. Log aldrig selve webhook-secreten eller komplette følsomme payloads som standard.

Vælg implementering efter den eksisterende stack

Webhook-principperne er de samme, men værktøjerne behøver ikke være det. En Azure-app kan eksempelvis bruge en HTTP-trigger og Service Bus eller Storage Queue. En Firebase- eller Google Cloud-løsning kan bruge en HTTP-funktion og en passende kø- eller opgavetjeneste. Andre apps kan bruge frameworkets serverroute og en administreret kø.

  • Vælg en løsning, der kan bevare raw body og leverandørens signaturheaders uændret.
  • Brug stackens normale secret-opbevaring, identiteter og mindst mulige rettigheder.
  • Kontrollér om køen leverer mindst én gang, hvordan synlighedstimeout virker, og hvordan fejl parkeres.
  • Hold test- og produktionsendpoints, secrets, køer, data og leverandørkonti adskilt.

Microsofts Web-Queue-Worker-mønster beskriver adskillelsen mellem den webdel, der modtager HTTP-kald, og workeren, der udfører længere arbejde via en kø. Det er et mønster – ikke et krav om Azure eller en bestemt kø.

Typiske fejl

  • Ingen signaturkontrol: Alle, der kender URL'en, kan forsøge at udløse forretningshandlinger.
  • JSON parses før kontrol: Den ændrede body matcher ikke leverandørens signatur.
  • Secret i URL eller kode: Adgangen lækker via logs eller repository og kan ikke roteres roligt.
  • Lang behandling før svar: Leverandøren oplever timeout og sender eventet igen.
  • Event-id gemmes efter handlingen: Et nedbrud mellem handling og registrering gør retry til en dublet.
  • Alle events antages at komme i orden: En forsinket ældre hændelse overskriver den aktuelle status.
  • 2xx betyder “alt er godt”: Endpointet ser grønt ud, mens køen eller forretningsbehandlingen er stoppet.
  • Ingen afstemning: En hændelse, der aldrig blev leveret, bliver aldrig opdaget.

Tjekliste før webhooks får lov at ændre rigtige data

  • ☐ Hvert endpoint har en ejer, et miljø og en liste over nødvendige eventtyper.
  • ☐ Forretningsvirkning og konsekvens ved manglende, sen eller gentaget levering er beskrevet.
  • ☐ HTTPS bruges, og leverandørens dokumenterede signaturkontrol sker på den korrekte raw body.
  • ☐ Secrets ligger server-side, er adskilt pr. miljø og kan roteres uden ukontrolleret nedetid.
  • ☐ Requeststørrelse, eventtype, version og nødvendige felter valideres.
  • ☐ Hændelsen gemmes holdbart, før endpointet kvitterer for modtagelsen.
  • ☐ Lang eller fejlbar behandling er flyttet til en kø, der passer til stacken.
  • ☐ Event-id og relevante forretningsnøgler beskyttes med atomiske, entydige regler.
  • ☐ Sene og uordnede events kan ikke blindt rulle en nyere status tilbage.
  • ☐ Midlertidige fejl, permanente fejl og dubletter får hver sin synlige status.
  • ☐ Genbehandling bruger samme idempotente kontroller som normal behandling.
  • ☐ Logs og payload-opbevaring følger mindst mulige data, adgang og slettefrist.
  • ☐ Alarmer dækker både modtagelse, køalder, behandling og manglende forretningsresultat.
  • ☐ En test har simuleret ugyldig signatur, timeout, dublet, uordnet levering og worker-nedbrud.
  • ☐ En afstemning kan finde kritiske hændelser, der aldrig blev modtaget.

Officielle kilder

Leverandører bruger forskellige headers, signaturalgoritmer, tidsgrænser og retryregler. Kontrollér altid dokumentationen til den konkrete integration før implementering og ved ændringer i API-version eller framework.

Når integrationen skal kunne passe sig selv

Hvis appen allerede modtager betalinger, bookinger eller statusopdateringer, men I mangler overblik over signaturer, dubletter og fejlede events, kan Startklar hjælpe med at kortlægge webhook-flowet og gøre modtagelse, genbehandling og overvågning klar til daglig drift.

Se Startklar for AI-byggede apps