Back to docs

Webhooks

Webhooks

Ontvang ondertekende HTTP-meldingen wanneer links, campagnes en posts in je werkruimte veranderen.

Styrar-webhooks sturen ondertekende HTTP-meldingen wanneer resources in je werkruimte veranderen. Gebruik ze om links en clicks te synchroniseren met een CRM, automatiseringen in je stack te triggeren, of funnelgebeurtenissen naar een datawarehouse te streamen.

Dit vervangt de uitgefaseerde, alleen-link-webhooks-API (/v1/link-webhooks). Nieuwe integraties moeten uitsluitend /v1/webhooks/* gebruiken.

Een webhook instellen

Volg deze stappen om van nul naar een geverifieerd, productieklaar endpoint te gaan.

1. Bereid je ontvanger-URL voor

Je server heeft een publieke HTTPS-URL nodig die POST-verzoeken met een JSON-body accepteert. In productie moeten callback-URL's HTTPS gebruiken.

Je handler moet:

  • De ruwe request body lezen als string of buffer (parse de JSON niet voordat je de handtekening hebt geverifieerd).
  • De headers Styrar-Signature, Styrar-Event-Id en Styrar-Event-Type lezen.
  • De handtekening verifiëren (zie de sectie Handtekeningen verifiëren hieronder).
  • Snel 2xx teruggeven nadat de gebeurtenis is geaccepteerd. Plan zwaar werk asynchroon in.

Voorbeeldpad: https://your-app.com/webhooks/styrar

Styrar kan niet leveren aan private of loopback-adressen zoals localhost.

2. Verkrijg API-toegang (voor programmatische opzet)

Als je endpoints via de API aanmaakt in plaats van via het dashboard, heb je een Bearer-token nodig met:

ScopeToegang
webhooks:readEndpoints, leveringen en gebeurtenistypen opvragen
webhooks:writeAanmaken, bijwerken, verwijderen, testen, secret roteren, leveringen opnieuw proberen

Maak een API-sleutel aan in Instellingen → API-sleutels met webhooks:read en webhooks:write, of gebruik een OAuth-accesstoken van een gekoppelde app met dezelfde scopes.

Voor bedrijfswerkruimten geef je companyId mee bij list- en create-verzoeken.

3. Maak een endpoint aan in het dashboard

  1. Log in en open Instellingen → Webhooks (/settings/webhooks).
  2. Voer onder Endpoints je Endpoint-URL in (de publieke HTTPS-callback).
  3. Voeg optioneel een Omschrijving toe (bijvoorbeeld "Productie CRM-sync").
  4. Selecteer de Gebeurtenissen die je wilt (minimaal één is verplicht). Veelgebruikte keuzes:
    • link.clicked voor clicktracking
    • link.created / link.updated / link.deleted voor de levenscyclus van links
    • post.published en campaign.created voor funnelgebeurtenissen
  5. Klik op Endpoint toevoegen.

Na het aanmaken toont Styrar je signing secret (whsec_live_… of whsec_test_…). Kopieer deze direct en bewaar hem in je secrets manager. Hij wordt maar één keer getoond. Ben je hem kwijt? Gebruik Secret roteren op het endpoint en werk je server bij.

4. Maak een endpoint aan via de API

RequestPOST
Authorization: Bearer sty_live_your_api_key
Content-Type: application/json

{
  "companyId": "cmxyz_company",
  "url": "https://your-app.com/webhooks/styrar",
  "description": "Production CRM sync",
  "eventTypes": [
    "link.clicked",
    "link.created"
  ]
}
Response201 Created
{
  "id": "wh_ep_abc123",
  "url": "https://your-app.com/webhooks/styrar",
  "description": "Production CRM sync",
  "enabled": true,
  "eventTypes": [
    "link.clicked",
    "link.created"
  ],
  "secretPrefix": "whsec_l",
  "companyId": "cmxyz_company",
  "userId": null,
  "disabledAt": null,
  "createdAt": "2026-06-22T12:00:00.000Z",
  "updatedAt": "2026-06-22T12:00:00.000Z",
  "secret": "whsec_live_abc123onlyShownOnce"
}

Bewaar secret direct. Hij wordt niet teruggegeven bij latere GET-verzoeken. Een leeg eventTypes-array abonneert op alle gebeurtenistypen; het dashboard vereist minimaal één expliciete gebeurtenis.

5. Stuur een testgebeurtenis

Bevestig dat je server bereikbaar is voordat je op live verkeer vertrouwt.

Dashboard: Klik op de endpointregel op Test versturen. Styrar levert een webhook.test-gebeurtenis af. Je zou een succesmelding moeten zien met de HTTP-statuscode.

API:

RequestPOST
Authorization: Bearer sty_live_your_api_key
Response200 OK
{
  "ok": true,
  "statusCode": 200
}

Als de test slaagt, zou je server een webhook.test-gebeurtenis hebben ontvangen (zie Een gebeurtenis op je server ontvangen hieronder).

Bekijk Recente leveringen in het dashboard (of GET /v1/webhooks/deliveries) als de test mislukt. Veelvoorkomende problemen:

ProbleemWat te controleren
Connectie geweigerd / timeoutURL is publiek HTTPS, firewall laat Styrar toe, tunnel draait
HTTP 4xx/5xx van je appHandler geeft 2xx terug na verificatie; log ruwe body en headers
Handtekeningverificatie misluktGebruik ruwe body, juiste secret, constant-time vergelijking
Endpoint uitgeschakeldSchakel opnieuw in via dashboard of verhelp de oorzaak van HTTP 410

6. Verifieer en verwerk leveringen

Bij elke POST naar je URL:

  1. Parse Styrar-Signature naar timestamp t en digest v1.
  2. Weiger als t ouder is dan je tolerantie (5 minuten aanbevolen).
  3. Berekenen de HMAC-SHA256 van "{t}.{raw_body}" met je endpoint-secret.
  4. Vergelijk met v1 met een constant-time check.
  5. Parse de JSON pas na succesvolle verificatie.
  6. Dedupliceer op Styrar-Event-Id (at-least-once levering).

Zie de sectie Handtekeningen verifiëren hieronder voor een Node.js-voorbeeld.

7. Ga live

  • Houd het endpoint Ingeschakeld in het dashboard.
  • Abonneer alleen op gebeurtenissen die je nodig hebt (vermindert ruis en kosten).
  • Monitor Recente leveringen op fouten en gebruik Opnieuw proberen waar nodig.
  • Roteer het secret als het mogelijk is uitgelekt (Secret roteren in dashboard of POST …/rotate-secret).

Snelstart

  1. Verkrijg API-toegang met de scopes webhooks:read en webhooks:write (API-sleutel of OAuth).
  2. Stel een publieke HTTPS-ontvanger bloot en maak een endpoint aan in Instellingen → Webhooks of via POST /v1/webhooks/endpoints.
  3. Kopieer de signing secret zodra deze getoond wordt en bewaar hem veilig.
  4. Stuur een testgebeurtenis en bevestig dat je server Styrar-Signature verifieert en 2xx teruggeeft.
  5. Verwerk live gebeurtenissen met deduplicatie op Styrar-Event-Id.

Authenticatie

Webhookbeheer vereist een Bearer-token met de scopes uit stap 2 hierboven. API-sleutels met de juiste scopes werken op dezelfde manier als OAuth-accesstokens.

Gebeurtenistypen

Roep GET /v1/webhooks/event-types aan voor de actuele catalogus in jouw omgeving. Abonneer per endpoint op specifieke typen, of geef een leeg eventTypes-array op om alle gebeurtenissen te ontvangen.

webhook.test wordt alleen verstuurd wanneer je op Test versturen klikt; het wordt niet uitgezonden door normale werkruimteactiviteit.

Gebeurtenis-envelope

Elke levering gebruikt dezelfde envelopvorm. Gebeurtenisspecifieke velden staan onder data.object:

VeldTypeBeschrijving
idstringUnieke gebeurtenis-id. Zelfde waarde als de header Styrar-Event-Id.
typestringNaam van de gebeurtenis (bijvoorbeeld link.clicked).
api_versionstringSchemaversie van de payload (2026-06-22).
created_atstringISO 8601-tijdstempel van het ontstaan van de gebeurtenis.
workspace.typestringcompany of personal.
workspace.company_idstring | nullBedrijfs-id wanneer workspace.type company is.
data.objectobjectGebeurtenis-payload (hieronder per gebeurtenis gedocumenteerd).

Volledig leveringsvoorbeeld (envelope + link.created-payload):

JSON
{
  "id": "evt_outbox_abc123",
  "type": "link.created",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "id": "clink_abc123",
      "short_code": "summer",
      "title": "Summer sale",
      "original_url": "https://example.com/sale",
      "is_active": true,
      "company_id": "cmxyz_company",
      "campaign_id": "ccamp_abc",
      "link_group_id": null,
      "created_at": "2026-06-22T12:00:00.000Z"
    }
  }
}

Voor persoonlijke werkruimten is workspace.type gelijk aan personal en workspace.company_id is null. De payload kan company_id: null bevatten op linkobjecten.

Overzicht gebeurtenissen

GebeurtenisWanneer het vuurtTypisch volume
link.createdEen korte link wordt aangemaakt (POST /v1/links, bulk create, of bulk upsert)Laag
link.updatedEen korte link wordt bijgewerkt (PATCH /v1/links/:id, bulk update, of bulk upsert)Laag
link.deletedEen korte link wordt soft-deleted (DELETE /v1/links/:id of bulk delete)Laag
link.clickedEen getrackte click wordt geregistreerd (asynchroon, na redirect via de click worker)Hoog
link.experiment.completedEen A/B-linkexperiment is voltooid en er is een winnaar geselecteerdLaag
campaign.createdEen campagne wordt aangemaakt (POST /v1/campaigns)Laag
post.publishedEen social post wordt succesvol gepubliceerd naar alle platformdoelenLaag
webhook.testJe voert Test versturen uit op een endpointOp aanvraag

link.created

Vuurt wanneer een nieuwe korte link in je werkruimte wordt opgeslagen.

Veelvoorkomend gebruik: Nieuwe links synchroniseren naar een CRM, welkomstautomatiseringen triggeren, of links indexeren in een externe zoekopslag.

Velden van data.object:

VeldTypeBeschrijving
idstringLink-id
short_codestringPublieke korte code
titlestring | nullLinktitel
original_urlstring | nullBestemmings-URL
is_activebooleanOf de link actief is
company_idstring | nullEigenaarbedrijf (bedrijfswerkruimte)
campaign_idstring | nullGekoppelde campagne, indien aanwezig
link_group_idstring | nullMap/groep-id, indien aanwezig
created_atstringISO 8601-aanmaaktijd
JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "original_url": "https://example.com/sale",
  "is_active": true,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": null,
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.updated

Vuurt wanneer een bestaande korte link wordt aangepast (bestemming, titel, tags, map, UTM-instellingen, enzovoort).

Veelvoorkomend gebruik: Externe systemen gesynchroniseerd houden wanneer een link verandert zonder hem opnieuw aan te maken.

Velden van data.object: Zelfde als link.created (zie hierboven).

JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale (updated)",
  "original_url": "https://example.com/sale-v2",
  "is_active": true,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": "lgrp_promos",
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.deleted

Vuurt wanneer een korte link wordt soft-deleted (isActive ingesteld op false). De link wordt niet langer publiek opgelost, maar blijft in je werkruimtegeschiedenis.

Veelvoorkomend gebruik: Links verwijderen uit externe catalogi of automatiseringen die aan die korte code gekoppeld zijn pauzeren.

Velden van data.object: Zelfde vorm als link.created, met is_active altijd false.

VeldTypeBeschrijving
idstringLink-id
short_codestringKorte code op moment van verwijdering
titlestring | nullLinktitel
original_urlstring | nullBestemmings-URL
is_activebooleanfalse na soft delete
company_idstring | nullEigenaarbedrijf
campaign_idstring | nullGekoppelde campagne, indien aanwezig
link_group_idstring | nullMap/groep-id, indien aanwezig
created_atstringOorspronkelijke aanmaaktijd
JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "original_url": "https://example.com/sale",
  "is_active": false,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": null,
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.clicked

Vuurt nadat een bezoekersclick is opgeslagen. Wordt asynchroon afgeleverd (niet op het redirectpad), dus verwacht een lichte vertraging bij hoge belasting.

Veelvoorkomend gebruik: Realtime click-analytics, geo-gebaseerde routering in je stack, CRM-activiteitsfeeds, of warehouse-ingestie.

Privacy: Payloads bevatten geo- en apparaatdimensies, geen ruwe IP-adressen.

Velden van data.object:

VeldTypeBeschrijving
idstringLink-id
link_idstringZelfde als id
short_codestringKorte code waarop geklikt werd
titlestring | nullLinktitel
countrystring | nullISO-landcode (geo-lookup)
citystring | nullStad uit geo-lookup
devicestring | nullApparaatklasse (bijvoorbeeld mobile, desktop)
browserstring | nullBrowsernaam
osstring | nullBesturingssysteem
platformstring | nullPlatformhint uit user-agent parsing
referrerstring | nullReferrer-URL indien beschikbaar
routing_rule_idstring | nullGematchte geo/apparaat-routeringsregel, indien aanwezig
experiment_variant_idstring | nullA/B-variant-id wanneer de click via een experiment liep
clicked_atstringISO 8601-clicktijd
JSON
{
  "id": "clink_abc123",
  "link_id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "country": "NL",
  "city": "Amsterdam",
  "device": "mobile",
  "browser": "Chrome",
  "os": "iOS",
  "platform": null,
  "referrer": "https://instagram.com/",
  "routing_rule_id": null,
  "experiment_variant_id": null,
  "clicked_at": "2026-06-22T12:00:00.000Z"
}

link.experiment.completed

Vuurt wanneer een A/B-test op een korte link wordt afgerond en er een winnende variant wordt geselecteerd.

Veelvoorkomend gebruik: Experimentresultaten loggen, dashboards bijwerken, of vervolgcampagnes triggeren op basis van de winnaar.

Velden van data.object:

VeldTypeBeschrijving
idstringExperiment-id
link_idstringBovenliggende link-id
short_codestring | nullKorte code van de bovenliggende link
statusstringcompleted
assignment_modestring | nullHoe verkeer werd verdeeld (bijvoorbeeld gewogen)
winning_variant_idstring | nullId van de winnende variant
ended_atstring | nullISO 8601-afrondingstijd
variantsarrayResultaten per variant (zie onder)

Elk item in variants:

VeldTypeBeschrijving
idstringVariant-id
labelstringLeesbaar label
weightnumberVerkeersgewicht gebruikt in de test
destination_urlstringURL waar deze variant verkeer naartoe stuurde
clicksnumberTotaal aantal clicks geregistreerd voor deze variant
JSON
{
  "id": "lexp_abc123",
  "link_id": "clink_abc123",
  "short_code": "summer",
  "status": "completed",
  "assignment_mode": "weighted",
  "winning_variant_id": "lvar_b",
  "ended_at": "2026-06-22T14:00:00.000Z",
  "variants": [
    {
      "id": "lvar_a",
      "label": "Control",
      "weight": 50,
      "destination_url": "https://example.com/a",
      "clicks": 120
    },
    {
      "id": "lvar_b",
      "label": "Variant B",
      "weight": 50,
      "destination_url": "https://example.com/b",
      "clicks": 184
    }
  ]
}

campaign.created

Vuurt wanneer een nieuwe campagne wordt aangemaakt in je werkruimte.

Veelvoorkomend gebruik: Campagnemappen aanmaken in externe tools, attributieworkflows starten, of accountmanagers informeren.

Velden van data.object:

VeldTypeBeschrijving
idstringCampagne-id
namestringCampagnenaam
descriptionstring | nullCampagnebeschrijving
company_idstring | nullEigenaarbedrijf
user_idstring | nullAanmakende gebruiker (persoonlijke campagnes)
brand_idstring | nullMerkscope indien ingesteld
created_atstringISO 8601-aanmaaktijd
JSON
{
  "id": "ccamp_abc123",
  "name": "Summer launch",
  "description": "Q2 product push",
  "company_id": "cmxyz_company",
  "user_id": null,
  "brand_id": "cbrand_abc",
  "created_at": "2026-06-22T12:00:00.000Z"
}

post.published

Vuurt wanneer een geplande of directe post succesvol wordt gepubliceerd naar alle geconfigureerde platformdoelen.

Veelvoorkomend gebruik: Downstream-systemen informeren dat content live is, campagne-automatiseringen afronden, of publicatiestatus synchroniseren naar een datawarehouse.

Let op: Wordt alleen uitgezonden wanneer elk doel slaagt. Gedeeltelijke fouten zenden deze gebeurtenis vandaag niet uit.

Velden van data.object:

VeldTypeBeschrijving
idstringPost-id
post_idstringZelfde als id
statusstringPUBLISHED
company_idstring | nullEigenaarbedrijf
user_idstring | nullEigenaargebruiker (persoonlijke werkruimte)
brand_idstring | nullMerkscope indien ingesteld
campaign_idstring | nullGekoppelde campagne indien ingesteld
published_atstringISO 8601-publicatietijd
platform_countnumberAantal platformdoelen op de post
JSON
{
  "id": "cpost_abc123",
  "post_id": "cpost_abc123",
  "status": "PUBLISHED",
  "company_id": "cmxyz_company",
  "user_id": null,
  "brand_id": "cbrand_abc",
  "campaign_id": "ccamp_abc123",
  "published_at": "2026-06-22T12:00:00.000Z",
  "platform_count": 3
}

webhook.test

Synthetische ping die alleen wordt verstuurd wanneer je op Test versturen klikt in het dashboard of POST /v1/webhooks/endpoints/:id/test aanroept.

Veelvoorkomend gebruik: Je ontvanger-URL, TLS, handtekeningverificatie en responsafhandeling valideren voordat je live gaat.

Velden van data.object:

VeldTypeBeschrijving
endpoint_idstringEndpoint dat de test ontving
messagestringVast bericht: Styrar webhook test ping
JSON
{
  "endpoint_id": "wh_ep_abc123",
  "message": "Styrar webhook test ping"
}

API-voorbeelden

Endpoints opvragen

RequestGET
Authorization: Bearer sty_live_your_api_key
Response200 OK
[
  {
    "id": "wh_ep_abc123",
    "url": "https://your-app.com/webhooks/styrar",
    "description": "Production CRM sync",
    "enabled": true,
    "eventTypes": ["link.clicked", "link.created"],
    "secretPrefix": "whsec_l",
    "companyId": "cmxyz_company",
    "userId": null,
    "disabledAt": null,
    "createdAt": "2026-06-22T12:00:00.000Z",
    "updatedAt": "2026-06-22T12:00:00.000Z"
  }
]

Een gebeurtenis op je server ontvangen

Wanneer een geabonneerde gebeurtenis plaatsvindt, doet Styrar een POST naar je endpoint-URL. Dit is de payload die je handler ontvangt:

RequestPOST
Content-Type: application/json
Styrar-Event-Id: evt_outbox_abc123
Styrar-Event-Type: link.clicked
Styrar-Signature: t=1719052800,v1=8f4b2c1a9e0d3f7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3
User-Agent: Styrar-Webhooks/1.0

{
  "id": "evt_outbox_abc123",
  "type": "link.clicked",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "id": "clink_abc123",
      "link_id": "clink_abc123",
      "short_code": "summer",
      "title": "Summer sale",
      "country": "NL",
      "city": "Amsterdam",
      "device": "mobile",
      "browser": "Chrome",
      "os": "iOS",
      "referrer": "https://instagram.com/",
      "routing_rule_id": null,
      "experiment_variant_id": null,
      "clicked_at": "2026-06-22T12:00:00.000Z"
    }
  }
}
Response200 OK
{
  "received": true
}

Je responsbody mag leeg zijn. Geef een willekeurige 2xx-status terug nadat je de handtekening hebt geverifieerd en de gebeurtenis hebt geaccepteerd. Styrar probeert het opnieuw bij niet-2xx-responses.

Test-ping-payload

Een actie Test versturen levert webhook.test af met een kleinere payload:

RequestPOST
Content-Type: application/json
Styrar-Event-Id: evt_test_abc123
Styrar-Event-Type: webhook.test
Styrar-Signature: t=1719052800,v1=...

{
  "id": "evt_test_abc123",
  "type": "webhook.test",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "endpoint_id": "wh_ep_abc123",
      "message": "Styrar webhook test ping"
    }
  }
}
Response200 OK

Recente leveringen opvragen

RequestGET
Authorization: Bearer sty_live_your_api_key
Response200 OK
[
  {
    "id": "wh_del_abc123",
    "endpointId": "wh_ep_abc123",
    "outboxEventId": "wh_out_abc123",
    "eventType": "link.clicked",
    "status": "delivered",
    "attemptCount": 1,
    "lastStatusCode": 200,
    "lastError": null,
    "durationMs": 142,
    "nextAttemptAt": null,
    "deliveredAt": "2026-06-22T12:00:01.000Z",
    "createdAt": "2026-06-22T12:00:00.500Z"
  }
]

Endpoints beheren

Plain text
GET    /v1/webhooks/endpoints?companyId={id}
POST   /v1/webhooks/endpoints
GET    /v1/webhooks/endpoints/:id
PATCH  /v1/webhooks/endpoints/:id
DELETE /v1/webhooks/endpoints/:id
POST   /v1/webhooks/endpoints/:id/test
POST   /v1/webhooks/endpoints/:id/rotate-secret
VeldBeschrijving
urlHTTPS-callback-URL
descriptionOptioneel label
eventTypesArray van geabonneerde gebeurtenistypen; leeg betekent alle gebeurtenissen
enabledStandaard true

De signing secret (whsec_live_… / whsec_test_…) wordt precies één keer teruggegeven bij het aanmaken en bij rotate-secret. Je kunt tot 25 endpoints per werkruimtescope registreren.

Leveringen

Plain text
GET  /v1/webhooks/deliveries?endpointId={id}
GET  /v1/webhooks/deliveries/:id
POST /v1/webhooks/deliveries/:id/retry

Elke leveringsregel houdt status, attemptCount, nextAttemptAt, lastStatusCode, lastError en deliveredAt bij. Bekijk mislukkingen in het dashboard onder Instellingen → Webhooks of probeer het opnieuw via de API.

Leveringsformaat

Elke live gebeurtenis is een HTTP-POST naar je callback-URL. Headers en body staan hierboven onder Een gebeurtenis op je server ontvangen.

HeaderBeschrijving
Styrar-Event-IdUnieke gebeurtenis-id (gebruik voor deduplicatie)
Styrar-Event-Typebijv. link.clicked
Styrar-Signaturet={unix_ts},v1={hmac_sha256_hex}
User-AgentStyrar-Webhooks/1.0

Envelopvelden:

VeldBeschrijving
idGebeurtenis-id (komt overeen met Styrar-Event-Id)
typeGebeurtenistype-string
api_versionSchemaversie van de payload
created_atISO 8601-tijdstempel
workspaceScope company of personal
data.objectGebeurtenisspecifieke payload

Clickpayloads bevatten geo- en apparaatdimensies, geen ruwe IP-adressen.

Handtekeningen verifiëren

De handtekening volgt een Stripe-achtig schema. Het ondertekent "{timestamp}.{raw_body}" met HMAC-SHA256 met je endpoint-secret.

  1. Parse Styrar-Signature naar t (unix-tijdstempel) en v1 (hex-digest).
  2. Weiger als t buiten je tolerantie valt (we adviseren 5 minuten).
  3. Berekenen de verwachte digest en vergelijk met v1 met een constant-time check.
JavaScript
import crypto from 'node:crypto'

function verifyStyrarWebhook(secret, signatureHeader, rawBody, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.trim().split('=')),
  )

  const timestamp = Number(parts.t)
  const receivedDigest = parts.v1 || ''

  if (!Number.isFinite(timestamp)) return false
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false

  const expectedDigest = crypto
    .createHmac('sha256', secret)
    .update(\`${timestamp}.${rawBody}\`)
    .digest('hex')

  try {
    return crypto.timingSafeEqual(
      Buffer.from(expectedDigest, 'utf8'),
      Buffer.from(receivedDigest, 'utf8'),
    )
  } catch {
    return false
  }
}

Verifieer altijd tegen de ruwe request body voordat je JSON parset.

Betrouwbaarheid

  • Leveringen zijn at-least-once. Dedupliceer met Styrar-Event-Id of het envelopveld id.
  • Mislukte leveringen worden opnieuw geprobeerd met exponentiële backoff tot succes of het maximale aantal pogingen.
  • Als je server HTTP 410 teruggeeft, schakelt Styrar het endpoint automatisch uit.
  • Reageer met 2xx zodra je de gebeurtenis hebt geaccepteerd; verwerk zwaar werk asynchroon.

Limieten

  • HTTPS verplicht in productie voor callback-URL's.
  • 25 endpoints per persoonlijke of bedrijfswerkruimtescope.
  • Signing secrets worden eenmalig getoond bij aanmaken en roteren; bewaar ze in je secrets manager.

Verwant

Join the beta waitlist

By signing up you agree to receive marketing email. See our Privacy Policy.