API de Agregação
GET /v1/codes/:id/scans — Séries temporais + principais países/dispositivos/SO para um único objeto de código.
Cada scan de um código QR dinâmico gera um registro de scan (Scan-Record) no seu Workspace. A captura ocorre inteiramente no Cloudflare Edge — sem serviços de rastreamento externos, sem cookies e sem que o IP original chegue ao seu banco de dados.
Três formas de consumir os dados de scan:
API de Agregação
GET /v1/codes/:id/scans — Séries temporais + principais países/dispositivos/SO para um único objeto de código.
Webhooks (Tempo real)
Evento qr.scanned por scan, assinado com HMAC-SHA256. Veja Webhooks.
Dashboard
Visualização no painel do qr3.app — sem necessidade de chamada de API.
Para cada scan, um registro é criado na tabela scans:
| Campo | Origem | Exemplo |
|---|---|---|
id | UUID gerado pelo servidor | scn_d1f8… |
code_id | ID do código QR escaneado | qr_a1b2c3d4 |
workspace_id | Workspace do código | ws_xxx |
country | Cloudflare cf.country | AT |
region | Cloudflare cf.region | Vienna |
city | Cloudflare cf.city | Wien |
device_type | Análise do User-Agent | mobile, tablet, desktop |
os | Análise do User-Agent | iOS, Android, macOS, Windows |
browser | Análise do User-Agent | Safari, Chrome, Firefox |
referer | Cabeçalho HTTP Referer | https://example.com/landing |
language | Cabeçalho Accept-Language (primeiro idioma) | de |
redirected_to | Destino real do redirecionamento | https://example.com |
ip_hash | SHA-256(IP + salt diário) — não reversível | 8f3a… |
scanned_at | Timestamp ISO-8601 | 2026-05-12T14:32:11.000Z |
Todos os dados geográficos (country, region, city) vêm do objeto cf da Cloudflare e são baseados no banco de dados Geo-IP da Cloudflare. Não são consultados serviços externos de Geo-IP — a resolução ocorre no mesmo Worker que executa o redirecionamento.
Isso tem três consequências:
city nem sempre está disponível (por exemplo, com VPNs, operadoras de celular ou regiões pequenas). Espere valores null e planeje seus painéis considerando isso.GET /v1/codes/:id/scansRetorna análises agregadas para um único código QR em um período selecionável.
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/scans?days=30" \ -H "Authorization: Bearer qr3_sk_..."const analytics = await qr3.scans.get('qr_a1b2c3d4', { days: 30 });console.log(analytics.period_scans, analytics.top_countries);qr3 scans qr_a1b2c3d4 --days 30Parâmetros de Query:
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
days | integer | 30 | Período em dias (1–365) |
Resposta (HTTP 200):
{ "data": { "code_id": "qr_a1b2c3d4", "short_code": "r7f3Kx", "total_scans": 1842, "period_days": 30, "period_scans": 367, "scans_by_day": [ { "date": "2026-04-13", "count": 12 }, { "date": "2026-04-14", "count": 18 } ], "top_countries": [ { "value": "AT", "count": 142 }, { "value": "DE", "count": 98 }, { "value": "CH", "count": 41 } ], "top_devices": [ { "value": "mobile", "count": 281 }, { "value": "desktop", "count": 72 }, { "value": "tablet", "count": 14 } ], "top_os": [ { "value": "iOS", "count": 158 }, { "value": "Android", "count": 123 }, { "value": "macOS", "count": 48 } ] }, "meta": { "request_id": "req_xyz123" }}Campos de Resposta:
| Campo | Descrição |
|---|---|
total_scans | Total acumulado de scans do código (independente da janela de days) |
period_scans | Total de scans no período selecionado |
scans_by_day | Agrupamentos diários, em ordem crescente de data, dias vazios são omitidos |
top_countries | Principais 8 países no período, em ordem decrescente |
top_devices | Principais 5 tipos de dispositivos (mobile, tablet, desktop) |
top_os | Principais 5 sistemas operacionais |
Os totais de todo o Workspace (por exemplo, scans por mês em todos os códigos) estão disponíveis no campo scans_this_month via GET /v1/workspaces/:id. Para análises cruzadas de códigos, recomendamos o painel ou uma exportação periódica.
Se você deseja processar eventos de scan assim que eles acontecem — por exemplo, para painéis em tempo real, rastreamento de leads ou integrações de CRM — assine o evento qr.scanned:
curl -X POST https://qr3.app/v1/webhooks \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/webhooks/qr3", "events": ["qr.scanned"], "secret": "my-secret-key-min-16-chars" }'Payload:
{ "id": "evt_abc123xyz", "type": "qr.scanned", "created": "2026-05-12T14:32:11.000Z", "data": { "code_id": "qr_a1b2c3d4", "short_code": "r7f3Kx", "scan_id": "scn_d1f8...", "country": "AT", "device_type": "mobile", "os": "iOS" }}Documentação completa sobre verificação de assinatura, lógica de repetição e logs de entrega em API → Webhooks.
Os registros de scan não contêm endereços IP pessoais. O IP original é substituído no Edge Worker por uma função de hash criptográfica (SHA-256) com um salt rotativo diário. Isso significa:
A retenção depende do plano:
| Plano | Retenção |
|---|---|
| Free | 7 dias |
| Pro | 90 dias |
| Business / Agency | 1 ano |
| Enterprise | Personalizado (SLA) |
Uma tarefa cron diária (purgeOldScans) remove registros mais antigos automaticamente — o total_scans no objeto do código permanece inalterado.
days=365), o payload pode ter vários KB. Faça cache no lado do cliente com um TTL curto (por exemplo, 60 s).top_countries, top_devices, top_os são limitados no lado do servidor a 8 ou 5 entradas. Para análises mais profundas, exporte os dados brutos.null: country, region, city, referer, language podem ser null. Trate isso como “Desconhecido” em sua análise.