{
  "openapi": "3.1.0",
  "info": {
    "title": "Lunium — crypto ⇄ PIX settlement (Brazil)",
    "version": "1.33.1",
    "summary": "Settlement between cryptocurrencies and PIX in Brazil.",
    "x-lunium-partners": {
      "name": "Lunium Partners — comunidade oficial de integradores",
      "url": "https://t.me/+FerOZMRRP_g5MDk5",
      "description": "Operational notices, API contract changes and partner discussions. Never post an API key in the group."
    },
    "description": "Lunium API: PIX collection, BRL custody, crypto delivery, external crypto-to-PIX and balance-funded PIX payouts. For custody send destino=saldo explicitly; the HTTP charge default remains cripto. A fixed settlement wallet is not required for custody. Asset/network availability, fees, limits and holds are dynamic: read the appropriate key, balance, catalog and preview endpoints. Payment completion, settlement and available balance are distinct states. Receipt/E2E fields are provided for PIX when available, not for every crypto transaction.\n\nSend X-API-Key. Use stable external_id and unchanged payload on retries. Public payment verification: GET /v1/verificar/{e2e}. Sandbox simulates cash-in, custody, crypto withdrawals, PIX payouts, internal transfers and cash-out. Confirm non-payable test PIX using POST /sandbox/cashin/{cashin_id}/pay. No bank, MEXC or blockchain transaction is performed. See https://docs.luniumpay.com/en/sandbox . Errors include erro/acao/detail and request_id/agent_guidance when available; support unknown fields, events and error codes.\n\nMCP: https://api.luniumpay.com/mcp (discover with tools/list). Manual: https://docs.luniumpay.com/en/manual · English: https://docs.luniumpay.com/en/manual. This patch corrects documentation to match deployed behavior; financial request fields are unchanged.\n\nAI onboarding: https://docs.luniumpay.com/en/integrar-com-ia . Public test-only MCP: https://api.luniumpay.com/mcp/onboarding . Machine-readable integration plan: https://docs.luniumpay.com/integration.json .",
    "contact": {
      "name": "Lunium",
      "email": "contato@luniumpay.com",
      "url": "https://luniumpay.com/integrar?utm_source=openapi&utm_medium=spec"
    },
    "x-documentation-revision": "2026-09-17.4"
  },
  "servers": [
    {
      "url": "https://api.luniumpay.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Cash-out",
      "description": "Receive crypto and pay out PIX."
    },
    {
      "name": "Cash-in",
      "description": "Receive PIX and deliver crypto."
    },
    {
      "name": "Catálogo",
      "description": "Currently available settlement routes. Read this source of truth instead of hardcoding a list."
    },
    {
      "name": "Verificação",
      "description": "Verify a PIX payment without an account or API key."
    },
    {
      "name": "Conta",
      "description": "API key, limits and usage."
    },
    {
      "name": "Mesh · Discovery",
      "description": "How an agent discovers Lunium and its capabilities without contacting a person."
    },
    {
      "name": "Mesh · Identity",
      "description": "Agent registration, credentials and lifecycle through production activation."
    },
    {
      "name": "Mesh · Policy",
      "description": "The agent's own mandate and settlement configuration."
    },
    {
      "name": "Mesh · Network",
      "description": "Verified referral lineage, referral graph and network volume."
    },
    {
      "name": "Mesh · Economy",
      "description": "0.10% of settled volume from your referrals. Registration earns no reward."
    },
    {
      "name": "Contato",
      "description": "Human assistance for volume pricing, contracts, partnerships or questions not covered by the documentation."
    },
    {
      "name": "Comissão (sub fee)",
      "description": "The partner fee added to Lunium's fee, paid by the partner's end customer, and withdrawal of that commission as crypto."
    },
    {
      "name": "Sandbox",
      "description": "Fictitious financial journeys and deterministic simulation controls."
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key created by `POST /keys`. The full key is returned only at creation; save it immediately."
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Your API key. `lun_test_…` is sandbox and moves no real funds. New production keys use `lun_live_…`; legacy `lun_…` production keys remain valid."
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "description": "API error. Fields may vary by route, including infrastructure responses. Interpret the HTTP status together with erro and acao when present; detail is for display, not control flow. Accept unknown error codes.",
        "properties": {
          "erro": {
            "type": "string",
            "description": "Stable error code. Branch on this field, never on the detail text. This list is generated from codes actually emitted by the API.",
            "x-known-values": [
              "amount_invalido",
              "asset_invalido",
              "br_code_indisponivel",
              "br_code_sem_valor",
              "brl_amount_invalido",
              "campos_conflitantes",
              "campos_obrigatorios",
              "carencia_primeiro_deposito",
              "cashin_indisponivel",
              "cashout_indisponivel",
              "catalogo_indisponivel",
              "chave_ausente",
              "chave_desconhecida",
              "chave_incorreta",
              "chave_nao_encontrada",
              "conflito",
              "consulta_indisponivel",
              "corpo_grande_demais",
              "cotacao_expirada",
              "cotacao_indisponivel",
              "custodia_desligada",
              "deposit_obrigatorio",
              "destino_invalido",
              "documento_invalido",
              "em_processamento",
              "email_invalido",
              "endpoint_nao_respondeu",
              "erro_interno",
              "external_id_divergente",
              "formato_invalido",
              "ja_entregue",
              "limite_consultas",
              "limite_de_chaves_teste",
              "limite_diario",
              "limite_diario_recebedor",
              "limite_do_pagador",
              "limite_indisponivel",
              "liquidante_indisponivel",
              "mandate_contraparte_nao_autorizada",
              "mandate_valor_acima_do_teto",
              "memo_obrigatorio",
              "metodo_nao_permitido",
              "muitas_tentativas",
              "nao_autenticado",
              "nao_encontrado",
              "nao_permitido",
              "nao_processavel",
              "origem_igual_destino",
              "pagador_recusado_pelo_provedor",
              "payer_tax_invalido",
              "payer_tax_number_invalido",
              "payout_address_invalido",
              "payout_address_obrigatorio",
              "payout_nao_liberado",
              "payout_recusado",
              "pix_key_invalida",
              "pix_key_obrigatoria",
              "provedor_indisponivel",
              "provedor_sem_resposta",
              "rate_limit",
              "rede_indisponivel",
              "refund_address_invalida",
              "requisicao_invalida",
              "saldo_insuficiente",
              "sandbox_sem_cashin",
              "sandbox_sem_saldo",
              "sandbox_sem_saque",
              "saque_comissao_diario",
              "saque_indisponivel",
              "status_invalido",
              "taxa_alterada",
              "tempo_esgotado",
              "temporariamente_indisponivel",
              "tipo_ambiguo",
              "valor_abaixo_do_minimo",
              "valor_acima_do_maximo",
              "valor_invalido",
              "webhook_nao_configurado",
              "webhook_url_invalida"
            ]
          },
          "acao": {
            "type": "string",
            "enum": [
              "corrigir",
              "repetir",
              "esperar",
              "parar",
              "falar_com_suporte"
            ],
            "description": "corrigir = fix the request; an identical retry will fail. repetir = transient failure; retry. esperar = wait for the quota to renew. parar = stop retrying and contact us. falar_com_suporte = do not retry in a loop; preserve request_id and external_id and contact Lunium (for example, config_provedor)."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation. Never branch on this text."
          },
          "limits": {
            "type": "object",
            "description": "Included in limit errors, already expressed in the order's currency."
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "request_id": {
            "type": "string",
            "description": "Request identifier, also returned in the X-Request-ID header. Include it when contacting support. A supplied X-Request-ID matching [A-Za-z0-9._:-]{8,64} is preserved end to end.",
            "examples": [
              "req_62f05f21b3794830a241"
            ]
          },
          "code": {
            "type": "string",
            "deprecated": true,
            "description": "LEGACY alias of `erro`. SUNSET: no longer returned from 2026-11-09. Use the canonical `erro` field for control flow. This alias is never returned without `erro`."
          }
        }
      },
      "CashOut": {
        "type": "object",
        "properties": {
          "cashout_id": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "type": "string",
            "enum": [
              "QUOTE_CREATED",
              "AWAITING_DEPOSIT",
              "DEPOSIT_DETECTED",
              "DEPOSIT_CONFIRMED",
              "SELLING",
              "SOLD",
              "FORWARDING",
              "PAYING_OUT",
              "COMPLETED",
              "MANUAL_REVIEW",
              "REFUNDING_CRYPTO",
              "REFUNDED",
              "EXPIRED",
              "FAILED",
              "DELAYED"
            ],
            "description": "Order state. COMPLETED confirms the PIX payment. Intermediate stages vary by settlement route. DELAYED belongs to a sandbox scenario."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "FAST",
              "DEX",
              "CONVERT",
              null
            ],
            "description": "FAST, DEX or CONVERT settlement route. Timing depends on the route, confirmations and processing."
          },
          "asset": {
            "type": "string",
            "examples": [
              "USDT"
            ],
            "description": "Asset to sell. Use the EXACT id from GET /catalog (for example, \"usdt\"). The (asset, network) pair must exist in that catalog."
          },
          "network": {
            "type": "string",
            "examples": [
              "polygon"
            ],
            "description": "Blockchain deposit network, as listed in the catalog (for example, \"polygon\"). The returned deposit address is valid only on this network."
          },
          "amount": {
            "type": "string",
            "description": "Crypto amount as a decimal string. Never use a floating-point number."
          },
          "brl_amount": {
            "type": [
              "string",
              "null"
            ],
            "description": "Amount in Brazilian reais (BRL) that the PIX recipient will receive."
          },
          "pix_key": {
            "type": "string",
            "description": "Destination PIX key: CPF, CNPJ, +55 phone number, email or random key. For 11 bare digits, also send pix_key_type (\"cpf\" or \"phone\"); otherwise the API returns erro=tipo_ambiguo instead of guessing."
          },
          "pix_key_type": {
            "type": "string",
            "enum": [
              "cpf",
              "cnpj",
              "phone",
              "email",
              "random"
            ],
            "description": "Usually omit it: the type is inferred from the key for e-mails, CNPJs, random keys and phones written with the +55 country code. Only required when the key is 11 bare digits, because a CPF and a phone number are the same length and guessing would pay the wrong person. An explicit type always wins over inference."
          },
          "deposit_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Address to which the customer sends crypto. Returned only after acceptance."
          },
          "deposit_tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Memo/tag that must accompany the deposit when returned by the accept operation. Use only networks listed in GET /catalog."
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
            "maxLength": 64
          },
          "refund_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Return wallet supplied when requesting the quote: the destination of any refund. null means no wallet was supplied; a refund would go to the original deposit address (deposit_from)."
          },
          "refund_tx_hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "Refund transaction hash when completed. Its presence does not imply a fixed refund amount or time for all cases."
          },
          "deposit_from": {
            "type": [
              "string",
              "null"
            ],
            "description": "Address that SENT the deposit, read on-chain. Used as the refund destination when refund_address was not supplied."
          },
          "br_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "PIX copy-and-paste payment string supplied with the quote, if any. brl_amount is the QR payment amount."
          },
          "merchant_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient name read from the PIX payment QR."
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Quote expiration timestamp in ISO 8601 UTC (for example, 2026-09-02T14:03:00Z). Acceptance after this time fails with erro=cotacao_expirada. Request a new quote instead of retrying acceptance."
          },
          "pix_e2e": {
            "type": [
              "string",
              "null"
            ],
            "description": "The completed PIX payment's Central Bank end-to-end identifier. Anyone can verify it at GET /v1/verificar/{e2e} without an API key. Return it to your end customer as the payment reference.",
            "examples": [
              "E37293930202607312006361894c4a82"
            ]
          },
          "pix_paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "receipt_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Shareable receipt page that opens on the end customer's phone.",
            "examples": [
              "https://app.luniumpay.com/comprovante/uwscff6ASNS1oUcH2LHbvw"
            ]
          },
          "receipt_pdf_url": {
            "type": [
              "string",
              "null"
            ],
            "nullable": true,
            "format": "uri",
            "description": "Receipt as a PDF file for support tickets, customer messages or accounting. Contains recipient name, tax ID, institution, amount, date, E2E and verification link. Generated from the same data as the receipt page. null until the order reaches the state that supplies it.",
            "example": "https://app.luniumpay.com/comprovante/qigpnCTx3gM-Ge7hN27Mvw.pdf"
          },
          "verify_url": {
            "type": [
              "string",
              "null"
            ],
            "nullable": true,
            "format": "uri",
            "description": "Public verification link requiring no API key. Share it so the counterparty can check the payment independently. Does not expose the PIX key, full name or tax ID. null until the order reaches the state that supplies it.",
            "example": "https://api.luniumpay.com/v1/verificar/E3729393020260731214021222ac6ff1"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "timeline": {
            "type": "array",
            "description": "Timeline timestamped by the SERVER at each transition, rather than by your polling: AWAITING_DEPOSIT → DEPOSIT_DETECTED → DEPOSIT_CONFIRMED → (SELLING → SOLD → FORWARDING, exchange route only) → PAYING_OUT → COMPLETED. Use it in the customer's tracker.",
            "items": {
              "type": "object",
              "properties": {
                "state": {
                  "type": "string"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "confirmations": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Deposit confirmations observed live. Returned only while the order is confirming; not persisted and may change with each block. Display progress using this field and confirmations_required."
          },
          "confirmations_required": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of confirmations the exchange requires before crediting a deposit on this network."
          },
          "failure_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Failure reason when returned, including sandbox scenarios."
          },
          "sandbox": {
            "type": "boolean",
            "description": "True for fictitious sandbox operations."
          },
          "simulation": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "EventoWebhook": {
        "type": "object",
        "description": "Body sent to your webhook endpoint. Treat unknown event types as a no-op: new types can be added, and your receiver must tolerate them.",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "cashin.paid",
              "cashin.delayed",
              "cashin.held",
              "cashin.settled",
              "cashin.settlement_failed",
              "cashin.expired",
              "cashin.refunded",
              "cashin.failed",
              "cashout.awaiting_deposit",
              "cashout.deposit_detected",
              "cashout.confirming",
              "cashout.processing",
              "cashout.under_review",
              "cashout.refunding",
              "cashout.completed",
              "cashout.refunded",
              "cashout.expired",
              "cashout.failed",
              "payout.sent",
              "payout.failed",
              "payout.refunded",
              "webhook.test",
              "saldo.liberado",
              "saldo.congelado",
              "saldo.transferido"
            ],
            "description": "Branch on the event type. `cashin.settled` signals when to credit your customer.\n\n`cashout.confirming` reports deposit progress while the exchange waits for confirmations. Emitted at 25%, 50% and 75% only on networks requiring a substantial wait (≥120 confirmations), with `confirmations` and `confirmations_required` in the payload.\n\n`cashin.held`: PIX paid but delivery held by the key's policy; `data` contains `liberar_em`. This differs from a provider hold, represented by `status: delayed`. `cashin.delayed`: PIX paid and held by the provider for 24 hours (`delay_until`)."
          },
          "event_id": {
            "type": "string",
            "pattern": "^evt_[0-9a-f]{24}$",
            "description": "STABLE event identifier, unchanged across retries. Persist it and ignore duplicates to avoid crediting a customer twice.",
            "examples": [
              "evt_9c3f21a70b5e4d8812ff0a63"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "description": "Same format as the corresponding operation's status endpoint."
          }
        },
        "required": [
          "event",
          "created_at",
          "data"
        ]
      },
      "EntregaWebhook": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string"
          },
          "event": {
            "type": "string",
            "enum": [
              "cashin.paid",
              "cashin.delayed",
              "cashin.held",
              "cashin.settled",
              "cashin.settlement_failed",
              "cashin.expired",
              "cashin.refunded",
              "cashin.failed",
              "cashout.awaiting_deposit",
              "cashout.deposit_detected",
              "cashout.confirming",
              "cashout.processing",
              "cashout.under_review",
              "cashout.refunding",
              "cashout.completed",
              "cashout.refunded",
              "cashout.expired",
              "cashout.failed",
              "payout.sent",
              "payout.failed",
              "payout.refunded",
              "webhook.test",
              "saldo.liberado",
              "saldo.congelado",
              "saldo.transferido"
            ]
          },
          "operation_id": {
            "type": "string",
            "description": "Identifier of the operation that generated the event."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sent",
              "failed"
            ],
            "description": "failed means all 12 attempts were exhausted. Use the retry endpoint to recover the delivery."
          },
          "attempts": {
            "type": "integer"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "next_attempt_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TitularPix": {
        "type": "object",
        "required": [
          "pix_key",
          "pix_key_type",
          "owner_name",
          "verified",
          "source",
          "checked_at"
        ],
        "properties": {
          "pix_key": {
            "type": "string",
            "description": "Normalized PIX key; phone numbers use the +55 format."
          },
          "pix_key_type": {
            "type": "string",
            "enum": [
              "cpf",
              "cnpj",
              "phone",
              "email",
              "random"
            ],
            "description": "Type of the queried PIX key: \"cpf\", \"cnpj\", \"phone\", \"email\" or \"random\"."
          },
          "owner_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Account holder's name as recorded in DICT, the PIX key directory.",
            "examples": [
              "João Silva"
            ]
          },
          "owner_tax_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "MASKED CPF/CNPJ. Never returned in full.",
            "examples": [
              "***.202.745-**"
            ]
          },
          "institution_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Institution where the PIX key is registered.",
            "examples": [
              "NU PAGAMENTOS - IP"
            ]
          },
          "ispb": {
            "type": [
              "string",
              "null"
            ],
            "description": "Institution's eight-digit ISPB identifier.",
            "examples": [
              "18236120"
            ]
          },
          "verified": {
            "type": "boolean",
            "description": "true when holder details were retrieved or simulated (source=sandbox); false when not verified."
          },
          "source": {
            "type": "string",
            "enum": [
              "dict",
              "sandbox",
              "disabled"
            ]
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "cached": {
            "type": "boolean",
            "description": "true when the response was served from the 24-hour cache."
          },
          "sandbox": {
            "type": "boolean",
            "description": "Sandbox keys only: fictitious account holder."
          },
          "available": {
            "type": "boolean",
            "description": "false when lookup is unavailable; may accompany HTTP 200."
          },
          "optional": {
            "type": "boolean",
            "description": "Holder lookup is auxiliary and is not a payment requirement."
          },
          "verification_status": {
            "type": "string",
            "description": "not_performed when verification was not performed."
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "NextAction": {
        "type": "object",
        "description": "The next step expressed as an API call. An agent should not need to interpret human-readable prose to continue.",
        "properties": {
          "method": {
            "type": "string",
            "example": "POST"
          },
          "endpoint": {
            "type": "string",
            "example": "/mesh/agents/{agent_id}/settlement"
          },
          "why": {
            "type": "string",
            "example": "sem rota de liquidacao o dinheiro nao tem para onde ir"
          }
        }
      },
      "ErroAutocorrigivel": {
        "type": "object",
        "description": "Error the agent can handle itself. `acao` is a stable enum: corrigir (fix request), esperar (wait for quota), parar (stop retrying), repetir (retry a transient failure).",
        "properties": {
          "erro": {
            "type": "string",
            "example": "mandate_valor_acima_do_teto"
          },
          "acao": {
            "type": "string",
            "enum": [
              "corrigir",
              "esperar",
              "parar",
              "repetir"
            ]
          },
          "detail": {
            "type": "string"
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "next_actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NextAction"
            }
          }
        },
        "required": [
          "erro",
          "acao"
        ]
      },
      "Capability": {
        "type": "object",
        "description": "Lunium capabilities described by attributes, not internal names, so an agent can match its intent without knowing our vocabulary.",
        "properties": {
          "descricao": {
            "type": "string"
          },
          "intent": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "sell_crypto",
              "receive_fiat",
              "offramp",
              "cash_out"
            ]
          },
          "input_assets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "USDT"
            ]
          },
          "input_networks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "polygon"
            ]
          },
          "output_currencies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "BRL"
            ]
          },
          "payment_rails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "PIX"
            ]
          },
          "endpoint": {
            "type": "string",
            "example": "/cash-outs"
          },
          "direction": {
            "type": "string",
            "example": "crypto->fiat"
          },
          "settlement_speed": {
            "type": "string",
            "enum": [
              "seconds",
              "minutes"
            ]
          }
        }
      },
      "MeshDiscovery": {
        "type": "object",
        "description": "Single discovery document answering the questions an agent needs before integrating. Generated from the live configuration to reflect API behavior.",
        "properties": {
          "quem_somos": {
            "type": "object"
          },
          "como_falar_comigo": {
            "type": "object",
            "description": "REST, OpenAPI, MCP, A2A and Mesh."
          },
          "capacidades": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Capability"
            }
          },
          "como_escolher_capacidade": {
            "type": "object",
            "description": "Intent-to-capability index and instructions for filtering by attribute.",
            "properties": {
              "por_intencao": {
                "type": "object",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "execucao": {
            "type": "object",
            "description": "Endpoint, required fields and ready-to-use example for each capability."
          },
          "ativos_e_redes": {
            "type": "object"
          },
          "limites": {
            "type": "object"
          },
          "como_comecar": {
            "type": "object"
          },
          "regra_de_seguranca": {
            "type": "object"
          },
          "atribuicao": {
            "type": "object"
          }
        }
      },
      "AgentIdentity": {
        "type": "object",
        "description": "PERMANENT agent identity. Credentials can be replaced; lineage, volume, rewards, mandate and reputation belong to agent_id.",
        "properties": {
          "agent_id": {
            "type": "string",
            "example": "agt_2319c9da313e84af3b"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/AgentLifecycle"
          },
          "environment": {
            "type": "string",
            "enum": [
              "sandbox",
              "production"
            ]
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "settlement_address": {
            "type": [
              "string",
              "null"
            ]
          },
          "referred_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "Immutable after registration, enforced by a database trigger."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AgentLifecycle": {
        "type": "string",
        "enum": [
          "registered",
          "sandbox_active",
          "validated",
          "production_active",
          "suspended"
        ],
        "description": "Production is activated by policy without a human approval queue. Risk controls apply through payer limits for cash-in, per-operation limits, daily PIX-recipient limits for cash-out and the key's own mandate. Since 2026-09-10 there is no general daily API-key limit or approval queue."
      },
      "AgentRegistration": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 80
          },
          "description": {
            "type": "string"
          },
          "contact": {
            "type": "string"
          },
          "agent_card_url": {
            "type": "string"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "referral_token": {
            "type": "string",
            "description": "Attestation signed by the referrer. This is the ONLY way to establish referral lineage. Client-supplied `referred_by` is rejected because lineage determines financial rewards."
          }
        }
      },
      "AgentKey": {
        "type": "object",
        "description": "Credential. `lun_test_*` = sandbox; `lun_live_*` = production. Keys issued before 2026-08-29 begin with `lun_` and remain valid. Authentication uses the hash, never the prefix; the prefix is a human-readable environment hint.",
        "properties": {
          "api_key": {
            "type": "string",
            "example": "lun_live_a977c15a…",
            "description": "Returned only ONCE. Only its hash is stored."
          },
          "sandbox": {
            "type": "boolean"
          }
        }
      },
      "Mandate": {
        "type": "object",
        "description": "Policy imposed by the key itself. It can only tighten limits, never expand them, so an agent can set it independently. Required before production activation.",
        "properties": {
          "max_por_operacao_cents": {
            "type": "integer",
            "example": 30000
          },
          "max_diario_cents": {
            "type": "integer",
            "example": 200000
          },
          "contrapartes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allowed PIX destination keys. Empty means no restriction."
          }
        }
      },
      "SettlementConfiguration": {
        "type": "object",
        "required": [
          "settlement_address"
        ],
        "properties": {
          "settlement_address": {
            "type": "string",
            "example": "0x51e3…75e0",
            "description": "Wallet on a supported settlement network."
          }
        }
      },
      "ProductionActivation": {
        "type": "object",
        "description": "AUTOMATIC activation. `activated_by` is always `policy`, never `operator`.",
        "properties": {
          "status": {
            "type": "string",
            "example": "production_active"
          },
          "agent_id": {
            "type": "string"
          },
          "environment": {
            "type": "string",
            "example": "production"
          },
          "activated_at": {
            "type": "string",
            "format": "date-time"
          },
          "activated_by": {
            "type": "string",
            "example": "policy"
          },
          "api_key": {
            "type": "string",
            "description": "Production credential (`lun_live_*`), returned only once."
          },
          "settlement": {
            "type": "object"
          },
          "mandate": {
            "$ref": "#/components/schemas/Mandate"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ReferralAttestation": {
        "type": "object",
        "description": "Signed, single-use, expiring token (JWS HS256) proving the referrer. Without it, the agent becomes a root agent and generates no referral reward for another agent.",
        "properties": {
          "type": {
            "type": "string",
            "example": "mesh_referral"
          },
          "referrer_agent_id": {
            "type": "string"
          },
          "referral_token": {
            "type": "string"
          },
          "capability": {
            "type": [
              "string",
              "null"
            ]
          },
          "nonce": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "one_time_use": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "AgentNetwork": {
        "type": "object",
        "description": "An agent's referral tree. `network_volume` counts the entire tree for reputation; `reward_eligible_volume` counts only reward-eligible volume.",
        "properties": {
          "agent_id": {
            "type": "string"
          },
          "referred_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "depth": {
            "type": "integer"
          },
          "direct_children": {
            "type": "integer"
          },
          "total_descendants": {
            "type": "integer"
          },
          "own_volume_cents": {
            "type": "integer"
          },
          "own_transactions": {
            "type": "integer"
          },
          "network_volume_cents": {
            "type": "integer"
          },
          "network_transactions": {
            "type": "integer"
          },
          "reward_eligible_volume_cents": {
            "type": "integer"
          },
          "lifetime_rewards_cents": {
            "type": "integer"
          },
          "first_operation": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "production_since": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "children": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "MeshEconomyPolicy": {
        "type": "object",
        "description": "Public network economy rules. NO SETTLEMENT → NO REWARD.",
        "properties": {
          "model": {
            "type": "string",
            "example": "transaction_attribution"
          },
          "direct_rate": {
            "type": "string",
            "example": "0.10%"
          },
          "direct_rate_bps": {
            "type": "integer",
            "example": 10
          },
          "max_paid_levels": {
            "type": "integer",
            "example": 1
          },
          "recruitment_reward": {
            "type": "boolean",
            "example": false
          },
          "requires_settled_transaction": {
            "type": "boolean",
            "example": true
          },
          "revenue_share_cap": {
            "type": "string"
          }
        }
      },
      "RewardEvent": {
        "type": "object",
        "description": "Immutable ledger entry. A reversal is a new NEGATIVE entry, never an UPDATE or DELETE.",
        "properties": {
          "transaction_id": {
            "type": "string"
          },
          "transaction_kind": {
            "type": "string",
            "enum": [
              "cashout",
              "cashin"
            ]
          },
          "source_agent_id": {
            "type": "string",
            "description": "Agent that generated the volume."
          },
          "referral_level": {
            "type": "integer",
            "example": 1
          },
          "volume_cents": {
            "type": "integer"
          },
          "rate_bps": {
            "type": "integer",
            "example": 10
          },
          "gross_reward_cents": {
            "type": "integer"
          },
          "revenue_cents": {
            "type": "integer",
            "description": "Lunium revenue from the operation."
          },
          "revenue_cap_cents": {
            "type": "integer",
            "description": "Applicable reward cap."
          },
          "final_reward_cents": {
            "type": "integer",
            "description": "Negative for a reversal."
          },
          "reward_usdt": {
            "type": [
              "number",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "available",
              "paid",
              "reversed"
            ]
          },
          "motivo": {
            "type": [
              "string",
              "null"
            ]
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RewardBalance": {
        "type": "object",
        "description": "Balance belongs to agent_id, never to a credential. Rotating a key does not lose the balance.",
        "properties": {
          "agent_id": {
            "type": "string"
          },
          "own_volume_cents": {
            "type": "integer"
          },
          "direct_referral_volume_cents": {
            "type": "integer"
          },
          "network_volume_cents": {
            "type": "integer"
          },
          "pending_rewards_cents": {
            "type": "integer"
          },
          "available_rewards_cents": {
            "type": "integer"
          },
          "paid_rewards_cents": {
            "type": "integer"
          },
          "lifetime_rewards_cents": {
            "type": "integer"
          },
          "reward_events": {
            "type": "integer"
          },
          "reversals": {
            "type": "integer"
          },
          "policy": {
            "$ref": "#/components/schemas/MeshEconomyPolicy"
          },
          "ledger": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RewardEvent"
            }
          }
        }
      },
      "ServiceRecommendation": {
        "type": "object",
        "description": "What one agent passes to another: only the domain, capability and optional attestation, never an API key, private endpoint or schema. The receiving agent must still verify Lunium independently.",
        "properties": {
          "type": {
            "type": "string",
            "example": "service_recommendation"
          },
          "from_agent": {
            "type": "string"
          },
          "domain": {
            "type": "string",
            "example": "https://luniumpay.com"
          },
          "capability": {
            "type": "string",
            "example": "usdt_to_pix"
          },
          "referral_token": {
            "type": "string"
          },
          "verify_yourself": {
            "type": "string"
          }
        }
      },
      "Cobranca": {
        "type": "object",
        "description": "Charge creation response, including the QR. See StatusCobranca for status, list and webhook representations.",
        "properties": {
          "cashin_id": {
            "type": "string",
            "description": "Charge identifier (ci_…)."
          },
          "status": {
            "type": "string",
            "description": "PIX state. paid alone does not prove credit or delivery; also read settlement_status.",
            "enum": [
              "pending",
              "delayed",
              "under_review",
              "paid",
              "expired",
              "refunded",
              "failed"
            ]
          },
          "amount_cents": {
            "type": "integer",
            "description": "PIX amount in BRL cents."
          },
          "destino": {
            "type": "string",
            "description": "cripto delivers on-chain; saldo credits the key's BRL custody balance for use with POST /payouts and POST /saldo/sacar-cripto.",
            "enum": [
              "cripto",
              "saldo"
            ]
          },
          "fonte": {
            "type": "string",
            "enum": [
              "pix",
              "saldo"
            ],
            "description": "Funding source at creation: PIX or balance withdrawal."
          },
          "customer_ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your end-customer reference, identifying a balance subaccount.",
            "maxLength": 80
          },
          "payout_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Wallet receiving crypto when destino=cripto."
          },
          "payout_tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Destination wallet memo/tag on networks with shared addresses, for destino=cripto."
          },
          "chain": {
            "type": "string",
            "description": "Delivery network identifier from GET /cashin/catalog."
          },
          "asset": {
            "type": "string",
            "description": "Asset delivered (usdt, usdc, btc, …)."
          },
          "lunium_fee_bps": {
            "type": "integer",
            "description": "Percentage fee locked into the charge, in basis points."
          },
          "lunium_fee_fixed_cents": {
            "type": "integer",
            "description": "Fixed fee locked into the charge, in BRL cents."
          },
          "partner_fee_bps": {
            "type": "integer",
            "description": "Partner fee locked into the charge."
          },
          "qr_copypaste": {
            "type": [
              "string",
              "null"
            ],
            "description": "PIX copy-and-paste string at creation; null for a custody withdrawal."
          },
          "qr_image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "QR image (PNG), returned only in the creation response."
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
            "maxLength": 64
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Charge expiration timestamp. Read this value, including when validity has been extended by the bot."
          },
          "delay_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Provider hold release timestamp, when available."
          },
          "liberar_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the balance credit becomes available after its waiting period. null when immediately available, the default since 2026-09-16."
          },
          "hold_hours": {
            "type": "integer",
            "description": "Local charge hold in hours. Not an alias of held_hours or the general balance waiting period."
          },
          "held_hours": {
            "type": "integer",
            "description": "Hold requested from the provider. May be zero even when a local hold exists (hold_hours/liberar_em)."
          },
          "held": {
            "type": "boolean",
            "description": "true when held_hours > 0. Does not indicate whether a local hold exists."
          },
          "sandbox": {
            "type": "boolean",
            "description": "True for fictitious sandbox operations."
          },
          "simulation": {
            "type": "object",
            "additionalProperties": true
          },
          "sandbox_payment": {
            "type": "object",
            "properties": {
              "method": {
                "const": "POST"
              },
              "path": {
                "type": "string"
              }
            }
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "StatusCobranca": {
        "type": "object",
        "description": "Charge status. GET may add trilho, timeline and tempos_tipicos; list and webhook responses use the base object.",
        "properties": {
          "cashin_id": {
            "type": "string",
            "description": "Charge identifier (ci_…)."
          },
          "status": {
            "type": "string",
            "description": "PIX state. paid alone does not prove credit or delivery; also read settlement_status.",
            "enum": [
              "pending",
              "delayed",
              "under_review",
              "paid",
              "expired",
              "refunded",
              "failed"
            ]
          },
          "settlement_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Credit/delivery state: sent means completed; incerto requires reconciliation. PIX payment and delivery are separate states.",
            "enum": [
              "pending",
              "sending",
              "entregando",
              "sent",
              "incerto",
              "failed",
              null
            ]
          },
          "amount_cents": {
            "type": "integer",
            "description": "PIX amount in BRL cents."
          },
          "depix_received_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Amount received from the settlement provider before deducting the key's deposit fees. This is not the net custody credit."
          },
          "usdt_amount": {
            "type": [
              "string",
              "null"
            ],
            "description": "Legacy amount field returned by settlement. Interpret it alongside asset and the route-specific fields."
          },
          "settlement_tx_hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "On-chain delivery hash, or internal identifier when delivery uses an exchange."
          },
          "settlement_tx_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Block explorer link for that hash, when available."
          },
          "payout_address": {
            "type": [
              "string",
              "null"
            ],
            "description": "Wallet receiving crypto when destino=cripto."
          },
          "payout_tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Destination wallet memo/tag on networks with shared addresses, for destino=cripto."
          },
          "chain": {
            "type": "string",
            "description": "Delivery network identifier from GET /cashin/catalog."
          },
          "asset": {
            "type": "string",
            "description": "Asset delivered (usdt, usdc, btc, …)."
          },
          "payer_tax_number": {
            "type": "string",
            "description": "Payer's CPF/CNPJ: the person or business that must pay the QR. Payment from a different tax ID is refunded with refund_reason PAYER_MISMATCH."
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
            "maxLength": 64
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Charge expiration timestamp. Read this value, including when validity has been extended by the bot."
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "settled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "destino": {
            "type": "string",
            "description": "cripto delivers on-chain; saldo credits the key's BRL custody balance for use with POST /payouts and POST /saldo/sacar-cripto.",
            "enum": [
              "cripto",
              "saldo"
            ]
          },
          "held_hours": {
            "type": "integer",
            "description": "Hold requested from the provider. May be zero even when a local hold exists (hold_hours/liberar_em)."
          },
          "held": {
            "type": "boolean",
            "description": "true when held_hours > 0. Does not indicate whether a local hold exists."
          },
          "delay_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Provider hold release timestamp, when available."
          },
          "liberar_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the balance credit becomes available after its waiting period. null when immediately available, the default since 2026-09-16."
          },
          "e2e": {
            "type": [
              "string",
              "null"
            ],
            "description": "Central Bank EndToEndId of the incoming PIX payment."
          },
          "payer_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Payer's name, when supplied or identified by the bank."
          },
          "customer_ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your end-customer reference, identifying a balance subaccount.",
            "maxLength": 80
          },
          "refund_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Refund reason when status=refunded, for example PAYER_MISMATCH (different payer tax ID), TEST_AMOUNT (test amount) or PROVIDER_REJECTED."
          },
          "refund_reason_detail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable refund explanation."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "trilho": {
            "type": "string",
            "description": "Operation route: casa, corretora, saldo or liquid. Not a timing guarantee."
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "tempos_tipicos": {
            "type": "object",
            "description": "Measured median duration in seconds for each stage, grouped by route. Use it to display typical processing times.",
            "additionalProperties": true
          },
          "sandbox": {
            "type": "boolean",
            "description": "True for fictitious sandbox operations."
          },
          "simulation": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Payout": {
        "type": "object",
        "description": "PIX payout funded by the key's custody balance (PIX→PIX).",
        "properties": {
          "payout_id": {
            "type": "string"
          },
          "customer_ref": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80
          },
          "status": {
            "type": "string",
            "description": "processing, sent, failed or refunded. Reconcile balance using the statement and tolerate new states."
          },
          "amount_cents": {
            "type": "integer",
            "description": "Amount the recipient receives."
          },
          "fee_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Additional amount debited beyond the payout amount: fee_service_cents + fee_provider_cents."
          },
          "fee_service_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Key-specific service fee, from saque_fee_bps in GET /saldo."
          },
          "fee_provider_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Effective provider fee, fixed or percentage-based. Read the saque_taxa_provedor_* fields in GET /saldo."
          },
          "pix_key": {
            "type": "string"
          },
          "pix_key_type": {
            "type": "string",
            "enum": [
              "cpf",
              "cnpj",
              "phone",
              "email",
              "random"
            ]
          },
          "tax_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Masked recipient tax ID, when supplied; optional in the request."
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
            "maxLength": 64
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Reason when the operation is failed or refunded."
          },
          "e2e": {
            "type": [
              "string",
              "null"
            ],
            "description": "EndToEndId of the outgoing PIX payment."
          },
          "receiver_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient name obtained after payment, when available; otherwise null."
          },
          "receiver_tax_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "verify_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public PIX verification (GET /v1/verificar/{e2e})."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sandbox": {
            "type": "boolean",
            "description": "True for fictitious sandbox operations."
          },
          "simulation": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "ChaveMe": {
        "type": "object",
        "description": "Your key, current limits and enabled capabilities.",
        "properties": {
          "key": {
            "type": "object",
            "properties": {
              "sandbox": {
                "type": "boolean"
              },
              "key_id": {
                "type": "integer"
              },
              "prefix": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "null for a sandbox key or a key created without an email."
              },
              "cashin_enabled": {
                "type": "boolean"
              },
              "cashout_enabled": {
                "type": "boolean"
              },
              "payout_enabled": {
                "type": "boolean"
              },
              "settlement_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Default settlement wallet on Polygon; null until configured."
              },
              "chain": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "fee_bps": {
                "type": "integer"
              },
              "rate_limit_per_minute": {
                "type": "integer"
              },
              "webhook_url": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "null until configured using PATCH /keys/me. Without a webhook URL, cashin.paid/settled/delayed callbacks cannot be delivered."
              },
              "webhook_configured": {
                "type": "boolean"
              },
              "telegram_linked": {
                "type": "boolean"
              },
              "created_at": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "partner_fee_bps": {
                "type": "integer",
                "minimum": 0,
                "maximum": 1000,
                "description": "Partner fee in basis points, ADDED to `fee_bps` (Lunium's fee). 100 = 1%. Paid by the end customer; Lunium's share is unchanged. 0 disables it. Configure using PATCH /keys/me."
              }
            }
          },
          "limits": {
            "type": "object",
            "description": "Current key limits and usage, by operation and payer. A null daily cap means that particular cap is absent, not that all restrictions are removed. Mandates and per-person limits may still apply.",
            "additionalProperties": true
          },
          "payout": {
            "type": "object",
            "description": "enabled, via, unlocks_at_settled_volume_cents, settled_volume_cents, remaining_cents.",
            "additionalProperties": true
          },
          "monitor_url": {
            "type": "string",
            "description": "Monitoring page for this key."
          },
          "telegram": {
            "type": "object",
            "additionalProperties": true
          },
          "grupos_obrigatorios": {
            "type": "object",
            "description": "Links to operational notice, partner and community groups.",
            "additionalProperties": true
          },
          "comissao": {
            "type": "object",
            "description": "Accrued partner commission. See GET /comissao for details.",
            "properties": {
              "partner_fee_bps": {
                "type": "integer"
              },
              "max_partner_fee_bps": {
                "type": "integer"
              },
              "disponivel_cents": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "creditado_cents": {
                "type": "integer"
              },
              "estornado_cents": {
                "type": "integer"
              },
              "sacado_cents": {
                "type": "integer"
              },
              "operacoes": {
                "type": "integer"
              },
              "ultimo_credito_em": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "moeda": {
                "type": "string"
              },
              "nota": {
                "type": "string"
              }
            }
          }
        }
      },
      "Catalogo": {
        "type": "object",
        "description": "Cash-out catalog for selling crypto.",
        "properties": {
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "fast": {
            "type": "array",
            "description": "Pairs available on the FAST route. Deposit and PIX timing depend on the operation; this is not a fixed SLA.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "string"
                },
                "network": {
                  "type": "string"
                }
              }
            }
          },
          "dex": {
            "type": "object",
            "description": "Long-tail tokens via DEX: chains and notes.",
            "additionalProperties": true
          },
          "convert": {
            "type": "array",
            "description": "Exchange route: one entry per asset with supported networks. Includes solana and tron (since 2026-09-06) and shared-address networks (XRP, XLM, ATOM, HBAR, KAVA, HIVE, STEEM, IOST), where acceptance returns deposit_tag.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "string"
                },
                "networks": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "min": {
                  "type": "string",
                  "description": "Minimum amount in asset units; 6 for stablecoins."
                },
                "max": {
                  "type": "string"
                },
                "precision": {
                  "type": "integer"
                },
                "deposit_eta": {
                  "type": "array",
                  "description": "Expected wait AFTER sending crypto, by network. Display this on the crypto-selling screen. Derived from exchange deposit confirmation requirements, not our withdrawal time for crypto purchases. Sorted from fastest to slowest network.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "network": {
                        "type": "string"
                      },
                      "confirmations": {
                        "type": "integer",
                        "description": "Confirmations required by the exchange, for example 1,000 on Base, 5,000 on Arbitrum and 61 on BSC."
                      },
                      "eta_seconds": {
                        "type": "integer",
                        "description": "Estimated seconds: required confirmations × network block time, rounded up."
                      },
                      "eta": {
                        "type": "string",
                        "description": "The same estimate as short text, for example \"about 34 min\"."
                      }
                    },
                    "required": [
                      "network",
                      "confirmations",
                      "eta_seconds",
                      "eta"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "CatalogoCompra": {
        "type": "object",
        "description": "Cash-in catalog: assets we can deliver after receiving PIX.",
        "properties": {
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "instant": {
            "type": "array",
            "description": "House-funded delivery routes; may be empty depending on configuration. Do not assume availability or fixed timing.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "string"
                },
                "network": {
                  "type": "string"
                },
                "eta": {
                  "type": "string"
                },
                "entregavel": {
                  "type": "boolean"
                }
              }
            }
          },
          "convert": {
            "type": "array",
            "description": "Exchange route: one entry per (asset, network) pair.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "string"
                },
                "network": {
                  "type": "string"
                },
                "etaSeconds": {
                  "type": "integer"
                },
                "eta": {
                  "type": "string"
                },
                "fastest": {
                  "type": "boolean"
                },
                "withdrawFee": {
                  "type": "string"
                },
                "withdrawMin": {
                  "type": "string"
                },
                "withdrawMax": {
                  "type": "string"
                },
                "minBuyAmount": {
                  "type": "string",
                  "description": "Smallest deliverable amount: minimum plus exchange withdrawal fee. POST /cashin/preview returns the BRL minimum as min_brl_cents."
                },
                "precision": {
                  "type": "integer"
                },
                "memoRequired": {
                  "type": "boolean",
                  "description": "Shared-address network: payout_tag is required."
                },
                "entregavel": {
                  "type": "boolean"
                }
              }
            }
          },
          "dropped": {
            "type": "array",
            "description": "Unavailable pairs and reasons, for example sem_par_usdt.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "string"
                },
                "network": {
                  "type": "string"
                },
                "motivo": {
                  "type": "string"
                }
              }
            }
          },
          "totals": {
            "type": "object",
            "additionalProperties": true
          },
          "stale": {
            "type": "boolean",
            "description": "true if the catalog was served from a fallback cache."
          }
        }
      },
      "Comissao": {
        "type": "object",
        "properties": {
          "disponivel_cents": {
            "type": "integer"
          },
          "creditado_cents": {
            "type": "integer"
          },
          "estornado_cents": {
            "type": "integer"
          },
          "sacado_cents": {
            "type": "integer"
          },
          "operacoes": {
            "type": "integer"
          },
          "ultimo_credito_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "moeda": {
            "type": "string"
          },
          "sandbox": {
            "type": "boolean"
          },
          "min_saque_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "US$20 converted at the CURRENT rate. null means no quote is available and withdrawal is refused."
          },
          "pode_sacar_agora": {
            "type": "boolean"
          },
          "ultimo_saque_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "proximo_saque_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "politica": {
            "type": "object"
          }
        },
        "required": [
          "disponivel_cents",
          "creditado_cents",
          "sacado_cents",
          "operacoes",
          "moeda",
          "sandbox",
          "pode_sacar_agora",
          "politica"
        ]
      },
      "ComissaoEvento": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "credito",
              "estorno",
              "saque",
              "saque_estorno"
            ]
          },
          "valor_cents": {
            "type": "integer",
            "description": "Signed amounts: credit +, reversal −, withdrawal −, withdrawal reversal +."
          },
          "sentido": {
            "type": "string",
            "enum": [
              "credito",
              "debito"
            ]
          },
          "origem_id": {
            "type": "string",
            "description": "ci_… identifier of the charge (credit/reversal) or withdrawal."
          },
          "base_cents": {
            "type": "integer"
          },
          "partner_fee_bps": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "motivo": {
            "type": [
              "string",
              "null"
            ]
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SaqueCripto": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Cobranca"
          },
          {
            "type": "object",
            "properties": {
              "settlement_status": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Credit/delivery state: sent means completed; incerto requires reconciliation. PIX payment and delivery are separate states.",
                "enum": [
                  "pending",
                  "sending",
                  "entregando",
                  "sent",
                  "incerto",
                  "failed",
                  null
                ]
              },
              "settlement_tx_hash": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "On-chain delivery hash, or internal identifier when delivery uses an exchange."
              },
              "fee_cents": {
                "type": "integer",
                "description": "House withdrawal fee debited in addition to amount_cents."
              },
              "debited_cents": {
                "type": "integer",
                "description": "amount_cents plus the house withdrawal fee."
              }
            }
          }
        ]
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "This key's requests-per-minute limit (= rate_limit_per_minute)."
      },
      "X-RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests remaining in the current rate-limit window."
      },
      "X-RateLimit-Reset": {
        "schema": {
          "type": "integer"
        },
        "description": "Seconds until the rate-limit bucket fully refills."
      },
      "Retry-After": {
        "schema": {
          "type": "integer"
        },
        "description": "HTTP 429 only: seconds to wait before retrying."
      }
    }
  },
  "security": [
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/leads": {
      "post": {
        "tags": [
          "Contato"
        ],
        "operationId": "contactIntegrationTeam",
        "summary": "Request human assistance for a commercial or technical question",
        "description": "Public route requiring no API key. Use for volume pricing, contracts, partnerships or a question not resolved by the documentation. The person must have provided the contact address for this request; do not discover, scrape or reuse email addresses collected for another purpose. To start without contacting anyone, use `POST /keys/sandbox`.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "consentimento"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 200
                  },
                  "nome": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "empresa": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "whatsapp": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "mensagem": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "fluxo": {
                    "type": "string",
                    "enum": [
                      "cashin",
                      "cashout",
                      "cashin_cashout",
                      "payout",
                      "outro",
                      "custody"
                    ]
                  },
                  "volume_mensal": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "prazo": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "estagio_produto": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "como_encontrou": {
                    "type": "string",
                    "description": "Source reported by the person, separate from UTM attribution. Examples: chatgpt, google, indicacao."
                  },
                  "consentimento": {
                    "type": "boolean",
                    "const": true,
                    "description": "Confirms that the person supplied their contact details to receive a response to this request."
                  },
                  "origem": {
                    "type": "string",
                    "description": "Page or context where the request began."
                  },
                  "utm_source": {
                    "type": "string"
                  },
                  "utm_medium": {
                    "type": "string"
                  },
                  "utm_campaign": {
                    "type": "string"
                  },
                  "utm_content": {
                    "type": "string"
                  },
                  "utm_term": {
                    "type": "string"
                  },
                  "ref_agent": {
                    "type": "string"
                  },
                  "website": {
                    "type": "string",
                    "description": "Honeypot. Legitimate clients must omit this field or send an empty value."
                  }
                }
              },
              "examples": {
                "empresa_vinda_do_chatgpt": {
                  "value": {
                    "email": "integracao@empresa.com.br",
                    "empresa": "Empresa Exemplo",
                    "fluxo": "cashin_cashout",
                    "volume_mensal": "R$ 250 mil a R$ 1 milhão",
                    "prazo": "Neste mês",
                    "como_encontrou": "chatgpt",
                    "consentimento": true,
                    "utm_source": "chatgpt",
                    "utm_medium": "answer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing contact updated within the deduplication window. With explicit consent, returns a new lead_token and invalidates the previous token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "lead_id": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "lead_token": {
                      "type": "string",
                      "pattern": "^ldt_[A-Za-z0-9_-]{43}$",
                      "minLength": 47,
                      "maxLength": 47,
                      "description": "Opaque attribution token returned with explicit consent. Send only in POST /keys, POST /keys/sandbox or lunium_start_sandbox_demo. Never place it in URLs or logs."
                    },
                    "detail": {
                      "type": "string"
                    },
                    "integration_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Start the self-service integration immediately; human contact is optional."
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Contact request received. With explicit consent, lead_token links this contact to a subsequently created key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "lead_id"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "lead_id": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "lead_token": {
                      "type": "string",
                      "pattern": "^ldt_[A-Za-z0-9_-]{43}$",
                      "minLength": 47,
                      "maxLength": 47,
                      "description": "Opaque attribution token returned with explicit consent. Send only in POST /keys, POST /keys/sandbox or lunium_start_sandbox_demo. Never place it in URLs or logs."
                    },
                    "detail": {
                      "type": "string"
                    },
                    "integration_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Start the self-service integration immediately; human contact is optional."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid email or request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts from the same address.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "Could not save the contact request. Try again or use the published contact email."
          }
        },
        "externalDocs": {
          "description": "Page for accessing sandbox and contacting the integration team",
          "url": "https://luniumpay.com/integrar?utm_source=openapi&utm_medium=spec"
        }
      }
    },
    "/v1/verificar/{e2e}": {
      "get": {
        "tags": [
          "Verificação"
        ],
        "operationId": "verificarPagamento",
        "security": [],
        "summary": "Verify a PIX payment publicly, without an API key",
        "description": "Check a payment independently of the sender's claim. No account or API key required.\n\nDoes not return the PIX key, full name or tax ID, avoiding disclosure of the parties' identity.\n\nA not-found response explicitly states that another institution may have processed the PIX. Absence here is not evidence that no payment occurred.",
        "parameters": [
          {
            "name": "e2e",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Central Bank identifier: E followed by 32 characters.",
            "example": "E37293930202607312006361894c4a82"
          }
        ],
        "responses": {
          "200": {
            "description": "Payment settled through Lunium.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verificado": {
                      "type": "boolean"
                    },
                    "pago": {
                      "type": "boolean"
                    },
                    "e2e": {
                      "type": "string",
                      "description": "Central Bank end-to-end identifier, echoed from the request: E followed by the receipt code. Any third party can verify it using this endpoint."
                    },
                    "valor_brl": {
                      "type": "string"
                    },
                    "pago_em": {
                      "type": "string",
                      "format": "date-time",
                      "example": "2026-08-01T22:35:49-03:00",
                      "description": "ISO 8601 timestamp with an explicit time-zone offset (Brasilia time). Do not assume UTC or the client's local time; read the supplied offset."
                    },
                    "recebedor_iniciais": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "instituicao": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "liquidado_por": {
                      "type": "string"
                    },
                    "comprovante_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not settled through Lunium; another institution may have processed it."
          },
          "400": {
            "description": "Invalid format."
          }
        },
        "x-lunium-capability": [
          "payment_verification"
        ],
        "x-lunium-intents": [
          "verify_payment",
          "prove_settlement"
        ],
        "x-lunium-agent-safe": true
      }
    },
    "/catalog": {
      "get": {
        "tags": [
          "Catálogo"
        ],
        "operationId": "obterCatalogo",
        "summary": "Currently supported assets, networks and settlement limits",
        "description": "Incoming crypto catalog for cash-out. Use the currently returned pairs, minimums, maximums and estimates instead of hardcoding networks. fast, convert and dex represent different settlement routes. Availability differs from the delivery catalog at /cashin/catalog. If acceptance returns deposit_tag, include it with the deposit. stale=true indicates fallback data.",
        "responses": {
          "200": {
            "description": "Current catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Catalogo"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/cash-outs": {
      "post": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "criarCotacao",
        "summary": "Request a quote (step 1 of 3)",
        "description": "Create a quote for external crypto to PIX. The deposit address is returned only after acceptance. Send exactly one of amount or brl_amount as a decimal string, and a pair from GET /catalog. Read key and per-operation limits in GET /keys/me and effective recipient limits in the response. The mandate may impose additional restrictions. Supply refund_address to control the destination of any refund. br_code has separate availability and may return 503 br_code_indisponivel even when preview or sandbox accepts it. Production returns 200 on creation; sandbox may return 201.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "asset",
                  "network",
                  "pix_key"
                ],
                "properties": {
                  "asset": {
                    "type": "string",
                    "examples": [
                      "USDT"
                    ],
                    "description": "Asset to sell. Use the EXACT id from GET /catalog (for example, \"usdt\"). The (asset, network) pair must exist in that catalog."
                  },
                  "network": {
                    "type": "string",
                    "description": "Incoming crypto network from GET /catalog. Do not confuse it with delivery networks from /cashin/catalog.",
                    "examples": [
                      "polygon"
                    ]
                  },
                  "amount": {
                    "type": "string",
                    "description": "Crypto quantity as a decimal string (`\"50\"`), never a floating-point number. Supply exactly one of `amount` or `brl_amount`.",
                    "examples": [
                      "50"
                    ]
                  },
                  "brl_amount": {
                    "type": "string",
                    "description": "REVERSE quote: desired PIX amount in BRL as a decimal string with up to two decimal places (`\"250.00\"`). Lunium calculates the crypto amount; the response's `amount` is what the customer must deposit. Supply exactly one of `amount` or `brl_amount`. Range: R$6.00–R$250,000.00 per transaction, also subject to the recipient's R$100,000.00 daily cap; the lower limit applies.",
                    "examples": [
                      "250.00"
                    ]
                  },
                  "pix_key": {
                    "type": "string",
                    "description": "PIX key receiving BRL. Accepted formats are normalized to the settlement provider's format: CPF (11 digits), CNPJ (14 digits), international phone +55 followed by area code and number (for example, +5548996005588), email or UUID random key (for example, 6602ede6-b1a9-4e63-9178-c6883fd0095e). Invalid formats return 400 pix_key_invalida before any deposit is created."
                  },
                  "pix_key_type": {
                    "type": "string",
                    "enum": [
                      "cpf",
                      "cnpj",
                      "phone",
                      "email",
                      "random"
                    ],
                    "description": "Optional: inferred from email, CNPJ, UUID or a +55 phone number. Required for 11 bare digits, where CPF and phone numbers cannot be distinguished. In that case the API returns tipo_ambiguo instead of guessing."
                  },
                  "token_address": {
                    "type": "string",
                    "description": "Exact token contract address or mint. Required for tokens from `/catalog/dex`, where symbols may be shared by different tokens."
                  },
                  "external_id": {
                    "type": "string",
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
                    "maxLength": 64
                  },
                  "refund_address": {
                    "type": "string",
                    "description": "Your customer's RETURN wallet on the same network as the sale. Used for refunds, such as provider rejection, PIX reversal or failure before payout. Always supply it: otherwise refunds go to the on-chain source of the deposit, which may be the exchange's wallet rather than the customer's own wallet.",
                    "examples": [
                      "0x51e3d44172868acc60d68ca99591ce4230bc75e0"
                    ]
                  },
                  "br_code": {
                    "type": "string",
                    "description": "PIX copy-and-paste string for a charge with a specified amount, when supported. USDT/USDC only; replaces pix_key, amount and brl_amount. May return 503 br_code_indisponivel in production.",
                    "examples": [
                      "00020126330014br.gov.bcb.pix0111498113948905204000053039865406…6304ABCD"
                    ]
                  }
                }
              },
              "examples": {
                "usdt": {
                  "summary": "USDT on Polygon",
                  "value": {
                    "asset": "USDT",
                    "network": "polygon",
                    "amount": "50",
                    "pix_key": "12345678901",
                    "pix_key_type": "cpf",
                    "refund_address": "0x51e3d44172868acc60d68ca99591ce4230bc75e0",
                    "external_id": "saque-4471"
                  }
                },
                "reverso": {
                  "summary": "Quote from a BRL amount (reverse quote)",
                  "value": {
                    "asset": "USDT",
                    "network": "polygon",
                    "brl_amount": "250.00",
                    "pix_key": "vendas@loja.com.br",
                    "external_id": "pedido-9921"
                  }
                },
                "cobranca": {
                  "summary": "Pay a PIX QR or copy-and-paste code with USDT/USDC on a catalog network",
                  "value": {
                    "asset": "USDC",
                    "network": "polygon",
                    "br_code": "00020126330014br.gov.bcb.pix0111498113948905204000053039865406…6304ABCD",
                    "refund_address": "0x51e3d44172868acc60d68ca99591ce4230bc75e0",
                    "external_id": "pedido-9922"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Quote created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashOut"
                }
              }
            }
          },
          "200": {
            "description": "Quote created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashOut"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unavailable network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "`external_id` was already used with different parameters."
          },
          "422": {
            "description": "Semantically invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-lunium-capability": [
          "usdt_to_pix",
          "usdc_to_pix",
          "crypto_to_pix"
        ],
        "x-lunium-intents": [
          "sell_crypto",
          "receive_fiat",
          "offramp",
          "cash_out"
        ],
        "x-lunium-reward-eligible": true
      },
      "get": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "listarCashOuts",
        "summary": "List orders",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Idempotent recovery: returns the operation with this external_id, if any (0 or 1). Unique per key and product, case-sensitive and retained permanently."
          }
        ],
        "responses": {
          "200": {
            "description": "Orders belonging to your key, newest first."
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/cash-outs/{cashout_id}/accept": {
      "post": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "aceitarCotacao",
        "summary": "Accept the quote and obtain a deposit address (step 2 of 3)",
        "description": "Lock the quote and receive `deposit_address`. Send EXACTLY the quoted crypto amount.\n\nIf the network requires a memo/tag, acceptance returns `deposit_tag`. Omitting it may prevent the deposit from being credited.",
        "parameters": [
          {
            "name": "cashout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deposit address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashOut"
                }
              }
            }
          },
          "404": {
            "description": "Order not found."
          },
          "422": {
            "description": "Quote expired or already accepted."
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/cash-outs/{cashout_id}": {
      "get": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "consultarCashOut",
        "summary": "Track the order (step 3 of 3)",
        "description": "Prefer webhooks. If polling, query every 10–15 seconds; once per second alone uses the key's 60-requests-per-minute allowance.\n\nWhen `state` is `COMPLETED`, `pix_e2e`, `pix_paid_at` and `receipt_url` are populated.",
        "parameters": [
          {
            "name": "cashout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashOut"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/cashin/charge": {
      "post": {
        "tags": [
          "Cash-in"
        ],
        "operationId": "criarCobranca",
        "summary": "Create a PIX charge for BRL custody or direct crypto delivery",
        "description": "Create a PIX charge for BRL custody (destino=saldo, no wallet required) or direct crypto delivery (destino=cripto, the default). Supply the payer's tax ID. Check GET /cashin/limits and key-specific conditions. Fees, limits and the provider determine the effective minimum; creation revalidates them. Holds may apply at the provider (held_hours/delay_until) or locally (hold_hours/liberar_em). A paid PIX does not prove completed delivery or credit: track settlement_status and the statement. Sandbox creates a non-payable QR; confirm it with POST /sandbox/cashin/{cashin_id}/pay. No bank transaction occurs.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents",
                  "payer_tax_number"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "description": "Charge amount as integer BRL CENTS (for example, 15000 = R$150.00). Read GET /cashin/limits before creation for the payer's current instant and held-payment bands.",
                    "examples": [
                      25000
                    ]
                  },
                  "chain": {
                    "type": "string",
                    "default": "polygon",
                    "description": "Delivery route network. Supply the catalog's network value in this chain field."
                  },
                  "asset": {
                    "type": "string",
                    "default": "usdt",
                    "description": "Deliverable asset from GET /cashin/catalog; not limited to stablecoins."
                  },
                  "payout_address": {
                    "type": "string",
                    "description": "Per-charge wallet for destino=cripto. If omitted, the key's settlement_address may be used. Omit for destino=saldo. The address must match the selected network."
                  },
                  "payer_tax_number": {
                    "type": "string",
                    "description": "Payer's CPF (11 digits) or CNPJ (14 digits), digits only. Identifies the payer for anti-fraud limits and holds published by GET /cashin/limits."
                  },
                  "external_id": {
                    "type": "string",
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
                    "maxLength": 64
                  },
                  "destino": {
                    "type": "string",
                    "enum": [
                      "cripto",
                      "saldo"
                    ],
                    "default": "cripto",
                    "description": "saldo credits BRL custody net of fees without requiring a wallet. cripto (default) delivers to the supplied or configured wallet. Read fees and waiting periods in GET /saldo, and holds in the charge/status response."
                  },
                  "customer_ref": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Optional sub-account of the balance (your end customer id). With `destino: \"saldo\"`, the credit lands on this sub-account; GET /saldo?customer_ref= reads it and POST /payouts with the same `customer_ref` spends it. Omit to use the key's main balance."
                  },
                  "allow_hold": {
                    "type": "boolean",
                    "default": true,
                    "description": "false rejects the charge when payer rules require a hold. It does not remove other key holds or freezes. true or omission allows the applicable hold. Read both held_hours AND hold_hours/liberar_em."
                  },
                  "payout_tag": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Destination memo/tag. REQUIRED on shared-address networks such as XRP, XLM, TON, ATOM, HBAR, ALGO, EOS, KAVA and LUNA, where it identifies the recipient. If missing or invalid, the API returns 400 `memo_obrigatorio` before creating a charge. For XRP, the destination tag is an integer from 0 to 4294967295. Accepted aliases: `memo`, `tag`, `destination_tag`. The catalog marks these routes with `memoRequired: true`."
                  },
                  "payer_name": {
                    "type": "string",
                    "description": "Payer's name, when supplied."
                  },
                  "sandbox_scenario": {
                    "type": "string",
                    "enum": [
                      "success",
                      "delayed",
                      "held",
                      "expired",
                      "refunded",
                      "failed",
                      "payer_mismatch",
                      "settlement_failed",
                      "settlement_uncertain",
                      "route_unavailable",
                      "provider_unavailable"
                    ],
                    "description": "Only for a sandbox key. GET /sandbox provides the scenario matrix by flow. Omit in production. All prices, payments and withdrawals remain fictitious."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Charge created. Display qr_copypaste as the PIX payment code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cobranca"
                }
              }
            }
          },
          "403": {
            "description": "Payer limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters, amount outside the limits or cash-in disabled for this key. `valor_abaixo_do_minimo`: selected asset/network has a route-specific minimum; minimo_estimado_cents indicates an estimated starting amount, checked before funds are moved. `memo_obrigatorio`: required memo/tag missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "502": {
            "description": "No charge was created. Inspect the error code and action: `provedor_indisponivel` with `repetir` or `esperar` indicates a transient settlement-provider failure; retry the SAME request with the same external_id after waiting. `config_provedor` with `falar_com_suporte` indicates invalid provider configuration on our side, such as a PIX key, credential or account. Waiting or retrying does not resolve that error; contact support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "503": {
            "description": "catalogo_indisponivel / cotacao_indisponivel: an exchange quote is temporarily unavailable; retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "Conflicting external_id parameters."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-lunium-capability": [
          "pix_to_usdt",
          "pix_to_usdc"
        ],
        "x-lunium-intents": [
          "buy_crypto",
          "onramp",
          "fiat_to_crypto"
        ],
        "x-lunium-reward-eligible": true
      }
    },
    "/keys": {
      "post": {
        "tags": [
          "Conta"
        ],
        "operationId": "criarChave",
        "security": [],
        "summary": "Create an API key (self-service)",
        "description": "The full key is returned only ONCE at creation; save it immediately. Only its hash is stored. The response also includes links to groups where API contract changes are announced.",
        "responses": {
          "201": {
            "description": "API key created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_key": {
                      "type": "string",
                      "description": "Plaintext API key, returned ONLY in this creation response. Only its hash is stored."
                    },
                    "email_sent": {
                      "type": "boolean",
                      "description": "true when a copy of the key was sent to the supplied `email`; false when no email was provided or sending failed."
                    },
                    "webhook_secret": {
                      "type": "string",
                      "description": "Present when webhook_url was supplied."
                    },
                    "key": {
                      "type": "object",
                      "description": "Public key metadata: prefix, name and feature flags."
                    },
                    "limits": {
                      "type": "object",
                      "description": "Current limits."
                    },
                    "monitor_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Private read-only live monitor for this key's operations."
                    },
                    "lead_attribution": {
                      "type": "object",
                      "description": "Attribution result when a consented lead_token is supplied. Attribution never blocks key creation.",
                      "required": [
                        "requested",
                        "linked",
                        "status"
                      ],
                      "properties": {
                        "requested": {
                          "type": "boolean",
                          "description": "true if lead_token was supplied in the request body."
                        },
                        "linked": {
                          "type": "boolean",
                          "description": "true if the key was linked to a contact with consent."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "nao_solicitado",
                            "vinculado",
                            "token_invalido",
                            "indisponivel"
                          ],
                          "description": "Attribution link status."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields: name is required and webhook_url must be a public HTTPS URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "API-key creation limit for this IP address reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80,
                    "description": "Business name, displayed in the dashboard and notifications."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Recommended. The newly created key is emailed to this address as well as returned in the response."
                  },
                  "settlement_address": {
                    "type": "string",
                    "description": "EVM settlement wallet on Polygon. Optional; may be configured later."
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS webhook URL. Optional."
                  },
                  "lead_token": {
                    "type": "string",
                    "pattern": "^ldt_[A-Za-z0-9_-]{43}$",
                    "minLength": 47,
                    "maxLength": 47,
                    "description": "Opaque `ldt_…` token returned by POST /leads when the person consented to technical contact. Links this key to the lead. Request body only, never the URL. Optional; a missing or invalid token does not prevent key creation."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/keys/me": {
      "get": {
        "tags": [
          "Conta"
        ],
        "operationId": "consultarConta",
        "summary": "Current limits and daily usage",
        "description": "Read current limits here instead of hardcoding them.\n\n**Cash-out (selling crypto):** R$6.00–R$250,000.00 per transaction, plus a R$100,000.00 daily cap for the recipient's CPF/CNPJ (per PIX key when the key is not a tax ID), resetting at midnight in Brasilia time. The effective maximum is the LOWER of the two and appears in `limits.max_brl_cents`; the per-transaction cap is `limits.max_brl_cents_por_transacao`. There is no general daily API-key cap on crypto sales.\n\n**Cash-in and payouts:** since 2026-09-10 there is no general daily API-key cap: `limits.daily_limit_cents`, `limits.available_today_cents` and `limits.next_tier` are null, `limits.tier` is `\"Sem teto\"` (no daily cap), and `limits.daily_limit_applies_to` is `[]`. Each charge ranges from R$1.00 to R$6,000.00, subject to the effective minimum in `limits.per_operation.cashin.min_brl_cents` and the payer ladder in GET /cashin/limits. A key may impose its own daily cap through `mandate.max_diario_cents`.",
        "responses": {
          "200": {
            "description": "Your key and limits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChaveMe"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update key settings, settlement wallet, webhook or tokens",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "settlement_address": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Polygon address beginning with 0x; null clears it."
                  },
                  "webhook_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Public HTTPS URL; null clears it. Setting it generates webhook_secret if the key does not yet have one."
                  },
                  "rotate_webhook_secret": {
                    "type": "boolean",
                    "description": "true rotates the webhook secret. The new secret is returned ONCE in the response."
                  },
                  "rotate_monitor_token": {
                    "type": "boolean",
                    "description": "true rotates the monitor token. The old URL immediately stops exposing data; the replacement is returned in monitor_url."
                  },
                  "partner_fee_bps": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000,
                    "description": "Partner fee in basis points, added to Lunium's fee and paid by the end customer (100 = 1%; maximum 1000 = 10%). Applies to NEW charges only; existing charges retain their locked fee. 0 disables it."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key updated. May include a webhook_secret returned once and a replacement monitor_url."
          },
          "400": {
            "description": "Invalid fields or nothing to update.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "updateMyKey"
      }
    },
    "/ping": {
      "get": {
        "tags": [
          "Conta"
        ],
        "operationId": "ping",
        "security": [],
        "summary": "API health check",
        "responses": {
          "200": {
            "description": "pong"
          }
        }
      }
    },
    "/keys/sandbox": {
      "post": {
        "summary": "Get a sandbox API key — one call, no API key needed",
        "description": "Returns a lun_test_ key without email or wallet. All six financial journeys are simulated with fictitious funds using the normal endpoints. GET /sandbox returns the supported flows, scenario matrix and simulation controls. POST /sandbox/cashin/{cashin_id}/pay confirms a non-payable test charge. Cash-in, custody and payouts are durable; cash-out retention is two hours. Signed webhooks use the normal delivery pipeline with sandbox:true. No financial provider is called. Catalogs and prices are synthetic snapshots, not live quotes. See https://docs.luniumpay.com/en/sandbox .",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Optional label to recognise the key later."
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Optional HTTPS webhook."
                  },
                  "lead_token": {
                    "type": "string",
                    "pattern": "^ldt_[A-Za-z0-9_-]{43}$",
                    "description": "Optional opaque token returned by consented POST /leads. Links this TEST key to the contact. Invalid or unavailable attribution never blocks key creation. Never put this token in a URL or log."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sandbox key created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_key": {
                      "type": "string",
                      "example": "lun_test_1df82296e3459819702c6a6087aab1c7"
                    },
                    "sandbox": {
                      "type": "boolean",
                      "const": true
                    },
                    "gatilhos": {
                      "type": "object",
                      "description": "The deterministic triggers, described above."
                    },
                    "diferencas_para_producao": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "lead_link": {
                      "type": "object",
                      "properties": {
                        "requested": {
                          "type": "boolean"
                        },
                        "linked": {
                          "type": "boolean"
                        },
                        "status": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many keys from this IP today",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "createSandboxKey"
      }
    },
    "/cashin/limits": {
      "get": {
        "summary": "How much this taxpayer can pay right now",
        "description": "Advisory CPF/CNPJ limits, usage and instant/held-payment bands. Creation revalidates key conditions, including instant custody. max_amount_cents does not replace fee minimums, route/provider constraints or contractual gates. Provider or local holds may apply; read held_hours, hold_hours and liberar_em in the charge response. Do not hardcode the ladder in your client.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "payer_tax",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]{11}|[0-9]{14})$"
            },
            "description": "CPF (11 digits) or CNPJ (14 digits), digits only."
          }
        ],
        "responses": {
          "200": {
            "description": "Current ladder state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payer_tax": {
                      "type": "string",
                      "description": "Masked back to you, never in full."
                    },
                    "stage": {
                      "enum": [
                        "first_transaction",
                        "first_24h",
                        "mature",
                        "disabled",
                        "desconhecido"
                      ]
                    },
                    "max_amount_cents": {
                      "type": "integer",
                      "description": "Advisory maximum for this tax ID, including possible holds. Creation revalidates the key, minimums and availability."
                    },
                    "used_cents": {
                      "type": "integer"
                    },
                    "available_cents": {
                      "type": [
                        "integer",
                        "null"
                      ],
                      "description": "Amount still eligible for instant clearing without a hold at the current stage. Alias: instant_available_cents. null when the limit rule is disabled (stage=disabled)."
                    },
                    "limit_cents": {
                      "type": [
                        "integer",
                        "null"
                      ],
                      "description": "null when the limit rule is disabled (stage=disabled)."
                    },
                    "next_stage": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "When the ceiling rises and to what."
                    },
                    "instant_available_cents": {
                      "type": "integer",
                      "description": "Same as available_cents — what clears instantly, spelled out."
                    },
                    "held_qr": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Held-payment band conditions, when applicable. Funds may be held by the provider or through a local charge hold. Read the creation/status response.",
                      "properties": {
                        "stage": {
                          "type": "string",
                          "enum": [
                            "held_qr"
                          ]
                        },
                        "max_amount_cents": {
                          "type": "integer"
                        },
                        "used_cents": {
                          "type": "integer",
                          "description": "Paid + in-flight in the last 24h."
                        },
                        "available_cents": {
                          "type": "integer"
                        },
                        "hold_hours": {
                          "type": "integer"
                        },
                        "explicacao": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "getCashinLimits"
      }
    },
    "/cashin/{cashin_id}/status": {
      "get": {
        "summary": "State of a PIX charge",
        "description": "Track PIX payment and credit/delivery separately. paid alone does not prove crypto delivery or available balance. settlement_status=sent completes credit/delivery; for custody also check available and blocked balance. delayed represents a provider hold; paid with liberar_em may indicate a local hold. Do not request another payment because delivery is still pending. Prefer webhooks; polling must respect the key's rate limit.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "cashin_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current state with a server-timestamped timeline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusCobranca"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "getPixChargeStatus"
      }
    },
    "/payouts": {
      "post": {
        "summary": "Send a PIX directly (no crypto leg)",
        "description": "Send PIX using available house or customer_ref subaccount balance. Check payout.enabled in GET /keys/me, and custodia_ativa and fees in GET /saldo. Amount plus fees are reserved before calling the provider. Insufficient balance returns 402. Provider fees may be fixed or percentage-based; read current conditions and reconcile the operation's fee_cents. Limits and the key's mandate still apply. Use a stable external_id; after a timeout, query the original operation. Sandbox supports payouts from previously credited fictitious balance and uses a synthetic provider fee of 100 BRL cents.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Payout amount as integer BRL CENTS (for example, 5000 = R$50.00)."
                  },
                  "pix_key": {
                    "type": "string",
                    "description": "Destination PIX key: CPF, CNPJ, +55 phone number, email or random key. For 11 bare digits, also send pix_key_type (\"cpf\" or \"phone\"); otherwise the API returns erro=tipo_ambiguo instead of guessing."
                  },
                  "pix_key_type": {
                    "enum": [
                      "cpf",
                      "cnpj",
                      "phone",
                      "email",
                      "random"
                    ],
                    "description": "Optional: inferred from email, CNPJ, UUID or a +55 phone number. Required for 11 bare digits, where CPF and phone numbers cannot be distinguished. In that case the API returns tipo_ambiguo instead of guessing."
                  },
                  "tax_number": {
                    "type": "string",
                    "description": "Optional. CPF or CNPJ of the beneficiary, digits only. Forwarded to the provider only when sent."
                  },
                  "beneficiary_name": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Optional. Beneficiary's full name, forwarded to the PIX provider as the end user's name. Not required — payouts to third-party PIX keys are allowed."
                  },
                  "external_id": {
                    "type": "string",
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict.",
                    "maxLength": 64
                  },
                  "customer_ref": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Sub-account to debit (custody keys). Debited BEFORE the PIX is sent: amount + house fee (`saque_fee_bps`) + provider fee; on explicit provider refusal the debits are reversed. 402 `saldo_insuficiente` when available balance < amount + fees (`saque_fee_bps`, `saque_taxa_estimada_cents` in GET /saldo). Sub-account (e.g. the merchant) whose balance is debited. Same value used on the deposit."
                  },
                  "sandbox_scenario": {
                    "type": "string",
                    "enum": [
                      "success",
                      "delayed",
                      "held",
                      "expired",
                      "refunded",
                      "failed",
                      "payer_mismatch",
                      "settlement_failed",
                      "settlement_uncertain",
                      "route_unavailable",
                      "provider_unavailable"
                    ],
                    "description": "Only for a sandbox key. GET /sandbox provides the scenario matrix by flow. Omit in production. All prices, payments and withdrawals remain fictitious."
                  }
                },
                "required": [
                  "amount_cents",
                  "pix_key"
                ]
              }
            }
          }
        },
        "responses": {
          "403": {
            "description": "Administrative kill switch or `custodia_desligada`. Production keys are enabled by default; if this response appears, stop and contact support instead of retrying. No PIX was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "external_id already used with different parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "423": {
            "description": "carencia_primeiro_deposito — first-deposit hold (only keys with a contractual holding period; none by default since 2026-09-16): no withdrawal for this sub-account until `libera_em`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "erro": {
                      "type": "string",
                      "enum": [
                        "carencia_primeiro_deposito"
                      ]
                    },
                    "acao": {
                      "type": "string",
                      "enum": [
                        "esperar"
                      ]
                    },
                    "detail": {
                      "type": "string"
                    },
                    "libera_em": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`saque_indisponivel`: the funds used to finance PIX payouts do not currently cover this withdrawal. Nothing is debited and no order is created. Retry later or request a smaller amount. The response includes disponivel_para_saque_cents when it can be calculated."
          },
          "200": {
            "description": "Payout created, or idempotent replay of the original operation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            }
          },
          "400": {
            "description": "Refusal or failure. Read erro, acao and detail when present.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "402": {
            "description": "Refusal or failure. Read erro, acao and detail when present.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "500": {
            "description": "Refusal or failure. Read erro, acao and detail when present.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "createPixPayout"
      },
      "get": {
        "summary": "List payouts for this key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "processing",
                "sent",
                "failed",
                "refunded"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Idempotent recovery: returns the operation with this external_id, if any (0 or 1). Unique per key and product, case-sensitive and retained permanently."
          }
        ],
        "responses": {
          "200": {
            "description": "List, newest first. An empty list returns 200, never 403.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payouts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payout"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Payouts are not enabled for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "listPixPayouts"
      }
    },
    "/payouts/{payout_id}": {
      "get": {
        "summary": "State of a payout",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "payout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Withdrawal state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "getPixPayout"
      }
    },
    "/webhooks/deliveries": {
      "get": {
        "summary": "Webhook delivery history for this key",
        "description": "Diagnose what was sent, what failed and why. Does not return the event body; use retry to resend the original body.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "sent",
                "failed"
              ]
            }
          },
          {
            "name": "event",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "cashin.paid",
                "cashin.delayed",
                "cashin.held",
                "cashin.settled",
                "cashin.settlement_failed",
                "cashin.expired",
                "cashin.refunded",
                "cashin.failed",
                "cashout.awaiting_deposit",
                "cashout.deposit_detected",
                "cashout.confirming",
                "cashout.processing",
                "cashout.under_review",
                "cashout.refunding",
                "cashout.completed",
                "cashout.refunded",
                "cashout.expired",
                "cashout.failed",
                "payout.sent",
                "payout.failed",
                "payout.refunded",
                "webhook.test",
                "saldo.liberado",
                "saldo.congelado",
                "saldo.transferido"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deliveries, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntregaWebhook"
                      }
                    },
                    "failed_count": {
                      "type": "integer",
                      "description": "Number of deliveries in this response that exhausted their attempts."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "listWebhookDeliveries"
      }
    },
    "/webhooks/deliveries/{event_id}/retry": {
      "post": {
        "summary": "Retry an event delivery",
        "description": "Attempt delivery immediately and return the result. If unsuccessful, return the delivery to the queue with 12 new attempts. Refuses to resend a delivery already acknowledged with 2xx.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivered immediately.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event_id": {
                      "type": "string"
                    },
                    "delivered": {
                      "type": "boolean",
                      "const": true
                    },
                    "status_code": {
                      "type": "integer"
                    },
                    "ms": {
                      "type": "integer"
                    },
                    "delivery_id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Not delivered immediately; returned to the retry queue."
          },
          "404": {
            "description": "Not found for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "Already delivered; replaying would duplicate delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "retryWebhookDelivery"
      }
    },
    "/webhooks/test": {
      "post": {
        "summary": "Send a webhook test event now",
        "description": "Send `webhook.test` to your webhook_url using the SAME transport as production and return your endpoint's HTTP status and latency. No funds move and nothing is queued. Use before the first real charge. Limited to six tests per minute.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your endpoint returned 2xx.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "event_id": {
                      "type": "string"
                    },
                    "delivery_id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "status_code": {
                      "type": "integer"
                    },
                    "ms": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "webhook_url is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "More than six tests per minute.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "502": {
            "description": "Your endpoint did not return 2xx. The response body describes what happened.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "testWebhook"
      }
    },
    "/cashin/charges": {
      "get": {
        "summary": "List or recover cash-in charges for this key",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Idempotent recovery: returns the operation with this external_id, if any (0 or 1). Unique per key and product, case-sensitive and retained permanently."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "charges": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Cobranca"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Listing requires X-API-Key; it is not public.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "listPixCharges"
      }
    },
    "/cashin/preview": {
      "post": {
        "summary": "Preview a cash-in conversion without creating a charge",
        "description": "Estimate PIX/BRL conversion for a delivery route. Does not create a QR or lock the exchange rate until payment. Read min_brl_cents and route-specific fields. This is not a complete custody withdrawal preview: the house withdrawal fee is additional.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "BRL amount in integer cents. The effective minimum depends on the key, fees and route. Read GET /keys/me and returned min_brl_cents/limits; do not hardcode the example minimum."
                  },
                  "asset": {
                    "type": "string",
                    "default": "usdt",
                    "description": "Deliverable asset from GET /cashin/catalog; not limited to stablecoins."
                  },
                  "chain": {
                    "type": "string",
                    "default": "polygon",
                    "description": "Delivery route network. Supply the catalog's network value in this chain field."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote with the key's fee applied.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "asset": {
                          "type": "string",
                          "description": "Settlement stablecoin, echoed from the request."
                        },
                        "amount_cents": {
                          "type": "integer",
                          "description": "Charge amount in cents, echoed from the request."
                        },
                        "admin_fee_bps": {
                          "type": "integer"
                        },
                        "admin_fee_fixed_cents": {
                          "type": "integer"
                        },
                        "fee_total_cents": {
                          "type": "integer",
                          "description": "ALL deductions from the gross amount: fixed fee + Lunium percentage fee + partner fee. Invariant: fee_total_cents + net_cents == amount_cents. Read lunium_fee_cents and partner_fee_cents for the allocation."
                        },
                        "net_cents": {
                          "type": "integer",
                          "description": "Net amount converted to crypto for the end customer, after any partner fee."
                        },
                        "brl_per_usdt": {
                          "type": "string",
                          "description": "Exchange rate rounded for display. Delivery uses the full-precision rate."
                        },
                        "usdt_amount": {
                          "type": "string",
                          "description": "Net delivered quantity, the source of truth."
                        },
                        "partner_fee_bps": {
                          "type": "integer",
                          "description": "Partner fee applied to this quote, in basis points. 0 means disabled."
                        },
                        "lunium_fee_cents": {
                          "type": "integer",
                          "description": "Lunium's share: fixed plus percentage fee. Equals fee_total_cents when there is no partner fee."
                        },
                        "partner_fee_cents": {
                          "type": "integer",
                          "description": "Partner's share, credited as commission when crypto is delivered. Calculated as the remainder after a single floor operation; adding the partner fee does not change Lunium's share."
                        },
                        "sandbox": {
                          "const": false
                        }
                      }
                    },
                    {
                      "type": "object",
                      "description": "Isolated sandbox quote using synthetic rates and route withdrawal fees without calling a provider. fee_bps and fee_fixed_cents are simulation fees, not a production quote.",
                      "required": [
                        "sandbox",
                        "synthetic",
                        "amount_cents",
                        "min_brl_cents",
                        "fee_bps",
                        "fee_fixed_cents",
                        "partner_fee_bps",
                        "asset",
                        "chain",
                        "usdt_amount",
                        "asset_amount",
                        "withdraw_fee",
                        "withdraw_min",
                        "brl_per_usdt",
                        "brl_per_asset"
                      ],
                      "properties": {
                        "sandbox": {
                          "const": true
                        },
                        "synthetic": {
                          "const": true
                        },
                        "amount_cents": {
                          "type": "integer"
                        },
                        "min_brl_cents": {
                          "type": "integer"
                        },
                        "fee_bps": {
                          "type": "integer"
                        },
                        "fee_fixed_cents": {
                          "type": "integer"
                        },
                        "partner_fee_bps": {
                          "type": "integer"
                        },
                        "asset": {
                          "type": "string"
                        },
                        "chain": {
                          "type": "string"
                        },
                        "usdt_amount": {
                          "type": "string"
                        },
                        "asset_amount": {
                          "type": "string"
                        },
                        "withdraw_fee": {
                          "type": "string"
                        },
                        "withdraw_min": {
                          "type": "string"
                        },
                        "brl_per_usdt": {
                          "type": "number"
                        },
                        "brl_per_asset": {
                          "type": "number"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Amount outside the key's limits or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        },
        "operationId": "previewPixCharge"
      }
    },
    "/pix/keys/lookup": {
      "get": {
        "operationId": "consultarTitularChavePix",
        "summary": "Look up the PIX account holder when verification is available",
        "description": "Auxiliary holder lookup. When disabled, returns HTTP 200 with verified=false, available=false, verification_status=not_performed, source=disabled and null holder details. Payments remain available. When enabled, returns DICT data subject to caching and rate limits. Sandbox returns a fictitious holder with source=sandbox. HTTP 200 alone does not prove holder verification. Supply an explicit type when known.",
        "tags": [
          "Pix"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "PIX key: CPF, CNPJ, email, phone with or without +55, or random key.",
            "examples": {
              "email": {
                "value": "vendas@loja.com.br"
              },
              "telefone": {
                "value": "+5511987654321"
              }
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "cpf",
                "cnpj",
                "phone",
                "email",
                "random"
              ]
            },
            "description": "Optional. Inferred from the format when omitted."
          }
        ],
        "responses": {
          "200": {
            "description": "Account holder found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TitularPix"
                }
              }
            }
          },
          "400": {
            "description": "Invalid PIX key format (`pix_key_invalida`) or missing key (`pix_key_obrigatoria`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "PIX key does not exist in DICT (`chave_nao_encontrada`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Account limit of five lookups per minute (`limite_consultas`). Read Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "503": {
            "description": "DICT provider unavailable (`provedor_indisponivel`, retry) or lookup disabled (`consulta_indisponivel`, wait).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/saldo": {
      "get": {
        "tags": [
          "Conta"
        ],
        "summary": "BRL balance (custody) — available, on hold, next releases",
        "description": "BRL balance for the house or a customer_ref subaccount. Returns available and blocked amounts, upcoming releases and effective custody conditions. Fees and waiting periods depend on the key. Local charge holds, provider holds and balance waiting periods are separate rules. Only disponivel_cents can fund withdrawals; GET /saldo/consolidado combines house and customer balances. Sandbox returns persistent fictitious balances and supports simulated deposits, withdrawals and transfers.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "customer_ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Sub-account (your end customer id). Omit for the key's main balance."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "disponivel_cents",
                    "bloqueado_cents",
                    "total_cents"
                  ],
                  "properties": {
                    "customer_ref": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "maxLength": 80
                    },
                    "disponivel_cents": {
                      "type": "integer"
                    },
                    "bloqueado_cents": {
                      "type": "integer"
                    },
                    "total_cents": {
                      "type": "integer"
                    },
                    "movimentos": {
                      "type": "integer"
                    },
                    "proximas_liberacoes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "disponivel_em": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "valor_cents": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "custodia_ativa": {
                      "type": "boolean",
                      "description": "false = this key cannot hold BRL (destino \"saldo\" is refused)."
                    },
                    "carencia_horas": {
                      "type": "integer",
                      "description": "Waiting period configured for this key; zero for instant-balance keys. Charge holds and blocked credits remain independent."
                    },
                    "deposito_fee_bps": {
                      "type": "integer",
                      "description": "Effective deposit fee in basis points, deducted when crediting the balance."
                    },
                    "saque_taxa_estimada_cents": {
                      "type": "integer",
                      "description": "Fixed provider fee or estimated fee floor. For percentage-based fees, apply saque_taxa_provedor_formula. This is not the total fee for every withdrawal."
                    },
                    "saque_fee_bps": {
                      "type": "integer",
                      "description": "House withdrawal fee in basis points. Read this key's conditions; 100 bps = 1%."
                    },
                    "saque_cripto_fee_bps": {
                      "type": "integer",
                      "description": "House withdrawal fee in basis points. Read this key's conditions; 100 bps = 1%."
                    },
                    "primeiro_deposito_em": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time",
                      "description": "When the first deposit of this sub-account was credited (null = never deposited)."
                    },
                    "carencia_ate": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time",
                      "description": "End of the first-deposit waiting period when active; otherwise null. Also read bloqueado_cents and proximas_liberacoes."
                    },
                    "retencao_acima_cents": {
                      "type": "integer",
                      "description": "Policy threshold for the first eligible custody payment. Does not imply a hold on every deposit above this amount; payer rules and key settings also apply."
                    },
                    "deposito_fee_fixed_cents": {
                      "type": [
                        "integer",
                        "null"
                      ],
                      "description": "Effective fixed portion of the deposit fee, in BRL cents."
                    },
                    "saque_taxa_provedor_formula": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Current formula: fixed (piso_cents) or percentage with a floor. Do not assume one provider is always active."
                    },
                    "saque_taxa_provedor_tipo": {
                      "type": "string",
                      "enum": [
                        "fixo",
                        "percentual"
                      ],
                      "description": "Current payout-provider fee type."
                    },
                    "saque_taxa_provedor_piso_cents": {
                      "type": "integer",
                      "description": "Fixed fee or floor of a percentage-based fee, in BRL cents."
                    },
                    "sandbox": {
                      "type": "boolean",
                      "description": "true in the reduced test response."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key"
          }
        },
        "operationId": "getBalance"
      }
    },
    "/saldo/extrato": {
      "get": {
        "tags": [
          "Conta"
        ],
        "summary": "Balance statement (movements, newest first)",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "customer_ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "movimentos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "valor_cents": {
                            "type": "integer"
                          },
                          "sentido": {
                            "type": "string",
                            "enum": [
                              "credito",
                              "debito"
                            ]
                          },
                          "tipo": {
                            "type": "string",
                            "enum": [
                              "cashin",
                              "payout",
                              "cashout",
                              "estorno",
                              "ajuste"
                            ]
                          },
                          "origem_tipo": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "origem_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "disponivel_em": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "disponivel": {
                            "type": "boolean"
                          },
                          "descricao": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "criado_em": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "proxima_pagina": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key"
          }
        },
        "operationId": "getBalanceStatement"
      }
    },
    "/saldo/sacar-cripto": {
      "post": {
        "tags": [
          "Conta"
        ],
        "summary": "Withdraw BRL balance as crypto to a self-custodial wallet",
        "description": "Convert available BRL balance to crypto. Select a route with entregavel=true from GET /cashin/catalog and supply a wallet and memo per withdrawal; no fixed wallet is needed. Liquid/DePix are not supported. Debits amount_cents plus the house fee before delivery; conversion and route costs affect the final crypto quantity. Track cashin_id at GET /cashin/{cashin_id}/status. Shares the external_id namespace with charges. There is no public withdrawal-preview endpoint.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents",
                  "payout_address",
                  "tax_number"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 100,
                    "description": "BRL amount in integer cents. The effective minimum depends on the key, fees and route. Read GET /keys/me and returned min_brl_cents/limits; do not hardcode the example minimum."
                  },
                  "chain": {
                    "type": "string",
                    "default": "polygon",
                    "description": "Network (aliases accepted: sol, trc20, erc20, bep20, arbitrum, base…)."
                  },
                  "asset": {
                    "type": "string",
                    "default": "usdt",
                    "description": "Asset code in lowercase (usdt, usdc, btc, eth, sol…), as listed by GET /cashin/catalog."
                  },
                  "payout_address": {
                    "type": "string",
                    "description": "Destination wallet, validated for the network."
                  },
                  "tax_number": {
                    "type": "string",
                    "description": "CPF (11 digits) or CNPJ (14) of the customer who owns the balance."
                  },
                  "customer_ref": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Sub-account to debit. Omit for the key's main balance."
                  },
                  "external_id": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict."
                  },
                  "payout_tag": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Destination memo/tag. REQUIRED on shared-address networks such as XRP, XLM, TON, ATOM, HBAR, ALGO, EOS, KAVA and LUNA, where it identifies the recipient. Missing or invalid values return 400 `memo_obrigatorio` before creation. For XRP, the destination tag is an integer from 0 to 4294967295. Accepted aliases: `memo`, `tag`, `destination_tag`. Catalog routes requiring it have `memoRequired: true`."
                  },
                  "max_debited_cents": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional cap on the BRL debit: amount plus house fee. Exceeding it returns 409 taxa_alterada. Does not lock the exchange rate or token quantity."
                  },
                  "sandbox_scenario": {
                    "type": "string",
                    "enum": [
                      "success",
                      "delayed",
                      "held",
                      "expired",
                      "refunded",
                      "failed",
                      "payer_mismatch",
                      "settlement_failed",
                      "settlement_uncertain",
                      "route_unavailable",
                      "provider_unavailable"
                    ],
                    "description": "Only for a sandbox key. GET /sandbox provides the scenario matrix by flow. Omit in production. All prices, payments and withdrawals remain fictitious."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Debited and queued for delivery. Same view as POST /cashin/charge (cashin_id, status = `paid` — the balance is the payment —, chain, asset, payout_address, amount_cents, settlement_status, settlement_tx_hash) plus `fee_cents` (house fee debited), `debited_cents` (amount + fee), `fonte: \"saldo\"`, `destino: \"cripto\"`, `customer_ref`. Follow `settlement_status` on GET /cashin/{cashin_id}/status until `sent`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaqueCripto"
                }
              }
            }
          },
          "400": {
            "description": "rede_indisponivel | asset_invalido | payout_address_invalido | documento_invalido | valor_abaixo_do_minimo. `memo_obrigatorio` means the required memo/tag is missing or invalid."
          },
          "402": {
            "description": "saldo_insuficiente — available < amount + fee. Body carries `saldo` and `fee_cents`."
          },
          "409": {
            "description": "external_id_divergente"
          },
          "423": {
            "description": "carencia_primeiro_deposito — first-deposit hold (only keys with a contractual holding period); `libera_em` says when."
          },
          "503": {
            "description": "entrega_indisponivel — no stock/route to deliver right now; nothing was debited."
          }
        },
        "operationId": "withdrawBalanceToCrypto"
      }
    },
    "/mesh": {
      "get": {
        "tags": [
          "Mesh · Discovery"
        ],
        "operationId": "meshDiscovery",
        "summary": "Everything an agent needs before integrating",
        "description": "One public GET describes Lunium, settlement capabilities, assets, networks, endpoints, key creation, production activation, limits and schemas. No credential required.",
        "security": [],
        "x-lunium-agent-safe": true,
        "x-lunium-environment": "any",
        "responses": {
          "200": {
            "description": "Discovery document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeshDiscovery"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/economy": {
      "get": {
        "tags": [
          "Mesh · Economy"
        ],
        "operationId": "meshEconomy",
        "summary": "Public network economy rules",
        "description": "0.10% of SETTLED volume from direct referrals, level 1 only. Registration, referrals, quotes and sandbox activity generate no payment.",
        "security": [],
        "x-lunium-agent-safe": true,
        "responses": {
          "200": {
            "description": "Current policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeshEconomyPolicy"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/agents": {
      "post": {
        "tags": [
          "Mesh · Identity"
        ],
        "operationId": "meshRegisterAgent",
        "summary": "Register an agent and receive a sandbox credential",
        "description": "Register and issue a key in one call. referral_token establishes verified lineage; without it, the agent is registered as a root.",
        "security": [],
        "x-lunium-agent-safe": true,
        "x-lunium-environment": "sandbox",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentRegistration"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Agent created, with credential and next step.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "agent": {
                      "$ref": "#/components/schemas/AgentIdentity"
                    },
                    "api_key": {
                      "type": "string"
                    },
                    "sandbox": {
                      "type": "boolean"
                    },
                    "lineage": {
                      "type": "object"
                    },
                    "proximo_passo": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or rejected referral_token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Mesh · Network"
        ],
        "operationId": "meshListAgents",
        "summary": "List agents in the network",
        "security": [],
        "x-lunium-agent-safe": true,
        "description": "Public directory. Never returns keys, hashes or tokens.",
        "responses": {
          "200": {
            "description": "Agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "agents": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentIdentity"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mesh/referrals": {
      "post": {
        "tags": [
          "Mesh · Network"
        ],
        "operationId": "meshIssueReferral",
        "summary": "Issue a referral attestation",
        "description": "Requires the referring agent's X-API-Key. Returns a signed, single-use, expiring token. This is the only way to establish referral lineage and the corresponding 0.10% reward eligibility.",
        "x-lunium-agent-safe": true,
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "capability": {
                    "type": "string"
                  },
                  "expires_in_minutes": {
                    "type": "integer",
                    "default": 60,
                    "maximum": 10080
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Attestation issued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralAttestation"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "404": {
            "description": "Key is not associated with an agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}": {
      "get": {
        "tags": [
          "Mesh · Identity"
        ],
        "operationId": "meshGetAgent",
        "summary": "Read an agent's state, mandate, metrics and lineage",
        "security": [],
        "x-lunium-agent-safe": true,
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "responses": {
          "200": {
            "description": "Agent details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentIdentity"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}/validate": {
      "post": {
        "tags": [
          "Mesh · Identity"
        ],
        "operationId": "meshValidateAgent",
        "summary": "Validate sandbox usage",
        "description": "Creating a key alone is insufficient: the agent must create AND accept a sandbox order. This is the required usage check before real funds are involved. Independently verify your application's error handling, polling and webhook processing.",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "x-lunium-agent-safe": true,
        "responses": {
          "200": {
            "description": "Completed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "403": {
            "description": "Key does not belong to this agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "409": {
            "description": "Missing prerequisite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}/settlement": {
      "post": {
        "tags": [
          "Mesh · Policy"
        ],
        "operationId": "meshSetSettlement",
        "summary": "Set the settlement destination",
        "description": "Address on a supported settlement network.",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "x-lunium-agent-safe": true,
        "responses": {
          "200": {
            "description": "Completed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "403": {
            "description": "Key does not belong to this agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "409": {
            "description": "Missing prerequisite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettlementConfiguration"
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}/mandate": {
      "post": {
        "tags": [
          "Mesh · Policy"
        ],
        "operationId": "meshSetMandate",
        "summary": "Set the agent's own limits policy",
        "description": "Can only tighten key limits, never expand them. Required before production activation.",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "x-lunium-agent-safe": true,
        "responses": {
          "200": {
            "description": "Completed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "403": {
            "description": "Key does not belong to this agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "409": {
            "description": "Missing prerequisite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Mandate"
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}/production-request": {
      "post": {
        "tags": [
          "Mesh · Identity"
        ],
        "operationId": "meshActivateProduction",
        "summary": "Activate production automatically",
        "description": "Automatically checks validated sandbox usage, a settlement address on a supported network, a policy-compliant mandate and an active credential. If satisfied, production is activated in the same response. Otherwise returns 422 with missing and next_actions so the agent can correct the configuration and retry.",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "x-lunium-agent-safe": true,
        "responses": {
          "200": {
            "description": "Completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductionActivation"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "403": {
            "description": "Key does not belong to this agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "409": {
            "description": "Missing prerequisite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          },
          "422": {
            "description": "Incomplete prerequisites, in machine-readable form.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        },
        "x-lunium-settlement-required": true
      }
    },
    "/mesh/agents/{agent_id}/network": {
      "get": {
        "tags": [
          "Mesh · Network"
        ],
        "operationId": "meshAgentNetwork",
        "summary": "Referral lineage, tree and network volume",
        "security": [],
        "x-lunium-agent-safe": true,
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "description": "Recursive network query. network_volume counts the entire tree; reward_eligible_volume counts only eligible direct-referral volume (level 1).",
        "responses": {
          "200": {
            "description": "Network details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentNetwork"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/agents/{agent_id}/rewards": {
      "get": {
        "tags": [
          "Mesh · Economy"
        ],
        "operationId": "meshAgentRewards",
        "summary": "Reward balance and ledger",
        "security": [],
        "x-lunium-agent-safe": true,
        "x-lunium-reward-eligible": true,
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agt_2319c9da313e84af3b"
          }
        ],
        "responses": {
          "200": {
            "description": "Balance and ledger.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RewardBalance"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroAutocorrigivel"
                }
              }
            }
          }
        }
      }
    },
    "/saldo/consolidado": {
      "get": {
        "summary": "Consolidated custody: house plus customer balances",
        "description": "Sum of all custody balances controlled by this key. casa contains movements without customer_ref: partner margin, adjustments and the key's own funds. clientes sums subaccounts with customer_ref. total_custodiado_cents = casa + clientes. Use this total for financial reconciliation.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "tags": [
          "Conta"
        ],
        "responses": {
          "200": {
            "description": "Consolidated balances.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "casa": {
                      "type": "object",
                      "properties": {
                        "disponivel_cents": {
                          "type": "integer"
                        },
                        "bloqueado_cents": {
                          "type": "integer"
                        },
                        "total_cents": {
                          "type": "integer"
                        }
                      }
                    },
                    "clientes": {
                      "type": "object",
                      "properties": {
                        "qtd": {
                          "type": "integer"
                        },
                        "disponivel_cents": {
                          "type": "integer"
                        },
                        "bloqueado_cents": {
                          "type": "integer"
                        },
                        "total_cents": {
                          "type": "integer"
                        }
                      }
                    },
                    "total_custodiado_cents": {
                      "type": "integer"
                    },
                    "movimentos": {
                      "type": "integer"
                    },
                    "ultimo_movimento_em": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/saldo/clientes": {
      "get": {
        "summary": "List customer subaccounts and balances with pagination",
        "description": "List each customer_ref with available, blocked and total balances. Sorted by customer_ref; continue with cursor=next_cursor. com_saldo=1 hides zero-balance subaccounts.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "tags": [
          "Conta"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page, containing a customer_ref."
          },
          {
            "name": "com_saldo",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            },
            "description": "1 lists only subaccounts with a nonzero balance."
          }
        ],
        "responses": {
          "200": {
            "description": "Page of subaccounts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "clientes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "customer_ref": {
                            "type": "string",
                            "maxLength": 80
                          },
                          "disponivel_cents": {
                            "type": "integer"
                          },
                          "bloqueado_cents": {
                            "type": "integer"
                          },
                          "total_cents": {
                            "type": "integer"
                          },
                          "movimentos": {
                            "type": "integer"
                          },
                          "primeiro_movimento_em": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "ultimo_movimento_em": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/keys/painel-link": {
      "post": {
        "summary": "Request a dashboard link by email without an API key",
        "description": "Request the monitoring link using the email registered on the key. The response is always generic and does not reveal whether the email exists. Limited to three emails per address and ten per IP each hour. For the current partner dashboard, use https://parceiros.luniumpay.com/entrar and its activation or recovery flow; monitor tokens and dashboard login credentials are distinct.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request accepted; generic response."
          },
          "400": {
            "description": "Invalid email."
          },
          "429": {
            "description": "Hourly limit reached."
          }
        }
      }
    },
    "/saldo/transferir": {
      "post": {
        "summary": "Transfer balance internally between subaccounts and the house",
        "description": "Move AVAILABLE balance between an end customer's customer_ref and the house (`\"casa\"`, the key's own balance), or between two customers, without PIX. Common uses include collecting a fee, crediting a bonus or returning funds. Frozen funds (24-hour holds or MED holds) cannot move. A source subaccount in its contractual first-deposit waiting period returns 423. Idempotent by external_id. Emits saldo.transferido.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "tags": [
          "Conta"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "from_customer_ref",
                  "to_customer_ref",
                  "amount_cents"
                ],
                "properties": {
                  "from_customer_ref": {
                    "type": "string",
                    "description": "Source customer_ref, or `\"casa\"`."
                  },
                  "to_customer_ref": {
                    "type": "string",
                    "description": "Destination customer_ref, or `\"casa\"`."
                  },
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "descricao": {
                    "type": "string",
                    "maxLength": 140,
                    "description": "Description shown on both sides' statements."
                  },
                  "external_id": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transfer completed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "transfer_id": {
                      "type": "string"
                    },
                    "from_customer_ref": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "to_customer_ref": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "amount_cents": {
                      "type": "integer"
                    },
                    "descricao": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "movimentos": {
                      "type": "object"
                    },
                    "saldos": {
                      "type": "object",
                      "description": "Both balances after the transfer."
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Idempotent replay (`idempotente: true`)."
          },
          "400": {
            "description": "valor_invalido (invalid amount), origem_igual_destino (same source and destination), or custodia_desligada (custody disabled)."
          },
          "409": {
            "description": "saldo_insuficiente (insufficient funds, with disponivel_cents/bloqueado_cents), or external_id_divergente (idempotency conflict)."
          },
          "423": {
            "description": "carencia_primeiro_deposito: source subaccount is in its first-deposit waiting period."
          }
        }
      }
    },
    "/cash-outs/preview": {
      "post": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "previaCotacao",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "summary": "Preview a quote without creating an order",
        "description": "Preview conversion in either direction (amount OR brl_amount) without an order or pix_key. Does not reserve funds, limits or an address. Creation and acceptance enforce additional checks, including br_code availability, recipient limits and the mandate. A successful preview does not guarantee order acceptance.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "asset",
                  "network"
                ],
                "properties": {
                  "asset": {
                    "type": "string",
                    "examples": [
                      "USDT"
                    ],
                    "description": "Asset to sell. Use the EXACT id from GET /catalog (for example, \"usdt\"). The (asset, network) pair must exist in that catalog."
                  },
                  "network": {
                    "type": "string",
                    "description": "Incoming crypto network from GET /catalog. Do not confuse it with delivery networks from /cashin/catalog.",
                    "examples": [
                      "polygon"
                    ]
                  },
                  "amount": {
                    "type": "string",
                    "description": "Crypto quantity as a decimal string (`\"50\"`), never a floating-point number. Supply exactly one of `amount` or `brl_amount`.",
                    "examples": [
                      "50"
                    ]
                  },
                  "brl_amount": {
                    "type": "string",
                    "description": "REVERSE quote: desired PIX amount in BRL as a decimal string with up to two decimal places (`\"250.00\"`). Lunium calculates the crypto amount; the response's `amount` is what the customer must deposit. Supply exactly one of `amount` or `brl_amount`. Range: R$6.00–R$250,000.00 per transaction, also subject to the recipient's R$100,000.00 daily cap; the lower limit applies.",
                    "examples": [
                      "250.00"
                    ]
                  },
                  "token_address": {
                    "type": "string",
                    "description": "Exact token contract address or mint. Required for tokens from `/catalog/dex`, where symbols may be shared by different tokens."
                  },
                  "br_code": {
                    "type": "string",
                    "description": "PIX copy-and-paste string for a CHARGE with a specified amount. Preview decodes the QR and returns amount, brl_amount (QR amount), merchant_name and the masked PIX key without creating an order. With br_code, omit amount and brl_amount. Same rules as POST /cash-outs: USDT or USDC on a catalog network."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview calculated; no order created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "preview": {
                      "type": "boolean",
                      "const": true
                    },
                    "asset": {
                      "type": "string"
                    },
                    "network": {
                      "type": "string"
                    },
                    "path": {
                      "type": "string",
                      "enum": [
                        "FAST",
                        "DEX",
                        "CONVERT",
                        "simulated"
                      ],
                      "description": "Settlement route the sale would use."
                    },
                    "amount": {
                      "type": "string",
                      "description": "Crypto amount to send, as a decimal string."
                    },
                    "brl_amount": {
                      "type": "string",
                      "description": "PIX amount in BRL."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Expiration the quote would have."
                    },
                    "merchant_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "With br_code only: charge recipient's name."
                    },
                    "pix_key": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "With br_code only: masked recipient PIX key."
                    },
                    "pix_key_type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "preview",
                    "asset",
                    "network",
                    "amount",
                    "brl_amount"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unavailable network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "Semantically invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/cashin/catalog": {
      "get": {
        "tags": [
          "Cash-in"
        ],
        "operationId": "catalogoCompra",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "summary": "Cash-in delivery catalog for incoming PIX payments",
        "description": "Crypto delivery catalog for direct cash-in and custody withdrawals. Offer only items with entregavel=true from instant/convert; instant may be empty. Read memoRequired, withdrawFee, withdrawMin and estimates for each route. The BRL minimum depends on the quote from POST /cashin/preview. Exclude Liquid/DePix for custody withdrawals. stale=true indicates cached catalog data.",
        "responses": {
          "200": {
            "description": "Crypto purchase catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogoCompra"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/catalog/dex": {
      "get": {
        "tags": [
          "Cash-out"
        ],
        "operationId": "catalogoDex",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "summary": "Long-tail tokens available through DEX",
        "description": "List relay-allowlisted tokens for a DEX chain. Use address as token_address in POST /cash-outs. Symbols may be shared by different tokens; contract addresses distinguish them. An unsupported settlement network returns 400.",
        "parameters": [
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "polygon"
              ]
            },
            "description": "DEX chain. Currently only polygon."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by symbol or partial address."
          }
        ],
        "responses": {
          "200": {
            "description": "Allowlisted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "symbol": {
                        "type": "string",
                        "description": "Token symbol. NOT unique; use address."
                      },
                      "address": {
                        "type": "string",
                        "description": "Token contract address, used as token_address in the quote."
                      },
                      "decimals": {
                        "type": "integer"
                      }
                    },
                    "required": [
                      "symbol",
                      "address",
                      "decimals"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/cashin/events": {
      "get": {
        "tags": [
          "Cash-in"
        ],
        "operationId": "eventosDaChave",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "summary": "Operational event feed for this key",
        "description": "Recent key events, newest first: charges, crypto sales, withdrawals and webhook deliveries. Same feed as the monitoring page; useful for an operational screen. Accepts X-API-Key or the key's monitor token.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 60,
              "maximum": 200
            },
            "description": "Number of events to return; default 60."
          }
        ],
        "responses": {
          "200": {
            "description": "Recent events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projeto": {
                      "type": "string",
                      "description": "Key name."
                    },
                    "agora": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Server time, so the display clock does not depend on the client's clock."
                    },
                    "eventos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "ts": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "fluxo": {
                            "type": "string",
                            "description": "cashin · cashout · payout · webhook"
                          },
                          "provedor": {
                            "type": "string"
                          },
                          "ref": {
                            "type": "string",
                            "description": "Operation identifier."
                          },
                          "valor": {
                            "type": "string"
                          },
                          "estado": {
                            "type": "string"
                          },
                          "detalhe": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "tx": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown or incorrect X-API-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/comissao": {
      "get": {
        "tags": [
          "Comissão (sub fee)"
        ],
        "summary": "Partner commission balance",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "description": "Accrued partner fees. Credited when a PIX-to-crypto purchase or balance deposit is settled, never before, to avoid paying commission on funds that may be reversed. Crypto-to-PIX commission is a later phase. Calculation base: amount received minus Lunium's fixed fee. min_saque_cents is US$20 converted at the current rate.",
        "responses": {
          "200": {
            "description": "Balance, policy and withdrawal minimum",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Comissao"
                }
              }
            }
          },
          "401": {
            "description": "Missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/comissao/extrato": {
      "get": {
        "tags": [
          "Comissão (sub fee)"
        ],
        "summary": "Commission statement",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          },
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "id of the last item on the previous page"
          }
        ],
        "responses": {
          "200": {
            "description": "Ledger entries, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ComissaoEvento"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_before": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/comissao/sacar": {
      "post": {
        "tags": [
          "Comissão (sub fee)"
        ],
        "summary": "Withdraw commission as crypto",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "description": "Manually withdraw commission as crypto using a currently available route from GET /cashin/catalog. No additional commission-withdrawal fee: the end customer paid the partner fee in the original operation. Minimum US$20 at the current rate; read min_saque_cents in GET /comissao. Once per rolling 24-hour window. Track delivery using saque.cashin_id in GET /cashin/{cashin_id}/status or the cashin.settled webhook.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents",
                  "payout_address"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "BRL cents to convert, at least min_saque_cents."
                  },
                  "asset": {
                    "type": "string",
                    "default": "usdt",
                    "description": "usdt or usdc on Polygon, or an asset from GET /cashin/catalog."
                  },
                  "chain": {
                    "type": "string",
                    "default": "polygon"
                  },
                  "payout_address": {
                    "type": "string",
                    "description": "Your wallet on the selected network."
                  },
                  "payout_tag": {
                    "type": "string",
                    "description": "Memo/tag when required by the network."
                  },
                  "external_id": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Idempotency identifier, up to 64 characters. Keep the identifier and every request parameter unchanged on retries. Conflict detection differs by route; do not use a replay to modify an operation. 409 external_id_divergente indicates a detected conflict."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Withdrawal created and queued for delivery",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saque": {
                      "$ref": "#/components/schemas/Cobranca"
                    },
                    "comissao": {
                      "$ref": "#/components/schemas/Comissao"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "valor_invalido | valor_abaixo_do_minimo (includes min_saque_cents) | rede_indisponivel | asset_invalido | payout_address_invalido | sandbox_sem_saque",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "402": {
            "description": "saldo_insuficiente: available commission is lower than the requested amount",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "external_id_divergente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "saque_comissao_diario: includes proximo_saque_em, the next allowed withdrawal time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "503": {
            "description": "provedor_indisponivel: no quote available to calculate the minimum",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/mesh/graph": {
      "get": {
        "tags": [
          "Mesh · Discovery"
        ],
        "operationId": "meshGraph",
        "summary": "Mesh agent graph",
        "description": "Public agents, referral relationships and aggregated network totals. No credentials required; no secrets returned.",
        "security": [],
        "x-lunium-agent-safe": true,
        "x-lunium-environment": "any",
        "responses": {
          "200": {
            "description": "Statistics and public agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "stats",
                    "agents"
                  ],
                  "properties": {
                    "stats": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "agents": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "agent_id",
                          "name",
                          "status",
                          "capabilities"
                        ],
                        "properties": {
                          "agent_id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "referred_by": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "capabilities": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sandbox": {
      "get": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Discover sandbox capabilities",
        "description": "Supported journeys, scenarios by flow, QR semantics, limits and simulation control routes.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox result; sandbox=true; no real funds move.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "403": {
            "description": "Requires a sandbox key."
          },
          "404": {
            "description": "Operation not found for this key."
          },
          "409": {
            "description": "State conflict or divergent idempotency parameters."
          },
          "503": {
            "description": "Simulator unavailable; never falls through to a real provider."
          }
        }
      }
    },
    "/sandbox/cashin/{cashin_id}/pay": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Simulate payment of a test PIX charge",
        "description": "Only the owning sandbox key can confirm. Replays never duplicate credits. This endpoint cannot confirm a production payment.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox result; sandbox=true; no real funds move.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "403": {
            "description": "Requires a sandbox key."
          },
          "404": {
            "description": "Operation not found for this key."
          },
          "409": {
            "description": "State conflict or divergent idempotency parameters."
          },
          "503": {
            "description": "Simulator unavailable; never falls through to a real provider."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "payer_tax_number": {
                    "type": "string",
                    "description": "Optional synthetic payer document; a mismatch simulates a refund."
                  }
                },
                "required": []
              }
            }
          }
        },
        "parameters": [
          {
            "name": "cashin_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/sandbox/operations/{operation_id}/resolve": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Resolve an uncertain sandbox operation",
        "description": "Only a test operation already in an uncertain state can be resolved. Same outcome can be replayed safely.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox result; sandbox=true; no real funds move.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "403": {
            "description": "Requires a sandbox key."
          },
          "404": {
            "description": "Operation not found for this key."
          },
          "409": {
            "description": "State conflict or divergent idempotency parameters."
          },
          "503": {
            "description": "Simulator unavailable; never falls through to a real provider."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "outcome": {
                    "type": "string",
                    "enum": [
                      "sent",
                      "failed"
                    ]
                  }
                },
                "required": [
                  "outcome"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "operation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/sandbox/events": {
      "get": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Inspect generated sandbox events",
        "description": "Returns generated events even if no webhook was configured. Use /webhooks/deliveries for actual callback attempts.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox result; sandbox=true; no real funds move.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "403": {
            "description": "Requires a sandbox key."
          },
          "404": {
            "description": "Operation not found for this key."
          },
          "409": {
            "description": "State conflict or divergent idempotency parameters."
          },
          "503": {
            "description": "Simulator unavailable; never falls through to a real provider."
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ]
      }
    },
    "/sandbox/reset": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Reset this key’s fictitious state",
        "description": "Deletes only the owning key’s simulated state. Previously queued webhook deliveries retain their history. Production keys are refused.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox result; sandbox=true; no real funds move.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "403": {
            "description": "Requires a sandbox key."
          },
          "404": {
            "description": "Operation not found for this key."
          },
          "409": {
            "description": "State conflict or divergent idempotency parameters."
          },
          "503": {
            "description": "Simulator unavailable; never falls through to a real provider."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm": {
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "confirm"
                ]
              }
            }
          }
        }
      }
    },
    "/sandbox/qr/{cashin_id}.svg": {
      "get": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Non-payable sandbox QR image",
        "description": "Encodes `SANDBOX:NAO_PAGAVEL:<id>`; not a bank PIX code. No payment action or customer data.",
        "security": [],
        "parameters": [
          {
            "name": "cashin_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^ci_sbx_[a-f0-9]{24}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Synthetic SVG QR.",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Integration guide, costly mistakes to avoid and MCP tools",
    "url": "https://docs.luniumpay.com/#armadilhas"
  },
  "webhooks": {
    "evento": {
      "post": {
        "summary": "Event sent to your webhook endpoint",
        "description": "Configure a public HTTPS webhook_url in POST /keys or PATCH /keys/me. Respond with 2xx promptly after securely recording the event, then process asynchronously. Non-2xx responses trigger exponential-backoff retries: 12 attempts over approximately seven hours. ALWAYS verify the signature. Exhausted deliveries remain visible in GET /webhooks/deliveries and can be recovered with retry.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventoWebhook"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "description": "DEPRECATED; retirement scheduled for 2026-11-09. Keys created from 2026-08-08 do not receive this header. Verify v2 instead: X-Lunium-Signature, an HMAC of timestamp.body, rejecting timestamps older than five minutes. Until retirement, existing integrations continue receiving the legacy v1 HMAC of the raw body.",
            "deprecated": true
          },
          {
            "name": "X-Lunium-Signature",
            "in": "header",
            "schema": {
              "type": "string",
              "pattern": "^t=\\d+,v1=[0-9a-f]{64}$"
            },
            "description": "v2 signature: `t=<unix>,v1=<HMAC-SHA256 of \"<t>.<raw body>\">`. Prefer this version. The signed timestamp lets you reject old requests and limits replay of captured deliveries. Recommended tolerance: five minutes."
          },
          {
            "name": "X-Lunium-Event",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Event name for routing without parsing the body."
          },
          {
            "name": "X-Lunium-Event-Id",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Same as event_id in the body."
          },
          {
            "name": "X-Lunium-Delivery-Id",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Identifier of this ATTEMPT, changing with each retry. Include it when contacting support."
          },
          {
            "name": "X-Lunium-Attempt",
            "in": "header",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Attempt number. Values above 1 mean you may already have received this event."
          },
          {
            "name": "X-Lunium-Timestamp",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Unix send timestamp, matching t in the v2 signature."
          }
        ],
        "responses": {
          "200": {
            "description": "Acknowledged. Any 2xx response completes delivery."
          },
          "default": {
            "description": "A non-2xx response schedules another attempt."
          }
        }
      }
    }
  }
}
