pendingAguardandoCobrança criada e ainda não confirmada.
Crie cobranças, exiba o QR Code e acompanhe cada pagamento com uma API simples, previsível e pronta para o seu backend.
$ curl -X POST \
/api/v1/pix \
→ 200 OK
{
"status": "pending",
"transaction_id": "8a401...",
"pix": { ... }
}https://www.goupay.com.brCrie uma API Key no painel de integrações.
Envie valor e dados do cliente pelo backend.
Consulte o status ou receba um webhook.
Toda requisição precisa identificar sua conta por uma chave de API.
No painel, acesse Integrações → API Pix e selecione Gerar nova chave.
Armazene a chave em uma variável de ambiente e faça as chamadas somente pelo backend.
# Recomendado
x-api-key: SUA_CHAVE_AQUI
# Alternativa
Authorization: Bearer SUA_CHAVE_AQUINão inclua a chave em JavaScript entregue ao navegador, aplicativos distribuídos, repositórios públicos ou logs. Se houver exposição, desative a chave e gere uma nova.
A API v1 usa JSON, HTTPS e valores monetários inteiros em centavos.
São permitidas 20 requisições por minuto para cada API Key. Em uma resposta 429, respeite o header Retry-After.
Envie o valor em centavos e os dados essenciais do pagador.
https://www.goupay.com.br/api/v1/pix| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amount | integer | Sim | Valor em centavos. Mínimo de 100 (R$ 1,00). |
description | string | Não | Identificação interna da cobrança. |
customer.name | string | Sim | Nome completo do pagador. |
customer.email | string | Sim | E-mail válido do pagador. Também recebe os dados do PIX pendente. |
customer.cpf | string | Sim | CPF com 11 dígitos, somente números. |
customer.phone | string | Não | Telefone com DDD, somente números. |
const response = await fetch('https://www.goupay.com.br/api/v1/pix', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.GOUPAY_API_KEY
},
body: JSON.stringify({
amount: 2990,
description: 'Pedido #42',
customer: {
name: 'Maria Souza',
email: 'maria@email.com',
cpf: '12345678900',
phone: '11999999999'
}
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.error);
console.log(data.transaction_id);
console.log(data.pix.qr_code);{
"success": true,
"transaction_id": "8a40135d-e021-456d-a94f-3122c525d5d9",
"status": "pending",
"amount": 2990,
"pix": {
"qr_code": "00020126580014BR.GOV.BCB.PIX...",
"qr_code_url": "https://api.pagar.me/.../qrcode",
"expires_at": "2026-08-01T15:30:00.000Z"
},
"notifications": {
"pending_email_sent": true
}
}transaction_idGuarde para consultar a cobrança.pix.qr_codeCódigo PIX copia e cola.pix.qr_code_urlImagem pronta do QR Code.pix.expires_atValidade em ISO 8601.notifications.pending_email_sentConfirma se o e-mail do PIX foi aceito pelo SMTP.Use o transaction_id recebido na criação para obter o estado mais recente e reconciliar cobranças pendentes.
https://www.goupay.com.br/api/v1/pix/{transaction_id}const response = await fetch(
`https://www.goupay.com.br/api/v1/pix/${transactionId}`,
{
headers: {
'x-api-key': process.env.GOUPAY_API_KEY
}
}
);
const payment = await response.json();
if (!response.ok) throw new Error(payment.error);
if (payment.status === 'paid') {
await liberarPedidoUmaVez(payment.transaction_id);
}{
"success": true,
"transaction_id": "8a40135d-e021-456d-a94f-3122c525d5d9",
"status": "paid",
"raw_status": "paid",
"amount": 2990,
"payment_method": "pix",
"pagarme_id": "or_...",
"description": "Venda via API",
"customer": {
"name": "Maria Souza",
"email": "maria@email.com"
},
"created_at": "2026-08-01T15:00:00.000Z",
"pix": {
"qr_code": "00020126580014BR.GOV.BCB.PIX...",
"qr_code_url": "https://api.pagar.me/.../qrcode",
"expires_at": "2026-08-01T15:30:00.000Z"
}
}Ao receber paid, registre o transaction_id como processado. Assim, uma nova consulta ou notificação não libera o mesmo pedido duas vezes.
Quando o pedido local ainda está pendente, esta consulta também confere o estado diretamente no provedor de pagamento. Se o provedor estiver temporariamente indisponível, a API preserva o último estado conhecido e uma consulta posterior tenta novamente.
Use o status para controlar o ciclo de vida do pedido no seu sistema.
pendingAguardandoCobrança criada e ainda não confirmada.
paidPagoPagamento confirmado. Pode liberar o pedido.
failedFalhouA cobrança falhou durante o processamento.
refundedEstornadoO valor pago foi estornado.
chargebackChargebackContestação registrada para o pagamento.
A validade vem em pix.expires_at. Use esse campo para bloquear novas tentativas no checkout; expired não faz parte dos status retornados atualmente pelo endpoint.
Use consultas controladas como contingência do webhook e para reconciliar pagamentos pendentes.
O limite de 20 requisições/minuto é compartilhado por todas as cobranças da mesma chave. Para várias cobranças simultâneas, prefira webhooks e aplique backoff ao receber 429.
async function aguardarPagamento(transactionId, timeoutMs = 600_000) {
const inicio = Date.now();
while (Date.now() - inicio < timeoutMs) {
const response = await fetch(
`https://www.goupay.com.br/api/v1/pix/${transactionId}`,
{ headers: { 'x-api-key': process.env.GOUPAY_API_KEY } }
);
if (response.status === 429) {
const espera = Number(response.headers.get('Retry-After') || 60);
await new Promise(resolve => setTimeout(resolve, espera * 1000));
continue;
}
const payment = await response.json();
if (payment.status === 'paid') return payment;
if (['failed', 'refunded', 'chargeback'].includes(payment.status)) {
throw new Error(`Cobrança finalizada como ${payment.status}`);
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error('Tempo limite de consulta atingido');
}Ofereça a imagem e o código copia e cola para o cliente escolher como pagar.
pix.qr_codeTexto PIX copia e colapix.qr_code_urlURL da imagem PNGpix.expires_atExpiração em ISO 8601<img
src="{qr_code_url}"
alt="QR Code para pagamento via PIX"
width="240"
height="240"
/>
<label for="pix-code">PIX copia e cola</label>
<input id="pix-code" value="{qr_code}" readonly />
<button
type="button"
onclick="navigator.clipboard.writeText(
document.getElementById('pix-code').value
)"
>
Copiar código
</button>Receba uma notificação HTTP quando o status de uma cobrança mudar.
No painel, acesse Integrações → API Pix → Webhook da API Pix e cadastre uma URL HTTPS pública.
O payload de webhook ainda não inclui assinatura criptográfica. Antes de liberar um produto, consulte GET /api/v1/pix/{transaction_id} pelo backend e confirme status === "paid".
Cada URL configurada é processada de forma independente. Respostas fora da faixa 2xx, falhas de conexão ou demora superior a 10 segundos mantêm a entrega pendente. A GouPay realiza até 12 tentativas com intervalos progressivos. Por isso, o mesmo evento pode chegar mais de uma vez e seu endpoint deve ser idempotente.
| Evento | Quando ocorre | Ação sugerida |
|---|---|---|
order.paid | Pagamento confirmado | Consultar e liberar uma vez |
order.failed | Pagamento falhou | Informar o cliente |
order.refunded | Pagamento estornado | Atualizar o pedido |
order.chargeback | Chargeback registrado | Bloquear entrega pendente |
{
"event": "order.paid",
"data": {
"id": "8a40135d-e021-456d-a94f-3122c525d5d9",
"transaction_id": "8a40135d-e021-456d-a94f-3122c525d5d9",
"status": "paid",
"amount": 2990,
"amount_display": "29.90",
"description": null,
"payment_method": "pix",
"customer": {
"name": "Maria Souza",
"email": "maria@email.com",
"cpf": "12345678900",
"phone": "11999999999"
},
"created_at": "2026-08-01T15:00:00.000Z",
"updated_at": "2026-08-01T15:04:33.000Z"
}
}import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhooks/goupay', async (req, res) => {
const { event, data } = req.body;
try {
if (event === 'order.paid') {
// Confirme o status na API antes de liberar o pedido.
const response = await fetch(
`https://www.goupay.com.br/api/v1/pix/${data.transaction_id}`,
{
headers: {
'x-api-key': process.env.GOUPAY_API_KEY
}
}
);
const payment = await response.json();
if (payment.status === 'paid') {
await liberarPedidoUmaVez(payment.transaction_id);
}
}
return res.sendStatus(200);
} catch (error) {
console.error('Falha ao processar webhook', error);
return res.sendStatus(500);
}
});Trate o código HTTP antes de consumir o corpo da resposta.
| HTTP | Situação | Motivo comum | O que fazer |
|---|---|---|---|
| 400 | Requisição inválida | Valor inválido, cliente incompleto ou conta recebedora ausente | Revise o body e a configuração |
| 401 | Não autenticado | Chave ausente ou inválida | Envie uma API Key ativa |
| 403 | Acesso bloqueado | Chave inativa ou conta bloqueada | Verifique o painel |
| 404 | Não encontrado | Transação ou usuário não encontrado | Confira o transaction_id |
| 429 | Limite excedido | 20 requisições/minuto excedidas | Respeite Retry-After |
| 500 | Erro interno | Falha interna ou do processador | Registre o erro e tente mais tarde |
A maioria dos erros segue esta estrutura.
{
"error": "Chave de API inválida",
"status": "error"
}Além do JSON de erro, a resposta inclui Retry-After (segundos) e X-RateLimit-Reset (data ISO).
Um caminho seguro do primeiro teste até a liberação do pedido.
Salve a chave em uma variável de ambiente do backend.
Faça o POST, trate erros e guarde o transaction_id.
Mostre o QR Code, o copia e cola e a validade.
Use webhook como principal e polling como contingência.
Valide paid pela API e processe de forma idempotente.