Webhook-uri
Primește notificări HTTP semnate atunci când linkurile, campaniile și postările din spațiul tău de lucru se schimbă.
Webhook-urile Styrar trimit notificări HTTP semnate atunci când resursele din spațiul tău de lucru se schimbă. Folosește-le pentru a sincroniza linkuri și click-uri cu un CRM, pentru a declanșa automatizări în propriul stack sau pentru a transmite evenimente de funnel către un data warehouse.
Acestea înlocuiesc API-ul retras de webhook-uri doar pentru linkuri (/v1/link-webhooks). Integrările noi trebuie să folosească exclusiv /v1/webhooks/*.
Configurarea unui webhook
Urmează acești pași pentru a ajunge de la zero la un endpoint verificat, pregătit pentru producție.
1. Pregătește URL-ul receptorului
Serverul tău are nevoie de un URL public HTTPS care acceptă cereri POST cu corp JSON. În producție, URL-urile de callback trebuie să folosească HTTPS. HTTP este permis doar în dezvoltarea locală.
Handler-ul tău ar trebui să:
- Citească corpul brut al cererii ca string sau buffer (nu parsa JSON-ul înainte de a verifica semnătura).
- Citească header-ele
Styrar-Signature,Styrar-Event-IdșiStyrar-Event-Type. - Verifice semnătura (vezi secțiunea Verificarea semnăturilor de mai jos).
- Returneze rapid un cod 2xx după ce evenimentul este acceptat. Pune procesarea costisitoare în coadă, asincron.
Exemplu de path: https://your-app.com/webhooks/styrar
Styrar nu poate livra către adrese private sau loopback precum localhost.
2. Obține acces la API (pentru configurare programatică)
Dacă creezi endpoint-uri prin API în loc de dashboard, ai nevoie de un token Bearer cu:
| Scop | Acces |
|---|---|
webhooks:read | Listează endpoint-uri, livrări și tipuri de evenimente |
webhooks:write | Creează, actualizează, șterge, testează, rotește secretul, reîncearcă livrările |
Creează o cheie API în Setări → Chei API cu webhooks:read și webhooks:write, sau folosește un token de acces OAuth dintr-o aplicație conectată cu aceleași scopuri.
Pentru spațiile de lucru ale companiilor, transmite companyId la cererile de listare și creare.
3. Creează un endpoint din dashboard
- Conectează-te și deschide Setări → Webhook-uri (
/settings/webhooks). - La secțiunea Endpoint-uri, introdu URL-ul endpoint-ului (callback-ul public HTTPS).
- Opțional, adaugă o Descriere (de exemplu „Sincronizare CRM producție").
- Selectează Evenimentele dorite (este necesar cel puțin unul). Alegeri comune:
link.clickedpentru urmărirea click-urilorlink.created/link.updated/link.deletedpentru ciclul de viață al linkurilorpost.publishedșicampaign.createdpentru evenimente de funnel
- Apasă Adaugă endpoint.
După creare, Styrar îți arată secretul de semnare (whsec_live_… sau whsec_test_…). Copiază-l imediat și stochează-l în managerul tău de secrete. Este afișat o singură dată. Dacă îl pierzi, folosește Rotește secretul pe endpoint și actualizează-ți serverul.
4. Creează un endpoint prin API
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"
]
}{
"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"
}Stochează secret imediat. Nu este returnat la cererile GET ulterioare. Un array eventTypes gol abonează la toate tipurile de evenimente; dashboard-ul necesită cel puțin un eveniment explicit.
5. Trimite un eveniment de test
Confirmă că serverul tău este accesibil înainte de a te baza pe trafic live.
Dashboard: Pe rândul endpoint-ului, apasă Trimite test. Styrar livrează un eveniment webhook.test. Ar trebui să vezi un toast de succes cu codul de stare HTTP.
API:
Authorization: Bearer sty_live_your_api_key{
"ok": true,
"statusCode": 200
}Când testul are succes, serverul tău ar fi trebuit să primească un eveniment webhook.test (vezi Primirea unui eveniment pe serverul tău de mai jos).
Verifică Livrările recente din dashboard (sau GET /v1/webhooks/deliveries) dacă testul eșuează. Probleme frecvente:
| Problemă | Ce să verifici |
|---|---|
| Conexiune refuzată / timeout | URL-ul este public HTTPS, firewall-ul permite Styrar, tunelul este activ |
| HTTP 4xx/5xx de la aplicația ta | Handler-ul returnează 2xx după verificare; loghează corpul brut și header-ele |
| Verificarea semnăturii eșuează | Folosește corpul brut, secretul corect, comparație în timp constant |
| Endpoint dezactivat | Reactivează din dashboard sau remediază problema care a cauzat HTTP 410 |
6. Verifică și procesează livrările
La fiecare POST către URL-ul tău:
- Parsează
Styrar-Signatureîn timestamp-ultși digest-ulv1. - Respinge dacă
teste mai vechi decât toleranța ta (se recomandă 5 minute). - Calculează HMAC-SHA256 pentru
"{t}.{raw_body}"cu secretul endpoint-ului tău. - Compară cu
v1folosind o verificare în timp constant. - Parsează JSON-ul doar după ce verificarea a avut succes.
- Deduplică pe baza
Styrar-Event-Id(livrare cel-puțin-o-dată).
Vezi secțiunea Verificarea semnăturilor de mai jos pentru un exemplu Node.js.
7. Lansează în producție
- Păstrează endpoint-ul Activat în dashboard.
- Abonează-te doar la evenimentele de care ai nevoie (reduce zgomotul și costul).
- Monitorizează Livrările recente pentru eșecuri și folosește Reîncearcă când e nevoie.
- Rotește secretul dacă există suspiciunea că a fost expus (Rotește secretul din dashboard sau
POST …/rotate-secret).
Start rapid
- Obține acces la API cu scopurile
webhooks:readșiwebhooks:write(cheie API sau OAuth). - Expune un receptor public HTTPS și creează un endpoint din Setări → Webhook-uri sau prin
POST /v1/webhooks/endpoints. - Copiază secretul de semnare când este afișat și stochează-l în siguranță.
- Trimite un eveniment de test și confirmă că serverul tău verifică
Styrar-Signatureși returnează 2xx. - Procesează evenimentele live cu deduplicare pe baza
Styrar-Event-Id.
Autentificare
Gestionarea webhook-urilor necesită un token Bearer cu scopurile listate la pasul 2 de mai sus. Cheile API cu scopuri corespunzătoare funcționează la fel ca token-urile de acces OAuth.
Tipuri de evenimente
Apelează GET /v1/webhooks/event-types pentru catalogul live din mediul tău. Abonează-te la tipuri specifice per endpoint, sau transmite un array eventTypes gol pentru a primi toate evenimentele.
webhook.test este trimis doar când apeși Trimite test; nu este emis de activitatea normală a spațiului de lucru.
Plicul evenimentului
Fiecare livrare folosește aceeași structură la nivel superior. Câmpurile specifice evenimentului se află sub data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID unic al evenimentului. Aceeași valoare ca header-ul Styrar-Event-Id. |
type | string | Numele evenimentului (de exemplu link.clicked). |
api_version | string | Versiunea schemei payload-ului (2026-06-22). |
created_at | string | Timestamp ISO 8601 la care a fost creat evenimentul. |
workspace.type | string | company sau personal. |
workspace.company_id | string | null | ID-ul companiei când workspace.type este company. |
data.object | object | Payload-ul evenimentului (documentat per eveniment mai jos). |
Exemplu complet de livrare (plic + payload link.created):
{
"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"
}
}
}
Pentru spațiile de lucru personale, workspace.type este personal și workspace.company_id este null. Payload-ul poate include company_id: null pe obiectele de tip link.
Sumarul evenimentelor
| Eveniment | Când se declanșează | Volum tipic |
|---|---|---|
link.created | Este creat un short link (POST /v1/links, creare în masă sau upsert în masă) | Scăzut |
link.updated | Un short link este actualizat (PATCH /v1/links/:id, actualizare în masă sau upsert în masă) | Scăzut |
link.deleted | Un short link este șters logic (DELETE /v1/links/:id sau ștergere în masă) | Scăzut |
link.clicked | Este înregistrat un click urmărit (asincron, după redirect, prin worker-ul de click-uri) | Ridicat |
link.experiment.completed | Un experiment A/B pe un link este finalizat și este selectat un câștigător | Scăzut |
campaign.created | Este creată o campanie (POST /v1/campaigns) | Scăzut |
post.published | O postare socială este publicată cu succes pe toate platformele țintă | Scăzut |
webhook.test | Rulezi Trimite test pe un endpoint | La cerere |
link.created
Se declanșează când un short link nou este salvat în spațiul tău de lucru.
Utilizări comune: Sincronizarea linkurilor noi cu un CRM, declanșarea automatizărilor de bun venit sau indexarea linkurilor într-un motor de căutare extern.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul link-ului |
short_code | string | Codul scurt public |
title | string | null | Titlul link-ului |
original_url | string | null | URL-ul de destinație |
is_active | boolean | Dacă link-ul este activ |
company_id | string | null | Compania deținătoare (spațiu de lucru companie) |
campaign_id | string | null | Campania asociată, dacă există |
link_group_id | string | null | ID-ul folderului/grupului, dacă există |
created_at | string | Ora creării în format ISO 8601 |
{
"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
Se declanșează când un short link existent este modificat (destinație, titlu, etichete, folder, setări UTM etc.).
Utilizări comune: Păstrarea sincronizării sistemelor externe atunci când un link se schimbă, fără a-l recrea.
Câmpurile data.object: Identice cu link.created (vezi mai sus).
{
"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
Se declanșează când un short link este șters logic (isActive setat la false). Link-ul nu mai redirecționează public, dar rămâne în istoricul spațiului tău de lucru.
Utilizări comune: Eliminarea linkurilor din cataloagele externe sau întreruperea automatizărilor asociate codului scurt respectiv.
Câmpurile data.object: Aceeași structură ca link.created, cu is_active mereu false.
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul link-ului |
short_code | string | Codul scurt la momentul ștergerii |
title | string | null | Titlul link-ului |
original_url | string | null | URL-ul de destinație |
is_active | boolean | false după ștergerea logică |
company_id | string | null | Compania deținătoare |
campaign_id | string | null | Campania asociată, dacă există |
link_group_id | string | null | ID-ul folderului/grupului, dacă există |
created_at | string | Ora creării originale |
{
"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
Se declanșează după ce un click al unui vizitator este persistat. Livrat asincron (nu pe calea redirecționării), așa că poate exista o întârziere ușoară sub sarcină mare.
Utilizări comune: Analiză a click-urilor în timp real, rutare bazată pe geo în stack-ul tău, fluxuri de activitate CRM sau ingestie în data warehouse.
Confidențialitate: Payload-urile includ dimensiuni geo și de dispozitiv, nu adrese IP brute.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul link-ului |
link_id | string | Identic cu id |
short_code | string | Codul scurt care a fost accesat |
title | string | null | Titlul link-ului |
country | string | null | Codul ISO al țării (geo lookup) |
city | string | null | Orașul din geo lookup |
device | string | null | Clasa de dispozitiv (de exemplu mobile, desktop) |
browser | string | null | Numele browser-ului |
os | string | null | Sistemul de operare |
platform | string | null | Indicație de platformă din analiza user agent |
referrer | string | null | URL-ul de referință, când e disponibil |
routing_rule_id | string | null | Regula de rutare geo/dispozitiv potrivită, dacă există |
experiment_variant_id | string | null | ID-ul variantei A/B când click-ul a trecut printr-un experiment |
clicked_at | string | Ora click-ului în format ISO 8601 |
{
"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
Se declanșează când un test A/B pe un short link este marcat ca finalizat și este selectată o variantă câștigătoare.
Utilizări comune: Înregistrarea rezultatelor experimentelor, actualizarea dashboard-urilor sau declanșarea campaniilor de follow-up în funcție de câștigător.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul experimentului |
link_id | string | ID-ul link-ului părinte |
short_code | string | null | Codul scurt al link-ului părinte |
status | string | completed |
assignment_mode | string | null | Modul în care a fost împărțit traficul (de exemplu ponderat) |
winning_variant_id | string | null | ID-ul variantei câștigătoare |
ended_at | string | null | Ora finalizării în format ISO 8601 |
variants | array | Rezultate per variantă (vezi mai jos) |
Fiecare element din variants:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul variantei |
label | string | Etichetă lizibilă pentru oameni |
weight | number | Ponderea de trafic folosită în test |
destination_url | string | URL-ul către care această variantă a trimis traficul |
clicks | number | Numărul total de click-uri înregistrate pentru această variantă |
{
"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
Se declanșează când este creată o campanie nouă în spațiul tău de lucru.
Utilizări comune: Provizionarea folderelor de campanie în instrumente externe, începerea fluxurilor de atribuire sau notificarea managerilor de cont.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul campaniei |
name | string | Numele campaniei |
description | string | null | Descrierea campaniei |
company_id | string | null | Compania deținătoare |
user_id | string | null | Utilizatorul care a creat (campanii personale) |
brand_id | string | null | Domeniul de brand, când este setat |
created_at | string | Ora creării în format ISO 8601 |
{
"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
Se declanșează când o postare programată sau imediată este publicată cu succes pe toate platformele țintă configurate.
Utilizări comune: Notificarea sistemelor din aval că conținutul este live, închiderea ciclului automatizărilor de campanie sau sincronizarea stării publicării cu un data warehouse.
Notă: Este emis doar când toate țintele au succes. Eșecurile parțiale nu emit acest eveniment momentan.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
id | string | ID-ul postării |
post_id | string | Identic cu id |
status | string | PUBLISHED |
company_id | string | null | Compania deținătoare |
user_id | string | null | Utilizatorul deținător (spațiu de lucru personal) |
brand_id | string | null | Domeniul de brand, când este setat |
campaign_id | string | null | Campania asociată, când este setată |
published_at | string | Ora publicării în format ISO 8601 |
platform_count | number | Numărul de platforme țintă din postare |
{
"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
Ping sintetic trimis doar când apeși Trimite test în dashboard sau apelezi POST /v1/webhooks/endpoints/:id/test.
Utilizări comune: Validarea URL-ului receptorului tău, TLS, verificarea semnăturii și gestionarea răspunsului înainte de lansarea în producție.
Câmpurile data.object:
| Câmp | Tip | Descriere |
|---|---|---|
endpoint_id | string | Endpoint-ul care a primit testul |
message | string | Mesaj fix: Styrar webhook test ping |
{
"endpoint_id": "wh_ep_abc123",
"message": "Styrar webhook test ping"
}
Exemple API
Listarea endpoint-urilor
Authorization: Bearer sty_live_your_api_key[
{
"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"
}
]Primirea unui eveniment pe serverul tău
Când un eveniment abonat se declanșează, Styrar face POST către URL-ul endpoint-ului tău. Acesta este payload-ul pe care îl primește handler-ul tău:
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"
}
}
}{
"received": true
}Corpul răspunsului tău poate fi gol. Returnează orice cod 2xx după ce verifici semnătura și accepți evenimentul. Styrar reîncearcă la răspunsuri non-2xx.
Payload-ul ping-ului de test
O acțiune Trimite test livrează webhook.test cu un payload mai mic:
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"
}
}
}Listarea livrărilor recente
Authorization: Bearer sty_live_your_api_key[
{
"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"
}
]Gestionarea endpoint-urilor
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
| Câmp | Descriere |
|---|---|
url | URL de callback HTTPS (HTTP permis doar în dezvoltare locală) |
description | Etichetă opțională |
eventTypes | Array de tipuri de evenimente abonate; gol înseamnă toate evenimentele |
enabled | Implicit true |
Secretul de semnare (whsec_live_… / whsec_test_…) este returnat o singură dată la creare și la rotate-secret. Poți înregistra până la 25 de endpoint-uri per domeniu de spațiu de lucru.
Livrări
GET /v1/webhooks/deliveries?endpointId={id}
GET /v1/webhooks/deliveries/:id
POST /v1/webhooks/deliveries/:id/retry
Fiecare rând de livrare urmărește status, attemptCount, nextAttemptAt, lastStatusCode, lastError și deliveredAt. Inspectează eșecurile din dashboard la Setări → Webhook-uri sau reîncearcă prin API.
Formatul livrării
Fiecare eveniment live este o cerere HTTP POST către URL-ul tău de callback. Header-ele și corpul sunt prezentate în secțiunea Primirea unui eveniment pe serverul tău de mai sus.
| Header | Descriere |
|---|---|
Styrar-Event-Id | ID unic al evenimentului (folosit pentru deduplicare) |
Styrar-Event-Type | de exemplu link.clicked |
Styrar-Signature | t={unix_ts},v1={hmac_sha256_hex} |
User-Agent | Styrar-Webhooks/1.0 |
Câmpurile plicului:
| Câmp | Descriere |
|---|---|
id | ID-ul evenimentului (corespunde cu Styrar-Event-Id) |
type | String-ul tipului de eveniment |
api_version | Versiunea schemei payload-ului |
created_at | Timestamp ISO 8601 |
workspace | Domeniu company sau personal |
data.object | Payload specific evenimentului |
Payload-urile pentru click-uri includ dimensiuni geo și de dispozitiv, nu adrese IP brute.
Verificarea semnăturilor
Semnătura urmează o schemă similară celei de la Stripe. Semnează "{timestamp}.{raw_body}" cu HMAC-SHA256 folosind secretul endpoint-ului tău.
- Parsează
Styrar-Signatureînt(timestamp unix) șiv1(digest hex). - Respinge dacă
teste în afara toleranței tale (recomandăm 5 minute). - Calculează digest-ul așteptat și compară-l cu
v1folosind o verificare în timp constant.
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
}
}
Verifică mereu folosind corpul brut al cererii înainte de a parsa JSON-ul.
Fiabilitate
- Livrările sunt cel-puțin-o-dată. Deduplică folosind
Styrar-Event-Idsauid-ul din plic. - Livrările eșuate reîncearcă cu backoff exponențial până la succes sau numărul maxim de încercări.
- Dacă serverul tău returnează HTTP 410, Styrar dezactivează automat endpoint-ul.
- Răspunde cu 2xx imediat ce ai acceptat evenimentul; procesează sarcinile costisitoare asincron.
Limite
- HTTPS este obligatoriu în producție pentru URL-urile de callback.
- 25 de endpoint-uri per domeniu de spațiu de lucru personal sau companie.
- Secretele de semnare sunt afișate o singură dată la creare și rotire; stochează-le în managerul tău de secrete.
Conexe
- Pixel de conversie — urmărește conversiile pe pagini de destinație pe care nu le controlezi
- Linkuri scurte și coduri QR în centrul de ajutor
- Chei API și aplicații conectate