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.
Como os webhooks funcionam
Seção intitulada “Como os webhooks funcionam”- Você configura um webhook - Informe uma URL e quais eventos quer monitorar
- Um evento ocorre - Por exemplo, um lançamento é entregue a uma loja
- O LabelGrid envia uma requisição POST - Seu servidor recebe os dados do evento
- Seu sistema processa - Automatize fluxos de trabalho com base no evento
Como acessar os webhooks
Seção intitulada “Como acessar os webhooks”- Clique no ícone do seu perfil no canto superior direito
- Selecione Webhooks no menu suspenso
Como criar um webhook
Seção intitulada “Como criar um webhook”- Clique em Create Webhook
- Informe um Name para identificar este webhook
- Informe a URL onde você quer receber as notificações
- Selecione quais Events devem acionar este webhook
- Clique em Create
Chave secreta do webhook
Seção intitulada “Chave secreta do webhook”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
Eventos disponíveis
Seção intitulada “Eventos disponíveis”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 evento | Descrição |
|---|---|
delivery.completed | Disparado quando um lançamento é entregue com sucesso a uma loja |
delivery.failed | Disparado quando a entrega a uma loja falha |
takedown.completed | Disparado quando uma solicitação de remoção (takedown) é concluída |
release.review.status_changed | Disparado quando o status de revisão de um lançamento muda |
release.distributed | Disparado quando um lançamento é distribuído |
payment.statement_ready | Disparado 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.
Como gerenciar webhooks
Seção intitulada “Como gerenciar webhooks”Visualizar seus webhooks
Seção intitulada “Visualizar seus webhooks”A lista de webhooks mostra:
| Coluna | Descrição |
|---|---|
| Name | O nome que você atribuiu ao webhook |
| URL | Para onde as notificações são enviadas |
| Events | Número de eventos configurados |
| Status | Ativo ou Inativo |
| Success / Fail | Contagem de entregas bem-sucedidas e com falha |
| Last Triggered | Quando o webhook foi acionado pela última vez |
Editar um webhook
Seção intitulada “Editar um webhook”- Clique na ação Edit na linha do webhook
- Altere o nome, a URL ou os eventos
- Clique em Save
Ativar / desativar
Seção intitulada “Ativar / desativar”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
Excluir um webhook
Seção intitulada “Excluir um webhook”- Clique na ação Delete na linha do webhook
- Confirme a exclusão
Como testar webhooks
Seção intitulada “Como testar webhooks”Antes de depender de um webhook em produção, teste-o:
- Clique na ação Test no seu webhook
- O LabelGrid envia um payload de teste para a sua URL
- Verifique se o seu endpoint recebeu e processou tudo corretamente
Como visualizar os logs do webhook
Seção intitulada “Como visualizar os logs do webhook”Monitore a atividade do webhook e investigue problemas:
- Clique na ação View Logs em um webhook
- Veja o histórico de todas as entregas do webhook
Detalhes do log
Seção intitulada “Detalhes do log”Cada entrada do log mostra:
| Campo | Descrição |
|---|---|
| Event Type | Qual evento acionou esta entrega |
| Response Status | Código de status HTTP retornado pelo seu servidor |
| Duration | Quanto tempo a requisição levou |
| Attempt | Número da tentativa de reenvio |
| Timestamp | Quando a entrega ocorreu |
Formato do payload do webhook
Seção intitulada “Formato do payload do webhook”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).
Payloads de evento
Seção intitulada “Payloads de evento”A estrutura do objeto data depende do tipo de event. Todos os tipos de campo abaixo são tipos JSON, conforme serializados no payload.
delivery.completed
Seção intitulada “delivery.completed”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" }}| Campo | Tipo | Descrição |
|---|---|---|
distro_queue_id | integer | ID interno da fila para esta tentativa de entrega |
release_id | integer | O lançamento que foi entregue |
release_cat | string | null | A referência de catálogo do seu lançamento |
outlet_id | integer | O ID da loja de destino |
outlet_name | string | null | Nome legível da loja (ex.: "Spotify") |
status | string | Sempre "complete" para este evento |
delivery.failed
Seção intitulada “delivery.failed”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." }}| Campo | Tipo | Descrição |
|---|---|---|
status | string | Um de error, fault, rejected, batch_exception |
message | string | null | Motivo da falha informado pela loja ou pelo pipeline de distribuição |
takedown.completed
Seção intitulada “takedown.completed”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 }}release.distributed
Seção intitulada “release.distributed”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" }}release.review.status_changed
Seção intitulada “release.review.status_changed”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" }}| Campo | Tipo | Descrição |
|---|---|---|
previous_status | string | Status anterior. Um de draft, to_review, approved, rejected, require_changes, audit |
new_status | string | Novo status. Mesmo conjunto de valores |
payment.statement_ready
Seção intitulada “payment.statement_ready”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" }}| Campo | Tipo | Descrição |
|---|---|---|
payment_request_id | integer | ID interno da solicitação de pagamento |
invoice_number | string | Referência da fatura do extrato |
period | string | null | Data de fim do período (data ISO 8601, YYYY-MM-DD) |
amount | number | Valor do extrato na moeda indicada em currency |
total_due_usd | number | Total do extrato convertido para USD |
currency | string | Código de moeda ISO 4217 (padrão: USD) |
Como verificar as assinaturas dos webhooks
Seção intitulada “Como verificar as assinaturas dos webhooks”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.
Cabeçalhos da requisição
Seção intitulada “Cabeçalhos da requisição”Toda requisição POST de webhook inclui estes cabeçalhos:
| Cabeçalho | Descrição |
|---|---|
X-Webhook-Signature | HMAC-SHA256 do corpo bruto da requisição, em hexadecimal minúsculo, sem prefixo de algoritmo |
X-Webhook-Timestamp | Timestamp ISO 8601 da entrega (mesmo valor da propriedade timestamp no corpo) |
X-Webhook-Event | Identificador do evento (ex.: delivery.completed) |
X-Webhook-Id | O ID do webhook que está recebendo a entrega |
User-Agent | LabelGrid-Webhooks/1.0 |
Content-Type | application/json |
Algoritmo
Seção intitulada “Algoritmo”- 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)
Receita de verificação
Seção intitulada “Receita de verificação”- 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.
- Calcule
HMAC-SHA256(raw_body, your_webhook_secret)e use o digest em hexadecimal minúsculo. - Compare com
X-Webhook-Signatureusando uma comparação de tempo constante. - (Recomendado) Rejeite a requisição se
X-Webhook-Timestampfor mais antiga do que a sua janela de tolerância contra replay (sugerimos 5 minutos).
Exemplo em PHP
Seção intitulada “Exemplo em PHP”$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 minutesif (abs(time() - strtotime($timestamp)) > 300) { http_response_code(401); exit('Stale delivery');}
$payload = json_decode($rawBody, true);// ... process the eventhttp_response_code(200);Exemplo em Node.js
Seção intitulada “Exemplo em Node.js”const crypto = require('crypto');
// Express: capture raw body BEFORE any JSON middlewareapp.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);});Exemplo em Python
Seção intitulada “Exemplo em Python”import hmac, hashlibfrom datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, before any JSON parsingsignature = 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 ackArmadilhas comuns
Seção intitulada “Armadilhas comuns”- 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 semprehash_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.
Limites e confiabilidade
Seção intitulada “Limites e confiabilidade”Limites de requisição
Seção intitulada “Limites de requisição”| Limite | Valor |
|---|---|
| Tempo limite da requisição | 10 segundos |
| Tamanho máximo do payload | 64 KB |
| Máximo de webhooks por usuário | 10 |
Se o seu endpoint não responder em até 10 segundos, a entrega é tratada como falha e reenviada.
Cronograma de reenvios
Seção intitulada “Cronograma de reenvios”Se o seu endpoint retornar um status fora da faixa 2xx ou exceder o tempo limite, o LabelGrid reenvia com backoff exponencial:
| Tentativa | Espera antes do reenvio |
|---|---|
| 1 → 2 | 30 segundos |
| 2 → 3 | 1 minuto |
| 3 → 4 | 2 minutos |
| 4 → 5 | 4 minutos |
| 5 → 6 | 8 minutos |
| 6 → 7 | 16 minutos |
| 7 → 8 | 32 minutos |
| 8 → 9 | 64 minutos |
| 9 → 10 | 128 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.
Desativação automática
Seção intitulada “Desativação automática”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.
Boas práticas de confiabilidade
Seção intitulada “Boas práticas de confiabilidade”- 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
Casos de uso
Seção intitulada “Casos de uso”Notificações automatizadas
Seção intitulada “Notificações automatizadas”- 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
Automação de fluxos de trabalho
Seção intitulada “Automação de fluxos de trabalho”- 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
Monitoramento e alertas
Seção intitulada “Monitoramento e alertas”- 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
Solução de problemas
Seção intitulada “Solução de problemas”O webhook não recebe eventos
Seção intitulada “O webhook não recebe eventos”- Verifique o status - O webhook está Active?
- Confira a URL - O endpoint está acessível pela internet?
- Verifique os eventos - Os eventos certos estão selecionados?
- Revise os logs - Há algum erro registrado?
Contagem alta de falhas
Seção intitulada “Contagem alta de falhas”- Verifique o seu endpoint - Ele está retornando 200 OK?
- Verifique o tempo de resposta - Ele responde dentro do tempo limite?
- Revise as mensagens de erro - O que está falhando?
- Teste manualmente - Envie um webhook de teste
Como gerar uma nova chave secreta
Seção intitulada “Como gerar uma nova chave secreta”Se a chave secreta do seu webhook for comprometida:
- Clique em Regenerate Secret nas configurações do webhook
- Atualize a sua aplicação com a nova chave secreta
- A chave antiga deixa de funcionar imediatamente
Precisa de ajuda?
Seção intitulada “Precisa de ajuda?”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 →