Criar uma cobrança
Uma chamada, um header de idempotência, e a resposta já traz o QR Code.
#!/usr/bin/env bash
# Cria uma cobrança PIX. Precisa de LM_API_URL e LM_API_KEY no ambiente.
# export LM_API_URL=https://api.leztypay.com
# export LM_API_KEY=sk_test_...
set -euo pipefail
curl --fail-with-body -sS "$LM_API_URL/v1/transactions" \
-H "Authorization: Bearer $LM_API_KEY" \
-H "Idempotency-Key: pedido-A123-tentativa-1" \
-H "Content-Type: application/json" \
-d '{
"amount": 10000,
"payment_method": "pix",
"customer": {
"name": "Maria Silva",
"email": "maria@exemplo.com",
"document": "123.456.789-09"
},
"items": [{ "name": "Curso X", "quantity": 1, "unit_amount": 10000 }],
"pix": { "expires_in_seconds": 1800 },
"postback_url": "https://loja.exemplo.com/webhooks/leztypay",
"metadata": { "order_id": "A123" }
}'
O mesmo em Node, com tratamento de erro:
// Cria uma cobrança PIX com o fetch global do Node 22. Sem dependência.
// LM_API_URL=https://api.leztypay.com LM_API_KEY=sk_test_... node create-transaction.mjs
const apiUrl = process.env.LM_API_URL;
const apiKey = process.env.LM_API_KEY;
// A chave de idempotência é do SEU pedido, não da requisição. Repetir a mesma chave com o
// mesmo corpo devolve a cobrança já criada em vez de criar uma segunda.
const idempotencyKey = 'pedido-A123-tentativa-1';
const res = await fetch(`${apiUrl}/v1/transactions`, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 10000,
payment_method: 'pix',
customer: {
name: 'Maria Silva',
email: 'maria@exemplo.com',
document: '123.456.789-09',
},
items: [{ name: 'Curso X', quantity: 1, unit_amount: 10000 }],
pix: { expires_in_seconds: 1800 },
postback_url: 'https://loja.exemplo.com/webhooks/leztypay',
metadata: { order_id: 'A123' },
}),
});
const body = await res.json();
if (!res.ok) {
// Todo erro tem o mesmo envelope. `request_id` é o que o suporte pede.
console.error(res.status, body.error.code, body.error.message, body.error.request_id);
process.exit(1);
}
if (res.headers.get('Idempotent-Replayed') === 'true') {
console.log('resposta salva de uma tentativa anterior com a mesma chave');
}
console.log('id:', body.id);
console.log('status:', body.status);
console.log('expira em:', body.pix.expires_at);
console.log('copia e cola:', body.pix.payload);
A lista completa do que entra e do que volta está na referência da operação. Aqui ficam só as regras que a referência não conta.
O mínimo
Só amount e customer são obrigatórios. Todo o resto tem padrão.
O cliente precisa de nome, e-mail e documento. O documento é CPF ou CNPJ e é validado de verdade,
com dígito verificador; pode vir formatado ou só com dígitos, tanto faz. Documento inválido é
400 invalid_document.
payment_method aceita apenas pix, e é o padrão. Qualquer outro valor é
400 unsupported_payment_method.
A taxa é congelada na criação
A resposta traz fee, net e reserve já calculados com as condições vigentes naquele instante, e
eles não mudam mais. Uma cobrança criada hoje liquida com a taxa de hoje, mesmo que seja paga daqui
a uma semana com outra tabela em vigor.
Se a taxa consumisse a cobrança inteira, a criação é recusada com 400 amount_too_small. É por isso
que um valor acima do mínimo ainda pode ser recusado por ser pequeno demais.
Os campos que existem para você, não para nós
metadataé o seu campo livre: um objeto plano de strings que volta igual em toda consulta e em todo evento. É onde mora o id do pedido na sua loja. Nós não lemos, não indexamos e não interpretamos nada dele. Tetos em Limites.itemsé informativo. A soma dos itens não precisa bater comamount, e não validamos isso. Serve para o extrato e para o painel ficarem legíveis.descriptionviaja junto para o processador de pagamentos. Se você não mandar, geramos uma.trackingcarrega parâmetros de origem da venda. Só as sete chaves previstas são aceitas; chave desconhecida é400 validation_failed.
postback_url: webhook só desta cobrança
postback_url aponta o destino do webhook daquela cobrança, sem passar pelo endpoint da conta.
É o caminho rápido para testar e para quem precisa separar destinos por fluxo.
Regras: precisa ser https e precisa apontar para um destino público. Endereço interno, IP privado
ou localhost são recusados com 400 invalid_url, e não é configurável: é o que impede a API de
ser usada para varrer a rede de quem a hospeda.
Em produção, prefira o endpoint da conta, cadastrado no painel: ele tem segredo próprio, recebe todos os eventos e aparece no histórico de entregas.
Quando a criação falha
400de validação: nada foi criado. Corrija e repita com a mesmaIdempotency-Key.403 seller_not_allowed: a conta não pode cobrar neste ambiente agora. Ver Autenticação.409 idempotency_conflictou409 idempotency_in_progress: ver Idempotência.503 acquirer_timeout,acquirer_rejectedouacquirer_unavailable: o processador falhou. A cobrança pode ter ficado registrada comofailed, sem QR. Repita com uma chave de idempotência nova, porque a mesma chave devolveria esse mesmo503de novo.
Cobrança failed responde com pix.payload e pix.qr_base64 nulos. Nunca mostre a tela de
pagamento antes de conferir que eles vieram preenchidos.
Próximo passo
QR Code: o que fazer com o pix.payload e com o pix.qr_base64 que acabaram
de chegar.
Referência: Cria uma cobrança PIX.