Começar
API de pagamentos da Payze
Crie cobranças PIX, Bizum e SPEI a partir do seu sistema e receba a confirmação por webhook. REST, JSON e autenticação por API Key.
Como funciona
POST /api/v1/direct-payments com valor, método e comprador, autenticado pela API Key.payment_data: copia-e-cola, formulário ou CLABE.AUTHORIZED.A criação devolve a cobrança com status PENDING. A confirmação chega depois, quando o banco do comprador conclui o pagamento: por webhook ou pela consulta de status.
Métodos de pagamento
PIX
Copia-e-cola e QR Code no app do banco. paymentMethod: "pix"
Bizum
Formulário na sua página pelo SDK de checkout, aprovação no app do banco. paymentMethod: "bizum"
SPEI
Transferência para uma CLABE pelo app do banco. paymentMethod: "spei"
No Bizum e no SPEI o comprador paga em euros ou pesos. A Payze converte o valor para reais pela cotação da plataforma, e taxas e saldo são calculados em BRL. Os métodos internacionais precisam estar liberados no plano da sua conta; se não estiverem, a API recusa a cobrança e você deve falar com o suporte.
Endereço da API
https://api.pagpayze.com.br
Requisições e respostas usam JSON. Envie Content-Type: application/json nas requisições com corpo.
Endpoints
| Método | Caminho | Autenticação | Uso |
|---|---|---|---|
| POST | /api/v1/direct-payments | Header X-API-Key | Criar uma cobrança |
| GET | /api/v1/payments/{transaction_id}/status | Nenhuma | Consultar o status de uma transação |
Formato das respostas
Toda resposta tem o campo hasError. Com sucesso, os dados vêm em data; com erro, a mensagem vem em error (veja Erros).
{
"hasError": false,
"data": { "transaction_id": "7KQ2M9XA4T1B", "status": "PENDING" }
}
{
"hasError": true,
"error": "API key não fornecida. Envie a chave no header X-API-Key",
"errorFields": [],
"statusCode": 401,
"timestamp": "2026-10-08T15:19:01.612Z",
"path": "/api/v1/direct-payments"
}
Conceitos
- Transação. Cada cobrança criada gera uma transação, identificada por
transaction_id(12 caracteres, letras maiúsculas e números). Guarde esse valor junto com o seu pedido: é ele que liga a criação, a consulta de status e o webhook. - Valores. Na criação,
amounté um inteiro em centavos da moeda da cobrança. Nas respostas, os valores vêm em unidades decimais (99.9= R$ 99,90). Detalhes em Valores e limites. - Produção. As chaves de API são de produção (
pk_live_…) e não existe modo de teste separado: toda cobrança criada é real. Para testar a integração, crie um PIX de valor baixo e pague você mesmo.
Começar
Início rápido
Sua primeira cobrança PIX em quatro passos. Esse é o fluxo inteiro: nos outros métodos mudam só o paymentMethod, alguns campos do comprador e o que você mostra na tela.
-
Gere uma API Key
No painel da Payze, abra Integração → API Keys e clique em Nova API Key. Copie a chave (
pk_live_…) na hora: ela aparece uma única vez. Guarde-a numa variável de ambiente do seu servidor, por exemploPAYZE_API_KEY. -
Crie a cobrança
Chame o endpoint de cobrança a partir do seu servidor.
amountvai em centavos:9990= R$ 99,90.curl -X POST https://api.pagpayze.com.br/api/v1/direct-payments \ -H "Content-Type: application/json" \ -H "X-API-Key: $PAYZE_API_KEY" \ -d '{ "amount": 9990, "description": "Pedido 1234", "paymentMethod": "pix", "customer": { "name": "João da Silva", "email": "joao@exemplo.com", "document": "12345678909" } }'const res = await fetch("https://api.pagpayze.com.br/api/v1/direct-payments", { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": process.env.PAYZE_API_KEY, }, body: JSON.stringify({ amount: 9990, // R$ 99,90 em centavos description: "Pedido 1234", paymentMethod: "pix", customer: { name: "João da Silva", email: "joao@exemplo.com", document: "12345678909", }, }), }); const body = await res.json(); if (!res.ok) throw new Error(body.error); const { transaction_id, payment_data } = body.data; // Salve transaction_id no seu pedido antes de seguir.$payload = [ "amount" => 9990, // R$ 99,90 em centavos "description" => "Pedido 1234", "paymentMethod" => "pix", "customer" => [ "name" => "João da Silva", "email" => "joao@exemplo.com", "document" => "12345678909", ], ]; $ch = curl_init("https://api.pagpayze.com.br/api/v1/direct-payments"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "X-API-Key: " . getenv("PAYZE_API_KEY"), ], CURLOPT_POSTFIELDS => json_encode($payload), ]); $body = json_decode(curl_exec($ch), true); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http >= 400) throw new Exception($body["error"]); $transactionId = $body["data"]["transaction_id"]; // salve no seu pedido{ "hasError": false, "data": { "transaction_id": "7KQ2M9XA4T1B", "total_value": 99.9, "status": "PENDING", "email": "joao@exemplo.com", "payment_method": "pix", "payment_data": { "expiration_date": null, "payment_id": "c1a7e0b2-5d3f-4e8a-9b61-0f2d7c4e9a13", "pix_key": "00020126580014br.gov.bcb.pix0136…6304A1B2", "status": "PENDING", "status_detail": "WAITING_PAYMENT", "total_transaction_value": 99.9 } } } -
Mostre o PIX ao comprador
payment_data.pix_keyé o código copia-e-cola. Mostre-o com um botão de copiar e gere o QR Code a partir dele com a biblioteca de QR Code que preferir. Envie ao navegador só o que ele precisa exibir, nunca a API Key. -
Confirme o pagamento
Cadastre a URL do seu servidor em Integração → Webhooks. Quando o PIX for pago, a Payze envia um
POSTcom"status": "AUTHORIZED". Confirme na consulta de status e libere o pedido.curl https://api.pagpayze.com.br/api/v1/payments/7KQ2M9XA4T1B/status
A resposta da criação traz a cobrança ainda pendente. Libere o pedido apenas quando o seu servidor receber ou consultar o status AUTHORIZED.
Próximos passos
Começar
Autenticação
A criação de cobranças é autenticada por API Key, enviada no header X-API-Key. Cada chave pertence a uma conta: as cobranças criadas com ela entram nessa conta.
Criar uma API Key
- No painel da Payze, abra Integração → API Keys.
- Clique em Nova API Key, dê um nome (3 a 100 caracteres) e, se quiser, uma descrição.
- Copie a chave exibida. Ela aparece uma única vez: a Payze guarda só um hash da chave e não consegue mostrá-la de novo. Se perder, crie outra.
Formato
A chave tem o prefixo pk_live_ seguido de 48 caracteres hexadecimais (0-9 e a-f), 56 caracteres no total. Uma chave fora desse formato é recusada antes de qualquer outra verificação.
pk_live_0123456789abcdef0123456789abcdef0123456789abcdef
Enviar a chave
POST /api/v1/direct-payments HTTP/1.1
Host: api.pagpayze.com.br
Content-Type: application/json
X-API-Key: pk_live_…
A consulta de status não usa API Key.
Gerenciar chaves
- Limite: até 10 chaves ativas por conta.
- Pausar: em Editar, mude o status para pausada. A API passa a recusar a chave até você reativá-la.
- Deletar: remove a chave de vez. Chamadas com ela passam a receber
401.
Boas práticas
- Use a chave só no servidor. Nunca a coloque em front-end, app mobile ou repositório de código.
- Guarde-a em variável de ambiente ou num cofre de segredos.
- Crie uma chave por integração: dá para trocar ou pausar uma sem afetar as outras.
- Se suspeitar de vazamento, delete a chave e crie outra.
Erros de autenticação
Todos respondem HTTP 401, com a mensagem em error:
| Mensagem | Causa |
|---|---|
API key não fornecida. Envie a chave no header X-API-Key | Header ausente. |
Formato de API key inválido | O valor não segue pk_live_ + 48 caracteres hexadecimais (confira espaços e quebras de linha). |
API key inválida | Chave inexistente ou deletada. |
API key está inativa ou revogada | Chave pausada. Reative no painel. |
Seller está bloqueado para receber pagamentos | Conta bloqueada. Fale com o suporte. |
Cobranças
Criar cobrança
X-API-KeyCria uma cobrança para um comprador, sem produto cadastrado na Payze. O mesmo endpoint atende todos os métodos: o paymentMethod define a moeda, os dados exigidos do comprador e o que volta em payment_data.
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amount | inteiro | obrigatório | Valor em centavos da moeda da cobrança: centavos de real no pix, de euro no bizum e de peso mexicano no spei. Ex.: 9990 = R$ 99,90. Mínimos em Valores e limites. |
description | string | obrigatório | Descrição da cobrança, de 3 a 255 caracteres. |
paymentMethod | string | obrigatório | pix, bizum ou spei. |
customer | objeto | obrigatório | Dados do comprador (abaixo). |
returnUrl | string | condicional | Obrigatório no bizum. URL https (até 2048 caracteres) da página para onde o comprador volta depois de aprovar no banco. |
sourceUrl | string | opcional | Usado no bizum e no spei. URL https (até 2048 caracteres) da página do seu site de onde a cobrança se origina. Sem ela, vale a URL do checkout da plataforma. |
A API responde 400 se o corpo tiver um campo que ela não conhece (por exemplo currency). A moeda é sempre a do método.
Objeto customer
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | obrigatório | Nome completo, de 3 a 128 caracteres. |
email | string | obrigatório | E-mail válido do comprador. |
document | string | condicional | pix: CPF (11 dígitos) ou CNPJ (14 dígitos) válido, só números. spei: RFC ou CURP do comprador. bizum: não é exigido. |
phone | string | opcional | Formato E.164, com + e código do país, ex.: +5511999999999. Precisa ser um número válido. |
birthDate | string | opcional | Data de nascimento no formato DD/MM/AAAA, ex.: 15/01/1990. O formato AAAA-MM-DD é recusado. |
address | objeto | opcional | Endereço no formato brasileiro (abaixo). Não envie no bizum nem no spei. |
utm | objeto | opcional | Parâmetros de rastreamento da venda (abaixo). |
Objeto customer.address
Se enviar o endereço, os campos marcados como obrigatórios passam a ser exigidos.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
zipCode | string | obrigatório | CEP com 8 dígitos, sem hífen. |
street | string | obrigatório | Logradouro, de 3 a 128 caracteres. |
district | string | obrigatório | Bairro, de 3 a 128 caracteres. |
city | string | obrigatório | Cidade, de 3 a 128 caracteres. |
state | string | obrigatório | UF, ex.: SP. |
number | string | opcional | Número, de 1 a 6 caracteres. |
complement | string | opcional | Complemento, de 1 a 48 caracteres. |
Objeto customer.utm
| Campo | Tipo | Descrição |
|---|---|---|
source | string | utm_source, até 128 caracteres. |
medium | string | utm_medium, até 128 caracteres. |
campaign | string | utm_campaign, até 128 caracteres. |
term | string | utm_term, até 128 caracteres. |
content | string | utm_content, até 128 caracteres. |
src | string | Parâmetro src usado na integração com a Utmify, até 2048 caracteres. |
sck | string | Parâmetro sck usado na integração com a Utmify, até 256 caracteres. |
Exemplo completo
curl -X POST https://api.pagpayze.com.br/api/v1/direct-payments \
-H "Content-Type: application/json" \
-H "X-API-Key: $PAYZE_API_KEY" \
-d '{
"amount": 15000,
"description": "Assinatura anual",
"paymentMethod": "pix",
"customer": {
"name": "Maria Souza",
"email": "maria@exemplo.com",
"document": "12345678909",
"phone": "+5511999999999",
"birthDate": "15/01/1990",
"address": {
"zipCode": "01310100",
"street": "Avenida Paulista",
"number": "1000",
"complement": "Sala 101",
"district": "Bela Vista",
"city": "São Paulo",
"state": "SP"
},
"utm": { "source": "google", "medium": "cpc", "campaign": "lancamento" }
}
}'
const res = await fetch("https://api.pagpayze.com.br/api/v1/direct-payments", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.PAYZE_API_KEY,
},
body: JSON.stringify({
amount: 15000,
description: "Assinatura anual",
paymentMethod: "pix",
customer: {
name: "Maria Souza",
email: "maria@exemplo.com",
document: "12345678909",
phone: "+5511999999999",
birthDate: "15/01/1990",
address: {
zipCode: "01310100",
street: "Avenida Paulista",
number: "1000",
complement: "Sala 101",
district: "Bela Vista",
city: "São Paulo",
state: "SP",
},
utm: { source: "google", medium: "cpc", campaign: "lancamento" },
},
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error} ${body.errorFields.join("; ")}`);
$payload = [
"amount" => 15000,
"description" => "Assinatura anual",
"paymentMethod" => "pix",
"customer" => [
"name" => "Maria Souza",
"email" => "maria@exemplo.com",
"document" => "12345678909",
"phone" => "+5511999999999",
"birthDate" => "15/01/1990",
"address" => [
"zipCode" => "01310100",
"street" => "Avenida Paulista",
"number" => "1000",
"complement" => "Sala 101",
"district" => "Bela Vista",
"city" => "São Paulo",
"state" => "SP",
],
"utm" => ["source" => "google", "medium" => "cpc", "campaign" => "lancamento"],
],
];
$ch = curl_init("https://api.pagpayze.com.br/api/v1/direct-payments");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "X-API-Key: " . getenv("PAYZE_API_KEY")],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
Resposta
Com sucesso, a API responde 201 Created:
| Campo | Tipo | Descrição |
|---|---|---|
transaction_id | string | Identificador da transação na Payze. Use na consulta de status e para reconhecer o webhook. |
total_value | número | Valor cobrado em unidades da moeda da cobrança (não em centavos): reais no PIX, euros no Bizum, pesos no SPEI. |
currency | string | Só no bizum (EUR) e no spei (MXN). |
status | string | Status inicial da cobrança, normalmente PENDING. |
email | string | E-mail do comprador, em minúsculas. |
payment_method | string | O método enviado, em minúsculas (pix, bizum, spei). |
payment_data | objeto | O que o comprador precisa para pagar. Muda por método: veja PIX, Bizum e SPEI. |
A criação não tem chave de idempotência. Se a requisição falhar por timeout ou erro de rede, não repita automaticamente: confira em Vendas, no painel, se a cobrança foi criada antes de gerar outra.
Erros mais comuns
| HTTP | Mensagem | O que fazer |
|---|---|---|
| 401 | API key não fornecida… e similares | Veja Autenticação. |
| 400 | Erro na validação dos campos | Leia errorFields: ele lista cada campo com problema. |
| 400 | document é obrigatório para este método de pagamento | Envie o CPF ou CNPJ do comprador no PIX. |
| 400 | document deve ser um CPF ou CNPJ válido (somente números) | Confira os dígitos do documento. |
| 400 | Você ainda não possui documentos validados para gerar pagamentos | Conclua a validação de documentos da sua conta no painel. |
A lista completa está em Erros; os erros de cada método estão nas páginas do Bizum e do SPEI.
Métodos por país
Brasil · PIX
Cobrança em reais paga com copia-e-cola ou QR Code no app do banco.
Requisição
| Campo | Regra no PIX |
|---|---|
amount | Centavos de real. 9990 = R$ 99,90. |
customer.document | obrigatório CPF ou CNPJ válido, só números. |
returnUrl, sourceUrl | Não são usados. |
curl -X POST https://api.pagpayze.com.br/api/v1/direct-payments \
-H "Content-Type: application/json" \
-H "X-API-Key: $PAYZE_API_KEY" \
-d '{
"amount": 9990,
"description": "Pedido 1234",
"paymentMethod": "pix",
"customer": { "name": "João da Silva", "email": "joao@exemplo.com", "document": "12345678909" }
}'
const res = await fetch("https://api.pagpayze.com.br/api/v1/direct-payments", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.PAYZE_API_KEY },
body: JSON.stringify({
amount: 9990,
description: "Pedido 1234",
paymentMethod: "pix",
customer: { name: "João da Silva", email: "joao@exemplo.com", document: "12345678909" },
}),
});
const { data } = await res.json();
// Para o front: só o copia-e-cola e o valor
return { transactionId: data.transaction_id, pix: data.payment_data.pix_key, valor: data.total_value };
$ch = curl_init("https://api.pagpayze.com.br/api/v1/direct-payments");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "X-API-Key: " . getenv("PAYZE_API_KEY")],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 9990,
"description" => "Pedido 1234",
"paymentMethod" => "pix",
"customer" => ["name" => "João da Silva", "email" => "joao@exemplo.com", "document" => "12345678909"],
]),
]);
$data = json_decode(curl_exec($ch), true)["data"];
curl_close($ch);
$copiaECola = $data["payment_data"]["pix_key"];
Resposta
Campos de payment_data no PIX:
| Campo | Tipo | Descrição |
|---|---|---|
pix_key | string | Código PIX copia-e-cola. Mostre com botão de copiar e gere o QR Code a partir dele. |
expiration_date | string | null | Validade informada pelo processador, em ISO 8601. Pode vir null. |
payment_id | string | Identificador da cobrança no processador. Para tudo na Payze, use o transaction_id. |
status, status_detail | string | Situação no momento da criação (PENDING / WAITING_PAYMENT). Não muda depois: o status que vale é o da raiz, na consulta ou no webhook. |
total_transaction_value | número | Valor em reais. |
Dependendo do processador, payment_data pode trazer outros campos. Ignore os que você não usa.
Tela de pagamento
- Mostre o valor, o código copia-e-cola com botão Copiar e o QR Code gerado a partir de
pix_key. - Enquanto a tela estiver aberta, consulte o status a cada 5 a 15 segundos para trocar a mensagem quando o pagamento for confirmado. A consulta não exige API Key e pode ser feita pelo navegador.
- Essa consulta no navegador serve só para a experiência do comprador. A liberação do pedido acontece no seu servidor (webhook + consulta).
async function aguardarPagamento(transactionId, { intervalo = 10000, limite = 30 * 60 * 1000 } = {}) {
const url = `https://api.pagpayze.com.br/api/v1/payments/${transactionId}/status`;
const fim = Date.now() + limite;
while (Date.now() < fim) {
const res = await fetch(url);
if (res.ok) {
const { data } = await res.json();
if (data.status === "AUTHORIZED") return "pago";
if (["REJECTED", "CANCELED"].includes(data.status)) return "nao-pago";
}
await new Promise((r) => setTimeout(r, intervalo));
}
return "tempo-esgotado";
}
Vencimento
Um PIX vencido e não pago pode continuar PENDING ou mudar para REJECTED ou CANCELED, conforme o processador. Controle o prazo do pedido do seu lado e, se o comprador voltar depois, gere uma nova cobrança.
Métodos por país
Espanha · Bizum
Pagamento instantâneo espanhol, cobrado em euros. O formulário de pagamento é montado na sua página pelo SDK de checkout e o comprador aprova a cobrança no app do banco.
Como funciona
Seu servidor cria a cobrança
Com
paymentMethod: "bizum"e umreturnUrl. A resposta traz a sessão do formulário empayment_data.session.Sua página monta o formulário
Carregue o script de
session.sdk_urle chameCheckoutSDK.mountcom a sessão.O comprador aprova no banco
Ele preenche o formulário, confirma e aprova no app do banco. Nesse passo ele sai da sua página e depois volta para o seu
returnUrl.Você confirma no servidor
A página do
returnUrlmostra “aguardando confirmação”. O pedido é liberado quando o webhook ou a consulta trouxeremAUTHORIZED.
Requisição
| Campo | Regra no Bizum |
|---|---|
amount | Centavos de euro. 1612 = 16,12 €. Mínimo 100 (1,00 €). |
returnUrl | obrigatório URL https de uma página sua. |
sourceUrl | opcional URL https do seu checkout. Recomendado. |
customer.document | Não é exigido. Envie só nome e e-mail. |
customer.phone | opcional E.164, ex.: +34612345678. |
customer.address | Não envie (o formato é brasileiro). |
curl -X POST https://api.pagpayze.com.br/api/v1/direct-payments \
-H "Content-Type: application/json" \
-H "X-API-Key: $PAYZE_API_KEY" \
-d '{
"amount": 1612,
"description": "Pedido 1234",
"paymentMethod": "bizum",
"returnUrl": "https://loja.exemplo.com/pedido/1234/aguardando",
"sourceUrl": "https://loja.exemplo.com/checkout",
"customer": { "name": "Ana García López", "email": "ana@exemplo.com" }
}'
const res = await fetch("https://api.pagpayze.com.br/api/v1/direct-payments", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.PAYZE_API_KEY },
body: JSON.stringify({
amount: Math.round(pedido.totalEur * 100), // euros → centavos
description: `Pedido ${pedido.id}`,
paymentMethod: "bizum",
returnUrl: `https://loja.exemplo.com/pedido/${pedido.id}/aguardando`,
sourceUrl: "https://loja.exemplo.com/checkout",
customer: { name: pedido.nome, email: pedido.email },
}),
});
const body = await res.json();
if (!res.ok) throw new Error(body.error);
await salvarTransacao(pedido.id, body.data.transaction_id);
// Para o front: só a sessão (e o valor, se for exibir)
return { session: body.data.payment_data.session, valor: body.data.total_value, moeda: body.data.currency };
$ch = curl_init("https://api.pagpayze.com.br/api/v1/direct-payments");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "X-API-Key: " . getenv("PAYZE_API_KEY")],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 1612, // 16,12 € em centavos
"description" => "Pedido 1234",
"paymentMethod" => "bizum",
"returnUrl" => "https://loja.exemplo.com/pedido/1234/aguardando",
"sourceUrl" => "https://loja.exemplo.com/checkout",
"customer" => ["name" => "Ana García López", "email" => "ana@exemplo.com"],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$session = $body["data"]["payment_data"]["session"]; // repasse ao front
Resposta
{
"hasError": false,
"data": {
"transaction_id": "Q8W3E5R7T9Y2",
"total_value": 16.12,
"currency": "EUR",
"status": "PENDING",
"email": "ana@exemplo.com",
"payment_method": "bizum",
"payment_data": {
"payment_id": "…",
"status": "PENDING",
"status_detail": "WAITING_PAYMENT",
"total_transaction_value": 16.12,
"currency": "EUR",
"amount": 16.12,
"exchange_rate": 6.2,
"session": {
"session_token": "…",
"public_key": "…",
"account": null,
"transaction_id": "…",
"sdk_url": "https://compra-segura.pagpayze.com.br/sdk/v1/checkout.js",
"sandbox": false
}
}
}
}
Campo de payment_data | Descrição |
|---|---|
session | Sessão do formulário. Repasse o objeto inteiro, sem alterar, ao SDK de checkout. Pode ganhar campos novos com o tempo. |
session.sdk_url | URL do script do SDK. Carregue sempre a URL que veio na sessão. |
amount, total_transaction_value | Valor em euros que o comprador paga. |
currency | EUR. |
exchange_rate | Quantos reais vale 1 euro na conversão usada. Informativo: o comprador paga exatamente amount. |
payment_id | Identificador no processador. Use o transaction_id para tudo na Payze. |
Montar o formulário
Resumo do front. As opções completas estão em SDK de checkout.
<div id="pagamento-bizum"></div>
<!-- use a URL de session.sdk_url -->
<script src="https://compra-segura.pagpayze.com.br/sdk/v1/checkout.js"></script>
// session = payment_data.session, entregue pelo SEU servidor
CheckoutSDK.mount({
container: "#pagamento-bizum",
session,
locale: "es",
onSuccess: () => mostrarAguardando(), // não é confirmação de pagamento
onError: (e) => console.warn(e.code, e.message),
}).catch((e) => mostrarErro(e.message));
Página do returnUrl
- Mostre “aguardando confirmação do banco” e consulte o status a cada 5 a 15 segundos, com um limite de tempo.
- A consulta de status também devolve
payment_data.session: se o comprador voltar antes de pagar, você pode montar o formulário de novo com ela, sem criar outra cobrança. - Com
AUTHORIZED, mostre a confirmação. ComREJECTEDouCANCELED, ofereça gerar uma nova cobrança.
Erros específicos
| HTTP | Mensagem | O que fazer |
|---|---|---|
| 400 | returnUrl é obrigatório para pagamento via Bizum (em errorFields) | Envie returnUrl. |
| 400 | returnUrl deve ser uma URL https válida / sourceUrl deve ser uma URL https válida (em errorFields) | Use URL completa com https://. |
| 400 | Valor mínimo para pagamento via Bizum é € 1,00 (valor da cobrança: € 0,50) | Cobre no mínimo amount: 100. |
| 400 | Pagamento via Bizum não está habilitado nesta plataforma | Fale com o suporte. |
| 400 | Taxa de Bizum não configurada no plano de taxas do vendedor | Sua conta ainda não está liberada para Bizum. Fale com o suporte. |
| 400 | Cotação EUR não configurada no provedor de pagamento / Pagamento via Bizum indisponível para este produto | Configuração pendente na plataforma. Fale com o suporte. |
| 400 | Não foi possível gerar o pagamento. Tente novamente. | O processador não gerou a cobrança. Tente de novo manualmente (cria uma nova transação). |
Cobranças
SDK de checkout
Script da Payze que monta o formulário de pagamento do Bizum dentro da sua página, a partir da sessão devolvida pela API. Você fornece o container e a sessão; o SDK cuida do formulário e da confirmação.
Carregar o script
- Use sempre a URL de
payment_data.session.sdk_url. Não fixe a URL no seu código: a versão pode mudar. - O script cria o objeto global
CheckoutSDK. Carregá-lo mais de uma vez não tem efeito. - Em aplicações SPA, injete o
<script>uma vez e só chamemountdepois que ele carregar.
<div id="pagamento"></div>
<script src="https://compra-segura.pagpayze.com.br/sdk/v1/checkout.js"></script>
Montar o formulário
const form = await CheckoutSDK.mount({
container: "#pagamento", // elemento ou seletor CSS
session, // payment_data.session, como veio da API
locale: "es", // "pt" | "es" | "en" | "auto"
appearance: { accent: "#2E7CF6", radius: "8px", font: "inherit" },
onReady: () => esconderCarregando(),
onChange: ({ canConfirm, total }) => {},
onSuccess: (r) => mostrarAguardando(), // tentativa aceita, NÃO é pagamento confirmado
onError: (e) => console.warn(e.code, e.message),
});
// Ao sair da página ou desmontar o componente:
form.destroy();
Opções de mount
| Opção | Tipo | Obrigatório | Descrição |
|---|---|---|---|
container | elemento | string | obrigatório | Elemento, ou seletor CSS, onde o formulário é desenhado. O conteúdo do elemento é substituído. |
session | objeto | obrigatório | payment_data.session da resposta da API, sem alterações. |
locale | string | opcional | pt, es, en ou auto. Padrão: auto (idioma do navegador). |
button | objeto | false | opcional | { label: "Pagar" } troca o texto do botão. false esconde o botão: você chama form.confirm() no seu. |
appearance | objeto | opcional | accent: cor do botão e do destaque do formulário. radius: arredondamento (padrão 10px). font: fonte (padrão inherit). |
onReady | função | opcional | Chamada quando o formulário está pronto para uso. |
onChange | função | opcional | Recebe { canConfirm, total } quando o formulário muda. canConfirm diz se já dá para confirmar; total é o valor exibido, quando disponível. |
onSuccess | função | opcional | Chamada quando a confirmação é aceita sem sair da página. Recebe um objeto com transaction_id e sandbox. Não confirma o pagamento. |
onError | função | opcional | Recebe { code, message } quando algo falha. O formulário já mostra a mensagem ao comprador; use para log ou para a sua interface. |
Retorno de mount
mount devolve uma Promise que resolve com o controle do formulário:
| Membro | Descrição |
|---|---|
confirm() | Dispara a confirmação. Use com button: false. Devolve uma Promise. |
destroy() | Limpa o container. Chame ao sair da página ou desmontar o componente. |
sandbox | true quando a sessão é de teste. |
A Promise é rejeitada, sem chamar onError, quando o container não existe (code: "container") ou a sessão está incompleta (code: "session"). Se o formulário não carregar, onError recebe code: "load" e a Promise também é rejeitada. Trate sempre o .catch.
Botão próprio
const botao = document.querySelector("#pagar");
botao.disabled = true;
const form = await CheckoutSDK.mount({
container: "#pagamento",
session,
button: false,
onChange: ({ canConfirm }) => { botao.disabled = !canConfirm; },
});
botao.addEventListener("click", () => form.confirm());
Exemplo em React
import { useEffect, useRef } from "react";
function carregarSdk(src) {
return new Promise((resolve, reject) => {
if (window.CheckoutSDK) return resolve(window.CheckoutSDK);
const s = document.createElement("script");
s.src = src;
s.onload = () => resolve(window.CheckoutSDK);
s.onerror = () => reject(new Error("Não foi possível carregar o formulário"));
document.head.appendChild(s);
});
}
export function FormularioBizum({ session, onAceito, onErro }) {
const ref = useRef(null);
useEffect(() => {
let form;
let cancelado = false;
carregarSdk(session.sdk_url)
.then((sdk) => {
if (cancelado || !ref.current) return;
return sdk.mount({
container: ref.current,
session,
locale: "es",
onSuccess: onAceito,
onError: (e) => onErro?.(e.message),
});
})
.then((f) => {
form = f;
if (cancelado) form?.destroy();
})
.catch((e) => onErro?.(e.message));
return () => {
cancelado = true;
form?.destroy();
};
}, [session.session_token]);
return <div ref={ref} />;
}
Depois da confirmação
- No Bizum, o comprador normalmente sai da sua página para aprovar no banco e volta pelo
returnUrl. Nesse caminho,onSuccesspode nem ser chamado. Quem mostra “aguardando confirmação” e consulta o status é a página doreturnUrl. onSuccesssignifica “tentativa aceita”. O pagamento só está confirmado quando a transação chega aAUTHORIZED(webhook ou consulta).
Sessão de teste
Se session.sandbox vier true, o SDK mostra um formulário simulado, com o botão “Simular pagamento” (no idioma do locale). Nada é cobrado e onSuccess recebe sandbox: true.
Content Security Policy
script-src: o domínio desession.sdk_url(https://compra-segura.pagpayze.com.br) ehttps://js.stripe.comframe-src:https://js.stripe.com https://*.stripe.comconnect-src:https://api.stripe.comstyle-src: o SDK injeta o próprio CSS numa tag<style>; permita estilos inline ('unsafe-inline') ou o hash correspondente.
Métodos por país
México · SPEI
Transferência bancária instantânea do México, cobrada em pesos mexicanos. A API devolve uma CLABE e o comprador transfere o valor exato pelo app do banco. Não há SDK nem redirecionamento.
Requisição
| Campo | Regra no SPEI |
|---|---|
amount | Centavos de peso mexicano. 37400 = MX$ 374,00. Mínimo 100 (MX$ 1,00). |
customer.document | obrigatório RFC (12 ou 13 caracteres) ou CURP (18 caracteres) do comprador. A API converte para maiúsculas e remove espaços, pontos e hífens. CPF e CNPJ são recusados. |
sourceUrl | opcional URL https do seu checkout. Recomendado. |
returnUrl | Não é usado. |
customer.phone | opcional E.164, ex.: +525512345678. |
customer.address | Não envie (o formato é brasileiro). |
curl -X POST https://api.pagpayze.com.br/api/v1/direct-payments \
-H "Content-Type: application/json" \
-H "X-API-Key: $PAYZE_API_KEY" \
-d '{
"amount": 37400,
"description": "Pedido 1234",
"paymentMethod": "spei",
"sourceUrl": "https://loja.exemplo.com/checkout",
"customer": {
"name": "Sofía Hernández López",
"email": "sofia@exemplo.com",
"document": "HEGS900101MDFRRF09"
}
}'
const res = await fetch("https://api.pagpayze.com.br/api/v1/direct-payments", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.PAYZE_API_KEY },
body: JSON.stringify({
amount: Math.round(pedido.totalMxn * 100), // pesos → centavos
description: `Pedido ${pedido.id}`,
paymentMethod: "spei",
sourceUrl: "https://loja.exemplo.com/checkout",
customer: {
name: pedido.nome,
email: pedido.email,
document: pedido.curpOuRfc.toUpperCase().replace(/[\s.-]/g, ""),
},
}),
});
const body = await res.json();
if (!res.ok) throw new Error(body.error);
await salvarTransacao(pedido.id, body.data.transaction_id);
return { spei: body.data.payment_data.spei, valor: body.data.total_value, moeda: body.data.currency };
$ch = curl_init("https://api.pagpayze.com.br/api/v1/direct-payments");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "X-API-Key: " . getenv("PAYZE_API_KEY")],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 37400, // MX$ 374,00 em centavos
"description" => "Pedido 1234",
"paymentMethod" => "spei",
"sourceUrl" => "https://loja.exemplo.com/checkout",
"customer" => [
"name" => "Sofía Hernández López",
"email" => "sofia@exemplo.com",
"document" => "HEGS900101MDFRRF09",
],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$spei = $body["data"]["payment_data"]["spei"]; // CLABE e validade para o front
Resposta
{
"hasError": false,
"data": {
"transaction_id": "M4X8C2V6B0N3",
"total_value": 374,
"currency": "MXN",
"status": "PENDING",
"email": "sofia@exemplo.com",
"payment_method": "spei",
"payment_data": {
"payment_id": "…",
"status": "PENDING",
"status_detail": "WAITING_PAYMENT",
"total_transaction_value": 374,
"currency": "MXN",
"amount": 374,
"exchange_rate": 0.3,
"spei": {
"clabe": "012180001234567890",
"reference": "1234567",
"bank": null,
"beneficiary": null,
"expires_at": "2026-10-09T05:59:00.000Z"
}
}
}
}
Campo de payment_data.spei | Tipo | Descrição |
|---|---|---|
clabe | string | CLABE de 18 dígitos para onde o comprador transfere. Sempre presente. |
reference | string | null | Referência da transferência, quando houver. |
bank | string | null | Banco de destino, quando informado. |
beneficiary | string | null | Beneficiário, quando informado. |
expires_at | string | null | Validade da CLABE em ISO 8601 (UTC). |
Em payment_data também vêm currency (MXN), amount (valor em pesos) e exchange_rate (quantos reais vale 1 peso na conversão usada; informativo).
Tela de pagamento
- Valor em pesos, CLABE em fonte monoespaçada com botão Copiar, referência (se houver) e validade no fuso da Cidade do México.
- Instrua o comprador a transferir o valor exato pelo app do banco, escolhendo transferência SPEI.
- Se a página recarregar, recupere
payment_data.speipela consulta de status. Não crie outra cobrança. - Depois de
expires_at, ofereça gerar uma nova cobrança.
// spei, valor: dados que o seu servidor repassou da resposta da API
const valorFormatado = new Intl.NumberFormat("es-MX", { style: "currency", currency: "MXN" }).format(valor);
const validade = spei.expires_at
? new Intl.DateTimeFormat("es-MX", {
dateStyle: "short",
timeStyle: "short",
timeZone: "America/Mexico_City",
}).format(new Date(spei.expires_at))
: null;
document.querySelector("#clabe").textContent = spei.clabe;
document.querySelector("#copiar-clabe").addEventListener("click", () => navigator.clipboard.writeText(spei.clabe));
Validar o RFC ou o CURP no formulário
A API usa as mesmas regras abaixo. Validar antes evita uma ida e volta.
function documentoMexicoValido(valor) {
const doc = valor.toUpperCase().replace(/[\s.-]/g, "");
const RFC = /^[A-ZÑ&]{3,4}\d{6}[A-Z\d]{3}$/;
const CURP = /^[A-Z][AEIOUX][A-Z]{2}\d{6}[HMX][A-Z]{2}[B-DF-HJ-NP-TV-Z]{3}[A-Z\d]\d$/;
return RFC.test(doc) || CURP.test(doc);
}
Erros específicos
| HTTP | Mensagem | O que fazer |
|---|---|---|
| 400 | document (RFC ou CURP do comprador) é obrigatório para pagamento via SPEI | Envie customer.document. |
| 400 | document deve ser um RFC ou CURP válido para pagamento via SPEI | Confira o documento. CPF e CNPJ não valem no SPEI. |
| 400 | document deve ser um CPF/CNPJ válido (somente números) ou, no SPEI, um RFC/CURP válido (em errorFields) | O valor enviado não é nenhum documento aceito. |
| 400 | Valor mínimo para pagamento via SPEI é MX$ 1,00 (valor da cobrança: MX$ 0,50) | Cobre no mínimo amount: 100. |
| 400 | sourceUrl deve ser uma URL https válida (em errorFields) | Use URL completa com https://. |
| 400 | Pagamento via SPEI não está habilitado nesta plataforma | Fale com o suporte. |
| 400 | Taxa de SPEI não configurada no plano de taxas do vendedor | Sua conta ainda não está liberada para SPEI. Fale com o suporte. |
| 400 | Cotação MXN não configurada no provedor de pagamento / Pagamento via SPEI indisponível para este produto | Configuração pendente na plataforma. Fale com o suporte. |
| 400 | Não foi possível gerar o pagamento. Tente novamente. | O processador não gerou a cobrança. Tente de novo manualmente (cria uma nova transação). |
Depois do pagamento
Consultar status
Devolve o status atual da transação e os dados de pagamento gravados na criação. Não exige API Key: pode ser chamada pelo seu servidor, para confirmar um webhook, e pelo navegador, para atualizar a tela do comprador.
Parâmetro
| Parâmetro | Em | Descrição |
|---|---|---|
transaction_id | caminho | O transaction_id devolvido na criação da cobrança. |
Requisição
curl https://api.pagpayze.com.br/api/v1/payments/7KQ2M9XA4T1B/status
const res = await fetch(`https://api.pagpayze.com.br/api/v1/payments/${transactionId}/status`);
const body = await res.json();
if (!res.ok) throw new Error(body.error); // ex.: "Pedido não encontrado!"
console.log(body.data.status); // "PENDING", "AUTHORIZED"…
$url = "https://api.pagpayze.com.br/api/v1/payments/" . urlencode($transactionId) . "/status";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$status = $body["data"]["status"] ?? null; // "PENDING", "AUTHORIZED"…
Resposta
{
"hasError": false,
"data": {
"transaction_id": "7KQ2M9XA4T1B",
"total_value": 99.9,
"fee": 4.49,
"net_value": 95.41,
"status": "AUTHORIZED",
"product": null,
"payment_method": "PIX",
"producer": null,
"payment_data": {
"pix_key": "00020126580014br.gov.bcb.pix0136…6304A1B2",
"expiration_date": null,
"payment_id": "c1a7e0b2-5d3f-4e8a-9b61-0f2d7c4e9a13",
"status": "PENDING",
"status_detail": "WAITING_PAYMENT",
"total_transaction_value": 99.9
}
}
}
{
"hasError": false,
"data": {
"transaction_id": "Q8W3E5R7T9Y2",
"total_value": 99.94,
"fee": 5.99,
"net_value": 93.95,
"status": "PENDING",
"product": null,
"payment_method": "BIZUM",
"producer": null,
"payment_data": {
"international": {
"method": "BIZUM",
"currency": "EUR",
"amount": 16.12,
"brl_amount": 99.94,
"brl_per_unit": 6.2
},
"session": {
"session_token": "…",
"public_key": "…",
"account": null,
"transaction_id": "…",
"sdk_url": "https://compra-segura.pagpayze.com.br/sdk/v1/checkout.js",
"sandbox": false
}
}
}
}
{
"hasError": false,
"data": {
"transaction_id": "M4X8C2V6B0N3",
"total_value": 112.2,
"fee": 6.72,
"net_value": 105.48,
"status": "PENDING",
"product": null,
"payment_method": "SPEI",
"producer": null,
"payment_data": {
"international": {
"method": "SPEI",
"currency": "MXN",
"amount": 374,
"brl_amount": 112.2,
"brl_per_unit": 0.3
},
"spei": {
"clabe": "012180001234567890",
"reference": "1234567",
"bank": null,
"beneficiary": null,
"expires_at": "2026-10-09T05:59:00.000Z"
}
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
transaction_id | string | Identificador da transação. |
status | string | Status atual. É o campo que vale; veja Status da transação. |
total_value | número | Valor da transação em reais, também no Bizum e no SPEI. |
fee | número | Taxa da Payze, em reais. |
net_value | número | Valor líquido para você, em reais. |
payment_method | string | Método em maiúsculas: PIX, BIZUM, SPEI. |
product, producer | objeto | null | null nas cobranças criadas pela API. Vêm preenchidos nas vendas de produto feitas pelo checkout da Payze. |
payment_data | objeto | Dados gravados na criação: pix_key no PIX, session no Bizum, spei no SPEI. |
payment_data.international | objeto | Só no Bizum e no SPEI: currency e amount cobrados do comprador, brl_amount (valor convertido em reais) e brl_per_unit (cotação usada). |
No PIX, payment_data.status é a foto do momento da criação e continua PENDING mesmo depois do pagamento. O status atual é sempre data.status.
A resposta da criação mostra o valor na moeda da cobrança (EUR ou MXN). A consulta e o webhook mostram total_value, fee e net_value em reais. Não exiba ao comprador os valores da consulta como se fossem euros ou pesos: o valor cobrado está em payment_data.international.amount.
Erros
| HTTP | Mensagem | Causa |
|---|---|---|
| 400 | Pedido não encontrado! | Não existe transação com esse transaction_id. |
Polling
- Consulte a cada 5 a 15 segundos, com um limite de tempo, e pare quando o status deixar de ser
PENDING. - Polling é apoio. Para liberar pedidos, use o webhook e confirme com esta consulta.
Depois do pagamento
Webhooks
A Payze avisa o seu servidor com um POST em JSON quando uma transação sua é atualizada. Use o aviso como gatilho e confirme o status na consulta antes de liberar o pedido.
Cadastrar a URL
- No painel da Payze, abra Integração → Webhooks e clique em Novo Webhook.
- Informe um nome e a URL de destino. Use HTTPS.
- Clique em Cadastrar. O webhook já nasce ativo.
- Você pode cadastrar mais de uma URL (o painel aceita até 10). Cada URL ativa recebe todos os avisos.
- Em Editar, dá para pausar: webhooks pausados não recebem disparos.
- Os avisos cobrem todas as transações da sua conta, não só as criadas pela API. Ignore os
transaction_idque a sua integração não conhece.
Quando a Payze envia
- Quando o processador informa uma atualização da transação: pagamento aprovado, recusa, cancelamento, estorno, chargeback, disputa e atualizações de pendência.
- Quando a equipe da Payze aprova uma transação manualmente.
- Não há aviso na criação da cobrança. Uma falha ao gerar a cobrança (
FAILED) também não gera aviso: nesse caso a própria criação já respondeu erro. - O mesmo status pode chegar mais de uma vez, por exemplo duas atualizações seguidas com
PENDING.
Requisição enviada
POST para a sua URL, com Content-Type: application/json e este corpo:
{
"transaction_id": "7KQ2M9XA4T1B",
"total_value": 99.9,
"fee": 4.49,
"net_value": 95.41,
"status": "AUTHORIZED",
"product": null,
"payment_method": "PIX",
"producer": null,
"payment_data": {
"pix_key": "00020126580014br.gov.bcb.pix0136…6304A1B2",
"expiration_date": null,
"payment_id": "c1a7e0b2-5d3f-4e8a-9b61-0f2d7c4e9a13",
"status": "PENDING",
"status_detail": "WAITING_PAYMENT",
"total_transaction_value": 99.9
},
"customer": {
"name": "João da Silva",
"email": "joao@exemplo.com",
"document": "12345678909",
"phone": "+5511999999999",
"birth_date": "15/01/1990",
"address": {}
}
}
| Campo | Descrição |
|---|---|
transaction_id | A transação atualizada. Localize o seu pedido por ele. |
status | Status atual da transação. Não há campo de nome de evento: o que importa é o status. |
total_value, fee, net_value | Valor, taxa e líquido em reais. |
payment_method | Em maiúsculas: PIX, BIZUM, SPEI. |
product, producer | null nas cobranças da API; preenchidos nas vendas de produto do checkout da Payze. |
payment_data | O mesmo objeto da consulta de status. |
customer | Comprador: name, email, document, phone, birth_date e address (com as chaves cep, street, number, complement, neighborhood, city e state; vazio se não foi enviado). |
Entrega e retentativas
- Responda com HTTP
2xx. Qualquer outro status, ou erro de rede, conta como falha. - São até 3 tentativas no total, com 15 segundos entre elas. Depois da terceira falha, aquele aviso não é reenviado: recupere o estado pela consulta de status.
- Responda rápido: grave o aviso, devolva
200e processe em segundo plano. - A ordem de chegada não é garantida. Por isso, confirme o status atual na consulta antes de agir.
Segurança
Trate o corpo do webhook como um aviso, não como prova de pagamento. Antes de liberar o pedido, confirme com GET /api/v1/payments/{transaction_id}/status. Use HTTPS e uma URL difícil de adivinhar, por exemplo com um token secreto no caminho, e confira esse token ao receber.
Idempotência
- O mesmo aviso pode chegar mais de uma vez (retentativas e atualizações repetidas). Liberar o pedido duas vezes precisa ser impossível.
- Uma transação aprovada pode mudar depois para
REFUNDED,CHARGEBACKouIN_DISPUTE. Não descarte um aviso só porque já viu aqueletransaction_id: deduplique portransaction_id+status. - Torne a liberação atômica: marque o pedido como pago numa atualização condicional (por exemplo,
UPDATE … WHERE status <> 'pago') e entregue só se a atualização mudou uma linha.
Exemplo de receptor
import express from "express";
const app = express();
app.use(express.json());
const API = "https://api.pagpayze.com.br/api/v1";
app.post("/webhooks/payze/:token", async (req, res) => {
if (req.params.token !== process.env.PAYZE_WEBHOOK_TOKEN) return res.sendStatus(404);
res.sendStatus(200); // responda logo; processe em seguida
const transactionId = req.body?.transaction_id;
if (!transactionId) return;
const pedido = await db.pedidos.porTransacao(transactionId);
if (!pedido) return; // transação que não é desta integração
// Confirma o status na fonte antes de agir
const r = await fetch(`${API}/payments/${transactionId}/status`);
if (!r.ok) return;
const { data } = await r.json();
if (data.status === "AUTHORIZED") {
const mudou = await db.pedidos.marcarPagoSeAindaNao(pedido.id); // UPDATE condicional
if (mudou) await liberarPedido(pedido);
} else if (["REFUNDED", "CHARGEBACK"].includes(data.status)) {
await revogarPedido(pedido);
}
});
app.listen(3000);
<?php
// URL cadastrada: https://loja.exemplo.com/webhook-payze.php?token=SEU_TOKEN
if (!hash_equals(getenv("PAYZE_WEBHOOK_TOKEN"), $_GET["token"] ?? "")) {
http_response_code(404);
exit;
}
$aviso = json_decode(file_get_contents("php://input"), true);
http_response_code(200);
$transactionId = $aviso["transaction_id"] ?? null;
if (!$transactionId) exit;
// Confirma o status na fonte antes de agir
$ch = curl_init("https://api.pagpayze.com.br/api/v1/payments/" . urlencode($transactionId) . "/status");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$status = json_decode(curl_exec($ch), true)["data"]["status"] ?? null;
curl_close($ch);
if ($status === "AUTHORIZED") {
// UPDATE pedidos SET status = 'pago' WHERE transaction_id = ? AND status <> 'pago'
// Se mudou 1 linha, libere o pedido.
}
Depois do pagamento
Status da transação
O campo status da consulta e do webhook diz em que ponto a transação está. A venda está paga só com AUTHORIZED.
Ciclo de vida
Tabela de status
| Status | Significado | O que fazer | Webhook |
|---|---|---|---|
| PENDING | Cobrança criada, aguardando o pagamento. | Mostrar os dados de pagamento e aguardar. | sim |
| AUTHORIZED | Pago. | Liberar o pedido, uma única vez. | sim |
| REJECTED | Recusado. | Oferecer uma nova tentativa (nova cobrança). | sim |
| CANCELED | Cancelado. | Encerrar o pedido ou gerar nova cobrança. | sim |
| REFUNDED | Valor devolvido ao comprador. | Revogar acesso ou entrega. | sim |
| CHARGEBACK | Pagamento contestado pelo comprador. | Revogar acesso ou entrega. | sim |
| IN_DISPUTE | Disputa aberta, em análise. | Suspender a entrega e acompanhar. | sim |
| FAILED | O processador não gerou a cobrança. | A criação já respondeu erro; corrija e tente de novo. | não |
| DISPUTE_ACCEPTED | Disputa encerrada com devolução ao comprador. | Revogar acesso ou entrega. | não |
| DISPUTE_REJECTED | Disputa encerrada a favor da venda. | A venda segue válida. | não |
Os status sem webhook só aparecem na consulta de status e no painel.
Uma cobrança vencida e não paga pode continuar PENDING ou passar para REJECTED ou CANCELED, conforme o processador. Controle o prazo do pedido do seu lado.
AUTHORIZED pode mudar
Depois de pago, um pedido ainda pode virar REFUNDED, CHARGEBACK ou IN_DISPUTE. Mantenha o webhook tratando esses status mesmo para pedidos já entregues.
Referência
Erros
Erros respondem com hasError: true, o código HTTP em statusCode e a mensagem em error. Erros de validação listam cada problema em errorFields.
Formato
{
"hasError": true,
"error": "Erro na validação dos campos",
"errorFields": [
"amount must not be less than 1",
"customer.email must be an email"
],
"statusCode": 400,
"timestamp": "2026-10-08T15:19:00.782Z",
"path": "/api/v1/direct-payments"
}
| Campo | Descrição |
|---|---|
hasError | Sempre true em erro. |
error | Mensagem principal. Nos erros de validação, é Erro na validação dos campos. |
errorFields | Lista de problemas de validação, cada um citando o campo (ex.: customer.email). Vazia nos demais erros. As mensagens padrão de validação vêm em inglês. |
statusCode | O mesmo código HTTP da resposta. |
timestamp, path | Momento (ISO 8601, UTC) e caminho da requisição. Úteis ao falar com o suporte. |
Códigos HTTP
| HTTP | Quando |
|---|---|
| 200 | Consulta de status com sucesso. |
| 201 | Cobrança criada. |
| 400 | Dados inválidos ou regra de negócio: validação, documento, valor mínimo, método indisponível, recusa do processador. Também quando a transação consultada não existe. |
| 401 | API Key ausente, inválida ou pausada, ou conta bloqueada. |
| 404 | Rota inexistente. Confira o método HTTP e o caminho. |
| 429 | Muitas requisições em pouco tempo. Espere alguns segundos e tente de novo. |
| 500 | Erro inesperado. Tente de novo; se persistir, fale com o suporte informando timestamp e path. |
Mensagens comuns
Autenticação · 401
| Mensagem | Causa |
|---|---|
API key não fornecida. Envie a chave no header X-API-Key | Header ausente. |
Formato de API key inválido | Valor fora do formato pk_live_ + 48 hexadecimais. |
API key inválida | Chave inexistente ou deletada. |
API key está inativa ou revogada | Chave pausada. |
Seller está bloqueado para receber pagamentos | Conta bloqueada. |
Validação · 400, em errorFields
| Mensagem | Causa |
|---|---|
property currency should not exist | Campo desconhecido no corpo (aqui, currency). |
returnUrl é obrigatório para pagamento via Bizum | Bizum sem returnUrl. |
returnUrl deve ser uma URL https válida | URL sem https:// ou malformada. |
sourceUrl deve ser uma URL https válida | URL sem https:// ou malformada. |
document deve ser um CPF/CNPJ válido (somente números) ou, no SPEI, um RFC/CURP válido | O documento não é nenhum dos aceitos. |
A data de nascimento deve ser válida e estar no formato DD/MM/YYYY | birthDate fora do formato. |
Regras de negócio · 400, em error
| Mensagem | Causa |
|---|---|
document é obrigatório para este método de pagamento | PIX sem CPF/CNPJ. |
document deve ser um CPF ou CNPJ válido (somente números) | PIX com documento inválido. |
document (RFC ou CURP do comprador) é obrigatório para pagamento via SPEI | SPEI sem documento. |
document deve ser um RFC ou CURP válido para pagamento via SPEI | SPEI com documento inválido. |
Valor mínimo para pagamento via Bizum é € 1,00 (…) / … via SPEI é MX$ 1,00 (…) | amount abaixo de 100 no Bizum ou no SPEI. |
Pagamento via Bizum não está habilitado nesta plataforma (ou SPEI) | Método desligado. Fale com o suporte. |
Taxa de Bizum não configurada no plano de taxas do vendedor (ou SPEI) | Método não liberado na sua conta. Fale com o suporte. |
Cotação EUR não configurada no provedor de pagamento (ou MXN) | Configuração pendente. Fale com o suporte. |
Pagamento via Bizum indisponível para este produto (ou SPEI) | Configuração pendente. Fale com o suporte. |
Você ainda não possui documentos validados para gerar pagamentos | Validação de documentos da conta pendente. |
Não foi possível gerar o pagamento. Tente novamente. | Bizum ou SPEI: o processador não gerou a cobrança. A transação fica FAILED. |
| Mensagem variável | PIX: o processador não gerou a cobrança. A transação fica FAILED. |
Pedido não encontrado! | Consulta de status com transaction_id inexistente. |
Como tratar
- 400 de validação ou regra: corrija a requisição. Repetir igual dá o mesmo erro.
- Recusa do processador: pode tentar de novo, manualmente. Cada tentativa cria uma nova transação.
- 429, 500 e timeouts: espere e tente de novo com intervalo crescente. Antes de recriar uma cobrança, confira no painel se a anterior não foi criada.
Referência
Valores e limites
Unidades de valor, mínimos por método, formatos de dados e limites da conta.
Unidades de valor
| Onde | Unidade | Exemplo |
|---|---|---|
amount na criação | Inteiro, em centavos da moeda da cobrança | 9990 = R$ 99,90 · 1612 = 16,12 € · 37400 = MX$ 374,00 |
total_value na resposta da criação | Decimal, na moeda da cobrança | 99.9 · 16.12 · 374 |
total_value, fee, net_value na consulta e no webhook | Decimal, sempre em reais | 99.9 |
payment_data.international.amount | Decimal, na moeda da cobrança | 16.12 |
No Bizum e no SPEI, o comprador paga exatamente o amount enviado, na moeda dele. A Payze converte esse valor para reais pela cotação cadastrada na plataforma (exchange_rate na criação, brl_per_unit na consulta), e taxas, splits e saldo são calculados em BRL.
Valores mínimos
| Método | Mínimo de amount | Equivale a |
|---|---|---|
pix | 1 | R$ 0,01 (limite da validação da API) |
bizum | 100 | 1,00 € |
spei | 100 | MX$ 1,00 |
Tamanho dos campos
| Campo | Limite |
|---|---|
description | 3 a 255 caracteres |
customer.name | 3 a 128 caracteres |
returnUrl, sourceUrl | https, até 2048 caracteres |
customer.utm.* | até 128 caracteres; src até 2048 e sck até 256 |
customer.address.* | veja Criar cobrança |
Formatos
| Dado | Formato | Exemplo |
|---|---|---|
| CPF / CNPJ | Só números, 11 ou 14 dígitos, dígitos verificadores válidos | 12345678909 |
| RFC / CURP | Maiúsculas, sem espaços, pontos ou hífens | HEGS900101MDFRRF09 |
| Telefone | E.164 | +5511999999999 |
| Data de nascimento | DD/MM/AAAA | 15/01/1990 |
| CEP | 8 dígitos, sem hífen | 01310100 |
| Datas nas respostas | ISO 8601, UTC | 2026-10-08T15:19:00.782Z |
Limites da conta
- API Keys: até 10 ativas por conta.
- Webhooks: o painel aceita até 10 URLs.
- Requisições: a API limita o volume de chamadas em sequência e responde
429quando o limite é atingido. Faça polling a cada 5 a 15 segundos, nunca em laço contínuo.
Referência
Checklist de produção
Confira estes pontos antes de colocar a integração no ar.
Geral
- A API Key fica só no servidor, em variável de ambiente ou cofre de segredos. Nunca no front nem no repositório.
amounté inteiro, em centavos da moeda do método.- O
transaction_idé salvo no pedido logo após a criação. - A criação não é repetida automaticamente em erro ou timeout.
- O webhook está cadastrado com HTTPS e responde
2xxrápido. - Antes de liberar o pedido, o servidor confirma
AUTHORIZEDna consulta de status, e a liberação é idempotente. REFUNDED,CHARGEBACKeIN_DISPUTEsão tratados também em pedidos já entregues.- Valores da consulta e do webhook (em reais) não são exibidos ao comprador como se fossem euros ou pesos.
PIX
- Copia-e-cola com botão de copiar e QR Code gerado de
pix_key. - O prazo do pedido é controlado do seu lado; depois dele, uma nova cobrança é gerada.
Bizum
returnUrlhttps aponta para uma página que mostra “aguardando confirmação” e consulta o status.- O SDK é carregado de
session.sdk_url, o.catchdemounté tratado edestroy()é chamado ao sair. onSuccesssó mostra “aguardando”; nada é liberado por ele.- A CSP do site libera as origens listadas no SDK de checkout.
SPEI
- O formulário pede e valida RFC ou CURP; não pede CPF nem endereço brasileiro.
- A CLABE aparece copiável, com valor em pesos e validade no fuso da Cidade do México.
- Ao recarregar, a página usa os dados da consulta de status; depois de
expires_at, gera uma nova cobrança.