Lunium is the settlement layer between PIX and crypto in Brazil. A single key does all three things: cash-in (the customer pays a PIX and receives crypto in their wallet), cash-out (the customer delivers crypto and a PIX key receives reais) and balance/payouts (BRL custody for the end customer, withdrawable by PIX or as crypto). Every paid operation returns a receipt and the Central Bank's official identifier (E2E), which anyone can verify without a key. Everything in this manual is in production and was measured on the date above.
delayed)erro + acaoHigh-resolution version: https://docs.luniumpay.com/manual-fluxograma.png (labels in Portuguese).
curl -s -X POST https://api.luniumpay.com/keys/sandbox \
-H 'Content-Type: application/json' -d '{"name":"my-project"}'
→ {"api_key":"lun_test_…","sandbox":true,"como_usar":{…}}
The lun_test_… key runs on the same base URL, with the same shapes, states and error contract as production. Nothing moves. What the sandbox covers today:
| Surface | Sandbox | Notes |
|---|---|---|
Cash-out (POST /cash-outs → accept → status) | complete | the order walks the real states in ~15 s; deterministic triggers (section 5.3); the test E2E is verifiable at GET /v1/verificar/{e2e}. |
Cash-in (POST /cashin/charge) | no QR | answers 400 sandbox_sem_cashin: a test QR would be payable for real. Test cash-in with the production key and small amounts (R$ 1 to R$ 5); GET /cashin/limits, POST /cashin/preview, GET /cashin/catalog and GET /keys/me work in the sandbox. |
| Webhooks | yes | POST /webhooks/test fires a real webhook.test at your endpoint and returns status and latency. |
| MCP (AI agents) | yes | a sandbox key works at https://api.luniumpay.com/mcp with nothing special. |
curl -s -X POST https://api.luniumpay.com/keys \
-H 'Content-Type: application/json' -d '{"name":"My Company"}'
→ {"api_key":"lun_…", "dashboard_url":"…", "grupos_obrigatorios":{…}, "limits":{…}}
The key is born immediately with cash-in and cash-out enabled, in the Início tier (R$ 5,000/day on cash-in + payouts; it rises to R$ 25,000 at R$ 50k settled and to R$ 100,000 at R$ 500k). The response carries the raw key once only (only the hash is stored); keep it in a vault. Limit of 5 production keys per IP per day.
lun_… key in the Telegram group. If you need to recover it, create another (it is free) and swap it in your code; we can deactivate the old one.https://t.me/LuniumNotifyBot → /chave shows the lk… code./vincular lk…. Without it the group receives no notification at all./configurar (checklist), /carteira 0x…, /status, /extrato, /limites.curl -s -X PATCH https://api.luniumpay.com/keys/me -H "X-API-Key: $KEY" \
-H 'Content-Type: application/json' -d '{
"settlement_address": "0xYOUR_POLYGON_WALLET",
"webhook_url": "https://api.yourdomain.com/lunium/webhook"
}'
→ returns webhook_secret (whk_…) ONCE; rotate_webhook_secret:true generates another
settlement_address: default wallet that receives the cash-in crypto when the charge carries no payout_address.webhook_url + webhook_secret: HMAC signature of the events (section 7).GET /keys/me returns every limit currently in force for your key (tier, per operation, payer ladder, recipient ceiling). It is the number that never goes stale: read it instead of hard-coding the tables in this manual.| What | Where |
|---|---|
| Runnable quickstart (zero to an order with an E2E, in the sandbox) | https://api.luniumpay.com/quickstart |
| Documentation for humans (curl, Node, Python, networks × timing, webhooks) | https://docs.luniumpay.com/en/ · walkthrough: /en/comecar |
| OpenAPI 3.1 contract (importable into Postman/Insomnia) | https://api.luniumpay.com/openapi.json |
| Summary for AI agents / LLMs | https://api.luniumpay.com/llms.txt (EN) · /llms.pt.txt (PT) |
| Live status (real calls every 5 min) | https://docs.luniumpay.com/status · machine: /status.json |
| MCP server (Streamable HTTP, 10 tools) | https://api.luniumpay.com/mcp |
| Examples that run (Node/Python) and skills for coding agents | github.com/guilhermezanqueta-collab/lunium-examples · …/lunium-agent-skills |
| App to try the whole flow without writing code | https://app.luniumpay.com |
| Partner channel (incidents and contract changes before they go live) | https://t.me/+FerOZMRRP_g5MDk5 |
Flow: check the payer's limit → create the charge (QR + copy-and-paste) → the customer pays → the provider confirms → Lunium sends the crypto to payout_address → webhook cashin.settled with the transaction hash. The payer's CPF/CNPJ is required (a Central Bank requirement — the provider does not issue a QR without it) and it is what feeds the limit ladder.
There is an anti-fraud step per payer (CPF/CNPJ), independent of the key. It has two levels and applies from the document's very first operation — no history and no 24h wait needed:
| Amount in the day for that CPF/CNPJ | What happens | How it shows in the API |
|---|---|---|
| up to R$ 200.00 | Instant. PIX paid → crypto sent in seconds. | QR issued with held:false; status pending → paid; settlement_status: sent. |
| from R$ 200.00 to R$ 6,000.00 | Accepted with a 24h hold at the provider. The PIX is paid normally; the amount is held and released on its own at the end of the window. Not a failure and not a refusal. | QR issued with held:true, held_hours:24 (before payment). Once paid it becomes delayed with delay_until; on release it becomes paid and the crypto goes out. Webhooks cashin.delayed → cashin.paid → cashin.settled. |
| above R$ 6,000.00/day | Refused at creation. | 403 limite_do_pagador, acao: corrigir, with payer_limits saying how much fits. |
Per charge: minimum R$ 1.00 (with the default fee the effective minimum is R$ 1.02), maximum R$ 6,000.00. The ladder counts what was already paid and what is in flight (pending charges still valid); the clock only starts at the first confirmed payment — creating a QR does not mature the document.
GET /cashin/limits?payer_tax=CPF. Read instant_available_cents (what settles instantly) and max_amount_cents (the largest amount the POST accepts right now, hold included). Above the instant amount and up to the maximum, the charge is issued with a hold.POST /cashin/charge response carries held and held_hours. If held:true, say "the amount is held for 24h and releases on its own".delayed as a failure and do not cancel: the PIX was paid. Keep delay_until and show "paid, releases at …". The order becomes paid by itself.cashin.delayed (paid, held), then cashin.paid and cashin.settled (crypto sent, settlement_tx_hash). If you poll, call GET /cashin/{id}/status every 30–60 s while delayed.GET /cashin/limits?payer_tax=52998224725 (real response, payer with no history)
{
"stage": "first_transaction",
"instant_available_cents": 20000, ← settles instantly
"max_amount_cents": 600000, ← largest amount accepted now (with hold)
"held_qr": { "max_amount_cents": 600000, "used_cents": 0, "available_cents": 600000, "hold_hours": 24 },
"ladder": { "first_transaction_cents": 20000, "first_24h_cents": 20000,
"mature_day_cents": 600000, "held_max_cents": 600000, "hold_hours": 24 },
"next_stage": { "stage": "first_24h", "limit_cents": 20000, "quando": "após o primeiro pagamento confirmado" },
"explicacao": "Primeira operação deste CPF/CNPJ: até R$ 200.00 entra na hora; acima disso, até R$ 6000.00 o QR sai com retenção de 24h do provedor…"
}
403 pagador_recusado_pelo_provedor, acao: parar, with provider_reference: the PIX provider refused that CPF/CNPJ by its own compliance decision. Only another document, or a review with the provider quoting the reference, resolves it.403 limite_do_pagador with stage: provider_first_qr: the provider caps the first QR of a document it has not identified yet at R$ 200; from the next QR on, the document can use the whole ladder.502 provedor_indisponivel, acao: repetir: this one is instability; try again shortly.POST /cashin/charge (X-API-Key: lun_…)
{
"amount_cents": 15000, // R$ 150.00 — ALWAYS in cents, integer
"payer_tax_number": "12345678901", // CPF (11) or CNPJ (14), digits only — required
"payer_name": "Payer name", // optional
"asset": "usdt", "chain": "polygon", // pair from GET /cashin/catalog; omitted = usdt/polygon
"payout_address": "0x51e3d4…bc75e0", // YOUR customer's wallet; omitted = the key's settlement_address
"external_id": "dep-0001" // idempotent: repeating returns the same charge (200)
}
→ 200
{
"cashin_id": "ci_3ca9f23b…", "status": "pending",
"amount_cents": 15000, "asset": "usdt", "chain": "polygon", "payout_address": "0x51e3…",
"qr_copypaste": "00020126…", "qr_image_url": "https://…png",
"expires_at": "2026-09-02T23:25:00.000Z", // the QR is valid for 15 minutes
"held": false, "held_hours": 0, // true/24 when the amount requires a hold
"delay_until": null, "liberar_em": null, "hold_hours": 0,
"external_id": "dep-0001", "created_at": "…"
}
GET /cashin/{cashin_id}/status
{
"cashin_id": "ci_…", "status": "paid", // pending | delayed | under_review | paid | expired | refunded | failed
"settlement_status": "sent", // pending | sending | sent | incerto | failed
"amount_cents": 15000, "depix_received_cents": 14625, // net after fee
"usdt_amount": "28.620000", "settlement_tx_hash": "0x…", "settlement_tx_url": "https://polygonscan.com/tx/0x…",
"e2e": "E18236120202609021420…", "payer_name": "PAYER NAME", "payer_tax_number": "123.***.***-01",
"held": false, "held_hours": 0, "delay_until": null, "liberar_em": null,
"destino": "cripto", "customer_ref": null,
"paid_at": "…", "settled_at": "…", "expires_at": "…", "created_at": "…"
}
| State | Meaning | Webhook |
|---|---|---|
| pending | QR issued, nobody has paid. | — |
| delayed | PIX paid, the provider is holding the release (24h hold). delay_until says when it releases. Not a failure. | cashin.delayed |
| under_review | PIX received, settlement in transit. | — |
| paid | Credited. The crypto goes out next (settlement_status pending → sending → sent). | cashin.paid → cashin.settled (with settlement_tx_hash) · cashin.settlement_failed if the send fails (retried) |
| expired | Nobody paid before expires_at. | cashin.expired |
| refunded | Returned to the payer (e.g. a dispute executed by the provider). | cashin.refunded |
| failed | The provider cancelled or errored before payment. | cashin.failed |
GET /cashin/catalog is the source of truth and changes on its own. Real shape: {updatedAt, instant[], convert[], dropped[], totals}.
| Rail | Assets | Measured time (PIX paid → crypto in the wallet, 30 days) |
|---|---|---|
| instant (our own settlement) | USDT and USDC on Polygon | USDT: median 2 s (p90 2 s) · USDC: median 7 s (p90 8 s) |
| convert (via exchange) | 1,300+ assets and networks (BTC, ETH, SOL, TON, BNB…), each with eta, minimum and withdrawal fee | minutes; depends on the network — e.g. BTC on-chain ~37 min. Read etaSeconds on each item. |
| liquid | chain: "liquid" → the payment is delivered as DePix (BRL stablecoin on Liquid) straight to the Liquid wallet given, with no key fee deducted | seconds after the provider confirms |
Default key fee: admin_fee_bps: 250 (2.5%) + admin_fee_fixed_cents: 100 (R$ 1.00) per charge, deducted from the amount paid before conversion. POST /cashin/preview shows the maths without creating anything:
POST /cashin/preview {"amount_cents":10000,"asset":"usdt","chain":"polygon"}
→ {"amount_cents":10000,"admin_fee_bps":250,"admin_fee_fixed_cents":100,"fee_total_cents":348,"net_cents":9652,"brl_per_usdt":"5.11","usdt_amount":"18.874787"}
Different commercial terms (fee, per-payer ceilings, holding period) are configured per key by Lunium and show up in GET /keys/me.
For wallet apps that need a "deposit and withdraw" tab in reais. The key needs custody enabled by Lunium (custodia_ativa: true in GET /saldo) — ask in the group. No crypto leaves: the paid PIX becomes a BRL balance in your customer's sub-account (customer_ref).
| Step | Call | Rule |
|---|---|---|
| Deposit | POST /cashin/charge with "destino":"saldo" and "customer_ref":"your-customer-id" | Deposit fee 0%. Same payer ladder (200 / 6,000 per day per CPF). |
| Hold above R$ 60 | automatic | Up to R$ 60.00: credited immediately, available on D+1 (disponivel_em). Above R$ 60.00 per deposit: the QR is issued held for 24h at the provider (held:true); once paid, the balance shows as frozen (delayed) and, when the provider releases it, it becomes available immediately — the hold counts as the holding period. It is the window for a dispute (MED) before the money leaves. |
| Query | GET /saldo?customer_ref=… · GET /saldo/extrato | disponivel_cents, bloqueado_cents, proximas_liberacoes, carencia_ate, fees (deposito_fee_bps, saque_fee_bps, retencao_acima_cents). Append-only ledger: balance = sum. |
| Withdraw by PIX | POST /payouts with the same customer_ref, amount_cents, pix_key, tax_number | Debits amount + 1.8% (house fee) + provider fee (~R$ 1.00) before the PIX leaves; 402 saldo_insuficiente if short. The PIX key must belong to the tax_number (bank rule). The PIX lands within 24h, usually seconds. |
| Withdraw as crypto | POST /saldo/sacar-cripto {amount_cents, chain, asset, payout_address, tax_number, customer_ref} | Reais leave the balance, crypto goes to the customer's wallet through the same rail as cash-in; the response is a charge already paid — follow settlement_status. |
| 1st deposit | — | The first deposit of a sub-account blocks any withdrawal for 24h: 423 carencia_primeiro_deposito with libera_em. |
Nothing is advanced and no fee is absorbed: what the provider charges is what the balance pays. Charges carry fonte (pix | saldo) and destino (cripto | saldo) so a withdrawal is never confused with a purchase.
Three steps, in this order. The quote is already net: brl_amount is exactly what lands on the PIX key.
1) POST /cash-outs (quote — commits nothing)
{
"asset": "usdt", "network": "polygon",
"brl_amount": "250.00", // OR "amount": "50.77" (crypto) — exactly one of the two
"pix_key": "customer@example.com", // CPF · CNPJ · +55AREANUMBER · e-mail · UUID; 11 bare digits require pix_key_type
"refund_address": "0x51e3d4…bc75e0", // the customer's RETURN wallet, same network — always send it
"external_id": "sale-001"
}
→ 201 (real sandbox response)
{ "cashout_id": "sbx_141ce3e9…", "state": "QUOTE_CREATED", "amount": "50.774309", "brl_amount": "250.00",
"pix_key_type": "email", "deposit_address": null, "expires_at": "2026-09-03T02:33:31Z", … }
2) POST /cash-outs/{cashout_id}/accept (locks the quote — point of no return)
→ { "state": "AWAITING_DEPOSIT", "deposit_address": "0x2952552e…", "deposit_tag": null, … }
The customer sends EXACTLY "amount" to deposit_address, on the quoted network.
3) GET /cash-outs/{cashout_id} (follow it; or wait for the webhook)
→ { "state": "COMPLETED", "pix_e2e": "E0000000020260903…", "pix_paid_at": "…",
"receipt_url": "https://app.luniumpay.com/comprovante/…", "receipt_pdf_url": "….pdf",
"verify_url": "https://api.luniumpay.com/v1/verificar/E…", "refund_tx_hash": null, "deposit_from": "0x…" }
GET /pix/keys/lookup?key=… returns the holder's name, masked document and institution (DICT). 5 lookups/min per account; unknown key → 404 chave_nao_encontrada.expires_at: 15 min on Polygon, up to 300 min on other networks. Read the field; do not hard-code a window.503 liquidante_indisponivel (acao: esperar, retry_after_seconds: 120): the PIX settlement provider is down at that instant; wait and re-accept the same order. No address is issued in the meantime, on purpose — crypto never enters a stalled pipeline.br_code) instead of a key: disabled in production today (503 br_code_indisponivel). The sale pays PIX keys.| Limit | Value | In the API |
|---|---|---|
| Per transaction | R$ 6.00 to R$ 250,000.00 | a refusal returns limits.min_amount / max_amount already converted into the order's crypto |
| Per recipient per day | R$ 100,000.00 per CPF/CNPJ (or per key, when the key is not a document). Resets at midnight, Brasília time. | limits.max_brl_cents = the effective ceiling (the lower of the two); limits.max_brl_cents_por_transacao = nominal. Exceeded: limite_diario_recebedor, acao: esperar. |
| Per key per day | does not exist on cash-out | the tier (R$ 5k/25k/100k) applies only to cash-in and payouts — daily_limit_applies_to in GET /keys/me |
| Minimums per asset | e.g. USDT 10, USDC 20 on the convert rail | GET /catalog → min/max per item |
| Network | Time from confirmed deposit to PIX paid |
|---|---|
Polygon (USDT/USDC) — fast | our own settlement: seconds; measured 49–65 s from accept to PIX paid (the deposit itself takes ~10–20 s to confirm) |
Other networks — convert (1,300+ assets via exchange) | the network's confirmation count: TON/Aptos ~1 min · Avalanche/NEAR ~2 min · BSC ~3 min · Base ~5 min · Ethereum ~20 min · Arbitrum ~21 min · Optimism ~1 h · Celo ~3 h. Never promise "instant" outside Polygon. |
| Solana | temporarily out of cash-out — the quote refuses (rede_indisponivel) |
QUOTE_CREATED → accept → AWAITING_DEPOSIT → DEPOSIT_DETECTED → PROCESSING → COMPLETED · detours: MANUAL_REVIEW → REFUNDING → REFUNDED · EXPIRED · FAILED. Webhooks: cashout.awaiting_deposit, deposit_detected, processing, under_review, refunding, completed, refunded, expired, failed.
| Situation | What happens |
|---|---|
| The provider refuses the key after the deposit (invalid/non-existent) | MANUAL_REVIEW → the crypto is automatically returned to refund_address → REFUNDED with refund_tx_hash. The net amount the provider returned is refunded. |
| The send fails before leaving (settlement provider down, key rejected on submission) | retried every 5 min for up to 45 min; if it still does not settle, the full amount (fee included) returns to refund_address. While retrying the state is PROCESSING, not a failure. |
| PIX reversed after being paid (rare) | same path: REFUNDED + hash. |
| Deposit different from the quote | the amount actually received is paid; a different token goes to MANUAL_REVIEW. |
Deposit after expires_at | the order is revived when the deposit shows up (up to 7 days); after that, MANUAL_REVIEW. |
No refund_address | the refund goes to the on-chain origin of the deposit — wrong when it came from an exchange (that is the exchange's hot wallet). Hence: always send it. |
| Refund amount | automatic up to 5,000 USDT per order; above that a person from operations executes it and you receive the same REFUNDED + hash. Always on the deposit's network and token; the gas is ours. |
Receipt — three forms of the same fact, in the same response and the same webhook (never build URLs by hand): pix_e2e (Central Bank identifier), receipt_url (page), receipt_pdf_url (PDF with the recipient's name, document and institution, amount, date, E2E), verify_url. And anyone, with no key, can confirm the payment:
GET https://api.luniumpay.com/v1/verificar/{e2e}
→ { "verificado": true, "pago": true, "valor_brl": "250.00", "pago_em": "2026-09-03T02:18:47Z",
"recebedor_iniciais": "T. S. T.", "instituicao": "…", "liquidado_por": "Lunium", "comprovante_url": "…" }
(does not expose the PIX key, full name or document)
The first two decimals of amount (in crypto) choose the outcome — you can assert on it in CI:
amount ends in | What happens | What it proves |
|---|---|---|
.01 | goes to delayed and completes on its own | your code does not call a hold a failure |
.02 | fails | your error path runs |
.03 | the quote expires in 5 s | you re-quote instead of insisting |
.04 | refused on limits with limits filled | you read limits.min_amount/max_amount |
.05 | completes in ~2 min | your polling is patient |
.06 | compliance refusal at settlement → FAILED with failure_reason: pagador_recusado_pelo_provedor | you show the reason and do not retry |
.07 | 1st accept → 503 provedor_indisponivel; the 2nd accept of the same order works | your retry re-accepts instead of re-quoting |
.08 | refused at creation by limite_do_pagador | you read payer_limits |
Reusing an external_id with a different destination returns 409, same as production. Sandbox orders vanish after 2 h. Never send crypto to a sandbox deposit_address: it has no owner.
POST /payouts sends a PIX to a key. It requires payout_enabled on the key (born disabled; ask in the group). With custody, the amount leaves the sub-account's balance (customer_ref); without custody, it leaves Lunium's treasury as agreed commercially. Limits per operation: R$ 1.00 to R$ 6,000.00; counts towards the tier's daily quota.
POST /payouts { "amount_cents": 5000, "pix_key": "+5548999990000", "tax_number": "12345678901",
"external_id": "withdrawal-001", "customer_ref": "customer-42" }
→ { "payout_id": "po_…", "status": "processing", // processing | sent | failed | refunded
"amount_cents": 5000, "fee_cents": 100, "pix_key": "+5548*****0000", "sent_at": null, … }
Webhooks: payout.sent · payout.failed · payout.refunded
One envelope for every event. data is exactly the object the status GET returns for that resource.
POST {webhook_url}
X-Lunium-Event-Id: evt_9f2c… // id of the EVENT — stable across retries: deduplicate by it
X-Lunium-Delivery-Id: dlv_… // id of the ATTEMPT — quote it to support
X-Lunium-Signature: t=1756850000,v1=<hex HMAC-SHA256(secret, "t.body")>
{ "event": "cashin.settled", "event_id": "evt_9f2c…", "created_at": "2026-09-02T23:10:11.000Z",
"data": { "cashin_id": "ci_…", "status": "paid", "settlement_status": "sent", "settlement_tx_hash": "0x…", … } }
X-Webhook-Signature header (body only) stops being sent on 2026-11-09; keys created after 2026-08-08 no longer receive it.failed in GET /webhooks/deliveries and is recoverable with POST /webhooks/deliveries/{event_id}/retry. Nothing is lost silently: the bot also warns in the group.POST /webhooks/test fires webhook.test over the same transport and returns what YOUR endpoint answered. Run it before the first real charge.429 is protection, not failure).| Cash-in | Cash-out | Payout / other |
|---|---|---|
cashin.held (QR issued with a hold) · cashin.delayed · cashin.paid · cashin.settled · cashin.settlement_failed · cashin.expired · cashin.refunded · cashin.failed |
cashout.awaiting_deposit · cashout.deposit_detected · cashout.processing · cashout.under_review · cashout.refunding · cashout.completed · cashout.refunded · cashout.expired · cashout.failed |
payout.sent · payout.failed · payout.refunded · webhook.test |
// Node — verifying the v2 signature
const [t, v1] = req.get('X-Lunium-Signature').split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)) && Math.abs(Date.now()/1000 - t) < 300;
Every error carries erro (a stable code), acao, detail, request_id and agent_guidance. Branch on acao, not on the message:
acao | Meaning | Examples of erro |
|---|---|---|
| corrigir | the request is wrong; repeating it unchanged never passes | campos_obrigatorios · amount_invalido (decimal as a string) · pix_key_invalida · tipo_ambiguo (11 digits: send pix_key_type) · valor_abaixo_do_minimo / valor_acima_do_maximo (read limits) · limite_do_pagador · rede_indisponivel · nao_encontrado · campos_conflitantes |
| repetir | transient failure on our side | provedor_indisponivel |
| esperar | a quota renews or a service comes back | limite_diario (tier, cash-in/payouts only) · limite_diario_recebedor (sale, R$ 100k/day) · liquidante_indisponivel (retry_after_seconds) · br_code_indisponivel · cashout_indisponivel |
| parar | do not insist; show it to the user / talk to us | chave_ausente · chave_incorreta (key cut when copying) · chave_desconhecida · pagador_recusado_pelo_provedor · sandbox_sem_cashin |
Every timestamp is ISO 8601 with an explicit offset/timezone (2026-08-01T22:35:49-03:00 or …Z). Never assume local time or UTC.
| Product | Per operation | Per person | Per key | Default fee | Measured time |
|---|---|---|---|---|---|
| Cash-in (PIX → crypto) | R$ 1.00 to R$ 6,000.00 | payer (CPF/CNPJ): up to R$ 200/day instant · R$ 200 to R$ 6,000/day with a 24h hold · from the first operation | tier: R$ 5,000 → 25,000 → 100,000 per day (cash-in + payouts) | 2.5% + R$ 1.00 | USDT 2 s · USDC 7 s after the PIX lands (Polygon) |
| Balance deposit | same as cash-in | same; above R$ 60 per deposit it is held 24h (frozen) and then released as available; up to R$ 60 available on D+1 | same | 0% on deposit · withdrawal 1.8% + ~R$ 1.00 | PIX withdrawal: seconds, up to 24h |
| Cash-out (crypto → PIX) | R$ 6.00 to R$ 250,000.00 | recipient: R$ 100,000/day (CPF/CNPJ or key) | no daily cap | already inside the quote (brl_amount is net) | Polygon: 49–65 s from accept to PIX paid; other networks: the network's time |
| Payout (direct PIX) | R$ 1.00 to R$ 6,000.00 | — | tier | provider ~R$ 1.00 (+1.8% when it leaves the balance) | seconds, up to 24h |
| Requests | 60 per minute per key (configurable) · a cash-in QR is valid for 15 min · a cash-out quote is valid for 15 min on Polygon | ||||
Every number here can change; GET /keys/me returns the ones that apply to your key. Specific commercial terms (fee, per-payer ceilings, holding period) are agreed with Lunium and reflected on the key.
POST /keys) and stored in a vault; never in chat./vincular done by an admin; /configurar shows everything ✅.settlement_address (Polygon) and webhook_url configured via PATCH /keys/me; POST /webhooks/test answered 2xx.X-Lunium-Signature v2, deduplicates by event_id, ignores unknown events, answers in < 15 s.GET /cashin/limits before charging, shows held/held_hours, treats delayed as "paid, releases at …" and credits only on cashin.settled (or paid with settlement_status: sent). Tested with a real PIX of R$ 1 to R$ 5./pix/keys/lookup) and the amount → accept → show the exact deposit_address and amount; always sends refund_address and external_id; polls every 10–15 s or uses the webhook; handles 503 liquidante_indisponivel by re-accepting the same order. Triggers .01–.08 passed in the sandbox.acao; limits read from the response instead of hard-coded; expires_at read instead of a fixed window.https://t.me/+FerOZMRRP_g5MDk5) and follows docs.luniumpay.com/status.| API | https://api.luniumpay.com · OpenAPI /openapi.json · /quickstart · /llms.txt · MCP /mcp · health /ping |
| Docs | https://docs.luniumpay.com/en/ · /en/comecar · /status |
| Code | github.com/guilhermezanqueta-collab/lunium-examples · github.com/guilhermezanqueta-collab/lunium-agent-skills |
| Operations | your project's group (Lunium <> YourProject) with @LuniumNotifyBot · human: @luniumB2B · partner channel t.me/+FerOZMRRP_g5MDk5 · e-mail contato@luniumpay.com |
GET /keys/me, live catalogs and measurements from the last 30 days). Limits and verification proportional to volume, as per Lunium's policy.