Skip to content
peleteiroPublic

About

Transforma URL em QR Code PIX

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

pixlink

Cloudflare Worker que gera QR Codes de pagamento PIX a partir da URL.

Caso de uso

Tenho uma planilha com as contas que pago todo mes, cada linha com a chave PIX e o valor. Montando um link pixlink por linha, o pagamento vira um clique: abro o link, aponto o celular para o QR Code e pago. Sem digitar chave nem valor, sem erro de transcricao.

Usando a URL .png da para incorporar o QR Code direto numa celula da planilha (via =IMAGE(...) no Google Sheets, por exemplo) e escanear sem precisar sair dela.

URL

/{chave-pix}/{valor}?d={descricao}

Chaves aceitas

  • Telefone — 11912345678, 5511912345678 ou +5511912345678
  • CPF — 111.444.777-35 ou 11144477735
  • CNPJ — 12.345.678/0001-95 ou 12345678000195
  • E-mail — joana@example.com
  • Chave aleatoria — UUID, com ou sem hifens: 123e4567-e89b-12d3-a456-426614174000 ou 123e4567e89b12d3a456426614174000

O parser é permissivo:

  1. Se contém @ → e-mail. Validacao basica: localpart@dominio.tld (rejeita @, foo@, @bar, foo@bar sem TLD).
  2. Se bate com o formato UUID (36 chars com hifens ou 32 hex) → chave aleatória, normalizada para lowercase com hifens.
  3. Caso contrário, tudo que não for dígito é removido (pontuação, espaços, +, parênteses) e o que sobra é classificado pelo tamanho — 11 dígitos = CPF, 14 = CNPJ, 10–13 com ou sem DDI 55 = telefone. CPF e CNPJ são validados pelos dígitos verificadores.

CNPJ com / na URL

A barra do CNPJ quebraria o roteamento, então existe uma rota auxiliar que aceita o CNPJ com a barra literal e redireciona (301) para a forma canônica com os dois segmentos unidos:

/12.345.678/0001-95/25000  →  /12.345.6780001-95/25000

Assim o usuário pode colar o CNPJ formatado direto na URL sem precisar escapar o / como %2F.

PIX copia e cola

Também aceita o payload EMV inteiro (o "copia e cola" gerado por apps de banco e marketplaces) como path único:

/{payload-emv-completo}

O parser valida o CRC16 e confere o GUI br.gov.bcb.pix antes de aceitar. A página renderiza direto naquele caminho preservando o payload original no QR Code e no botão copiar — isso mantém o txid (campo 62.05), o merchant name e a cidade intactos, essenciais para marketplaces como Mercado Pago reconciliarem o pagamento com o pedido específico.

Sem valor (valor a definir) a página também renderiza direto, com "Valor a definir no app" no lugar do total — o pagador escolhe o valor no app do banco na hora de pagar. Importante: nunca caímos pra calculadora nesse caso, mesmo que pareça "completar" o pagamento. A calculadora regeraria o payload do zero e perderia o txid — pior do que não suportar o caso. Pagamento com txid preserva txid; ponto.

A forma curta /{chave}/{valor} continua disponível e útil pra envio avulso, mas o QR gerado por ela perde o txid (regenera tudo). Use o payload completo quando o pagamento precisa estar amarrado a uma transação específica. Páginas servidas a partir do payload completo não declaram <link rel="canonical"> curto justamente pra não induzir crawlers a indexar a forma lossy.

Valor

O valor usa , como separador de centavos. Ambos os formatos sao aceitos sem redirect, mas a forma normalizada gerada pelo form na home e {reais},{centavos} com dois digitos:

Entrada na URL Centavos Formatado
/50,00 5000 R$ 50,00
/50 5000 R$ 50,00
/0,50 50 R$ 0,50
/0,01 1 R$ 0,01
/50000,00 5000000 R$ 50.000,00
/R$50 5000 R$ 50,00
/$50,00 5000 R$ 50,00
/R$1.000,50 100050 R$ 1.000,50

Heuristica: se o valor terminar com . + 1 ou 2 digitos (ex: 50.00, 50.5), tratamos esse ponto como virgula — conveniencia para quem cola valores em formato em ingles. /50.00 equivale a /50,00 e /50.5 equivale a /50,50.

Prefixo R$ ou $: opcional, com ou sem espaco apos. /R$50, /R$ 50, /$50, /$ 50 e o equivalente URL-encoded /R%2450 sao todos aceitos e equivalentes a /50. Util pra colar o valor exatamente como veio de uma planilha ou nota fiscal. Caveat: a combinacao %24 (=$) + %20 (=espaco) e bloqueada no nivel de routing pelo adapter Cloudflare antes de chegar no app — pra valor com espaco use o form da home, ou monte a URL sem espaco (/R$50).

Invalidos (retornam HTTP 400 com pagina estilizada):

  • Zero ou negativo (/0, /0,00, /-50)
  • Caracteres nao numericos alem de R$/$, , ou do ponto final (/50abc, /USD50)
  • Ponto no meio que nao seja o final com 1-2 digitos (/50.000)
  • Valor acima de Number.MAX_SAFE_INTEGER centavos (~R$ 90 trilhoes) — acima disso o parseFloat perde precisao.

Valor no form da home

O campo de valor no form da home e mais permissivo que a URL: aceita qualquer formatacao e gera a URL canonica. A regra e "so digitos e virgula importam, o resto e ignorado":

Entrada no form URL gerada
50 /50,00
50,00 /50,00
R$ 50,00 /50,00
R$50 /50,00
$50 /50,00
50.00 /50,00
50.000,00 /50000,00
-50,00 /50,00
0,015 /0,02

Detalhes:

  • , separa os centavos; se ausente, o valor e tratado como reais inteiros.
  • Tudo que nao for digito ou , e removido (inclusive -, entao valores negativos viram positivos).
  • Como na URL, . no final seguido de 1 ou 2 digitos vira , (50.00 = 50,00, 50.5 = 50,50).
  • Fracoes menores que 1 centavo sao arredondadas para o inteiro mais proximo (0,015 → 2 centavos).

Descricao (opcional)

Query param ?d=Almoco — incluida no payload PIX.

A descricao e sanitizada antes de entrar no QR Code: acentos sao transliterados (café → cafe) e caracteres nao-ASCII (emojis, simbolos Unicode, controles) sao removidos. A especificacao EMV usa encoding restrito e bancos podem rejeitar o QR Code silenciosamente sem esse passo. O texto maximo no payload e 72 caracteres (o que passar disso e truncado).

PNG

Adicione .png ao valor para receber apenas a imagem do QR Code (1024x1024):

/11912345678/50,00.png

URL canonica

Todas as paginas incluem <link rel="canonical"> apontando para a home. As URLs de pagamento sao entradas do servico, e nao paginas independentes para indexacao. og:url aponta para a pagina compartilhada, para que o preview abra o pagamento correto.

Previews em redes sociais

A pagina do PIX inclui Open Graph (Facebook, WhatsApp, Telegram, LinkedIn, Discord e Slack) e Twitter Cards (X), renderizados no servidor. O titulo usa R$ 50,00 / {CHAVE}, ou Valor a definir / {CHAVE}. A descricao usa Pix de R$ 50,00 para chave {CHAVE}: {descricao}; sem descricao do pagamento, omite os dois-pontos finais. Sem valor, usa Pix com valor a definir para chave {CHAVE}.

A imagem social e um PNG de 1200x630 com o QR Code centralizado em fundo branco e margem de quatro modulos. O QR cabe em recortes centrais quadrados e 2:1. A rota /preview.png?v=1&payload=... valida o payload e o preserva integralmente, incluindo txid, nome e cidade, mesmo sem valor definido. O PNG avulso /{chave}/{valor}.png continua em 1024x1024.

A home usa um QR que abre o servico; os links com apenas a chave usam um QR que abre a calculadora correspondente. Esses previews nao inventam um pagamento antes de o valor ser escolhido.

As imagens incluem dimensoes, tipo e texto alternativo nas metatags. O tamanho e a exibicao finais dependem de cada plataforma e de seu cache; metatags nao obrigam uma rede a mostrar ou atualizar o preview.

Para LLMs e agentes de IA

https://pix.peleteiro.net/llms.txt documenta a API de URL no formato llms.txt — versao concisa e em ingles otimizada pra agentes que precisam construir links pixlink (ex: bots de WhatsApp, assistentes financeiros, agentes que ajudam usuarios a cobrar via PIX).

Exemplos

URL Resultado
/11912345678/50,00 Pagina com QR Code de R$ 50,00
/11912345678/50 Mesmo resultado (forma compacta)
/111.444.777-35/15 QR Code para CPF, R$ 15,00
/12.345.678%2F0001-95/250,00 QR Code para CNPJ, R$ 250,00
/123e4567-e89b-12d3-a456-426614174000/50 QR Code para chave aleatoria, R$ 50,00
/joana@example.com/100?d=Consultoria QR Code com descricao
/11912345678/50,00.png Imagem PNG do QR Code
/11912345678/R$50 Prefixo R$ aceito (= R$ 50,00)
/00020126...DA46 Renderiza o payload "copia e cola"

Estrutura

src/
├── components/     # CopyButton, ShareButton, PixForm, PixCalculator (React);
│                   # ErrorPage, GoogleAnalytics, PixPage (Astro)
├── layouts/        # Base.astro — shell com head/meta/GA
├── lib/pix/        # dominio: chave, valor, payload EMV (gerar + parsear),
│                   # qrcode, montarDadosPix
├── pages/          # rotas: /, /[chave] (copia e cola + calculadora),
│                   # /[chave]/[valor], /[chave]/[valor].png,
│                   # rota auxiliar /[chave1]/[chave2]/[valor] (CNPJ com barra)
└── styles/         # global.css (Tailwind 4 + btn utilities)
public/             # favicon.svg, robots.txt

Imports usam o alias @/ para src/ (ex: @/lib/pix, @/layouts/Base.astro).

Desenvolvimento

pnpm install     # ja instala os git hooks (lefthook) via `prepare`
tilt up          # servidor dev na porta 3000

Git hooks (lefthook)

Configurados em lefthook.yml:

  • pre-commit — prettier --write nos arquivos staged (auto-fix e re-stage) + vitest run rapido.
  • pre-push — mise run check (verificacao completa de CI).

Tarefas

mise run deploy  # build + deploy Cloudflare Workers
mise run lint    # format + type check
mise run test    # roda todas as suites de teste
mise run test:unit         # roda os testes unitarios
mise run test:integration  # roda os testes de integracao
mise run check   # verificacao CI (format + types + testes)
mise run clean   # limpar gerados

Infraestrutura

DNS e Worker custom domain gerenciados via OpenTofu em sysadmin/tofu/.

mise run tofu:plan   # ver mudancas

Aplicacao de mudancas de infra fica fora do fluxo normal de desenvolvimento. Neste repositorio, agentes nao devem executar tofu apply/terraform apply, e deploy do app continua separado via mise run deploy.

Stack

About

Transforma URL em QR Code PIX

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages