Ga naar inhoud
Support

Webhooks

Met webhooks ontvang je realtime meldingen wanneer er iets gebeurt in je LabelGrid-account. Gebruik webhooks om workflows te automatiseren en aan externe systemen te koppelen.

Voor ontwikkelaars: Je kunt webhooks ook programmatisch beheren via de API. Zie de LabelGrid API-documentatie voor endpoints en voorbeelden.

  1. Je stelt een webhook in - Geef een URL op en de gebeurtenissen waarop je wilt reageren
  2. Er gebeurt iets - Bijvoorbeeld: een release wordt geleverd aan een winkel
  3. LabelGrid stuurt een POST-verzoek - Je server ontvangt de gegevens van de gebeurtenis
  4. Je systeem verwerkt het - Automatiseer workflows op basis van de gebeurtenis

  1. Klik rechtsboven op je profielpictogram
  2. Kies Webhooks in het uitklapmenu

  1. Klik op Create Webhook
  2. Voer een Naam in om deze webhook te herkennen
  3. Voer de URL in waarop je de meldingen wilt ontvangen
  4. Kies welke Gebeurtenissen deze webhook moeten activeren
  5. Klik op Create

Bij het aanmaken van een webhook krijg je een secret key. Daarmee controleer je of binnenkomende verzoeken echt van LabelGrid komen:

  • Bewaar de secret veilig
  • Controleer de handtekening van binnenkomende verzoeken
  • Genereer de secret opnieuw als die is gelekt

Stel je webhook in om op deze gebeurtenissen te reageren. De Gebeurtenis-identifier is de waarde die je terugziet in de event-property van de payload en in de X-Webhook-Event-header:

Gebeurtenis-identifierBeschrijving
delivery.completedTreedt op wanneer een release succesvol is geleverd aan een outlet
delivery.failedTreedt op wanneer de levering aan een outlet mislukt
takedown.completedTreedt op wanneer een takedown-verzoek is voltooid
release.review.status_changedTreedt op wanneer de reviewstatus van een release verandert
release.distributedTreedt op wanneer een release wordt gedistribueerd
payment.statement_readyTreedt op wanneer een afrekening klaarstaat om te bekijken

Je kunt meerdere gebeurtenissen selecteren voor één webhook, of aparte webhooks aanmaken voor verschillende gebeurtenistypen.


De webhooklijst toont:

KolomBeschrijving
NaamDe naam die je aan de webhook hebt gegeven
URLWaar de meldingen naartoe gaan
GebeurtenissenAantal ingestelde gebeurtenissen
StatusActief of inactief
Geslaagd / MisluktAantal geslaagde en mislukte leveringen
Laatst geactiveerdWanneer de webhook voor het laatst is aangeroepen
  1. Klik op de actie Edit op de webhookrij
  2. Pas de naam, URL of gebeurtenissen aan
  3. Klik op Save

Wissel de actieve status van een webhook zonder hem te verwijderen:

  • Actief - De webhook ontvangt meldingen
  • Inactief - De webhook staat op pauze, er worden geen meldingen verstuurd
  1. Klik op de actie Delete op de webhookrij
  2. Bevestig het verwijderen

Test een webhook voordat je er in productie op vertrouwt:

  1. Klik op de actie Test bij je webhook
  2. LabelGrid stuurt een testpayload naar je URL
  3. Controleer of je endpoint die correct heeft ontvangen en verwerkt

Houd webhookactiviteit in de gaten en los problemen op:

  1. Klik op de actie View Logs bij een webhook
  2. Bekijk de volledige geschiedenis van webhookleveringen

Elke logregel toont:

VeldBeschrijving
GebeurtenistypeWelke gebeurtenis deze levering heeft geactiveerd
ResponsstatusHTTP-statuscode van je server
DuurHoe lang het verzoek duurde
PogingNummer van de herhaalpoging
TijdstempelWanneer de levering plaatsvond

Wanneer er iets gebeurt, stuurt LabelGrid een POST-verzoek naar je URL met een JSON-payload:

{
"event": "delivery.completed",
"timestamp": "2026-05-05T10:00:00+00:00",
"webhook_id": "123",
"data": {
// Event-specific data
}
}

Het timestamp-veld gebruikt de ISO 8601-notatie. webhook_id is de ID van je ingestelde webhook (die overeenkomt met de X-Webhook-Id-header).


De structuur van het data-object hangt af van het event-type. Alle veldtypen hieronder zijn de JSON-typen zoals ze in de payload zijn geserialiseerd.

Wordt één keer per outlet afgevuurd wanneer de levering van een release een definitieve succesvolle status bereikt.

{
"event": "delivery.completed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "complete"
}
}
VeldTypeBeschrijving
distro_queue_idintegerInterne queue-ID voor deze leveringspoging
release_idintegerDe geleverde release
release_catstring | nullJe catalogusreferentie voor de release
outlet_idintegerDe ID van de doel-outlet
outlet_namestring | nullLeesbare naam van de outlet (bijv. "Spotify")
statusstringAltijd "complete" bij deze gebeurtenis

Wordt één keer per outlet afgevuurd wanneer de levering van een release definitief mislukt. Dezelfde payload als delivery.completed, plus een message-veld.

{
"event": "delivery.failed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "error",
"message": "Outlet rejected the delivery: missing ISRC."
}
}
VeldTypeBeschrijving
statusstringEen van error, fault, rejected, batch_exception
messagestring | nullReden van het mislukken vanuit de outlet of de distributiepijplijn

Wordt één keer per outlet afgevuurd wanneer een takedown-verzoek slaagt. Dezelfde vorm als delivery.completed, plus een takedown: true-vlag.

{
"event": "takedown.completed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "complete",
"takedown": true
}
}

Wordt één keer per release afgevuurd wanneer de release overgaat naar de leveringsstatus distributed. Vuurt alleen af bij de overgang naar distributed, niet bij latere bewaaracties terwijl de release al gedistribueerd is.

{
"event": "release.distributed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"release_id": 789,
"release_cat": "ABC123",
"release_title": "Summer EP",
"delivery_status": "distributed"
}
}

Wordt afgevuurd telkens als een release tussen reviewstatussen wisselt.

{
"event": "release.review.status_changed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"release_id": 789,
"release_cat": "ABC123",
"release_title": "Summer EP",
"previous_status": "to_review",
"new_status": "approved"
}
}
VeldTypeBeschrijving
previous_statusstringVorige status. Een van draft, to_review, approved, rejected, require_changes, audit
new_statusstringNieuwe status. Dezelfde set waarden

Wordt afgevuurd wanneer een afrekening is gegenereerd en klaarstaat om te bekijken.

{
"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"
}
}
VeldTypeBeschrijving
payment_request_idintegerInterne ID van het betaalverzoek
invoice_numberstringFactuurreferentie van de afrekening
periodstring | nullEinddatum van de periode (ISO 8601-datum, YYYY-MM-DD)
amountnumberBedrag van de afrekening in currency
total_due_usdnumberTotaal van de afrekening omgerekend naar USD
currencystringISO 4217-valutacode (standaard USD)

Elke webhooklevering is ondertekend, zodat je kunt controleren of die echt van LabelGrid komt. Verifieer de handtekening altijd voordat je de gebeurtenis verwerkt.

Elk webhook-POST-verzoek bevat deze headers:

HeaderBeschrijving
X-Webhook-SignatureHMAC-SHA256 van de ruwe request-body, kleine letters hex, zonder algoritmeprefix
X-Webhook-TimestampISO 8601-tijdstempel van de levering (dezelfde waarde als de timestamp-property in de body)
X-Webhook-EventGebeurtenis-identifier (bijv. delivery.completed)
X-Webhook-IdDe ID van de webhook die de levering ontvangt
User-AgentLabelGrid-Webhooks/1.0
Content-Typeapplication/json
  • Algoritme: HMAC-SHA256
  • Codering: Hexadecimaal in kleine letters
  • Prefix: Geen. De waarde is enkel de hex-digest, niet sha256=...
  • Ondertekende inhoud: De volledige ruwe JSON request-body (de body bevat de timestamp zelf als property, dus de timestamp wordt impliciet mee-ondertekend)
  1. Lees de ruwe request-body voordat je JSON parseert of transformeert. De geparseerde JSON opnieuw serialiseren kan andere bytes opleveren en de handtekening breken.
  2. Bereken HMAC-SHA256(raw_body, your_webhook_secret) en neem de hex-digest in kleine letters.
  3. Vergelijk die met X-Webhook-Signature met een vergelijking in constante tijd.
  4. (Aanbevolen) Weiger het verzoek als X-Webhook-Timestamp ouder is dan je replay-tolerantievenster. We raden 5 minuten aan.
$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('Invalid signature');
}
// Reject deliveries older than 5 minutes
if (abs(time() - strtotime($timestamp)) > 300) {
http_response_code(401);
exit('Stale delivery');
}
$payload = json_decode($rawBody, true);
// ... process the event
http_response_code(200);
const crypto = require('crypto');
// Express: capture raw body BEFORE any JSON middleware
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('Invalid signature');
}
if (Math.abs(Date.now() - new Date(timestamp).getTime()) > 5 * 60 * 1000) {
return res.status(401).send('Stale delivery');
}
const payload = JSON.parse(rawBody.toString('utf8'));
// ... process the event
res.sendStatus(200);
});
import hmac, hashlib
from datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, before any JSON parsing
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 ('Invalid signature', 401)
delivery_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
if abs((datetime.now(timezone.utc) - delivery_time).total_seconds()) > 300:
return ('Stale delivery', 401)
return ('', 200) # process the event, then ack
  • De body opnieuw serialiseren voordat je hasht. Frameworks die JSON automatisch parsen (Express express.json(), de standaard request-body van Laravel) verliezen de oorspronkelijke bytes. Leg eerst de ruwe body vast.
  • Een vergelijking gebruiken die niet in constante tijd werkt (==, ===). Die is vatbaar voor timingaanvallen. Gebruik altijd hash_equals (PHP), crypto.timingSafeEqual (Node), hmac.compare_digest (Python) of het equivalent in jouw taal.
  • Een sha256=-prefix verwachten. De headerwaarde is enkel de hex-digest, zonder prefix.
  • De timestampcontrole overslaan. Zonder die controle kan een gelekte handtekening eindeloos worden hergebruikt.

LimietWaarde
Time-out van het verzoek10 seconden
Maximale payloadgrootte64 KB
Maximaal aantal webhooks per gebruiker10

Reageert je endpoint niet binnen 10 seconden, dan geldt de levering als mislukt en wordt die opnieuw geprobeerd.

Geeft je endpoint een status buiten de 2xx-reeks of een time-out, dan probeert LabelGrid het opnieuw met exponentiële backoff:

PogingWachttijd voor herhaling
1 → 230 seconden
2 → 31 minuut
3 → 42 minuten
4 → 54 minuten
5 → 68 minuten
6 → 716 minuten
7 → 832 minuten
8 → 964 minuten
9 → 10128 minuten

Elk interval bevat 0 tot 30 seconden jitter. Na 10 pogingen (in totaal ongeveer 4,5 uur) wordt de levering gelogd als definitief mislukt en niet meer opnieuw geprobeerd.

Loopt een webhook op tot 100 mislukte leveringen in totaal, dan wordt die automatisch uitgeschakeld. Schakel hem na het herstellen van je endpoint handmatig weer in vanuit de webhooklijst. Een uitgeschakelde webhook opnieuw activeren zet de teller met mislukte leveringen op nul.

  • Geef snel (binnen 10 seconden) een 2xx-respons
  • Verwerk de gegevens asynchroon nadat je hebt bevestigd
  • Verifieer de handtekening van elk verzoek (zie Webhook-handtekeningen verifiëren)
  • Houd je aantal mislukte leveringen in de webhooklijst in de gaten
  • Bekijk de leveringslogs als je gemiste gebeurtenissen onderzoekt

  • Stuur Slack-berichten wanneer releases live gaan
  • Mail je team wanneer leveringen mislukken
  • Werk interne dashboards bij
  • Start marketingcampagnes wanneer releases worden gedistribueerd
  • Werk je website bij wanneer er nieuwe content beschikbaar is
  • Synchroniseer de status naar externe projectmanagementtools
  • Krijg meteen meldingen bij mislukte leveringen
  • Volg de distributievoortgang in realtime
  • Houd wijzigingen in de reviewstatus in de gaten

  1. Controleer de status - Staat de webhook op actief?
  2. Controleer de URL - Is het endpoint bereikbaar vanaf het internet?
  3. Controleer de gebeurtenissen - Zijn de juiste gebeurtenissen geselecteerd?
  4. Bekijk de logs - Staan er fouten geregistreerd?
  1. Controleer je endpoint - Geeft het 200 OK terug?
  2. Controleer de responstijd - Reageert het binnen de time-out?
  3. Bekijk de foutmeldingen - Wat gaat er mis?
  4. Test handmatig - Stuur een testwebhook

Als je webhook-secret is gelekt:

  1. Klik op Regenerate Secret in de webhookinstellingen
  2. Werk je applicatie bij met de nieuwe secret
  3. De oude secret werkt meteen niet meer

Heb je vragen over webhooks, neem dan contact op met ons supportteam.

Gebruik je LabelGrid nog niet?

Alles wat je net hebt gelezen, kun je gebruiken op ons platform.

Ontdek wat LabelGrid kan →