Webhooks
Alle sidene
Kom i gang
Referanse
Oppsett
Du legger inn en adresse under Innstillinger, fanen API, huker av for hendelsene du bryr deg om og får en signeringsnøkkel du bruker til å sjekke at forespørselen kom fra skribb.
Adressen må være https og nås utenfra. Vi sender ingenting til en adresse på ditt eget nett eller tilbake til skribb, og vi sjekker det både når du legger den inn og hver gang vi sender.
Hendelser
- order.paidNy betalt bestilling
- order.fulfilledBestilling merket som sendt
- order.refundedBestilling refundert
- subscriber.confirmedNy bekreftet abonnent
- post.publishedInnlegg publisert
Body
Bodyen er JSON. id er unik per utsending, så du kan deduplisere på den uten å se på headerne. En bestilling kommer i samme form som i /v1/orders, så du slipper å håndtere to beskrivelser av det samme.
{
"id": "3f9a1c7e-...",
"event": "order.paid",
"created_at": "2026-07-26T18:25:50.000Z",
"data": {
"order": { "id": "ord_3Ln9Ra", "status": "paid", "total_ore": 57700, "…": "…" }
}
}Sjekk signaturen
Hver forespørsel har Skribb-Signature: t=<sekunder>,v1=<hex>. Signaturen dekker t og bodyen sammen, ikke bodyen alene. Signaturen blir værende gyldig, men tidsstempelet røper alderen på en forespørsel som spilles av på nytt. Avvis alt som er mer enn fem minutter gammelt.
Regn på den rå bodyen, ikke på noe du har parset og skrevet ut igjen. Et rammeverk som normaliserer JSON-en for deg, endrer bytene, og da stemmer ikke signaturen lenger.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t));
if (!Number.isFinite(age) || age > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(parts.v1 ?? "", "hex");
return a.length === b.length && timingSafeEqual(a, b);
}Svar og gjentatte forsøk
Svar 2xx så fort du kan, og gjør det tunge arbeidet etterpå. Vi venter i ti sekunder. Alt annet enn 2xx, og et svar som ikke kommer, teller som mislykket.
Da prøver vi igjen etter ett minutt, så fem, så tretti, så to timer, så seks. Fem forsøk i alt, så serveren din kan være nede i rundt åtte timer og likevel få alt når den kommer tilbake. Etter det gir vi opp for den ene utsendingen. Svarer adressen ikke over lengre tid, slår vi den av og sier fra i innstillingene.
Vi lover ikke rekkefølge. To hendelser kan komme i motsatt rekkefølge av at de skjedde, så se på innholdet, ikke på ankomsten. Vi lover heller ikke at noe kommer bare én gang: et nytt forsøk etter et svar som gikk tapt, ser likt ut for oss. Derfor er id der.