Wallets e apps · trocar o ramp

PIX e stablecoin para wallets e apps

Seu app já está publicado e o depósito em reais é o gargalo. Aqui cada usuário tem limite próprio, cada operação tem estado, e a tela consegue mostrar em que etapa está — sem você guardar nada.

Criar chave sandbox Falar com integração Documentação completa

Para quem é

O problema

Num app de carteira, o depósito é onde o usuário desiste. Ele digita um valor, o provedor recusa sem dizer quanto caberia, e a tela mostra "erro". Depois de pagar, ele fica olhando um spinner sem saber se são cinco segundos ou cinco minutos. Esses dois momentos custam mais usuário que qualquer taxa.

Os dois têm resposta de API. O limite de cada pagador é consultável antes do teclado aparecer, e o status traz a linha do tempo carimbada pelo servidor, com a mediana medida de cada etapa — dá para escrever "etapa 3 de 5, costuma levar 39 s" sem inventar número.

O fluxo, ponta a ponta

  1. O usuário informa o CPF uma vez. Você consulta GET /cashin/limits?payer_tax= e já mostra quanto ele pode depositar na hora e quanto cabe com retenção.
  2. Ele escolhe o valor. POST /cashin/charge com customer_ref (o id dele no seu sistema) devolve o copia e cola.
  3. Ele paga. O webhook cashin.paid chega; a tela troca de etapa sem polling.
  4. A entrega acontece e cashin.settled traz o hash. Se o destino for saldo, o crédito aparece com liberar_em.
  5. Para sacar: POST /payouts (PIX) ou POST /saldo/sacar-cripto (qualquer moeda do catálogo), sempre com o mesmo customer_ref.

Endpoints usados

EndpointPara quê
GET /cashin/limits?payer_tax=Quanto este usuário pode pagar agora — antes de a tela pedir o valor.
POST /cashin/chargeDepósito, com customer_ref ligando a operação ao usuário.
GET /cashin/{cashin_id}/statusLinha do tempo e tempos típicos por etapa: é o que alimenta o rastreador.
GET /saldo?customer_ref=Saldo, carência e próximas liberações daquele usuário.
POST /saldo/sacar-criptoSaque em qualquer moeda do catálogo, debitando do saldo do usuário.
POST /payoutsSaque por PIX para a chave do próprio usuário ou de um terceiro.

Exemplo que roda

# depósito do usuário: PIX identificado pelo CPF dele, cripto na carteira dele
curl -X POST https://api.luniumpay.com/cashin/charge -H "X-API-Key: $LUNIUM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount_cents":15000,"asset":"usdt","chain":"polygon",
       "payout_address":"0xCarteiraDoUsuario",
       "payer_tax_number":"12345678909",
       "customer_ref":"user_8842","external_id":"dep-8842-17"}'

# limite daquele usuário ANTES de mostrar o teclado de valor
curl "https://api.luniumpay.com/cashin/limits?payer_tax=12345678909" -H "X-API-Key: $LUNIUM_KEY"
async function limiteDoUsuario(cpf) {
  const r = await fetch(`${API}/cashin/limits?payer_tax=${cpf}`, {
    headers: { "X-API-Key": process.env.LUNIUM_KEY },
  });
  const l = await r.json();
  return { naHora: l.instant_available_cents, comRetencao: l.held_qr?.available_cents ?? 0 };
}

async function depositar({ cents, cpf, carteira, userId, idempotencia }) {
  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: cents, asset: "usdt", chain: "polygon",
      payout_address: carteira, payer_tax_number: cpf,
      customer_ref: userId, external_id: idempotencia,
    }),
  });
  if (r.status === 403) throw new Error("acima do limite deste pagador");
  return r.json();
}
import os, requests

API, H = "https://api.luniumpay.com", {"X-API-Key": os.environ["LUNIUM_KEY"]}

def limite_do_usuario(cpf):
    l = requests.get(f"{API}/cashin/limits", headers=H, params={"payer_tax": cpf}, timeout=20).json()
    return l["instant_available_cents"], (l.get("held_qr") or {}).get("available_cents", 0)

def depositar(cents, cpf, carteira, user_id, idempotencia):
    r = requests.post(f"{API}/cashin/charge", headers=H, timeout=30, json={
        "amount_cents": cents, "asset": "usdt", "chain": "polygon",
        "payout_address": carteira, "payer_tax_number": cpf,
        "customer_ref": user_id, "external_id": idempotencia})
    if r.status_code == 403:
        raise RuntimeError("acima do limite deste pagador")
    return r.json()

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çãoR$ 1,00 a R$ 6.000,00
Venda (cash-out), por operaçãoa partir de R$ 6,00
Validade do QR15 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 escadao 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:

TrechoMedianap90Amostra
PIX recebido → stablecoin entregue (Polygon)6 s70 s112 operações
Aceite da cotação → PIX pago (Polygon)81 s580 s27 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

Acima do limite do pagador: 403 limite_do_pagador com acao: "corrigir" e quanto cabe. Mostre o número, não a palavra "erro" — foi o que mais converteu nos apps que já usam.

Abaixo do mínimo da rota: a resposta traz o mínimo estimado em reais e nada é debitado. Ofereça o valor certo em um toque.

Primeiro depósito de uma subconta: saques ficam travados por 24 h (423 carencia_primeiro_deposito com libera_em). Diga a hora, não "tente mais tarde".

Segurança

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

O caminho crítico do app são duas chamadas: limite e cobrança. As duas existem no sandbox, com o mesmo contrato — dá para montar a tela inteira antes de existir contrato comercial.

Perguntas que os integradores fazem

Preciso guardar o estado das operações?

Não. GET /cashin/{id}/status traz a linha do tempo carimbada pelo servidor e os tempos típicos por etapa; o webhook avisa cada transição. O seu banco guarda o external_id e o resto vem daqui.

Como separo os usuários?

Pelo customer_ref. Ele viaja na cobrança, no saldo, no saque e no extrato — o livro-razão mantém cada cliente separado sem você criar chave por usuário.

Consigo saque em outras moedas além de USDT?

Sim. POST /saldo/sacar-cripto entrega qualquer moeda do catálogo pelo mesmo trilho da compra, com o mínimo da rota checado antes do débito.

O usuário pode depositar mais que o limite inicial?

Pode: acima da escada instantânea o QR ainda é aceito e o provedor retém 24 h. Se o seu produto não pode esperar, mande allow_hold: false e receba um 403 dizendo quanto sai na hora.

Criar chave sandbox Falar com integração

Contrato OpenAPI 1.25.0 · fatos desta página em product-truth.json · status