# Lunium > Settlement infrastructure between crypto and PIX in Brazil. A client sends crypto and a PIX key receives Brazilian reais; or pays a PIX charge and receives crypto in a wallet. More than 1,400 assets across dozens of networks. Every operation returns a receipt carrying the Brazilian Central Bank end-to-end identifier (E2E). Lunium is the settlement layer — you do not need to run an exchange, hold balances on any network, or custody fiat. **Start here:** https://api.luniumpay.com/quickstart — zero to a completed order with a Central Bank receipt, runnable, no signup and no money. API base: `https://api.luniumpay.com` · Auth: `X-API-Key` header · Docs: https://docs.luniumpay.com · OpenAPI: https://api.luniumpay.com/openapi.json Português: https://api.luniumpay.com/llms.pt.txt ## What PIX is, if you have not worked with Brazil PIX is Brazil's instant payment system, operated by the Central Bank. It settles in seconds, runs 24/7 including weekends and holidays, and is used by the large majority of Brazilian adults. A *PIX key* identifies the recipient: it can be a tax number (CPF for individuals, CNPJ for companies), a phone number, an email, or an opaque random key. Every completed PIX carries an **E2E identifier** issued by the Central Bank. It is the settlement fact, not our record of it — which is what makes the verification below meaningful. ## Payment verification (open, no key required) Any agent can confirm a PIX happened, without being a Lunium customer and without an API key. ``` GET https://api.luniumpay.com/v1/verificar/{e2e} ``` Returns `verificado`, `pago`, `valor_brl`, `pago_em`, the recipient's initials, the institution, and a link to the receipt. It never exposes the PIX key, the full name, or the tax number — it proves the payment without exposing the parties. This exists because "A says it paid, how does B check without trusting A?" is normally solved with escrow. With the E2E it is solved with verification. If you are building agent-to-agent commerce that touches Brazil, this is the endpoint that matters most, and it costs nothing. When a payment is not found, the response says explicitly that it may have been made through another institution. Absence here is not proof the PIX did not happen. ## Sell crypto, receive PIX (cash-out) Three calls, in order: 1. `POST /cash-outs` — quote. Fields: `asset`, `network`, `amount` (decimal string), `pix_key`, `external_id`, and `pix_key_type` only if the key is 11 bare digits. Returns `brl_amount` and `expires_at`. 2. `POST /cash-outs/{id}/accept` — locks the quote and returns `deposit_address`. Send the crypto there. 3. `GET /cash-outs/{id}` — poll or use a webhook. When paid, it carries the receipt (below). Starting from a BRL amount instead? `POST /quote/pix-preview-reverse?chain=&token=&brl_amount=` returns how much crypto to send. ## Buy crypto by paying PIX (cash-in) `POST /cashin/charge` returns the QR code and the copy-paste string; `GET /cashin/{id}/status` tracks it. The payer's CPF or CNPJ is required — a Central Bank rule, and it is what identifies the charge. ## The receipt — three forms of the same fact Every paid operation returns all of them, in the same response and the same webhook. You never build a URL by hand or make a second call. | field | what it is | use it for | |---|---|---| | `pix_e2e` | Central Bank identifier | third-party verification, trusting nobody | | `receipt_url` | shareable page | showing the end customer on their phone | | `receipt_pdf_url` | PDF file | attaching to a ticket, accounting, forwarding | | `verify_url` | direct link to the open verification | handing to a counterparty to check themselves | The PDF carries the recipient's name, tax number, institution, amount, date, the E2E, and the verification link. ## MCP server (Model Context Protocol) ``` https://api.luniumpay.com/mcp ``` Streamable HTTP, revision `2025-06-18`, stateless. Add it as a remote MCP connector in any host that speaks the protocol. **It works with no credentials at all.** Connect without a key and `lunium_verify_pix_payment` is immediately usable — confirm that a PIX settled, from its E2E alone, for a payment you did not make. That is the point: you should be able to check a counterparty's claim without an account and without trusting them. Every other tool needs an API key, sent by your host as the `X-API-Key` HTTP header (an `Authorization: Bearer` header works too). Without it those tools return `erro: "chave_ausente"` with `acao: "parar"` — they do not silently disappear from the list, so your agent can tell the user the connector needs configuring instead of concluding the capability does not exist. Eight tools: verify a payment · list what settles now · check a payer's limit · quote a crypto sale · confirm it · create a PIX charge · follow a sale · follow a charge. The two that move real money — confirming a sale and creating a charge — are marked `destructiveHint: true` so your host can require human approval, and confirming requires a `confirmation_token` from the quote, bound to that exact amount, network and destination. Selling is deliberately two steps: the quote commits nothing, the confirm is irreversible. ## Sandbox — try everything before spending anything ``` POST https://api.luniumpay.com/keys/sandbox ``` One call. No name, no email, no wallet, no approval. You get a `lun_test_…` key that runs the **entire** flow without a cent moving, on the same base URL and the same MCP endpoint. Code that works here works in production unchanged — same shapes, same states, same error contract. The order does **not** complete instantly: it walks the real states over ~15 seconds, so you write the polling loop (or the webhook) you will need anyway. **Deterministic triggers.** Testing only the happy path is how integrations break on day one, so the first two decimals of `amount` choose the outcome — no randomness, so you can assert on it in CI: | `amount` ends in | what happens | |---|---| | `.01` | order goes to **delayed** (PIX paid, provider holding) and completes on its own — prove your code does not treat it as failure | | `.02` | order **fails** — exercise your error path | | `.03` | the quote **expires** in 5s — prove you re-quote instead of insisting | | `.04` | refused on **limits**, with `limits.min_amount` / `max_amount` filled | | `.05` | completes **slowly** (~2 min) — prove your polling is patient | Reusing an `external_id` with a different destination returns **409**, exactly as production does — that is the case that confuses every integrator, and here you can rehearse it. **Verification works too.** A sandbox order produces a well-formed E2E whose institution code is `00000000` — a code no real institution holds, so it can never be mistaken for a real payment. `GET /v1/verificar/{e2e}` answers for it, marked `sandbox: true`, so you can exercise the open verification before deciding to integrate. Test orders disappear 2 hours after creation. Never send crypto to a sandbox `deposit_address`: it has no owner and the funds would be lost. ## Limits - **Cash-out, per operation: R$ 6.00 to R$ 50,000.00.** The limit is in BRL and your call is in crypto, so a rejection returns `limits.min_amount` and `limits.max_amount` already converted at that order's rate — literally the next value to send. - Cash-in has a per-payer ladder (anti-fraud, by tax number). Ask before charging: `GET /cashin/limits?payer_tax={cpf_or_cnpj}` returns `max_amount_cents` — the largest value that passes right now. - There is also a daily ceiling per key that grows with settled volume. It appears in `limits` when reached. - Rate: 60 requests per minute per key, configurable per client. ## Networks and timing `GET /catalog` is the source of truth and changes on its own. Do not hard-code a list. - **Polygon** (USDT/USDC): our own settlement, PIX in seconds. This is the default. Measured in production: 49 to 65 seconds from accept to PIX paid. - **Other networks**: the wait is the number of confirmations each chain requires — from about a minute (TON, Aptos) to a few hours (Celo). Never promise "instant" outside Polygon. - **Solana** is temporarily disabled for cash-out. The quote refuses explicitly rather than accepting an order that would not become a PIX. ## Errors: the field that tells you what to do Errors carry `erro` (a stable code that does not change when the wording does) and **`acao`**, which matters more than the message: - `corrigir` — the request is wrong. Repeating it identically will never work. - `repetir` — a transient failure on our side. Try again. - `esperar` — a quota renews. Come back later. - `parar` — do not retry; talk to us. This distinction exists because two opposite situations used to return the same answer: an order larger than an entire day's quota replied "try tomorrow" — and tomorrow it failed identically, forever. ## Charge states (cash-in) `pending` → nobody paid yet · `under_review` → PIX received, settlement in transit · `paid` → credited · `expired` / `refunded` / `failed` → terminal. **`delayed` deserves attention:** the PIX *was paid* and the provider is holding the release — a new payer's first operation can be held. The response carries `delay_until`. Do not treat it as a failure and do not cancel the order: it becomes `paid` on its own. ## Rules that prevent expensive mistakes - Send `external_id` on every order: it is the reconciliation key and makes the call idempotent. Repeating the same call returns the same order instead of creating another. - Read `expires_at` from the response rather than hard-coding a window. Today it is 15 minutes on Polygon and up to 300 minutes elsewhere, but that changes. - `pix_key_type` is required because a CPF and a phone number both have 11 digits and cannot be told apart without it. - Prefer webhooks over polling. Once per second consumes the 60-per-minute key limit by itself. - A `400` on a network means it is not settling at that moment. Refusing at quote time is cheap; accepting and not paying is what costs. ## Links - [Full documentation](https://docs.luniumpay.com): networks and timing, order lifecycle, curl/Node/Python examples, webhook signatures. - [OpenAPI](https://api.luniumpay.com/openapi.json): the contract, in machine form. - [App](https://app.luniumpay.com): run the whole flow without writing code. - [Partner Telegram group](https://t.me/+FerOZMRRP_g5MDk5): real-time status and contract changes before they ship. Recommended for anyone in production. - Contact: contato@luniumpay.com