Referência da API de cobrança · v1
Uma API REST para criar cobranças PIX e acompanhar pagamentos. Autenticação por chave; respostas em JSON.
https://easypay.linkjohn.com/api/v1
Authorization: Bearer pk_live_xxxxx
Cada sistema integrado usa uma chave própria, revogável a qualquer momento. Uma chave só enxerga as cobranças criadas por ela.
POST/charges
curl -X POST https://easypay.linkjohn.com/api/v1/charges \
-H "Authorization: Bearer pk_live_xxxxx" \
-H "Idempotency-Key: pedido-8421" \
-H "Content-Type: application/json" \
-d '{
"external_id": "PEDIDO-8421",
"customer": { "name": "Maria Souza", "document": "12345678909" },
"amount_cents": 5990,
"description": "Plano VPS",
"method": "pix",
"expires_in": 3600
}'
| campo | tipo | |
|---|---|---|
external_id | string | O id da cobrança no seu sistema. Único por integração. |
customer.name | string | Nome do pagador. |
customer.document | string | CPF (11) ou CNPJ (14 dígitos). |
customer.email | string | Opcional. |
amount_cents | inteiro | Valor em centavos. 5990 = R$ 59,90. |
description | string | Opcional. Aparece para o pagador. |
method | string | pix. |
expires_in | inteiro | Segundos até o código deixar de ser pagável. Padrão 3600. |
201:
{
"id": 185,
"external_id": "PEDIDO-8421",
"status": "pending",
"amount_cents": 5990,
"amount_paid_cents": 0,
"payment_url": "https://easypay.linkjohn.com/p/m2znt-N-aTWg",
"pix": {
"copy_paste": "00020101021226830014BR.GOV.BCB.PIX...",
"qr_code": null,
"txid": "2b4351fd1a55b2e5e055e3d65440e98f"
},
"expires_at": "2026-08-05T20:27:04Z"
}
Você tem dois caminhos:
payment_url ao pagador
e acabou. É uma página pronta — veja abaixo.pix.copy_paste. O
campo qr_code costuma vir null; gere a imagem
localmente a partir do copy_paste, é a mesma string.Sem o header, a requisição é recusada com 400.
Use um valor estável e único por cobrança — o id do pedido no seu banco serve bem. Não use timestamp nem um UUID novo a cada tentativa: assim ele não protege de nada.
Toda chamada HTTP pode dar timeout sem você saber se chegou. Repetindo sem
chave, o cliente ganha duas cobranças. Com a mesma chave, você recebe de volta
a cobrança que já existia — com 200 em vez de 201, e
nunca uma segunda.
A mesma chave com um corpo diferente devolve 422: é sinal de
que a chave foi reaproveitada para outra cobrança.
"amount_cents": 5990 ✅ R$ 59,90
"amount": 59.90 ❌ 400
Toda cobrança nasce com um payment_url. É um link curto, feito
para caber numa mensagem de WhatsApp:
https://easypay.linkjohn.com/p/m2znt-N-aTWg
A página tem QR Code, botão de copiar o código PIX, valor, descrição e prazo. É responsiva — a maioria dos pagadores abre no celular.
Ela vira "Pagamento confirmado" sozinha. A página verifica o estado a cada poucos segundos e muda assim que o pagamento cai, sem o pagador precisar recarregar nem voltar ao seu site.
Também trata os outros estados: cobrança expirada, cancelada ou estornada mostram a mensagem certa em vez de oferecer um código que não funciona mais.
No topo aparece o nome da sua operação, para o pagador reconhecer de quem é a cobrança. Peça para configurá-lo junto com a sua chave.
Nome e documento do pagador não aparecem. Link é encaminhado; quem receber não pode ver o CPF de outra pessoa. Se você precisa que o pagador confira esses dados, mostre na sua própria tela antes de mandar o link.
O token é a credencial da página — não há senha. Trate o
payment_url como um dado do pedido: mande ao pagador, não publique
em página aberta nem em log compartilhado.
GET/events?since={id}&limit={n}
Não há webhook para o seu sistema. Você lê
a fila. Guarde o último id processado e peça dali para frente.
curl "https://easypay.linkjohn.com/api/v1/events?since=1841&limit=100" \
-H "Authorization: Bearer pk_live_xxxxx"
{
"events": [
{
"id": 1842,
"type": "payment.confirmed",
"external_id": "PEDIDO-8421",
"amount_cents": 5990,
"amount_paid_cents": 5990,
"paid_at": "2026-08-05T13:20:11Z",
"status": "paid"
}
],
"last_id": 1842,
"has_more": false
}
Ficou horas fora do ar? Ao voltar, peça a partir do último id que você processou e receba tudo o que passou no intervalo. A fila não expira, então não existe evento perdido — e você não precisa expor endpoint público nenhum.
a cada 10–30 segundos:
eventos = GET /events?since={ultimo_id_salvo}
para cada evento:
processa # libera o serviço, marca como pago
salva eventos.last_id # SÓ DEPOIS de processar
Salve o ponteiro depois de processar, nunca antes. Se o processo morrer no meio, o pior que acontece é reprocessar um evento na volta seguinte — inofensivo, desde que a sua liberação de serviço seja idempotente. Salvando antes, um crash perde o evento para sempre.
Sem eventos novos, last_id volta igual ao que você enviou. Não
zere seu ponteiro por causa disso.
| tipo | o que fazer |
|---|---|
payment.confirmed | libere o serviço |
payment.partial | pagou menos que o total; a cobrança segue pending. Não libere |
payment.overpaid | pagou mais; a cobrança fechou. Libere; o excesso vem no evento |
charge.expired | o prazo venceu. Ainda pode ser paga depois |
charge.cancelled | cancelada |
charge.created | informativo — você já soube pela resposta do POST |
GET/charges/{id}
DELETE/charges/{id}
curl https://easypay.linkjohn.com/api/v1/charges/185 \
-H "Authorization: Bearer pk_live_xxxxx"
curl -X DELETE https://easypay.linkjohn.com/api/v1/charges/185 \
-H "Authorization: Bearer pk_live_xxxxx"
Trate pelo code, nunca pelo texto — a mensagem pode mudar, o
code não.
{ "error": { "code": "idempotency_key_reused", "message": "..." } }
| HTTP | code | o que fazer |
|---|---|---|
| 400 | bad_request | falta o Idempotency-Key, ou o corpo está errado |
| 400 | validation_error | veja details |
| 401 | unauthorized | chave ausente, inválida ou revogada |
| 403 | forbidden | a chave não tem o escopo necessário |
| 404 | not_found | não existe, ou não pertence à sua chave |
| 409 | external_id_exists | já existe cobrança com esse external_id |
| 409 | idempotency_in_progress | a primeira requisição ainda está rodando; repita em 1–2s |
| 422 | idempotency_key_reused | mesma chave com corpo diferente |
| 502 | gateway_error | o provedor recusou ou está indisponível |
| 504 | gateway_timeout | o provedor não respondeu a tempo |
Em 502, 504 e
idempotency_in_progress, repita com a mesma
Idempotency-Key. É seguro: ou você recebe a cobrança que já existia,
ou ela é criada agora. Nunca duas.
pending ──┬──► paid ──► refunded
├──► expired ──► paid (PIX pago no limite acontece)
└──► cancelled
paid nunca volta para pendingexpired que recebe pagamento vira paidpending com amount_paid_cents menor