Pular para o conteúdo
Suporte

Webhooks

Os webhooks permitem que você receba notificações em tempo real quando ocorrem eventos na sua conta LabelGrid. Use webhooks para automatizar fluxos de trabalho e integrar com sistemas externos.

Para desenvolvedores: você também pode gerenciar webhooks de forma programática pela API. Consulte a documentação da API do LabelGrid para ver endpoints e exemplos.

  1. Você configura um webhook - Informe uma URL e quais eventos quer monitorar
  2. Um evento ocorre - Por exemplo, um lançamento é entregue a uma loja
  3. O LabelGrid envia uma requisição POST - Seu servidor recebe os dados do evento
  4. Seu sistema processa - Automatize fluxos de trabalho com base no evento

  1. Clique no ícone do seu perfil no canto superior direito
  2. Selecione Webhooks no menu suspenso

  1. Clique em Create Webhook
  2. Informe um Name para identificar este webhook
  3. Informe a URL onde você quer receber as notificações
  4. Selecione quais Events devem acionar este webhook
  5. Clique em Create

Ao criar um webhook, você recebe uma chave secreta. Use-a para verificar que as requisições recebidas realmente vêm do LabelGrid:

  • Guarde a chave secreta em local seguro
  • Verifique a assinatura nas requisições recebidas
  • Se ela for comprometida, gere uma nova chave secreta

Configure seu webhook para monitorar estes eventos. O identificador do evento é o valor que você verá na propriedade event do payload e no cabeçalho X-Webhook-Event:

Identificador do eventoDescrição
delivery.completedDisparado quando um lançamento é entregue com sucesso a uma loja
delivery.failedDisparado quando a entrega a uma loja falha
takedown.completedDisparado quando uma solicitação de remoção (takedown) é concluída
release.review.status_changedDisparado quando o status de revisão de um lançamento muda
release.distributedDisparado quando um lançamento é distribuído
payment.statement_readyDisparado quando um extrato de pagamento está pronto para visualização

Você pode selecionar vários eventos em um único webhook ou criar webhooks separados para tipos de evento diferentes.


A lista de webhooks mostra:

ColunaDescrição
NameO nome que você atribuiu ao webhook
URLPara onde as notificações são enviadas
EventsNúmero de eventos configurados
StatusAtivo ou Inativo
Success / FailContagem de entregas bem-sucedidas e com falha
Last TriggeredQuando o webhook foi acionado pela última vez
  1. Clique na ação Edit na linha do webhook
  2. Altere o nome, a URL ou os eventos
  3. Clique em Save

Alterne o status de ativação de um webhook sem excluí-lo:

  • Active - O webhook receberá notificações
  • Inactive - O webhook está pausado; nenhuma notificação é enviada
  1. Clique na ação Delete na linha do webhook
  2. Confirme a exclusão

Antes de depender de um webhook em produção, teste-o:

  1. Clique na ação Test no seu webhook
  2. O LabelGrid envia um payload de teste para a sua URL
  3. Verifique se o seu endpoint recebeu e processou tudo corretamente

Monitore a atividade do webhook e investigue problemas:

  1. Clique na ação View Logs em um webhook
  2. Veja o histórico de todas as entregas do webhook

Cada entrada do log mostra:

CampoDescrição
Event TypeQual evento acionou esta entrega
Response StatusCódigo de status HTTP retornado pelo seu servidor
DurationQuanto tempo a requisição levou
AttemptNúmero da tentativa de reenvio
TimestampQuando a entrega ocorreu

Quando um evento ocorre, o LabelGrid envia uma requisição POST para a sua URL com um payload JSON:

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

O campo timestamp usa o formato ISO 8601. webhook_id é o ID do webhook que você configurou (corresponde ao cabeçalho X-Webhook-Id).


A estrutura do objeto data depende do tipo de event. Todos os tipos de campo abaixo são tipos JSON, conforme serializados no payload.

Disparado uma vez por loja quando a entrega de um lançamento atinge um estado final de sucesso.

{
"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"
}
}
CampoTipoDescrição
distro_queue_idintegerID interno da fila para esta tentativa de entrega
release_idintegerO lançamento que foi entregue
release_catstring | nullA referência de catálogo do seu lançamento
outlet_idintegerO ID da loja de destino
outlet_namestring | nullNome legível da loja (ex.: "Spotify")
statusstringSempre "complete" para este evento

Disparado uma vez por loja quando a entrega de um lançamento atinge um estado final de falha. Mesmo payload de delivery.completed, acrescido do campo message.

{
"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."
}
}
CampoTipoDescrição
statusstringUm de error, fault, rejected, batch_exception
messagestring | nullMotivo da falha informado pela loja ou pelo pipeline de distribuição

Disparado uma vez por loja quando uma solicitação de remoção (takedown) é concluída com sucesso. Mesmo formato de delivery.completed, acrescido de um sinalizador takedown: true.

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

Disparado uma vez por lançamento quando o lançamento passa para o estado de entrega distributed. Dispara apenas na transição para distributed, e não nas gravações seguintes enquanto o lançamento já está distribuído.

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

Disparado sempre que um lançamento muda de um estado de revisão para outro.

{
"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"
}
}
CampoTipoDescrição
previous_statusstringStatus anterior. Um de draft, to_review, approved, rejected, require_changes, audit
new_statusstringNovo status. Mesmo conjunto de valores

Disparado quando um extrato de pagamento é gerado e fica pronto para visualização.

{
"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"
}
}
CampoTipoDescrição
payment_request_idintegerID interno da solicitação de pagamento
invoice_numberstringReferência da fatura do extrato
periodstring | nullData de fim do período (data ISO 8601, YYYY-MM-DD)
amountnumberValor do extrato na moeda indicada em currency
total_due_usdnumberTotal do extrato convertido para USD
currencystringCódigo de moeda ISO 4217 (padrão: USD)

Toda entrega de webhook é assinada para que você possa verificar que ela realmente veio do LabelGrid. Sempre verifique a assinatura antes de processar o evento.

Toda requisição POST de webhook inclui estes cabeçalhos:

CabeçalhoDescrição
X-Webhook-SignatureHMAC-SHA256 do corpo bruto da requisição, em hexadecimal minúsculo, sem prefixo de algoritmo
X-Webhook-TimestampTimestamp ISO 8601 da entrega (mesmo valor da propriedade timestamp no corpo)
X-Webhook-EventIdentificador do evento (ex.: delivery.completed)
X-Webhook-IdO ID do webhook que está recebendo a entrega
User-AgentLabelGrid-Webhooks/1.0
Content-Typeapplication/json
  • Algoritmo: HMAC-SHA256
  • Codificação: Hexadecimal minúsculo
  • Prefixo: Nenhum. O valor é apenas o digest em hexadecimal, não sha256=...
  • Conteúdo assinado: O corpo bruto completo da requisição JSON (o próprio corpo inclui o timestamp como uma propriedade, então o timestamp é assinado implicitamente)
  1. Leia o corpo bruto da requisição antes de qualquer parsing ou transformação de JSON. Reserializar o JSON já interpretado pode produzir bytes diferentes e invalidar a assinatura.
  2. Calcule HMAC-SHA256(raw_body, your_webhook_secret) e use o digest em hexadecimal minúsculo.
  3. Compare com X-Webhook-Signature usando uma comparação de tempo constante.
  4. (Recomendado) Rejeite a requisição se X-Webhook-Timestamp for mais antiga do que a sua janela de tolerância contra replay (sugerimos 5 minutos).
$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
  • Reserializar o corpo antes de calcular o hash. Frameworks que interpretam JSON automaticamente (express.json() do Express, corpo de requisição padrão do Laravel) perdem os bytes originais. Capture o corpo bruto primeiro.
  • Usar uma comparação que não seja de tempo constante (==, ===). Fica vulnerável a ataques de temporização. Use sempre hash_equals (PHP), crypto.timingSafeEqual (Node), hmac.compare_digest (Python) ou o equivalente na sua linguagem.
  • Esperar um prefixo sha256=. O valor do cabeçalho é apenas o digest em hexadecimal, sem prefixo.
  • Pular a verificação do timestamp. Sem ela, uma assinatura vazada poderia ser reenviada indefinidamente.

LimiteValor
Tempo limite da requisição10 segundos
Tamanho máximo do payload64 KB
Máximo de webhooks por usuário10

Se o seu endpoint não responder em até 10 segundos, a entrega é tratada como falha e reenviada.

Se o seu endpoint retornar um status fora da faixa 2xx ou exceder o tempo limite, o LabelGrid reenvia com backoff exponencial:

TentativaEspera antes do reenvio
1 → 230 segundos
2 → 31 minuto
3 → 42 minutos
4 → 54 minutos
5 → 68 minutos
6 → 716 minutos
7 → 832 minutos
8 → 964 minutos
9 → 10128 minutos

Cada intervalo inclui de 0 a 30 segundos de jitter. Após 10 tentativas (cerca de 4,5 horas de tempo total decorrido), a entrega é registrada como falha permanente e não é mais reenviada.

Se um webhook acumular 100 entregas com falha no total, ele é desativado automaticamente. Reative-o manualmente na lista de webhooks depois de corrigir o seu endpoint. Reativar um webhook desativado zera a contagem de falhas.

  • Retorne uma resposta 2xx rapidamente (em até 10 segundos)
  • Processe os dados de forma assíncrona depois de confirmar o recebimento
  • Verifique a assinatura em toda requisição (consulte Como verificar as assinaturas dos webhooks)
  • Acompanhe a contagem de falhas na lista de webhooks
  • Consulte os logs de entrega ao investigar eventos perdidos

  • Envie mensagens no Slack quando os lançamentos entram no ar
  • Envie e-mails para a sua equipe quando as entregas falham
  • Atualize painéis internos
  • Acione campanhas de marketing quando os lançamentos são distribuídos
  • Atualize seu site quando há novo conteúdo disponível
  • Sincronize o status com ferramentas externas de gestão de projetos
  • Receba alertas imediatos sobre falhas de entrega
  • Acompanhe o progresso da distribuição em tempo real
  • Monitore as mudanças de status de revisão

  1. Verifique o status - O webhook está Active?
  2. Confira a URL - O endpoint está acessível pela internet?
  3. Verifique os eventos - Os eventos certos estão selecionados?
  4. Revise os logs - Há algum erro registrado?
  1. Verifique o seu endpoint - Ele está retornando 200 OK?
  2. Verifique o tempo de resposta - Ele responde dentro do tempo limite?
  3. Revise as mensagens de erro - O que está falhando?
  4. Teste manualmente - Envie um webhook de teste

Se a chave secreta do seu webhook for comprometida:

  1. Clique em Regenerate Secret nas configurações do webhook
  2. Atualize a sua aplicação com a nova chave secreta
  3. A chave antiga deixa de funcionar imediatamente

Se você tem dúvidas sobre webhooks, fale com nossa equipe de suporte.

Ainda não usa a LabelGrid?

Tudo o que você acabou de ler está disponível na nossa plataforma.

Veja o que a LabelGrid pode fazer →