E-commerce · muitos pagadores
PIX no checkout, stablecoin na tesouraria
Cada comprador paga um PIX comum, no banco dele. A loja recebe stablecoin numa carteira corporativa. Como o limite é do CPF de quem paga, dez compradores são dez limites independentes.
Para quem é
- Loja ou marketplace B2C que vende no Brasil e quer o caixa em stablecoin.
- Operação com muitos pagadores diferentes e ticket médio baixo ou médio.
- Quem hoje concilia PIX na mão e quer pedido pago virar evento no sistema.
O problema
O medo de todo e-commerce que liquida em cripto é o teto: "e se o volume do dia estourar o limite da conta?". Essa pergunta vem de um modelo errado do produto. O limite que manda aqui é o do documento de quem paga, e é por ticket — a conta que recebe não tem um teto diário próprio que some tudo.
O segundo problema é conciliação. PIX numa chave fixa cai sem dono: você vê o valor e não sabe de qual pedido é.
Aqui cada cobrança nasce amarrada ao CPF do comprador e ao seu external_id, e um PIX pago por outro
documento é devolvido em vez de virar um crédito órfão.
O fluxo, ponta a ponta
- No checkout, você chama
POST /cashin/chargecom o total, o CPF do comprador e o número do pedido emexternal_id. - Mostre o
qr_copypastena tela. Ele vale 15 minutos — gere no momento de pagar, como Mercado Pago e bancos fazem. - O comprador paga. Chega
cashin.paid: é o gatilho para liberar o pedido. - A stablecoin cai na carteira da empresa e chega
cashin.settledcom o hash. - Conciliação:
GET /cashin/charges?external_id=devolve a cobrança daquele pedido, sempre.
Endpoints usados
| Endpoint | Para quê |
|---|---|
POST /cashin/charge | Uma cobrança por pedido, com o CPF do comprador e o seu número de pedido. |
GET /cashin/limits?payer_tax= | Quanto aquele comprador pode pagar agora — útil em ticket alto. |
GET /cashin/charges | Lista com filtro por external_id, status e período: é a conciliação. |
POST /webhooks/test | Testa a sua URL de webhook antes de a primeira venda depender dela. |
GET /cashin/events | Feed de operação da sua chave para uma tela interna, sem guardar estado. |
Exemplo que roda
# um pedido = uma cobrança, identificada pelo CPF de quem compra
curl -X POST https://api.luniumpay.com/cashin/charge -H "X-API-Key: $LUNIUM_KEY" \
-H "Content-Type: application/json" \
-d '{"amount_cents":34990,"asset":"usdt","chain":"polygon",
"payout_address":"0xCarteiraDaEmpresa",
"payer_tax_number":"12345678909",
"payer_name":"Maria S.",
"external_id":"pedido-2026-33871"}'// checkout: gera o QR no momento em que o comprador vai pagar
app.post("/checkout/:pedido/pix", async (req, res) => {
const { total_cents, cpf, nome } = req.body;
const r = await fetch(`${API}/cashin/charge`, {
method: "POST",
headers: { "X-API-Key": process.env.LUNIUM_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
amount_cents: total_cents, asset: "usdt", chain: "polygon",
payout_address: process.env.CARTEIRA_EMPRESA,
payer_tax_number: cpf, payer_name: nome,
external_id: `pedido-${req.params.pedido}`,
}),
});
const c = await r.json();
if (!r.ok) return res.status(r.status).json({ erro: c.erro, detalhe: c.detail });
res.json({ copiaECola: c.qr_copypaste, expiraEm: c.expires_at });
});
// webhook: só marca o pedido como pago depois de conferir a assinatura
app.post("/webhooks/lunium", verificarAssinatura, async (req, res) => {
if (req.body.event === "cashin.paid") await marcarPago(req.body.data.external_id);
res.sendStatus(200);
});import os, requests
from flask import Flask, request, jsonify
API, H = "https://api.luniumpay.com", {"X-API-Key": os.environ["LUNIUM_KEY"]}
app = Flask(__name__)
@app.post("/checkout/<pedido>/pix")
def cobrar(pedido):
dados = request.get_json()
r = requests.post(f"{API}/cashin/charge", headers=H, timeout=30, json={
"amount_cents": dados["total_cents"], "asset": "usdt", "chain": "polygon",
"payout_address": os.environ["CARTEIRA_EMPRESA"],
"payer_tax_number": dados["cpf"], "payer_name": dados.get("nome"),
"external_id": f"pedido-{pedido}"})
c = r.json()
if not r.ok:
return jsonify(erro=c.get("erro"), detalhe=c.get("detail")), r.status_code
return jsonify(copia_e_cola=c["qr_copypaste"], expira_em=c["expires_at"])Sandbox: teste antes de gastar
Uma chamada, sem cadastro, sem cartão. A chave lun_test_ exercita a superfície inteira
sem mover dinheiro nenhum.
curl -X POST https://api.luniumpay.com/keys/sandbox \
-H "Content-Type: application/json" \
-d '{"name":"meu-teste"}'
O que o sandbox não prova: liquidação real. Nenhuma cripto se move e nenhum PIX é pago — ele serve para acertar o contrato, não para medir o trilho.
Ativos e redes
Instantâneo (trilho próprio): USDT na Polygon e USDC na Polygon — liquidação em segundos, sem corretora no caminho.
Via corretora: 1.478 ativos em 241 redes na venda (1.668 pares ativo×rede) e 1.795 rotas na compra. O prazo é o número de confirmações que a rede exige, não uma escolha nossa.
Redes de endereço compartilhado (ALGO, ATOM, EOS, HBAR, KAVA, LUNA, TON, XLM, XRP): o depósito precisa levar o memo. Na venda ele vem
em deposit_tag no aceite; na compra você manda payout_tag junto do endereço.
O catálogo muda sozinho conforme redes entram e saem. Leia de GET /catalog e GET /cashin/catalog em vez de manter lista no código.
Limites e retenções
| O quê | Valor |
|---|---|
| Compra (cash-in) e saque PIX, por operação | R$ 1,00 a R$ 6.000,00 |
| Venda (cash-out), por operação | a partir de R$ 6,00 |
| Validade do QR | 15 minutos |
| Escada por pagador (CPF/CNPJ de quem paga) | R$ 60,00 na estreia → R$ 200,00 nas primeiras 24 h → R$ 6.000,00/dia |
| Acima da escada | o QR ainda é aceito e o provedor retém 24 h (D+1), até R$ 6.000,00/dia por pagador |
A escada é por documento de quem paga, não por conta que recebe: dez pagadores são dez limites
independentes. É isso que faz o produto servir a e-commerce e marketplace. Consulte o disponível de um
pagador antes de cobrar em GET /cashin/limits?payer_tax=, e leia os limites da sua chave em
GET /keys/me — tetos acima do tier são contratados.
Medições, não promessas
Medido em produção, janela de 90 dias, em 07/09/2026:
| Trecho | Mediana | p90 | Amostra |
|---|---|---|---|
| PIX recebido → stablecoin entregue (Polygon) | 6 s | 70 s | 112 operações |
| Aceite da cotação → PIX pago (Polygon) | 81 s | 580 s | 27 operações |
Fora da Polygon o relógio é o da rede: o prazo é o número de confirmações que a corretora
exige, e está em eta no catálogo. Não prometemos “instantâneo” fora do trilho próprio.
Idempotência
Mande external_id em toda operação que move dinheiro. Repetir a mesma chamada devolve a
mesma operação, nunca uma segunda; os mesmos parâmetros com id diferente criam duas, e o mesmo id
com parâmetros diferentes responde 409 external_id_divergente em vez de adivinhar.
Timeout não é recusa. Se a chamada não respondeu, consulte pelo external_id
antes de repetir — a operação pode existir.
Webhooks e reconciliação
Cada transição dispara um evento assinado em HMAC SHA-256 com timestamp (header
X-Lunium-Signature, formato t=…,v1=…) — o timestamp é o que impede replay de uma
entrega capturada. Confira a assinatura antes de confiar no corpo.
Webhook é o sinal principal; polling é opcional. Quando precisar pesquisar, o status traz a
timeline carimbada pelo servidor — desenhe a etapa a partir dela, porque o cronômetro do
seu polling mede a sua rede, não a operação.
Não respondeu 2xx? A entrega é retentada com backoff. Você reenvia à mão em
POST /webhooks/deliveries/{event_id}/retry e testa a sua URL em POST /webhooks/test.
Quando dá errado
Comprador estreante com ticket alto: a escada começa em R$ 60,00. Acima dela o QR ainda é aceito,
com retenção de 24 h — o pedido pode esperar D+1 ou você pede allow_hold: false e recusa na hora,
mostrando quanto cabe.
Pagou outra pessoa: PIX de documento diferente é devolvido automaticamente. É o caso que mais gera prejuízo em quem usa chave fixa, e aqui ele não acontece em silêncio.
QR venceu: a cobrança vira expired. Gere outra com um external_id novo — repetir o
mesmo id devolveria o QR velho, já vencido.
Segurança
- webhook assinado — Todo webhook vai assinado em HMAC SHA-256 com timestamp (header X-Lunium-Signature, formato t=…,v1=…), o que impede replay de uma entrega capturada.
- idempotencia — external_id em cash-in, cash-out e payout: repetir a mesma chamada devolve a MESMA operação, nunca uma segunda. Parâmetros diferentes no mesmo external_id respondem 409.
- egress validado — A URL de webhook é resolvida e validada antes de cada entrega: endereço interno, metadata de nuvem e redirect para rede privada são recusados, e a conexão é fixada no IP validado.
- retencao fail closed — A retenção é verificada na liquidação e repetida na reivindicação SQL: nenhum caminho (worker, consulta de status, fila) consegue liquidar antes da hora.
- payout duravel — O saque grava a operação e debita o saldo na MESMA transação, antes de qualquer chamada ao provedor: não existe débito sem ordem para reconciliar.
- verificacao aberta — GET /v1/verificar/{e2e} confere um PIX liquidado sem chave nenhuma — a contraparte não precisa confiar na nossa palavra.
A verificação aberta é a que mais importa numa negociação: a sua contraparte confere o PIX sozinha, sem chave e sem depender da nossa palavra.
Tempo até a primeira integração
Um endpoint no checkout e um handler de webhook. Os times que fizeram isso levaram uma tarde, porque não há onboarding: a chave de sandbox sai em uma chamada e o contrato é o mesmo da produção.
Perguntas que os integradores fazem
Existe um teto diário que trava a loja?
O limite que rege é o do CPF/CNPJ de quem paga, por ticket: R$ 60,00 na estreia, R$ 200,00 nas primeiras 24 h e R$ 6.000,00/dia depois. A sua chave tem um tier próprio, visível em GET /keys/me, e tetos maiores são contratados — mas dez compradores continuam sendo dez limites separados.
Posso usar uma chave PIX fixa em vez de gerar um QR por pedido?
Não, e é de propósito. Chave fixa recebe de qualquer pessoa sem identificação: você não saberia de qual pedido é o valor, e é exatamente esse cenário que gera devolução e disputa. Uma cobrança por pedido é o que torna a conciliação automática.
O comprador precisa ter cripto ou carteira?
Não. Ele paga um PIX comum no aplicativo do banco dele. A parte cripto é sua.
Como devolvo um pedido cancelado?
A devolução do PIX ao comprador é operada por você, com o dinheiro que já liquidou; a API não estorna um PIX pago por decisão comercial. O que ela devolve sozinha é o PIX que veio do documento errado.
Contrato OpenAPI 1.25.0 · fatos desta página em product-truth.json · status