Documentação da API PixToMe
Introdução
A API REST do PixToMe cria e consulta cobranças PIX. Respostas em JSON UTF-8, valores em centavos (inteiros) e horários em ISO 8601 UTC.
1https://api.pixtome.com/v1
- 1Crie a cobrança — POST /deposits do seu servidor com o CPF/CNPJ do pagador.
- 2Receba o QR Code — a API retorna pix.br_code (string EMV copia-e-cola).
- 3Exiba como QR — renderize com qualquer lib de QR Code.
- 4Confirme — webhook deposit.confirmed ou polling em GET /deposits/:id.
Em erros temporários (5xx) use exponential backoff com jitter. Sem o header Idempotency-Key, repetir o mesmo POST /deposits abre outra cobrança — guarde o id. Com Idempotency-Key, a mesma chave e o mesmo corpo devolvem a cobrança original (200, header Idempotency-Replayed: true) e não criam outro PIX.
Quickstart — receber seu primeiro PIX
Cinco passos para sair do zero e receber um pagamento real:
- Crie sua conta e complete o perfil com CPF/CNPJ em Configurações. Sem isso o provedor rejeita as cobranças (exigência do BACEN).
- Gere uma chave de API em API & Webhooks. A chave pix_live_… só aparece uma vez. Guarde em um cofre, nunca no front-end.
- Crie a cobrança com POST /deposits a partir do seu servidor, com o CPF/CNPJ do pagador e um header Idempotency-Key. A resposta traz pix.br_code.
- Exiba o QR Code renderizando o br_code.
- Receba a confirmação pelo webhook deposit.confirmed ou por polling em GET /deposits/:id até status confirmed.
Health check
Endpoint público (sem autenticação) para monitorar disponibilidade. O campo build identifica o release publicado.
/health1curl https://api.pixtome.com/v1/health
1{2"status": "ok",3"version": "1",4"build": "2026-10-13.3",5"time": "2026-06-17T13:40:00.000Z"6}
Autenticação
Cada requisição, exceto GET /health, precisa do header Authorization. Crie chaves no painel em API & Webhooks; o texto puro só aparece uma vez. Rotas desconhecidas respondem 404 e métodos errados respondem 405 sem exigir a chave.
1Authorization: Bearer pix_live_<48 chars hex>
Não há sandbox — chaves pix_test_… também geram cobranças PIX reais. Nunca exponha a chave no front-end.
Criar cobrança
Cria uma cobrança PIX e devolve o BR Code (copia-e-cola). A cobrança expira em 60 minutos — o mesmo prazo do painel.
O header opcional Idempotency-Key (1–128 caracteres: letras, dígitos e . _ : ~ -) torna o POST seguro para repetir. A mesma chave com o mesmo corpo devolve a cobrança original (200, header Idempotency-Replayed: true) sem gerar outro PIX. Corpo diferente com a mesma chave responde 409 IDEMPOTENCY_MISMATCH. Enquanto a primeira ainda não terminou, a resposta é 409 IDEMPOTENCY_IN_PROGRESS.
/deposits| Parâmetro | Tipo | Descrição |
|---|---|---|
| amount_brl | number, obrigatório | Valor em reais (ex.: 49.90). Mínimo 10,00; máximo 500,00. |
| description | string | Opcional, no máximo 80 caracteres. A PixToMe grava e devolve este campo no painel, no GET e nos webhooks. Não é enviado ao provedor e não entra no QR Code PIX. |
| customer.name | string | Nome do pagador (opcional, máx. 80). |
| customer.tax_number | string, obrigatório | CPF (11 dígitos) ou CNPJ (14). Sem ele a cobrança responde 422. |
description é só da PixToMe. O provedor não recebe esse texto e ele não aparece para o pagador no PIX.
1curl -X POST https://api.pixtome.com/v1/deposits \2-H "Authorization: Bearer $PIXTOME_KEY" \3-H "Content-Type: application/json" \4-H "Idempotency-Key: pedido-1024" \5-d '{6"amount_brl": 49.90,7"description": "Pedido #1024",8"customer": {9"name": "João Silva",10"tax_number": "390.533.447-05"11}12}'
1{2"id": "8f9a3b7c-1234-4abc-9def-1234567890ab",3"amount_cents": 4990,4"description": "Pedido #1024",5"status": "pending",6"pix": {7"br_code": "00020101021226540014br.gov.bcb.pix0116loja@pixtome.com..."8},9"customer": {10"name": "João Silva",11"tax_number": "***.***.***-05"12},13"created_at": "2026-06-17T13:40:00.000Z",14"expires_at": "2026-06-17T14:40:00.000Z",15"confirmed_at": null16}
O id é um UUID. O tax_number da resposta vem sempre mascarado. O documento completo fica guardado para conciliação e compliance.
Consultar cobrança
Devolve o status atual. O status muda pelo webhook do provedor e por uma reconciliação periódica. Faça polling a cada 3–5 segundos ou, de preferência, escute o webhook.
/deposits/:id1curl https://api.pixtome.com/v1/deposits/8f9a3b7c-1234-4abc-9def-1234567890ab \2-H "Authorization: Bearer $PIXTOME_KEY"
1{2"id": "8f9a3b7c-1234-4abc-9def-1234567890ab",3"amount_cents": 4990,4"description": "Pedido #1024",5"status": "confirmed",6"pix": {7"br_code": "00020101021226540014br.gov.bcb.pix0116loja@pixtome.com..."8},9"customer": {10"name": "João Silva",11"tax_number": "***.***.***-05"12},13"created_at": "2026-06-17T13:40:00.000Z",14"expires_at": "2026-06-17T14:40:00.000Z",15"confirmed_at": "2026-06-17T13:42:10.000Z"16}
Status possíveis: pending, confirmed, expired, error, refunded (estorno/MED depois do pagamento; pode ocorrer semanas depois).
Listar cobranças
Lista as cobranças mais recentes da conta, da mais nova para a mais antiga.
/deposits| Parâmetro | Tipo | Descrição |
|---|---|---|
| limit | integer | Quantidade de itens (1 a 100). Padrão: 20. |
1curl "https://api.pixtome.com/v1/deposits?limit=10" \2-H "Authorization: Bearer $PIXTOME_KEY"
1{2"data": [3{ "id": "8f9a3b7c-1234-4abc-9def-1234567890ab", "amount_cents": 4990, "status": "confirmed", "...": "..." },4{ "id": "a1b2c3d4-5678-4abc-9def-1234567890cd", "amount_cents": 12000, "status": "pending", "...": "..." }5]6}
Renderizar o QR Code
O campo pix.br_code é a string BR Code (EMV) — a mesma que o cliente cola no app do banco. Renderize com qualquer biblioteca.
1npm install qrcode.react
1import { QRCodeSVG } from "qrcode.react";23export function PixCheckout({ deposit }) {4return (5<div className="flex flex-col items-center gap-3">6<QRCodeSVG value={deposit.pix.br_code} size={256} level="M" />7<button onClick={() => navigator.clipboard.writeText(deposit.pix.br_code)}>8Copy PIX code9</button>10<p>Expira em {new Date(deposit.expires_at).toLocaleTimeString()}</p>11</div>12);13}
Em HTML puro use qrcode (QRCode.toDataURL). No servidor, gere PNG/SVG e sirva como imagem.
Configurar webhook
Sem webhook você precisa fazer polling. Com webhook, a PixToMe avisa seu servidor em segundos quando o cliente paga.
- Exponha um endpoint HTTPS público (ex.: https://seu-dominio.com/webhooks/pixtome).
- Em API & Webhooks, cadastre a URL. Cada endpoint tem o próprio secret — guarde como PIXTOME_WEBHOOK_SECRET. Até 10 endpoints por conta; o mesmo id de evento vai para todos os ativos.
- Valide o HMAC antes de processar o payload. Responda 2xx em até 10 segundos.
- Trate o evento de forma idempotente: o mesmo id pode chegar mais de uma vez (até 3 tentativas em ~8 s).
1import express from "express";2import { verifySignature } from "./verify.js";34const app = express();5const processed = new Set(); // use Redis/DB in production67// raw body is required for the HMAC8app.post("/webhooks/pixtome",9express.raw({ type: "application/json" }),10async (req, res) => {11const sig = req.header("X-Pixtome-Signature");12const raw = req.body.toString("utf8");13if (!sig || !verifySignature(raw, sig, process.env.PIXTOME_WEBHOOK_SECRET)) {14return res.status(401).send("invalid signature");15}16const evt = JSON.parse(raw);17if (processed.has(evt.id)) return res.sendStatus(200); // idempotent18processed.add(evt.id);1920if (evt.event === "deposit.confirmed") {21// fulfill the order — evt.data.id, evt.data.amount_cents22}23res.sendStatus(200);24},25);
Em desenvolvimento, exponha o localhost com ngrok ou Cloudflare Tunnel. URLs privadas são bloqueadas.
Eventos por webhook
A PixToMe envia POST para a URL cadastrada em API & Webhooks. Responda 2xx em até 10 s. Até 3 tentativas em ~8 s. Headers: X-Pixtome-Signature, X-Pixtome-Event, User-Agent: PixToMe-Webhook/1.
- deposit.confirmed — pagamento confirmado. Se o valor divergir, chega deposit.amount_mismatch e nada é creditado.
- deposit.expired — expirou sem pagamento.
- deposit.canceled — cancelada pelo pagador, pelo parceiro ou pelo provedor (não é expiração).
- deposit.failed — falha antes de o valor ser creditado.
- deposit.will_refund — PIX na fila de reembolso; o valor não é creditado.
- deposit.under_bank_review — bloqueio preventivo do banco; o valor não é creditado.
- deposit.refunded — pagamento confirmado estornado depois (estorno/MED).
- deposit.amount_mismatch — o valor pago não bate com amount_cents.
1{2"id": "evt_a3f0c1d27b8e4f5a6b7c8d9e",3"event": "deposit.confirmed",4"created_at": "2026-06-17T13:42:11.000Z",5"data": {6"id": "8f9a3b7c-1234-4abc-9def-1234567890ab",7"amount_cents": 4990,8"status": "confirmed",9"customer": { "tax_number": "***.***.***-12" },10"confirmed_at": "2026-06-17T13:42:10.000Z"11}12}
Assinatura HMAC
Cada webhook traz X-Pixtome-Signature com o HMAC-SHA256 do corpo bruto e o secret daquele endpoint. Compare sempre em tempo constante.
1X-Pixtome-Signature: t=1718630531,v1=8e3...c4
1import crypto from "node:crypto";23export function verifySignature(rawBody, header, secret) {4const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));5const expected = crypto6.createHmac("sha256", secret)7.update(`${parts.t}.${rawBody}`)8.digest("hex");9return crypto.timingSafeEqual(10Buffer.from(expected),11Buffer.from(parts.v1),12);13}
1import hmac, hashlib23def verify(raw_body: bytes, header: str, secret: str) -> bool:4parts = dict(p.split("=") for p in header.split(","))5expected = hmac.new(6secret.encode(),7f"{parts['t']}.".encode() + raw_body,8hashlib.sha256,9).hexdigest()10return hmac.compare_digest(expected, parts["v1"])
Códigos de erro
Todas as respostas de erro usam o mesmo formato:
1{2"error": {3"code": "VALIDATION_FAILED",4"message": "amount must be > 0",5"details": { "field": "amount_brl" }6}7}
| Parâmetro | Tipo | Descrição |
|---|---|---|
| 400 | INVALID_JSON | Corpo não é um JSON válido. |
| 400 | IDEMPOTENCY_KEY_INVALID | Idempotency-Key fora do formato (1–128: letras, dígitos e . _ : ~ -). |
| 401 | MISSING_AUTH / INVALID_KEY | Chave de API ausente, inválida ou revogada. |
| 403 | ACCOUNT_SUSPENDED | Conta suspensa. |
| 404 | NOT_FOUND | Cobrança inexistente ou rota desconhecida. Rota errada não exige autenticação. |
| 405 | METHOD_NOT_ALLOWED | Método não permitido nessa rota (Allow lista os métodos). Não exige autenticação. |
| 409 | IDEMPOTENCY_MISMATCH | A mesma Idempotency-Key já foi usada com outro corpo. |
| 409 | IDEMPOTENCY_IN_PROGRESS | A cobrança dessa chave ainda está sendo criada. Retry-After: 2. |
| 409 | PSP_OUTCOME_EXPIRED | O provedor não confirmou a cobrança e a janela de recuperação fechou. Nada foi creditado. Use uma Idempotency-Key nova. |
| 413 | PAYLOAD_TOO_LARGE | Corpo maior que 16 KB. |
| 422 | VALIDATION_FAILED | Parâmetro inválido (ex.: valor fora de R$ 10,00–R$ 500,00). |
| 422 | VALIDATION_FAILED (customer.tax_number) | CPF/CNPJ ausente, com tamanho errado ou dígitos inválidos. |
| 422 | PAYER_BLOCKED | CPF/CNPJ recusado pelo compliance do provedor PIX. |
| 422 | PROVIDER_REJECTED | O provedor recusou a cobrança. details.provider_code traz o código. |
| 429 | RATE_LIMITED | Mais de 6 cobranças por minuto na conta. Retry-After: 60. |
| 429 | GLOBAL_RATE_LIMITED | Limite por minuto do provedor. Retry-After: 60. |
| 500 | MISCONFIGURED | Configuração interna ausente. Fale com o suporte. |
| 500 | INTERNAL_ERROR | A cobrança foi criada no provedor, mas não foi salva. Repita com a mesma Idempotency-Key. |
| 502 | PSP_ERROR | Falha temporária no provedor. Use exponential backoff. |
| 503 | PSP_OUTCOME_UNKNOWN | O provedor não confirmou se a cobrança nasceu. Outro PIX não foi aberto. Repita com a mesma Idempotency-Key. Retry-After: 60. |
| 503 | PSP_BUSY | Provedor ocupado. Respeite o Retry-After. |
| 503 | PSP_UNAVAILABLE | Provedor em manutenção. Respeite o Retry-After. |