Salta ai contenuti
Supporto

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.

  1. Configuri un webhook - Specifichi un URL e quali eventi ascoltare
  2. Si verifica un evento - Ad esempio, una release viene consegnata a un negozio
  3. LabelGrid invia una richiesta POST - Il tuo server riceve i dati dell’evento
  4. Il tuo sistema li elabora - Automatizza i flussi di lavoro in base all’evento

  1. Clicca sull’icona del tuo profilo nell’angolo in alto a destra
  2. Seleziona Webhooks dal menu a tendina

  1. Clicca su Create Webhook
  2. Inserisci un Name per identificare questo webhook
  3. Inserisci l’URL dove vuoi ricevere le notifiche
  4. Seleziona quali Events devono attivare questo webhook
  5. Clicca su Create

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

Configura il tuo webhook per ascoltare questi eventi. L’identificatore evento e il valore che vedrai nella proprieta event del payload e nell’header X-Webhook-Event:

Identificatore eventoDescrizione
delivery.completedSi attiva quando una release viene consegnata con successo a un outlet
delivery.failedSi attiva quando la consegna a un outlet fallisce
takedown.completedSi attiva quando una richiesta di takedown viene completata
release.review.status_changedSi attiva quando lo stato di revisione di una release cambia
release.preflight.report_readySi attiva quando il rapporto Preflight QC di una release in attesa e pronto per essere recuperato
stream_radar.flag_createdSi attiva quando viene creata una segnalazione Stream Radar, o quando una segnalazione risolta si riapre su una nuova rilevazione
stream_radar.flag_resolvedSi attiva quando una segnalazione Stream Radar si risolve perche le rilevazioni sono cessate
release.distributedSi attiva quando una release viene distribuita
payment.statement_readySi attiva quando un rendiconto di pagamento e pronto per la visualizzazione
transcode.completedSi attiva quando la transcodifica audio di una traccia termina con successo
transcode.failedSi attiva quando la transcodifica di una traccia fallisce o termina in modo incompleto
distribution.outlet.status_changedSi attiva a ogni transizione dello stato di distribuzione per outlet

Puoi selezionare piu 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, cosi i consumatori con schema rigido possono ampliare in anticipo la loro validazione in ingresso.


L’elenco dei webhooks mostra:

ColonnaDescrizione
NameIl nome del webhook che hai assegnato
URLDove vengono inviate le notifiche
EventsNumero di eventi configurati
StatusAttivo o Inattivo
Success / FailConteggio delle consegne riuscite e fallite
Last TriggeredQuando il webhook e stato chiamato l’ultima volta
  1. Clicca sull’azione Edit nella riga del webhook
  2. Modifica il nome, l’URL o gli eventi
  3. Clicca su Save

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
  1. Clicca sull’azione Delete nella riga del webhook
  2. Conferma l’eliminazione

Prima di fare affidamento su un webhook in produzione, testalo:

  1. Clicca sull’azione Test sul tuo webhook
  2. LabelGrid invia un payload di test al tuo URL
  3. Verifica che il tuo endpoint l’abbia ricevuto ed elaborato correttamente

Monitora l’attivita dei webhooks e risolvi i problemi:

  1. Clicca sull’azione View Logs su un webhook
  2. Visualizza lo storico di tutte le consegne del webhook

Ogni voce di log mostra:

CampoDescrizione
Event TypeQuale evento ha attivato questa consegna
Response StatusCodice di stato HTTP dal tuo server
DurationQuanto tempo ha impiegato la richiesta
AttemptNumero del tentativo di ripetizione
TimestampQuando e avvenuta la consegna

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).


La struttura dell’oggetto data dipende dal tipo di event. Tutti i tipi di campo qui sotto sono tipi JSON come serializzati nel payload.

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"
}
}
CampoTipoDescrizione
distro_queue_idintegerID interno della coda per questo tentativo di consegna
release_idintegerLa release che e stata consegnata
label_idintegerL’etichetta proprietaria della release, cosi puoi instradare l’evento senza una ricerca aggiuntiva
release_catstring | nullIl tuo riferimento di catalogo della release
outlet_idinteger | nullL’ID dell’outlet di destinazione
outlet_namestring | nullNome leggibile dell’outlet (ad esempio, "Spotify")
statusstringSempre "complete" per questo evento

Viene attivato una volta per outlet quando la consegna di una release raggiunge uno stato di fallimento terminale. Stesso payload di delivery.completed piu 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."
}
}
CampoTipoDescrizione
statusstringUno tra error, fault, rejected, batch_exception
messagestring | nullMotivo del fallimento dall’outlet o dal pipeline di distribuzione

Viene attivato una volta per outlet quando una richiesta di rimozione ha successo. Stessa forma di delivery.completed piu 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
}
}

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 gia 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"
}
}

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"
}
}
CampoTipoDescrizione
previous_statusstringStato precedente. Uno tra draft, to_review, approved, rejected, require_changes, audit
new_statusstringNuovo stato. Lo stesso insieme di valori
review_issuesarray (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

Si attiva quando il rapporto di qualita Preflight QC di una release in attesa pre-revisione e 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 }
}
}
CampoTipoDescrizione
release_idintegerLa release a cui appartiene il rapporto
label_idintegerL’etichetta proprietaria della release
release_catstring | nullIl tuo riferimento di catalogo della release
release_titlestring | nullIl titolo della release
generated_atstringQuando i controlli sono terminati (ISO 8601). Corrisponde al report.generated_at dell’endpoint del rapporto di qualita
profileobjectIl profilo di qualita con cui sono stati calcolati i conteggi: {name, version}
countsobjectSolo conteggi aggregati: {blocking, informational, requires_feedback}. Il conteggio requires_feedback si sovrappone agli altri due

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
}
}
CampoTipoDescrizione
flag_idintegerL’identificatore stabile della segnalazione; corrisponde a id sugli endpoint Stream Radar
dspstringLa piattaforma su cui e stato osservato il pattern (p. es. spotify)
isrcstringL’ISRC della registrazione coinvolta
release_idintegerLa release a cui appartiene la registrazione
track_idinteger | nullLa traccia specifica, quando l’ISRC corrisponde in modo inequivocabile a una delle tue tracce
severitystringlow, medium o high
statusstringactive per questo evento
transitionstringpublished per una nuova segnalazione, reopened quando una segnalazione risolta e tornata attiva
first_detected_atstring | nullQuando il pattern e stato osservato per la prima volta per questa traccia e piattaforma (ISO 8601)
last_detected_atstring | nullLa rilevazione piu recente (ISO 8601)
estimated_affected_streamsinteger | nullUna stima di quanti ascolti sono coinvolti
published_atstringQuando la segnalazione ti e stata comunicata per la prima volta (ISO 8601)
resolved_atstring | nullnull mentre la segnalazione e attiva

Si attiva quando una segnalazione Stream Radar si risolve perche 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"
}
}

Viene attivato quando un estratto di pagamento viene generato ed e 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"
}
}
CampoTipoDescrizione
payment_request_idintegerID interno della richiesta di pagamento
invoice_numberstringRiferimento fattura per l’estratto
periodstring | nullData di fine periodo (data ISO 8601, YYYY-MM-DD)
amountnumberImporto dell’estratto nella valuta currency
total_due_usdnumberTotale dell’estratto convertito in USD
currencystringCodice valuta ISO 4217 (predefinito USD)

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" }
]
}
}
CampoTipoDescrizione
release_idintegerLa release a cui appartiene la traccia
label_idintegerL’etichetta proprietaria della release
track_idintegerLa traccia che e stata transcodificata
transcoder_queue_idintegerID interno della coda di transcodifica
statusstringStato grezzo della coda: complete, error o incomplete
status_messagestringCodice di motivo sicuro ed enumerato: transcode_complete, transcode_error o transcode_incomplete
filesarrayDettaglio per file della traccia: {asset_type_id, status} per ogni file transcodificato

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"
}
}
CampoTipoDescrizione
distro_queue_idintegerID interno della coda per questa consegna
release_idintegerLa release in fase di distribuzione
label_idintegerL’etichetta proprietaria della release
release_catstring | nullIl tuo riferimento di catalogo della release
outlet_idinteger | nullL’ID dell’outlet di destinazione
outlet_namestring | nullNome leggibile dell’outlet
previous_statusstring | nullLo stato precedente; null quando la riga non aveva uno stato precedente riconosciuto
statusstringIl nuovo stato

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.

Ogni richiesta POST webhook include questi header:

HeaderDescrizione
X-Webhook-SignatureHMAC-SHA256 del corpo grezzo della richiesta, in esadecimale minuscolo, senza prefisso di algoritmo
X-Webhook-TimestampTimestamp ISO 8601 della consegna (stesso valore della proprieta timestamp nel corpo)
X-Webhook-EventIdentificatore evento (ad esempio, delivery.completed)
X-Webhook-IdL’ID del webhook che riceve la consegna
User-AgentLabelGrid-Webhooks/1.0
Content-Typeapplication/json
  • Algoritmo: HMAC-SHA256
  • Codifica: Esadecimale minuscolo
  • Prefisso: Nessuno — il valore e solo il digest hex, non sha256=...
  • Contenuto firmato: L’intero corpo JSON grezzo della richiesta (il corpo include il timestamp come proprieta, quindi il timestamp e firmato implicitamente)
  1. Leggi il corpo grezzo della richiesta prima di qualsiasi parsing o trasformazione JSON. Riserializzare il JSON gia parsato puo produrre byte diversi e invalidare la firma.
  2. Calcola HMAC-SHA256(corpo_grezzo, il_tuo_segreto_webhook) e prendi il digest esadecimale minuscolo.
  3. Confronta con X-Webhook-Signature usando un confronto a tempo costante.
  4. (Consigliato) Rifiuta la richiesta se X-Webhook-Timestamp e piu vecchio della tua finestra di tolleranza al replay — suggeriamo 5 minuti.
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
if (! hash_equals($expected, $signature)) {
http_response_code(401);
exit('Firma non valida');
}
// Rifiuta consegne piu vecchie di 5 minuti
if (abs(time() - strtotime($timestamp)) > 300) {
http_response_code(401);
exit('Consegna obsoleta');
}
$payload = json_decode($rawBody, true);
// ... elabora l'evento
http_response_code(200);
const crypto = require('crypto');
// Express: cattura il corpo grezzo PRIMA di qualsiasi middleware JSON
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body; // Buffer
const signature = req.header('X-Webhook-Signature') || '';
const timestamp = req.header('X-Webhook-Timestamp') || '';
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');
}
if (Math.abs(Date.now() - new Date(timestamp).getTime()) > 5 * 60 * 1000) {
return res.status(401).send('Consegna obsoleta');
}
const payload = JSON.parse(rawBody.toString('utf8'));
// ... elabora l'evento
res.sendStatus(200);
});
import hmac, hashlib
from datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, prima di qualsiasi parsing JSON
signature = request.headers.get('X-Webhook-Signature', '')
timestamp = request.headers.get('X-Webhook-Timestamp', '')
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)
delivery_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
if abs((datetime.now(timezone.utc) - delivery_time).total_seconds()) > 300:
return ('Consegna obsoleta', 401)
return ('', 200) # elabora l'evento, poi conferma
  • 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 sempre hash_equals (PHP), crypto.timingSafeEqual (Node), hmac.compare_digest (Python), o l’equivalente nel tuo linguaggio.
  • Aspettarsi un prefisso sha256=. Il valore dell’header e solo il digest hex senza prefisso.
  • Saltare il controllo del timestamp. Senza di esso, una firma trapelata potrebbe essere riutilizzata indefinitamente.

LimiteValore
Timeout della richiesta10 secondi
Dimensione massima del payload64 KB
Numero massimo di webhook per utente10

Se il tuo endpoint non risponde entro 10 secondi, la consegna viene trattata come un fallimento e ritentata.

Se il tuo endpoint restituisce uno stato non 2xx o va in timeout, LabelGrid ritenta con backoff esponenziale:

TentativoAttesa prima del ritentativo
1 → 230 secondi
2 → 31 minuto
3 → 42 minuti
4 → 54 minuti
5 → 68 minuti
6 → 716 minuti
7 → 832 minuti
8 → 964 minuti
9 → 10128 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 piu ritentata.

Se un webhook accumula 100 consegne fallite cumulate, viene disattivato automaticamente. Riattivalo manualmente nella lista dei webhook dopo aver corretto il tuo endpoint. La riattivazione di un webhook disattivato azzera il conteggio dei fallimenti.

  • 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)
  • Monitora il conteggio dei fallimenti nella lista dei webhook
  • Controlla i log di consegna quando indaghi su eventi mancati

  • Invia messaggi Slack quando le release vanno online
  • Invia email al team quando le consegne falliscono
  • Aggiorna le dashboard interne
  • 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
  • Ricevi avvisi immediati per i fallimenti delle consegne
  • Monitora il progresso della distribuzione in tempo reale
  • Monitora i cambiamenti dello stato di revisione

  1. Controlla lo stato - Il webhook e Active?
  2. Verifica l’URL - L’endpoint e accessibile da internet?
  3. Controlla gli eventi - Sono selezionati gli eventi giusti?
  4. Rivedi i log - Ci sono errori registrati?
  1. Controlla il tuo endpoint - Restituisce 200 OK?
  2. Controlla il tempo di risposta - Risponde entro il timeout?
  3. Rivedi i messaggi di errore - Cosa sta fallendo?
  4. Testa manualmente - Invia un webhook di test

Se il segreto del tuo webhook e compromesso:

  1. Clicca su Regenerate Secret nelle impostazioni del webhook
  2. Aggiorna la tua applicazione con il nuovo segreto
  3. Il vecchio segreto smette immediatamente di funzionare

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 →