A API da PixGo é um REST simples, sem SDK, sem dependência exótica. Se você sabe fazer um POST em HTTP, você integra. Esse guia cobre todo o fluxo: gerar chave, criar pagamento, receber webhook, validar assinatura — com exemplos de código pra copiar e colar.
- Base URL:
https://pixgo.org/api/v1 - Auth: header
X-API-Key: pk_...(gera em Minha Loja) - 3 endpoints principais:
POST /payment/create,GET /payment/{id},GET /payment/{id}/status - Webhooks: 4 eventos (
order.created,payment.completed,payment.expired,payment.refunded) com HMAC-SHA256 - Rate limit: 10.000 req/24h default, 1.000 req/24h só no endpoint de status
- Sem sandbox: toda chave é produção. Teste com valores pequenos.
Gerando sua API Key
- Acesse o menu API Keys (pixgo.org/api-keys)
- Clique em Solicitar acesso e conclua a validação pedida na tela
- Com o acesso aprovado, a chave aparece na mesma página (campo API Key)
- Copie a chave (formato
pk_+ sequência aleatória) e guarde em local seguro
- É uma chave por usuário — gerar nova invalida a anterior automaticamente
- NÃO pode editar/renomear — só substituir
- Guarde em variável de ambiente (
.env, secrets manager) — nunca no código versionado - É chave de produção — toda chamada cobra/recebe de verdade
- Se vazar, gere uma nova IMEDIATAMENTE (a antiga para de funcionar)
Integre cobranças Pix ao seu sistema com API e webhooks. Conheça a API Pix da PixGo.
Criar contaEndpoint 1 — Criar pagamento
É o endpoint que você usa pra gerar um QR Code de cobrança. Tudo começa por aqui.
POST https://pixgo.org/api/v1/payment/create
Headers:
X-API-Key: pk_sua_chave_aqui
Content-Type: application/json
Body (JSON):
{
"amount": 100.00,
"description": "Produto X - SKU 123",
"external_id": "pedido_42",
"receiver_name": "Maria Silva",
"receiver_cpf": "12345678900",
"receiver_email": "[email protected]",
"receiver_phone": "11999998888",
"webhook_url": "https://seusite.com/webhooks/pixgo"
}Campos do request
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amount | number | Sim | Valor em Reais. Mín R$10, máx conforme seu nível |
description | string | Não | Aparece no comprovante do pagador |
external_id | string | Não | Seu ID interno do pedido — volta no webhook |
receiver_name | string | Não | Nome do cliente — volta no webhook |
receiver_cpf | string | Sim | CPF ou CNPJ do pagador, somente números (11 ou 14 dígitos). Sem ele a cobrança é recusada com 422 PAYER_DOC_REQUIRED |
receiver_email | string | Não | E-mail do cliente |
receiver_phone | string | Não | Telefone do cliente |
webhook_url | string | Não | URL específica desse pagamento (sobrescreve a global) |
Resposta de sucesso (201)
{
"success": true,
"data": {
"payment_id": "019c8b9149ec7433a5065b834cb45ccc",
"external_id": "pedido_42",
"amount": 100.00,
"status": "pending",
"qr_code": "00020126360014BR.GOV.BCB.PIX...",
"qr_image_url": "https://pixgo.org/qr/019c8b9149ec...png",
"expires_at": "2026-05-15T14:30:00-03:00",
"created_at": "2026-05-15T14:00:00-03:00"
}
}O campo qr_code é o Copia-e-Cola (BR Code, formato EMV). O qr_image_url é uma URL pública pra exibir a imagem do QR Code.
payment_id no seu banco de dados, vinculado ao seu external_id. É com ele que você vai consultar status depois e conferir os webhooks.Respostas de erro
Todo erro devolve success: false, um código estável em error e um texto em message. Trate pelo error — o texto do message pode mudar.
{
"success": false,
"error": "PAYER_DOC_REQUIRED",
"message": "Envie o campo receiver_cpf com o CPF ou CNPJ do pagador (somente números)."
}| HTTP | error | O que fazer |
|---|---|---|
| 401 | MISSING_API_KEY | Header X-API-Key ausente |
| 401 | INVALID_API_KEY | Chave inexistente ou desativada |
| 400 | VALIDATION_ERROR | Campo obrigatório ausente ou valor fora do formato |
| 400 | invalid_webhook_url | Use HTTPS com domínio ou IP público — localhost, 127.0.0.1 e IPs privados são recusados |
| 422 | PAYER_DOC_REQUIRED | Envie receiver_cpf com o CPF ou CNPJ do pagador. Obrigatório em qualquer valor |
| 422 | PAYER_BLOCKED | Documento do pagador reprovado na checagem antifraude. Peça outro CPF/CNPJ — repetir a chamada não resolve |
| 422 | PAYER_COMPLIANCE_BLOCKED | Mesma coisa, barrado na camada de compliance |
| 400 | LIMIT_EXCEEDED | Valor acima do limite do seu nível |
| 429 | PAYER_RATE_LIMIT | Muitas cobranças para o mesmo documento na última hora |
| 429 | RATE_LIMIT_EXCEEDED | Limite da sua chave estourado — respeite o Retry-After |
| 503 | PROVIDER_UNAVAILABLE | Parceiro bancário fora no momento. É transitório: tente de novo depois do Retry-After (120s) |
receiver_cpf passou a ser obrigatório em qualquer valor. Se a sua integração não enviava esse campo, ela vai receber 422 PAYER_DOC_REQUIRED até passar a enviar. Aceita CPF (11 dígitos) ou CNPJ (14), somente números — pontuação é ignorada.Endpoint 2 — Detalhes do pagamento
Retorna o objeto completo do pagamento — útil pra reconciliação batch ou pra mostrar status detalhado pro cliente.
GET https://pixgo.org/api/v1/payment/{id}
Headers:
X-API-Key: pk_sua_chave_aquiResposta inclui todos os campos do create + dados pós-pagamento (data, breakdown de taxas, dados do pagador mascarados). Esse é o endpoint com rate limit padrão (10.000 req/24h).
Endpoint 3 — Status do pagamento
Versão enxuta do endpoint anterior — retorna só o status atual + alguns campos básicos. Pensado pra polling rápido (você consulta a cada N segundos enquanto o cliente está na tela do PIX).
GET https://pixgo.org/api/v1/payment/{id}/status
Headers:
X-API-Key: pk_sua_chave_aqui
Response:
{
"success": true,
"data": {
"payment_id": "019c8b91...",
"external_id": "pedido_42",
"amount": 100.00,
"status": "completed",
"customer_name": "Maria Silva",
"customer_cpf": "***.***.***-00",
"customer_phone": "***988",
"created_at": "2026-05-15T14:00:00-03:00",
"updated_at": "2026-05-15T14:25:30-03:00"
}
}/payment/{id}. Use polling com intervalo razoável (a cada 3-5 segundos, não a cada 100ms). Pra confirmação confiável, prefira webhook em vez de polling intenso.Webhooks — o caminho recomendado
Webhooks são notificações HTTP que a PixGo envia automaticamente pro seu servidor quando o pagamento muda de status. É mais eficiente que ficar fazendo polling.
Configuração
Dois lugares onde você define a URL de webhook:
- Global (Minha Loja): URL única que recebe TODOS os eventos da sua conta. Configure em pixgo.org/minha-loja → Webhook.
- Por pagamento: passe
webhook_urlno body doPOST /payment/create. Sobrescreve a global só pra esse pagamento.
Eventos disponíveis
| Evento | Disparado quando |
|---|---|
order.created | Pagamento foi criado (logo após o POST /payment/create) |
payment.completed | PIX foi confirmado (status mudou pra completed) |
payment.expired | QR expirou sem pagamento (20min QR avulso, 30min Cobranças) |
payment.refunded | Pagamento foi estornado em definitivo (MED veredito contra ou estorno voluntário) |
Headers que a PixGo envia
POST /seu-endpoint
X-Webhook-Event: payment.completed
X-Webhook-Signature: a3f5...c4d (HMAC-SHA256)
X-Webhook-Timestamp: 1715789430
Content-Type: application/jsonPayload enriquecido — estrutura completa
Cada webhook envia um JSON com até 5 objetos. Aqui o exemplo de payment.completed:
{
"event": "payment.completed",
"payment_id": "019c8b91...",
"external_id": "pedido_42",
"amount": 100.00,
"completed_at": "2026-05-15T14:25:30-03:00",
"customer": {
"name": "Maria Silva",
"cpf": "12345678900",
"email": "[email protected]",
"phone": "11999998888",
"address": "...",
"custom_field": "campanha_outubro"
},
"payer": {
"name": "Maria",
"cpf": "***.***.789-00"
},
"product": {
"business_name": "Minha Loja",
"description": "Produto X - SKU 123",
"value": 100.00
},
"amounts": {
"gross": 100.00,
"fee_pixgo": 2.00,
"fee_liquid": 0.50,
"fee_total": 2.50,
"net": 97.50,
"currency": "BRL"
}
}O que cada objeto significa
customer— dados que o cliente preencheu no checkout (ou que você passou noPOST /payment/create). Use pra CRM, etiqueta de envio, recibo.payer— dados de quem efetivamente pagou o PIX (recebidos do banco). Geralmente igual ao customer, mas pode diferir (ex: marido paga pelo CPF da esposa). CPF vem mascarado por LGPD.product— dados da loja/cobrança no momento da criação.amounts— breakdown completo das taxas e o líquido que vai cair na sua carteira. Mais detalhes no artigo Taxas da PixGo.
Validando a assinatura HMAC
Toda webhook vem assinado pra você ter certeza que é a PixGo enviando, não um malicioso falsificando. Valide sempre.
Lógica da assinatura
- Pegue o cabeçalho
X-Webhook-Timestampe o body bruto (raw) da request - Concatene:
timestamp + "." + body_raw - Calcule HMAC-SHA256 dessa string usando o seu Webhook Secret (começa com
whsec_e aparece na página API Keys) como segredo - Compare com o valor de
X-Webhook-Signature - Se bater → autêntico. Se não → rejeite (HTTP 401 ou 400).
Exemplo em PHP
<?php
$secret = 'whsec_seu_webhook_secret_aqui';
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$received_sig = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$payload = $timestamp . '.' . $body;
$expected_sig = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected_sig, $received_sig)) {
http_response_code(401);
exit('Invalid signature');
}
// OK, processa o evento
$data = json_decode($body, true);
if ($data['event'] === 'payment.completed') {
// ... sua lógica
}
http_response_code(200);
echo 'OK';Exemplo em Python (Flask)
import hmac, hashlib
from flask import request, abort
SECRET = b'whsec_seu_webhook_secret_aqui'
@app.route('/webhooks/pixgo', methods=['POST'])
def webhook():
body = request.get_data()
timestamp = request.headers.get('X-Webhook-Timestamp', '')
received = request.headers.get('X-Webhook-Signature', '')
payload = f'{timestamp}.{body.decode()}'.encode()
expected = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, received):
abort(401)
data = request.get_json()
if data['event'] == 'payment.completed':
# ... sua lógica
pass
return 'OK', 200Exemplo em Node.js (Express)
const crypto = require('crypto');
const express = require('express');
const app = express();
const SECRET = 'whsec_seu_webhook_secret_aqui';
app.post('/webhooks/pixgo',
express.raw({type: 'application/json'}),
(req, res) => {
const body = req.body.toString();
const ts = req.header('X-Webhook-Timestamp') || '';
const received = req.header('X-Webhook-Signature') || '';
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${ts}.${body}`)
.digest('hex');
if (expected !== received) return res.status(401).send('Invalid');
const data = JSON.parse(body);
if (data.event === 'payment.completed') {
// ... sua lógica
}
res.send('OK');
}
);Rate Limits — o que importa saber
| Endpoint | Limite | Dica |
|---|---|---|
POST /payment/create | 10.000 req/24h | Mais que suficiente pra uso normal |
GET /payment/{id} | 10.000 req/24h | Use pra reconciliação batch |
GET /payment/{id}/status | 1.000 req/24h | Limitado — prefira webhook |
Esses valores são padrão pra todas as contas. Se você precisa de mais, abra chamado em pixgo.org/chamados explicando o caso — não é self-service.
Boas práticas pra integração robusta
- Idempotência: webhooks podem ser entregues mais de uma vez (em caso de retry). Use o
payment_id+eventcomo chave única no seu banco pra ignorar duplicados. - Responda 2xx rapidamente: receba o webhook, valide assinatura, enfileire o processamento pesado (queue/job) e responda 200. Não trave o webhook fazendo trabalho síncrono longo (vai dar timeout e a PixGo retenta).
- Armazene o
external_id: passe seu próprio ID interno noPOST /payment/create. Volta em todo webhook — facilita reconciliar com seu pedido. - Trate
payment.refundedobrigatoriamente: estorno acontece (MED, ou você mesmo pediu). Se ignorar o evento, sua contabilidade fica errada. - Não confie só no front-end: ao receber confirmação na tela do cliente via polling, valide com webhook server-side antes de liberar produto digital. Front pode ser manipulado.
- Logue tudo: salve cada webhook recebido + assinatura + status do processamento. Se der problema, é o que vai te salvar.
- Configure retry no seu webhook: PixGo retenta em caso de 5xx, mas se você responder 200 e depois falhar no processamento, perdeu. Tenha sua própria fila com retry interno.
WordPress, WooCommerce, plugins prontos?
Hoje a PixGo não tem plugin oficial pra nenhuma plataforma. A integração é sempre via API REST. Como a API é simples, qualquer dev consegue plugar em poucas horas:
- WordPress / WooCommerce: implementação via plugin custom — você escreve um payment gateway que chama nossa API no
process_paymente recebe webhook em URL própria. - Shopify: usa Shopify Apps com webhook próprio — mesma estrutura.
- Magento, OpenCart, PrestaShop: módulo custom seguindo o padrão de cada plataforma.
- SaaS personalizado: integração direta no seu backend, mais simples ainda.
Recorrência (assinatura)
A API atual não tem endpoint nativo de recorrência (tipo "criar assinatura mensal automática"). O caminho hoje é:
- No seu sistema, você mantém a lista de clientes ativos e o ciclo de cobrança
- Em cada vencimento, sua rotina chama
POST /payment/createcom o valor do cliente - Cliente paga (ou não) cada cobrança individualmente — a PixGo não faz débito automático
- Se ele paga, você processa o webhook
payment.completede renova o ciclo - Se não paga, você decide a regra (notificar, suspender, dar carência)
A PixGo tem também um módulo de cobrança recorrente Pix que faz isso pra quem prefere usar a interface pronta sem programar — vale conferir antes de implementar do zero.
FAQ pra desenvolvedores
Tem sandbox / ambiente de teste?
Não. Toda chave é produção. Pra testar, use valores pequenos (R$10-R$15) e pague do seu próprio CPF — depois faça swap dentro da PixGo Wallet se quiser recuperar.
Posso filtrar pagamentos por external_id?
Sim. Use GET /api/v1/payments?external_id=SEU_ID com a sua X-API-Key: a resposta traz a lista de pagamentos com esse external_id (até 50 caracteres) e volta vazia se não houver nenhum. Mesmo assim, guarde o payment_id no seu banco no momento do create, porque é ele que identifica cada cobrança nos webhooks.
O webhook tem retry automático?
Sim. Se sua URL responder 5xx ou der timeout, a PixGo retenta com backoff exponencial por algumas horas. Se mesmo assim falhar, eventualmente desiste. Por isso responda 2xx rápido (mesmo que processe assíncrono).
Posso usar a mesma chave em múltiplos servidores?
Sim. A chave não tem limite de origens. Mas vale lembrar do rate limit (cumulativo entre todos os servidores que usam a mesma chave).
Tem CORS habilitado? Posso chamar a API do front-end?
NÃO chame a API do front-end. Sua chave nunca pode ir parar no JavaScript do navegador. Use sempre seu backend como intermediário. CORS não é o problema — segurança da chave é.
Posso testar webhook localmente?
Sim, usando túneis (ngrok, localtunnel, Cloudflare Tunnel). Cria um túnel pro seu localhost, registra essa URL no webhook_url do pagamento de teste, e a PixGo manda direto pro seu servidor local.
Qual o timeout do webhook?
Você tem ~10 segundos pra responder 2xx. Se demorar mais, considera falha e retenta.
Tem SDK em alguma linguagem?
Não. A API é REST simples — qualquer cliente HTTP serve. Não temos SDK oficial em Node/Python/PHP/Go. Comunidade pode ter wrappers — mas não são oficiais e podem estar desatualizados.
O external_id precisa ser único?
Não é validado pela PixGo. Você pode até repetir, mas vai dificultar reconciliação do seu lado. Recomendado: uso UUIDs ou IDs auto-incrementais.
Pode passar custom_field com JSON?
O campo é uma string. Você pode passar JSON serializado ('{"tag":"out2026"}') — sua aplicação faz parse depois. Sem limite duro de tamanho, mas mantenha curto (alguns KB).
Resumo prático
- API REST simples — Base
https://pixgo.org/api/v1+ headerX-API-Key - 3 endpoints principais: criar, detalhar, status
- Webhooks com 4 eventos + HMAC-SHA256 (valide SEMPRE)
- Rate limit: 10k/24h geral, 1k/24h só no /status
- Sem SDK / sem sandbox — toda chave é produção
- Sem plugin oficial — integração custom em WP, Shopify, etc
- Recorrência: rotina externa chamando /create no vencimento
- Documentação live: pixgo.org/api/v1/docs
Leituras relacionadas: Taxas e breakdown amounts · Limites por nível · Tratamento de MED na sua integração