logo
APIIntegrações

Envie eventos de links e QR codes ao seu app com webhooks

Crie um webhook na CodeQR, escolha os eventos, verifique o cabeçalho CodeQR-Signature, trate reenvios e falhas e leia o log de entregas — com payload real.

Avatar for undefined
CodeQR Team
Equipe de Conteúdo

Um webhook é um POST HTTP que a CodeQR envia para uma URL sua no momento em que algo acontece — um link é criado, um QR code muda, um lead chega, alguém clica. Ao fim deste guia você terá um webhook recebendo eventos assinados, saberá provar que cada evento é legítimo e conhecerá o que a CodeQR faz quando o seu endpoint falha.

Disponibilidade

  • Plano: Pro ou superior para eventos de criação, atualização e exclusão de links, QR codes e páginas, e para Lead created / Sale created. Link clicked, QR Code scanned e Page visited — e anexar um webhook a links, códigos ou páginas específicos — exigem Business ou superior.
  • Onde: ConfiguraçõesConfigurações do DesenvolvedorWebhooks. Só o proprietário do workspace cria, edita ou apaga webhooks; membros veem a lista e os logs. A página de webhooks aparece em inglês, com alguns rótulos em português. Referência: Webhooks em docs.codeqr.io.

Antes de começar

  • Uma URL HTTPS pública que responda 2xx rápido. Para um primeiro teste use um inspetor de requisições como https://webhook.site (ele dá uma URL única e mostra o que chega) ou exponha um servidor local com um túnel.
  • Decida os eventos. Eventos de projeto disparam para todo link, código ou página do workspace; eventos de link, QR code e página disparam só para os que você anexar.
  • Um webhook por URL por workspace: criar um segundo webhook com a mesma URL atualiza o primeiro.

Passos

  1. Abra ConfiguraçõesWebhooks e clique em Create Webhook.
  2. Preencha Name (até 30 caracteres) e URL. O Signature secret é gerado para você (whsec_ + 32 caracteres hexadecimais) — copie agora para o ambiente do seu servidor; ele continua visível na página do webhook depois, e é com ele que você vai verificar as entregas.

Create webhook form: Name, URL, Signature secret and the project-level events

  1. Marque os eventos: - Project-level eventsThese events are triggered at the project level.: Link created, Link updated, Link deleted, QR Code created, QR Code updated, QR Code deleted, Page created, Page updated, Page deleted, Lead created, Sale created. - Link-level events (High traffic)Link clicked; marcar revela Select the links for which events should be sent com todos os links listados como <data> - <domínio/chave>. Marque os links que quiser. - QR Code-level events (High traffic)QR Code scanned, com o mesmo seletor para QR codes. - Page-level events (High traffic)Page visited.

Link-level and QR Code-level events with the pickers of links and QR codes

  1. Clique em Create webhook. A lista mostra o novo webhook como Ativado.
  2. Abra o webhook. (Abrir opções) oferece Copiar ID do Webhook, Enviar evento de teste, Desativar webhook e Excluir webhook; as abas são Logs do Webhook e Atualizar Detalhes.

Webhook options menu

  1. Envie um teste: Enviar evento de teste → escolha um evento em Send Test Webhook EventSend webhook test. Seu endpoint recebe um payload de exemplo daquele evento.

Send Test Webhook Event dialog

  1. Crie um link (no painel ou pela API). Em poucos segundos um link.created real chega, e a linha aparece em Logs do Webhook com o status HTTP que o seu endpoint devolveu; clique numa linha para ver Response e Request.

Webhook event log with 200 rows and the request/response panel

O que você recebe

Cabeçalhos:

Content-Type: application/json
User-Agent: Go-http-client/2.0
CodeQR-Signature: b66393f98f01e7cba58a20ea4654ee66c5c72ff3a8e09db4fcd73624560e4b25
CodeQR-Project-Id: cm73y7wm100008j24i1b137wr

Corpo — o envelope é sempre id, event, createdAt, data; dentro de data vêm eventName e o objeto de que o evento trata (link, qrcode, page, customer para leads, sale) e, para cliques e leituras, um objeto interaction com os detalhes do clique (país, dispositivo, navegador, referenciador, click_id). Uma entrega real de link.created, recortada:

{
  "id": "evt_YT2m0xh9aUWRTV1FkfNTvrvls",
  "event": "link.created",
  "createdAt": "2026-08-17T16:53:22.473Z",
  "data": {
    "eventName": "Link created",
    "link": {
      "id": "cmsxh367q0003wu8tzav2adsp",
      "domain": "go.example.com",
      "key": "docs-summer",
      "url": "https://example.com/summer-sale?utm_source=newsletter&utm_medium=email&utm_campaign=summer",
      "shortLink": "https://go.example.com/docs-summer",
      "externalId": null,
      "tags": [],
      "clicks": 0,
      "createdAt": "2026-08-17T16:53:20.822Z",
      "updatedAt": "2026-08-17T16:53:20.822Z"
    }
  }
}

O objeto link tem a mesma forma que a API devolve; eventos qrcode trazem o objeto do QR code (type, static, cores, image…). Listas completas de campos por evento: Webhook events.

Verifique a assinatura

CodeQR-Signature é o HMAC-SHA256 do corpo bruto da requisição, com o seu segredo whsec_… como chave, em hexadecimal minúsculo. Calcule sobre os bytes exatos que recebeu — antes de qualquer parse ou reserialização de JSON — e compare em tempo constante. Os dois trechos abaixo foram conferidos contra entregas reais.

Node.js (Express, corpo bruto):

import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.post('/codeqr', express.raw({ type: 'application/json' }), (req, res) => {
  const expected = crypto
    .createHmac('sha256', process.env.CODEQR_WEBHOOK_SECRET)
    .update(req.body) // Buffer com os bytes brutos
    .digest('hex');
  const received = req.get('CodeQR-Signature') || '';
  const ok = received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
  if (!ok) return res.status(401).send('bad signature');

  const event = JSON.parse(req.body);
  // trate event.event / event.data aqui e responda rápido
  res.status(200).send('ok');
});

Python:

import hmac, hashlib

def is_valid(raw_body: bytes, header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

Rejeite tudo o que não verificar; uma requisição sem o cabeçalho não veio da CodeQR.

Reenvios, duplicatas e falhas

  • As entregas ficam numa fila e são reenviadas quando o seu endpoint responde 4xx/5xx ou estoura o tempo, então o mesmo evento pode chegar mais de uma vez. Use id (evt_…) como chave de idempotência e ignore repetições.
  • Responda 2xx em poucos segundos e faça o trabalho pesado depois; um endpoint lento conta como falha.
  • Depois de 5, 10 e 15 falhas consecutivas o proprietário do workspace recebe um e-mail (Webhook is failing to deliver); na 20ª o webhook é desativado e o proprietário recebe Webhook has been disabled. Corrija o endpoint e reative em Ativar webhook na página do webhook. Entregas bem-sucedidas zeram o contador.
  • Endpoints do Zapier e do Make que respondem 410 cancelam a assinatura do webhook — é assim que essas plataformas desligam um gatilho.

Faça o mesmo pela API

Com uma chave que tenha Webhooks → Write (só proprietário):

curl https://api.codeqr.io/webhooks \
  -H "Authorization: Bearer codeqr_••••••••••••••••••••••••"

devolve cada webhook com id, name, url, secret, triggers, linkIds, qrcodeIds, pageIds, disabledAt. POST /webhooks cria um (name, url, triggers, linkIds/qrcodeIds/pageIds opcionais, secret opcional); PATCH /webhooks/{id} e DELETE /webhooks/{id} editam e removem. O módulo Watch Webhook Events do Make e a integração com a Pluga criam webhooks assim para você.

Verifique se funcionou

  1. Crie um link. Seu endpoint registra um POST; Logs do Webhook mostra uma linha 200 para link.created em segundos.
  2. Sua verificação de assinatura aceita. Troque um byte do segredo e ela precisa falhar.
  3. Envie o mesmo id de evento duas vezes pelo botão de teste e confirme que o seu handler processa uma vez.

Solução de problemas

A assinatura nunca bate

Você calculou o hash do JSON já parseado e reserializado, ou um framework já transformou o corpo em objeto. Faça o hash dos bytes brutos (Express express.raw, Next.js await req.text(), Django request.body); confira se está usando o segredo deste webhook, não o de outro webhook nem a chave de API.

O webhook está Desativado

Vinte entregas consecutivas com falha o desativam (você recebeu dois e-mails antes). Corrija o endpoint — veja os códigos de status em Logs do Webhook — e reative em Ativar webhook.

Nenhum evento chega para cliques ou leituras

Link clicked e QR Code scanned só disparam para os links e códigos que você marcou no seletor, e só no Business ou superior. Veja também a nota no topo: na data desta publicação essas entregas estavam sendo bloqueadas por um erro de validação no servidor (correção em revisão); eventos de criação, atualização e exclusão não são afetados.

O evento de teste de "Link clicked" não traz os detalhes do clique

O payload de teste contém só o objeto link; eventos reais de clique acrescentam interaction. Teste com um clique real num link anexado.

Links criados em massa não dispararam link.created

Links criados por POST /links/bulk não dispararam o evento no nosso teste; criações unitárias e pelo painel dispararam. Dispare a sua automação a partir da resposta do bulk.

O formulário diz "This webhook is managed by an integration"

Webhooks criados por Zapier, Make ou Pluga só têm gatilhos e links anexados editáveis aqui; a URL pertence à plataforma. Altere ou remova pelo lado da plataforma.

Artigos relacionados