Webhooks
I webhooks ti permettono di ricevere notifiche in tempo reale quando si verificano eventi nel tuo account LabelGrid. Usa i webhooks per automatizzare i flussi di lavoro e integrarti con sistemi esterni.
Per gli sviluppatori: Puoi anche gestire i webhooks in modo programmatico tramite l’API. Consulta la Documentazione API LabelGrid per endpoint ed esempi.
Come funzionano i webhooks
Sezione intitolata “Come funzionano i webhooks”- Configuri un webhook - Specifichi un URL e quali eventi ascoltare
- Si verifica un evento - Ad esempio, una release viene consegnata a un negozio
- LabelGrid invia una richiesta POST - Il tuo server riceve i dati dell’evento
- Il tuo sistema li elabora - Automatizza i flussi di lavoro in base all’evento
Accedere ai webhooks
Sezione intitolata “Accedere ai webhooks”- Clicca sull’icona del tuo profilo nell’angolo in alto a destra
- Seleziona Webhooks dal menu a tendina
Creare un webhook
Sezione intitolata “Creare un webhook”- Clicca su Create Webhook
- Inserisci un Name per identificare questo webhook
- Inserisci l’URL dove vuoi ricevere le notifiche
- Seleziona quali Events devono attivare questo webhook
- Clicca su Create
Segreto del webhook
Sezione intitolata “Segreto del webhook”Quando crei un webhook, riceverai una chiave segreta. Usala per verificare che le richieste in arrivo provengano effettivamente da LabelGrid:
- Conserva il segreto in modo sicuro
- Verifica la firma sulle richieste in arrivo
- Se compromesso, rigenera il segreto
Eventi disponibili
Sezione intitolata “Eventi disponibili”Configura il tuo webhook per ascoltare questi eventi. L’identificatore evento e il valore che vedrai nella proprietà event del payload e nell’header X-Webhook-Event:
| Identificatore evento | Descrizione |
|---|---|
delivery.completed | Si attiva quando una release viene consegnata con successo a un outlet |
delivery.failed | Si attiva quando la consegna a un outlet fallisce |
takedown.completed | Si attiva quando una richiesta di takedown viene completata |
release.review.status_changed | Si attiva quando lo stato di revisione di una release cambia |
release.preflight.report_ready | Si attiva quando il rapporto Preflight QC di una release in attesa è pronto per essere recuperato |
stream_radar.flag_created | Si attiva quando viene creata una segnalazione Stream Radar, o quando una segnalazione risolta si riapre su una nuova rilevazione |
stream_radar.flag_resolved | Si attiva quando una segnalazione Stream Radar si risolve perché le rilevazioni sono cessate |
release.distributed | Si attiva quando una release viene distribuita |
payment.statement_ready | Si attiva quando un rendiconto di pagamento è pronto per la visualizzazione |
transcode.completed | Si attiva quando la transcodifica audio di una traccia termina con successo |
transcode.failed | Si attiva quando la transcodifica di una traccia fallisce o termina in modo incompleto |
distribution.outlet.status_changed | Si attiva a ogni transizione dello stato di distribuzione per outlet |
Puoi selezionare più eventi per un singolo webhook, oppure creare webhook separati per diversi tipi di eventi.
Puoi anche leggere questo elenco in modo programmatico: GET /api/public/webhooks/event-types restituisce ogni evento insieme a uno schema data che descrive le chiavi e i tipi del suo payload, così i consumatori con schema rigido possono ampliare in anticipo la loro validazione in ingresso.
Gestire i webhooks
Sezione intitolata “Gestire i webhooks”Visualizzare i tuoi webhooks
Sezione intitolata “Visualizzare i tuoi webhooks”L’elenco dei webhooks mostra:
| Colonna | Descrizione |
|---|---|
| Name | Il nome del webhook che hai assegnato |
| URL | Dove vengono inviate le notifiche |
| Events | Numero di eventi configurati |
| Status | Attivo o Inattivo |
| Success / Fail | Conteggio delle consegne riuscite e fallite |
| Last Triggered | Quando il webhook è stato chiamato l’ultima volta |
Modificare un webhook
Sezione intitolata “Modificare un webhook”- Clicca sull’azione Edit nella riga del webhook
- Modifica il nome, l’URL o gli eventi
- Clicca su Save
Attivazione / Disattivazione
Sezione intitolata “Attivazione / Disattivazione”Attiva o disattiva lo stato di un webhook senza eliminarlo:
- Active - Il webhook ricevera le notifiche
- Inactive - Il webhook e in pausa, nessuna notifica inviata
Eliminare un webhook
Sezione intitolata “Eliminare un webhook”- Clicca sull’azione Delete nella riga del webhook
- Conferma l’eliminazione
Testare i webhooks
Sezione intitolata “Testare i webhooks”Prima di fare affidamento su un webhook in produzione, testalo:
- Clicca sull’azione Test sul tuo webhook
- LabelGrid invia un payload di test al tuo URL
- Verifica che il tuo endpoint l’abbia ricevuto ed elaborato correttamente
Visualizzare i log dei webhooks
Sezione intitolata “Visualizzare i log dei webhooks”Monitora l’attività dei webhooks e risolvi i problemi:
- Clicca sull’azione View Logs su un webhook
- Visualizza lo storico di tutte le consegne del webhook
Dettagli del log
Sezione intitolata “Dettagli del log”Ogni voce di log mostra:
| Campo | Descrizione |
|---|---|
| Event Type | Quale evento ha attivato questa consegna |
| Response Status | Codice di stato HTTP dal tuo server |
| Duration | Quanto tempo ha impiegato la richiesta |
| Attempt | Numero del tentativo di ripetizione |
| Timestamp | Quando è avvenuta la consegna |
Formato del payload del webhook
Sezione intitolata “Formato del payload del webhook”Quando si verifica un evento, LabelGrid invia una richiesta POST al tuo URL con un payload JSON:
{ "event": "delivery.completed", "timestamp": "2026-05-05T10:00:00+00:00", "webhook_id": "123", "data": { // Dati specifici dell'evento }}Il campo timestamp usa il formato ISO 8601. webhook_id e l’ID del tuo webhook configurato (corrisponde all’header X-Webhook-Id).
Payload degli eventi
Sezione intitolata “Payload degli eventi”La struttura dell’oggetto data dipende dal tipo di event. Tutti i tipi di campo qui sotto sono tipi JSON come serializzati nel payload.
delivery.completed
Sezione intitolata “delivery.completed”Viene attivato una volta per outlet quando la consegna di una release raggiunge uno stato di successo terminale.
{ "event": "delivery.completed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "label_id": 321, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "complete" }}| Campo | Tipo | Descrizione |
|---|---|---|
distro_queue_id | integer | ID interno della coda per questo tentativo di consegna |
release_id | integer | La release che è stata consegnata |
label_id | integer | L’etichetta proprietaria della release, così puoi instradare l’evento senza una ricerca aggiuntiva |
release_cat | string | null | Il tuo riferimento di catalogo della release |
outlet_id | integer | null | L’ID dell’outlet di destinazione |
outlet_name | string | null | Nome leggibile dell’outlet (ad esempio, "Spotify") |
status | string | Sempre "complete" per questo evento |
delivery.failed
Sezione intitolata “delivery.failed”Viene attivato una volta per outlet quando la consegna di una release raggiunge uno stato di fallimento terminale. Stesso payload di delivery.completed più un campo message.
{ "event": "delivery.failed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "label_id": 321, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "error", "message": "Outlet rejected the delivery: missing ISRC." }}| Campo | Tipo | Descrizione |
|---|---|---|
status | string | Uno tra error, fault, rejected, batch_exception |
message | string | null | Motivo del fallimento dall’outlet o dal pipeline di distribuzione |
takedown.completed
Sezione intitolata “takedown.completed”Viene attivato una volta per outlet quando una richiesta di rimozione ha successo. Stessa forma di delivery.completed più un flag takedown: true.
{ "event": "takedown.completed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "label_id": 321, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "status": "complete", "takedown": true }}release.distributed
Sezione intitolata “release.distributed”Viene attivato una volta per release quando la release passa allo stato di consegna distributed. Si attiva solo alla transizione verso distributed, non sui salvataggi successivi mentre la release e già distribuita.
{ "event": "release.distributed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "label_id": 321, "release_cat": "ABC123", "release_title": "Summer EP", "delivery_status": "distributed" }}release.review.status_changed
Sezione intitolata “release.review.status_changed”Viene attivato ogni volta che una release si sposta tra stati di revisione.
{ "event": "release.review.status_changed", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "label_id": 321, "release_cat": "ABC123", "release_title": "Summer EP", "previous_status": "to_review", "new_status": "approved" }}| Campo | Tipo | Descrizione |
|---|---|---|
previous_status | string | Stato precedente. Uno tra draft, to_review, approved, rejected, require_changes, audit |
new_status | string | Nuovo stato. Lo stesso insieme di valori |
review_issues | array (opzionale) | Presente solo nelle transizioni verso require_changes e rejected: i problemi che richiedono la tua attenzione. La chiave viene omessa in ogni altra transizione, quindi non dare per scontato che sia sempre presente |
release.preflight.report_ready
Sezione intitolata “release.preflight.report_ready”Si attiva quando il rapporto di qualità Preflight QC di una release in attesa pre-revisione è pronto per essere recuperato. Richiede il componente aggiuntivo Preflight QC sul tuo account.
{ "event": "release.preflight.report_ready", "timestamp": "2026-07-07T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "label_id": 321, "release_cat": "ABC123", "release_title": "Summer EP", "generated_at": "2026-07-07T09:58:12+00:00", "profile": { "name": "quality_report", "version": 2 }, "counts": { "blocking": 1, "informational": 2, "requires_feedback": 1 } }}| Campo | Tipo | Descrizione |
|---|---|---|
release_id | integer | La release a cui appartiene il rapporto |
label_id | integer | L’etichetta proprietaria della release |
release_cat | string | null | Il tuo riferimento di catalogo della release |
release_title | string | null | Il titolo della release |
generated_at | string | Quando i controlli sono terminati (ISO 8601). Corrisponde al report.generated_at dell’endpoint del rapporto di qualità |
profile | object | Il profilo di qualità con cui sono stati calcolati i conteggi: {name, version} |
counts | object | Solo conteggi aggregati: {blocking, informational, requires_feedback}. Il conteggio requires_feedback si sovrappone agli altri due |
stream_radar.flag_created
Sezione intitolata “stream_radar.flag_created”Si attiva quando viene creata una segnalazione Stream Radar: una segnalazione del tutto nuova oppure una segnalazione precedentemente risolta che si riapre su una nuova rilevazione. Richiede il componente aggiuntivo Stream Radar sul tuo account. Il campo transition distingue i due casi: published per una nuova segnalazione, reopened per una tornata attiva.
{ "event": "stream_radar.flag_created", "timestamp": "2026-07-07T10:00:00+00:00", "webhook_id": "123", "data": { "flag_id": 4501, "dsp": "spotify", "isrc": "USRC12345678", "release_id": 789, "track_id": 654, "severity": "high", "status": "active", "transition": "published", "first_detected_at": "2026-07-06T00:00:00+00:00", "last_detected_at": "2026-07-07T00:00:00+00:00", "estimated_affected_streams": 12500, "published_at": "2026-07-07T09:58:12+00:00", "resolved_at": null }}| Campo | Tipo | Descrizione |
|---|---|---|
flag_id | integer | L’identificatore stabile della segnalazione; corrisponde a id sugli endpoint Stream Radar |
dsp | string | La piattaforma su cui è stato osservato il pattern (p. es. spotify) |
isrc | string | L’ISRC della registrazione coinvolta |
release_id | integer | La release a cui appartiene la registrazione |
track_id | integer | null | La traccia specifica, quando l’ISRC corrisponde in modo inequivocabile a una delle tue tracce |
severity | string | low, medium o high |
status | string | active per questo evento |
transition | string | published per una nuova segnalazione, reopened quando una segnalazione risolta e tornata attiva |
first_detected_at | string | null | Quando il pattern è stato osservato per la prima volta per questa traccia e piattaforma (ISO 8601) |
last_detected_at | string | null | La rilevazione più recente (ISO 8601) |
estimated_affected_streams | integer | null | Una stima di quanti ascolti sono coinvolti |
published_at | string | Quando la segnalazione ti è stata comunicata per la prima volta (ISO 8601) |
resolved_at | string | null | null mentre la segnalazione è attiva |
stream_radar.flag_resolved
Sezione intitolata “stream_radar.flag_resolved”Si attiva quando una segnalazione Stream Radar si risolve perché le rilevazioni sono cessate. Richiede il componente aggiuntivo Stream Radar. Stessi campi di stream_radar.flag_created (senza transition), con status impostato su resolved e resolved_at valorizzato.
{ "event": "stream_radar.flag_resolved", "timestamp": "2026-07-14T10:00:00+00:00", "webhook_id": "123", "data": { "flag_id": 4501, "dsp": "spotify", "isrc": "USRC12345678", "release_id": 789, "track_id": 654, "severity": "high", "status": "resolved", "first_detected_at": "2026-07-06T00:00:00+00:00", "last_detected_at": "2026-07-12T00:00:00+00:00", "estimated_affected_streams": 18700, "published_at": "2026-07-07T09:58:12+00:00", "resolved_at": "2026-07-14T09:55:03+00:00" }}payment.statement_ready
Sezione intitolata “payment.statement_ready”Viene attivato quando un estratto di pagamento viene generato ed è pronto per la visualizzazione.
{ "event": "payment.statement_ready", "timestamp": "2026-05-18T10:00:00+00:00", "webhook_id": "123", "data": { "payment_request_id": 1024, "invoice_number": "INV-2026-001", "period": "2026-04-30", "amount": 1234.56, "total_due_usd": 1234.56, "currency": "USD" }}| Campo | Tipo | Descrizione |
|---|---|---|
payment_request_id | integer | ID interno della richiesta di pagamento |
invoice_number | string | Riferimento fattura per l’estratto |
period | string | null | Data di fine periodo (data ISO 8601, YYYY-MM-DD) |
amount | number | Importo dell’estratto nella valuta currency |
total_due_usd | number | Totale dell’estratto convertito in USD |
currency | string | Codice valuta ISO 4217 (predefinito USD) |
transcode.completed e transcode.failed
Sezione intitolata “transcode.completed e transcode.failed”Si attiva quando la transcodifica audio di una traccia termina. transcode.completed si attiva in caso di successo; transcode.failed si attiva quando la transcodifica fallisce o termina in modo incompleto. Entrambi condividono la stessa forma di payload.
{ "event": "transcode.completed", "timestamp": "2026-07-07T10:00:00+00:00", "webhook_id": "123", "data": { "release_id": 789, "label_id": 321, "track_id": 654, "transcoder_queue_id": 987, "status": "complete", "status_message": "transcode_complete", "files": [ { "asset_type_id": 2, "status": "complete" } ] }}| Campo | Tipo | Descrizione |
|---|---|---|
release_id | integer | La release a cui appartiene la traccia |
label_id | integer | L’etichetta proprietaria della release |
track_id | integer | La traccia che è stata transcodificata |
transcoder_queue_id | integer | ID interno della coda di transcodifica |
status | string | Stato grezzo della coda: complete, error o incomplete |
status_message | string | Codice di motivo sicuro ed enumerato: transcode_complete, transcode_error o transcode_incomplete |
files | array | Dettaglio per file della traccia: {asset_type_id, status} per ogni file transcodificato |
distribution.outlet.status_changed
Sezione intitolata “distribution.outlet.status_changed”Si attiva a ogni transizione dello stato di distribuzione per outlet (ad esempio scheduled → transcoding → batched → complete), non solo su quelle terminali coperte da delivery.completed, delivery.failed e takedown.completed. Questo evento e prolisso per natura: iscriviti solo se vuoi la progressione completa per outlet.
{ "event": "distribution.outlet.status_changed", "timestamp": "2026-07-07T10:00:00+00:00", "webhook_id": "123", "data": { "distro_queue_id": 456, "release_id": 789, "label_id": 321, "release_cat": "ABC123", "outlet_id": 12, "outlet_name": "Spotify", "previous_status": "transcoding", "status": "batched" }}| Campo | Tipo | Descrizione |
|---|---|---|
distro_queue_id | integer | ID interno della coda per questa consegna |
release_id | integer | La release in fase di distribuzione |
label_id | integer | L’etichetta proprietaria della release |
release_cat | string | null | Il tuo riferimento di catalogo della release |
outlet_id | integer | null | L’ID dell’outlet di destinazione |
outlet_name | string | null | Nome leggibile dell’outlet |
previous_status | string | null | Lo stato precedente; null quando la riga non aveva uno stato precedente riconosciuto |
status | string | Il nuovo stato |
Verifica delle firme del webhook
Sezione intitolata “Verifica delle firme del webhook”Ogni consegna webhook e firmata in modo che tu possa verificare che provenga davvero da LabelGrid. Verifica sempre la firma prima di elaborare l’evento.
Header della richiesta
Sezione intitolata “Header della richiesta”Ogni richiesta POST webhook include questi header:
| Header | Descrizione |
|---|---|
X-Webhook-Signature | HMAC-SHA256 del corpo grezzo della richiesta, in esadecimale minuscolo, senza prefisso di algoritmo |
X-Webhook-Timestamp | Copia di comodo della proprietà timestamp presente nel corpo. Non è coperta dalla firma — non usarla mai per stabilire se una consegna è recente. |
X-Webhook-Event | Identificatore evento (ad esempio, delivery.completed) |
X-Webhook-Id | L’ID della configurazione del webhook che riceve la consegna (non è l’ID della singola consegna) |
User-Agent | LabelGrid-Webhooks/1.0 |
Content-Type | application/json |
Algoritmo
Sezione intitolata “Algoritmo”- Algoritmo: HMAC-SHA256
- Codifica: Esadecimale minuscolo
- Prefisso: Nessuno — il valore è solo il digest hex, non
sha256=... - Contenuto firmato: L’intero corpo JSON grezzo della richiesta — e nient’altro. Nessun header è firmato.
Il corpo contiene una propria proprietà timestamp, quindi quel valore è protetto dalla firma. L’header X-Webhook-Timestamp ne è solo un duplicato, inviato per comodità, e chi intercetta una consegna può modificarlo liberamente senza invalidare la firma. Per stabilire se una consegna è recente devi quindi leggere timestamp dal corpo già parsato, mai dall’header.
Procedura di verifica
Sezione intitolata “Procedura di verifica”- Leggi il corpo grezzo della richiesta prima di qualsiasi parsing o trasformazione JSON. Riserializzare il JSON già parsato può produrre byte diversi e invalidare la firma.
- Calcola
HMAC-SHA256(corpo_grezzo, il_tuo_segreto_webhook)e prendi il digest esadecimale minuscolo. - Confronta con
X-Webhook-Signatureusando un confronto a tempo costante. Se non corrisponde, fermati qui. - Solo a questo punto esegui il parsing del corpo e rifiuta la richiesta se la sua proprietà
timestampè più vecchia della tua finestra di tolleranza al replay — suggeriamo 5 minuti. Poiché quel valore è firmato, un attaccante non può aggiornarlo per far sembrare attuale una consegna intercettata.
Ogni nuovo tentativo viene firmato di nuovo con un timestamp aggiornato, quindi una finestra di 5 minuti non rifiuta mai un tentativo legittimo, per quanto avanzato sia nel programma dei tentativi.
Esempio PHP
Sezione intitolata “Esempio PHP”$rawBody = file_get_contents('php://input');$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
if (! hash_equals($expected, $signature)) { http_response_code(401); exit('Firma non valida');}
// Esegui il parsing solo dopo aver verificato l'autenticità dei byte.$payload = json_decode($rawBody, true);
// Per sapere se la consegna è recente si usa il timestamp FIRMATO nel corpo,// mai l'header X-Webhook-Timestamp.if (! isset($payload['timestamp']) || abs(time() - strtotime($payload['timestamp'])) > 300) { http_response_code(401); exit('Consegna obsoleta');}
// ... elabora l'evento (vedi "Gestire le consegne ripetute" più sotto)http_response_code(200);Esempio Node.js
Sezione intitolata “Esempio Node.js”const crypto = require('crypto');
// Express: cattura il corpo grezzo PRIMA di qualsiasi middleware JSONapp.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const rawBody = req.body; // Buffer const signature = req.header('X-Webhook-Signature') || '';
const expected = crypto .createHmac('sha256', webhookSecret) .update(rawBody) .digest('hex');
const sigBuf = Buffer.from(signature, 'hex'); const expBuf = Buffer.from(expected, 'hex');
if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) { return res.status(401).send('Firma non valida'); }
// Esegui il parsing solo dopo aver verificato l'autenticità dei byte. const payload = JSON.parse(rawBody.toString('utf8'));
// Per sapere se la consegna è recente si usa il timestamp FIRMATO nel corpo, // mai l'header X-Webhook-Timestamp. const sentAt = new Date(payload.timestamp).getTime();
if (Number.isNaN(sentAt) || Math.abs(Date.now() - sentAt) > 5 * 60 * 1000) { return res.status(401).send('Consegna obsoleta'); }
// ... elabora l'evento (vedi "Gestire le consegne ripetute" più sotto) res.sendStatus(200);});Esempio Python
Sezione intitolata “Esempio Python”import hmac, hashlib, jsonfrom datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, prima di qualsiasi parsing JSONsignature = request.headers.get('X-Webhook-Signature', '')
expected = hmac.new( webhook_secret.encode('utf-8'), raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature): return ('Firma non valida', 401)
payload = json.loads(raw_body) # esegui il parsing solo a byte autenticati
delivery_time = datetime.fromisoformat(payload['timestamp']) # il valore FIRMATO, mai l'headerif abs((datetime.now(timezone.utc) - delivery_time).total_seconds()) > 300: return ('Consegna obsoleta', 401)
return ('', 200) # elabora l'evento, poi confermaErrori comuni
Sezione intitolata “Errori comuni”- Stabilire se una consegna è recente basandosi sull’header
X-Webhook-Timestamp. L’header non è firmato. Chi intercetta una consegna può rinviare corpo e firma identici con un valore dell’header aggiornato e superare all’infinito un controllo basato sull’header. Leggi invecetimestampdal corpo già parsato: quel valore è firmato. - Riserializzare il corpo prima di calcolare l’hash. I framework che parsano il JSON automaticamente (Express
express.json(), il corpo della richiesta predefinito di Laravel) perdono i byte originali. Cattura prima il corpo grezzo. - Usare un confronto non a tempo costante (
==,===). Suscettibile ad attacchi temporali — usa semprehash_equals(PHP),crypto.timingSafeEqual(Node),hmac.compare_digest(Python), o l’equivalente nel tuo linguaggio. - Aspettarsi un prefisso
sha256=. Il valore dell’header è solo il digest hex senza prefisso. - Saltare il controllo su quanto è recente la consegna. Senza di esso, una consegna intercettata può essere rinviata al tuo endpoint all’infinito.
- Considerare
X-Webhook-Idcome l’ID della consegna. Identifica la configurazione del webhook, non la singola consegna, e non è nemmeno firmato.
Gestire le consegne ripetute
Sezione intitolata “Gestire le consegne ripetute”La consegna dei webhook è at-least-once: una consegna che il tuo endpoint ha davvero elaborato può arrivare di nuovo se la tua risposta 2xx è andata persa o è arrivata dopo il timeout di 10 secondi, e LabelGrid la ritenta. Verificare la firma dimostra che una richiesta è autentica, non che tu non l’abbia già gestita.
Le consegne non hanno un ID univoco per singola consegna, quindi costruisci la tua chiave di idempotenza a partire dal payload firmato. Di solito bastano il tipo di evento più gli identificatori contenuti in data — per esempio delivery.completed più distro_queue_id, oppure transcode.completed più track_id. Registra la chiave quando elabori un evento e ignora tutto ciò che hai già registrato.
Non usare la firma o il timestamp come chiave. Ogni tentativo viene firmato di nuovo nel momento in cui viene inviato, quindi il rinvio di un evento che hai già gestito arriva con un timestamp diverso e una firma diversa: la chiave deve nascere dagli identificatori dell’evento stesso.
Combina questo con il controllo qui sopra su quanto è recente la consegna: quel controllo limita per quanto tempo una consegna intercettata resta riutilizzabile, mentre l’idempotenza rende innocua una ripetizione, che arrivi da un nuovo tentativo o da un attaccante entro la finestra.
Limiti e affidabilita
Sezione intitolata “Limiti e affidabilita”Limiti della richiesta
Sezione intitolata “Limiti della richiesta”| Limite | Valore |
|---|---|
| Timeout della richiesta | 10 secondi |
| Dimensione massima del payload | 64 KB |
| Numero massimo di webhook per utente | 10 |
Se il tuo endpoint non risponde entro 10 secondi, la consegna viene trattata come un fallimento e ritentata.
Programma dei tentativi
Sezione intitolata “Programma dei tentativi”Se il tuo endpoint restituisce uno stato non 2xx o va in timeout, LabelGrid ritenta con backoff esponenziale:
| Tentativo | Attesa prima del ritentativo |
|---|---|
| 1 → 2 | 30 secondi |
| 2 → 3 | 1 minuto |
| 3 → 4 | 2 minuti |
| 4 → 5 | 4 minuti |
| 5 → 6 | 8 minuti |
| 6 → 7 | 16 minuti |
| 7 → 8 | 32 minuti |
| 8 → 9 | 64 minuti |
| 9 → 10 | 128 minuti |
Ogni intervallo include 0–30 secondi di jitter. Dopo 10 tentativi (~4,5 ore di tempo totale trascorso), la consegna viene registrata come fallita in modo permanente e non viene più ritentata.
Disattivazione automatica
Sezione intitolata “Disattivazione automatica”Se l’endpoint di un webhook continua a fallire — consegne fallite consecutive senza alcuna consegna riuscita nel mezzo —, LabelGrid disattiva automaticamente il webhook per smettere di ritentare un endpoint che chiaramente non può ricevere eventi. Il contatore dei fallimenti si azzera a ogni consegna riuscita, quindi un problema occasionale non disattiva mai un webhook; solo un fallimento prolungato e ininterrotto lo fa.
Quando un webhook viene disattivato in questo modo, il suo proprietario riceve un’email. L’email indica il nome del webhook e l’URL del suo endpoint, oltre al tipo di errore che ha causato la disattivazione — ad esempio un timeout di connessione o errori HTTP ripetuti.
La riattivazione e in autonomia: correggi il tuo endpoint, poi riattiva il webhook da Profilo → Webhooks. Riattivare un webhook disattivato azzera il suo contatore dei fallimenti. La lista dei webhook mostra lo stato attivo e il numero di fallimenti attuale di ogni webhook, così puoi individuare a colpo d’occhio un endpoint con problemi.
Buone pratiche per l’affidabilita
Sezione intitolata “Buone pratiche per l’affidabilita”- Restituisci una risposta 2xx rapidamente (entro 10 secondi)
- Elabora i dati in modo asincrono dopo la conferma
- Verifica la firma su ogni richiesta (vedi Verifica delle firme del webhook)
- Rendi il tuo gestore idempotente: la consegna è at-least-once (vedi Gestire le consegne ripetute)
- Monitora il conteggio dei fallimenti nella lista dei webhook
- Controlla i log di consegna quando indaghi su eventi mancati
Casi d’uso
Sezione intitolata “Casi d’uso”Notifiche automatizzate
Sezione intitolata “Notifiche automatizzate”- Invia messaggi Slack quando le release vanno online
- Invia email al team quando le consegne falliscono
- Aggiorna le dashboard interne
Automazione dei flussi di lavoro
Sezione intitolata “Automazione dei flussi di lavoro”- Avvia campagne di marketing quando le release vengono distribuite
- Aggiorna il tuo sito web quando sono disponibili nuovi contenuti
- Sincronizza lo stato con strumenti di project management esterni
Monitoraggio e allerta
Sezione intitolata “Monitoraggio e allerta”- Ricevi avvisi immediati per i fallimenti delle consegne
- Monitora il progresso della distribuzione in tempo reale
- Monitora i cambiamenti dello stato di revisione
Risoluzione dei problemi
Sezione intitolata “Risoluzione dei problemi”Il webhook non riceve eventi
Sezione intitolata “Il webhook non riceve eventi”- Controlla lo stato - Il webhook e Active?
- Verifica l’URL - L’endpoint e accessibile da internet?
- Controlla gli eventi - Sono selezionati gli eventi giusti?
- Rivedi i log - Ci sono errori registrati?
Alto numero di fallimenti
Sezione intitolata “Alto numero di fallimenti”- Controlla il tuo endpoint - Restituisce 200 OK?
- Controlla il tempo di risposta - Risponde entro il timeout?
- Rivedi i messaggi di errore - Cosa sta fallendo?
- Testa manualmente - Invia un webhook di test
Rigenerazione del segreto
Sezione intitolata “Rigenerazione del segreto”Se il segreto del tuo webhook e compromesso:
- Clicca su Regenerate Secret nelle impostazioni del webhook
- Aggiorna la tua applicazione con il nuovo segreto
- Il vecchio segreto smette immediatamente di funzionare
Hai bisogno di aiuto?
Sezione intitolata “Hai bisogno di aiuto?”Se hai domande sui webhooks, contatta il nostro team di supporto.
Non usi ancora LabelGrid?
Tutto ciò che hai appena letto è disponibile sulla nostra piattaforma.
Scopri cosa può fare LabelGrid →