Hoppa till innehållet

Webhooks

Vägen ut ur Fluit. I stället för att ert system frågar om och om igen knackar Fluit på hos er när något faktiskt hänt.

API och integrationer Webhooks

Var det ställs in

I Fluit under Inställningar → Webhooks. En URL, en kryssruta per händelse.

Signering

HMAC-SHA256 i headern Fluit-Signature, med tidsstämpel mot uppspelning.

Omförsök

30 sekunder, 2 minuter, 10 minuter, 1 timme, 6 timmar. Sedan ligger leveransen kvar i loggen och kan skickas om manuellt.

Krav på mottagaren

https, nåbar från internet och svar inom tio sekunder.

Notisen bär en nyckel, inte er data

En webhook från Fluit säger vad som hänt och var det finns. Det är hela innehållet:

{
  "id": "01931f2c-8f4a-7c3e-9b21-4d5e6f708192",
  "type": "sales_order.placed",
  "occurred_at": "2026-08-01T09:14:22.118Z",
  "tenant": "dock",
  "api_version": "preview",
  "data": {
    "orderNumber": "SO-10042",
    "links": { "self": "/preview/orders/SO-10042" }
  }
}

Inga belopp, inga kunduppgifter, inga orderrader. Ert system följer links.self och hämtar detaljerna via REST-API:et med er API-nyckel. Det är ett medvetet val: en notis som bara bär en nyckel kan inte läcka något om den fastnar i en logg eller hos en mottagare som inte skyddar sina filer, och den kan aldrig visa ett inaktuellt värde — affärsnycklar ändrar sig inte.

Ni behöver därför också en API-nyckel

Utan en nyckel kan mottagaren inte hämta datan bakom länken. Nycklar skapas under Inställningar → API-nycklar och används av både REST-API:et och OData-flödet.

Händelser att prenumerera på

Kryssar ni i en hel grupp prenumererar ni på mönstret — då börjar nya händelser i gruppen levereras automatiskt när vi lägger till dem. Vill ni bestämma exakt vad ni får, kryssa i händelserna var för sig.

sales_order.* När en kundorder läggs eller makuleras.
sales_order.placed sales_order.cancelled
shipment.* När en leverans bokas hos transportören, blir redo för upphämtning eller levereras.
shipment.booked shipment.ready_for_pickup shipment.delivered
purchase_order.* När en inköpsorder skickas till leverantören, bekräftas, tas emot i sin helhet eller makuleras.
purchase_order.sent purchase_order.confirmed purchase_order.received purchase_order.cancelled
invoice.* När en faktura skapas.
invoice.created
work_order.* När en arbetsorder blir klar eller när tillverkat antal rapporteras in.
work_order.completed work_order.output_recorded
customer.* När en kund skapas eller ändras.
customer.created customer.updated
item.* När en artikel ändras.
item.updated
ticket.* När ett ärende skapas, tilldelas eller löses.
ticket.created ticket.assigned ticket.resolved

Räcker inte listan? entity.changed

Den generiska ändringsströmmen ger en notis varje gång en post ändras, även när ändringen inte har en egen händelse — ett justerat pris, ett flyttat leveransdatum. Ni får namnen på fälten som ändrades, aldrig värdena, och hämtar de nya värdena via länken som vanligt. Strömmen är av som standard och slås på per entitetstyp, eftersom en enda import annars kan ge tusentals notiser.

Verifiera signaturen

Varje anrop bär fyra headers:

Fluit-Signature: t=1785507262,v1=6a3f8c1e...
Fluit-Event:     sales_order.placed
Fluit-Delivery:  01931f2c-8f4a-7c3e-9b21-4d5e6f708192
Fluit-Attempt:   1

Signaturen är HMAC-SHA256 över tidsstämpeln, en punkt och den råa bodyn. Räkna samma sak med hemligheten från fliken Signering och jämför:

const crypto = require('crypto');

const [t, v1] = header.split(',').map((p) => p.split('=')[1]);
const expected = crypto
  .createHmac('sha256', secret)
  .update(`${t}.${rawBody}`)
  .digest('hex');

// Konstant tid — en vanlig jämförelse läcker hur många tecken som stämde.
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

Två saker är lätta att göra fel. Använd den råa bodyn, inte ett omtolkat JSON-objekt — serialiserar ni om det ändras signaturen. Och avvisa gamla anrop: är tidsstämpeln äldre än fem minuter ska anropet kastas, annars kan ett upphittat anrop spelas upp i evighet.

Testa innan ni bygger klart

Knappen Skicka testevent postar ett ping till er URL och visar svaret direkt — statuskod, svarstid och svarsbody. Under fliken Leveranser ser ni sedan varje riktigt utskick med exakt vad som skickades och vad ni svarade.

Vanliga frågor om webhooks

Har Fluit webhooks?
Ja. Under Inställningar → Webhooks anger ni en URL och kryssar i vilka händelser den ska få. När något inträffar i Fluit — en order läggs, en leverans bokas, ett ärende löses — postas en signerad notis till adressen inom någon sekund. Integrationen behöver alltså inte fråga API:et med jämna mellanrum för att upptäcka förändringar.
Vad innehåller en webhook från Fluit?
Affärsnyckeln och en länk — inte affärsdatan. En lagd order ger ordernumret och länken till ordern, inte belopp, kunduppgifter eller rader. Ert system hämtar detaljerna via https://api.erp.fluit.cloud/preview när det passar. Det gör att inga kunduppgifter hamnar i loggar hos er, hos mellanliggande servrar eller hos oss, och att notisen aldrig kan visa ett inaktuellt värde.
Behöver jag en API-nyckel för att använda webhooks?
Ja. Eftersom notisen bara bär nyckel och länk måste mottagaren kunna hämta datan bakom länken, och det kräver en API-nyckel. Nycklar skapas under Inställningar → API-nycklar i Fluit.
Hur vet jag att anropet kom från Fluit?
Varje anrop bär headern Fluit-Signature med en tidsstämpel och en HMAC-SHA256-signatur över "tidsstämpel.rå body". Ni räknar samma sak med hemligheten från fliken Signering och jämför i konstant tid. Stämmer det inte ska anropet avvisas. Avvisa också anrop där tidsstämpeln är äldre än fem minuter, annars kan någon spela upp ett gammalt anrop i evighet.
Vad händer om vår mottagare är nere?
Fluit försöker igen efter 30 sekunder, 2 minuter, 10 minuter, 1 timme, 6 timmar. Svarar ni fortfarande inte ger vi upp för just den händelsen, men den ligger kvar i leveransloggen och kan skickas om med en knapp. Går det fel tjugo gånger i rad stängs mottagaren av automatiskt, så att en nedlagd server inte belastar loggen i evighet.
Kan samma händelse komma två gånger?
Ja, vid nätverksfel. Leveransen är minst-en-gång, inte exakt-en-gång: svarar ni 200 men svaret aldrig når fram gör vi ett nytt försök. Varje notis har ett unikt id i fältet id och i headern Fluit-Delivery — spara det och hoppa över händelser ni redan behandlat.
Vilka krav ställs på vår mottagare?
Adressen måste vara https och nås från internet — interna adresser avvisas när ni sparar och kontrolleras igen vid varje utskick. Svara inom tio sekunder, helst genom att kvittera med 200 direkt och göra arbetet efteråt. Längre svarstid räknas som timeout och ger ett nytt försök.
Kan jag få en notis för alla ändringar, inte bara de färdiga händelserna?
Ja, med entity.changed. Den ger en notis varje gång en post ändras, även när ändringen inte har en egen händelse — ett justerat pris eller ett flyttat leveransdatum. Notisen innehåller namnen på fälten som ändrades, aldrig värdena. Strömmen är av som standard och slås på per entitetstyp, eftersom en enda import annars kan ge tusentals notiser. Ni får en notis per ändrad post, inte en per ändrat fält.
Kan en webhook-händelse starta något inne i Fluit?
Ja. En integration i Integration Center kan sättas att köras när en händelse inträffar i stället för på schema, och använder då samma händelselista som webhookarna. Det är användbart när ni vill att en exportfil ska skrivas i samma ögonblick som ordern läggs, i stället för vid nästa schemalagda körning.
Vad kostar webhooks?
Webhooks ingår i tilläggsmodulen API & Webhooks, som prissätts efter omsättningsnivå. Priserna står på prissidan.
Levererad order: effektiv order- och frakthantering

Vill ni slippa polla?

Berätta vad ert system behöver få veta så går vi igenom vilka händelser som passar och vad som krävs på er sida.