API Abundera QR Pro
Referência da REST API em pro.qr.abundera.ai. Crie, edite e analise QR codes dinâmicos via código. Tudo é JSON sobre HTTPS, autenticado via bearer token.
/docs/openapi.json, importe no Postman, Insomnia ou qualquer cliente OpenAPI 3.1. Cobre 36 endpoints voltados ao cliente em Códigos, Analytics, Grupos, Times, Webhooks e Usuário. Endpoints admin + webhook Stripe são excluídos intencionalmente (somente service-to-service).Introdução
A API do Abundera QR Pro permite criar, editar e analisar QR codes dinâmicos via código, tudo que um desenvolvedor quer automatizar a partir do painel. Gerenciamento de times, cobrança e fluxos de conta ficam na interface do painel; esta API é voltada a operações de código para desenvolvedores.
URL base: https://pro.qr.abundera.ai/api
Formato da requisição: JSON (Content-Type: application/json) on POST / PATCH / DELETE.
Formato da resposta: JSON (application/json; charset=utf-8).
Disponibilidade: Acesso à API é um recurso Business+. Planos Solo podem usar o painel, mas não a API.
Autenticação
Cada requisição carrega uma chave de API como bearer token:
Authorization: Bearer abnd_qrpro_...Crie e revogue chaves em /account/keys (planos Business, Team ou Agency). O token bruto abnd_qrpro_... é exibido apenas uma vez na criação, guarde-o imediatamente. Armazenamos apenas seu hash SHA-256; não há como recuperar uma chave perdida.
Requisições não autenticadas retornam 401 { "error": "not_signed_in" }. Chaves inválidas ou revogadas retornam 401 { "error": "invalid_api_key" }.
As chaves de API têm escopo do usuário que as criou. Se esse usuário for membro de um time, os endpoints abaixo operam nos códigos do time automaticamente (o contexto do time atual é armazenado na conta do usuário e gerenciado pelo painel).
Limites de taxa
Aplicados por chave de API. Cada resposta traz X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (segundos Unix quando a janela se renova).
| Plano | Limite | Janela |
|---|---|---|
| Business | 1.000 requisições / dia | dia UTC |
| Team | 10.000 requisições / dia | dia UTC |
| Agency | 50.000 requisições / dia | dia UTC |
| Solo | (403 insufficient_plan) | , |
Requisições acima do limite retornam 429 { "error": "rate_limited", "window": "day", "retry_at": 1234567890 } com um cabeçalho Retry-After em segundos.
Scans não têm limite de taxa, o caminho de redirecionamento (aqr.net/{shortcode}) não tem autenticação nem orçamento por scan. Cada plano tem um limite mensal explícito de scans (100k / 1M / 10M / 30M). Ao ultrapassar o limite, o redirecionamento continua funcionando; enviamos um e-mail para você decidir se quer fazer upgrade ou absorver um pico pontual. Planejando mais de ~10M de scans diários? Fale conosco para coordenar capacidade.
Erros
Toda resposta de erro é JSON com um código error legível por máquina e, quando relevante, contexto adicional:
{ "error": "plan_limit", "plan": "business", "limit": 500, "current": 500 }| Status | Código | Significado |
|---|---|---|
| 400 | validation_error | Campo do body falhou na validação. A resposta inclui field + message. |
| 401 | not_signed_in / invalid_api_key | Bearer token ausente, inválido ou revogado. |
| 402 | plan_limit | No limite de códigos ativos+pausados do seu plano. A resposta inclui plan, limit, current. |
| 402 | plan_expired | A conta ultrapassou o período de carência de 90 dias; faça upgrade para retomar. |
| 403 | insufficient_plan | Acesso à API requer Business ou superior. Usuários Solo recebem este erro. |
| 403 | insufficient_role | Seu papel no time não permite a mutação solicitada (admin+ necessário). |
| 404 | not_found | O recurso não existe ou não está visível no seu escopo. |
| 409 | code_not_editable | O código está em status de carência ou expirado; reative para editar. |
| 429 | rate_limited | Per-plan daily budget exceeded. See Limites de taxa. |
| 500 | internal | Erro de servidor não tratado, envie e-mail ao suporte se for reproduzível. |
Códigos
QR codes dinâmicos: um shortcode Base58 de 7 caracteres que redireciona por aqr.net/{shortcode}. Cada código tem um QR de backup estático que você pode baixar pelo painel, se parar de pagar, a versão estática continua funcionando sem depender do nosso redirecionamento.
GET /api/codes
Lista todos os códigos no seu escopo atual (pessoal ou o time em que você está atuando). Retorna um array com o rollup de scans dos últimos 30 dias por código.
$ curl -H "Authorization: Bearer abnd_qrpro_..." \
https://pro.qr.abundera.ai/api/codes
{
"codes": [
{ "id": "uuid", "shortcode": "aBc123x",
"url": "https://example.com/landing",
"label": "Q2 campaign", "tags": "q2,print",
"status": "active", "scans_30d": 1245,
"created_at": 1713288000, "updated_at": 1713370000 }
],
"plan": "business",
"plan_limit": 500,
"scope": { "type": "user" }
}POST /api/codes
Cria um novo código dinâmico. O limite de códigos ativos+pausados do seu plano é verificado antes do insert. Body mínimo:
{ "url": "https://example.com/landing" }Personalização completa (todos opcionais):
{ "url": "https://example.com/landing",
"label": "Spring campaign",
"tags": "q2,print",
"qr_type": "url",
"style_json": "{...}",
"logo_key": "instagram",
"frame_style": "scan-me",
"frame_text": "SCAN ME" }Retorna 201 + a linha criada incluindo o shortcode gerado e o short_url que você imprime.
GET /api/codes/{id}
Busca um único código. 404 se não estiver no seu escopo.
PATCH /api/codes/{id}
Atualiza qualquer campo mutável. O uso mais comum: alterar a URL de destino de um código já impresso.
$ curl -X PATCH \
-H "Authorization: Bearer abnd_qrpro_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/new-landing"}' \
https://pro.qr.abundera.ai/api/codes/uuidAs alterações se propagam ao redirecionamento em segundos. Valores válidos de status para PATCH: "active", "paused". Para excluir, use DELETE.
DELETE /api/codes/{id}
Exclusão suave. Transita para status=grace com grace_until = now + 90 dias. O redirecionamento continua funcionando por todo o período de carência, esta é a promessa concreta de preço sem lock-in. Após 90 dias o código fica expired e o redirecionamento retorna 410 Gone.
POST /api/codes/import
Criação em lote a partir de um array (também usado pelo fluxo "Salvar no Pro" em qr.abundera.ai). Aceita um único payload de código ou um array. O limite do plano é verificado uma vez antes do lote.
Analytics
GET /api/codes/{id}/analytics
Parâmetros de query:
range=7d|30d|90d|1y|3y, limitado à retenção do seu plano (Solo 1y, Business 2y, Team/Agency 3y).granularity=day|hour, granularidade por hora é exclusiva de Team e Agency; janela máxima de 7 dias para hourly.
{
"range": "30d", "days": 30, "granularity": "day",
"total": 4321,
"timeseries": [
{ "bucket": "2026-04-01", "scans": 142 },
{ "bucket": "2026-04-02", "scans": 178 },
...
],
"by_country": [
{ "key": "US", "total": 3012 },
{ "key": "CA", "total": 402 },
{ "key": "Other", "total": 108 }
],
"by_device": [
{ "key": "mobile", "total": 3850 },
{ "key": "tablet", "total": 312 },
{ "key": "desktop", "total": 159 }
]
}Countries with fewer than 5 scans in the window are folded into "Other" for privacy (see Modelo de privacidade).
Chaves de API
Crie e revogue chaves na página /account/keys do painel. O auto-gerenciamento programático é somente leitura via API, você pode listar e revogar suas chaves, mas criar uma nova chave requer o painel (ovo e galinha: você precisaria de uma chave para criar outra).
GET /api/keys
Lista suas chaves de API. Nunca retorna o token bruto, apenas metadados.
{
"keys": [
{ "id": "uuid", "label": "Production server",
"created_at": 1713288000, "last_used_at": 1713370000 }
],
"allowed": true,
"plan": "business"
}DELETE /api/keys/{id}
Revoga a chave. Ela para de funcionar imediatamente; qualquer requisição que a use retorna 401 invalid_api_key a partir daí.
Exportação de dados
GET /api/user/export
Baixa um ZIP com seu conjunto de dados completo, codes.csv (todos os códigos, incluindo carência + expirados), scans.csv (rollup diário agregado), e um README.txt explicando o formato. O arquivo é emitido como application/zip; redirecione para um arquivo:
$ curl -H "Authorization: Bearer abnd_qrpro_..." \
-o abundera-qr-export.zip \
https://pro.qr.abundera.ai/api/user/exportReimporte em qualquer lugar. Esta é a garantia de formato portátil, não há lock-in possível se você possui seus dados.
Modelo de privacidade
O agregado de scans é toda a história de privacidade. O que armazenamos por scan no caminho de redirecionamento:
code_id, qual dos seus códigos foi escaneadoday_bucket, data UTC (YYYY-MM-DD). Sem precisão sub-dia no agregado retornado para você.country, ISO-3166-1 alpha-2 do cabeçalhoCF-IPCountrydo Cloudflare. Sem cidade, sem região, sem lookup geo-IP.device_type,mobile/tablet/desktop/unknown, classificado por uma regex curta de User-Agent. A string UA bruta é descartada na classificação.scan_count, contador agregado, atualizado por upsert a cada hit.
O que não armazenamos: endereços IP (hashed ou não), strings User-Agent brutas, geo em nível de cidade, timestamps sub-dia, referer, cookies, pixels de retargeting ou qualquer vetor de identificação individual. Um piso de ruído de 5 suprime a re-identificação por agregados pequenos.
Os planos Team e Agency escrevem adicionalmente um agregado por hora paralelo com hour_bucket (YYYY-MM-DD-HH UTC). Mesmo modelo de privacidade, sem timestamps mais finos que uma hora, mesmo piso de ruído, mesma ausência de dados individuais do usuário.
Leia a história completa: /manifesto/ e /no-lock-in/ no site da ferramenta gratuita.