> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumx.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Collect BRL via Pix and Settle in USDC or USDT

> Receive BRL through Pix with the Lumx API and settle in USDC or USDT on-chain, with an autoconversion rule or a one-off on-ramp. Webhooks included.

To collect BRL via Pix and settle in USDC or USDT, create an autoconversion rule on your customer's BRL account: Lumx returns a static Pix QR code (`brCode`), and every Pix payment made with it is converted and delivered on-chain. For a single charge, `POST /transactions/on-ramp` with `rail` set to `PIX` returns a `brCode` for that one payment.

Both paths end the same way. The payer pays in BRL, Lumx converts, and the stablecoin is delivered on-chain, up to five minutes after the Pix. The receipt gives you the transaction hash.

## Choose a method

| | **Autoconversion rule** | **On-ramp transaction** |
| :- | :- | :- |
| Endpoint | `POST /autoconversion-rules` | `POST /transactions/on-ramp` |
| Pix code | Static, reused for every payment | One per transaction |
| Amount | Set by the payer | Set in the request (`sourceAmount`) |
| Exchange rate | Market rate at conversion | Floating, or locked with an `exchangeRateId` |
| Best for | Recurring collection, top-ups, donations | Invoices, checkouts, fixed amounts |

## Prerequisites

* A customer in `APPROVED` status with an `ACTIVE` BRL account. For a business, see [Open a named BRL account for a business](https://docs.lumx.io/guides/named-brl-account-for-businesses.md).
* An API key from the [Dashboard](https://dashboard.lumx.io) and a webhook endpoint. See [Webhooks](https://docs.lumx.io/developer/webhooks.md).
* The customer's `id`, and for rules, the BRL account's `id` from `GET /accounts?customerId={customerId}`.

## Option 1: standing rule with a static Pix QR code

Send a `POST` request to `/autoconversion-rules` with the BRL account, the asset, and the network.

```bash Request theme={null}
curl -X POST https://api-sandbox.lumx.io/autoconversion-rules \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "accountId": "44dd9734-176a-4ced-924f-103f8d50ea5e",
    "targetCurrency": "USDT",
    "blockchain": "TRON",
    "purpose": "TRADE_TRANSACTIONS",
    "name": "BRL to USDT collection"
  }'
```

The response carries the code to share, in `sourceDepositInfo`:

```json Response (excerpt) theme={null}
{
  "id": "c7f64332-5d53-4685-8aa9-48a5348c18c2",
  "status": "ACTIVE",
  "sourceCurrency": "BRL",
  "targetCurrency": "USDT",
  "blockchain": "TRON",
  "sourceDepositInfo": [
    {
      "rail": "PIX",
      "brCode": "00020126...5204",
      "depositIdentifier": "IIDCDYjYUTbKouEUOyvxZ3xnU"
    }
  ]
}
```

Render the `brCode` as a QR code or show it as copy-and-paste text. The `depositIdentifier` is embedded in it and matches each payment to the rule. A BRL account can have more than one rule.

The rule always converts at the market rate. It does not accept a locked quote. Each deposit must be worth at least 50 USD, or it is not converted.

Request fields, retrieving and listing rules, errors, and the minimum amount are in [Autoconversion Rules](https://docs.lumx.io/guides/autoconversion-rules.md).

## Option 2: one-off charge with an on-ramp

Send a `POST` request to `/transactions/on-ramp`. You set the amount, so the Pix code is for that payment.

```bash Request theme={null}
curl -X POST https://api-sandbox.lumx.io/transactions/on-ramp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "rail": "PIX",
    "sourceCurrency": "BRL",
    "sourceAmount": "10000.00",
    "targetCurrency": "USDC",
    "purpose": "TRADE_TRANSACTIONS",
    "blockchain": "POLYGON",
    "metadata": { "orderId": "ord_789" }
  }'
```

```json Response theme={null}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "type": "ON_RAMP",
  "request": {
    "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "rail": "PIX",
    "sourceCurrency": "BRL",
    "sourceAmount": "10000.00",
    "targetCurrency": "USDC",
    "purpose": "TRADE_TRANSACTIONS"
  },
  "state": {
    "status": "AWAITING_FUNDS",
    "payment": {
      "rail": "PIX",
      "brCode": "00020126...6304"
    }
  },
  "metadata": { "orderId": "ord_789" },
  "createdAt": "2024-03-20T15:30:00Z",
  "updatedAt": "2024-03-20T15:30:05Z"
}
```

Show `state.payment.brCode` to the payer. The `metadata` object comes back on the transaction and on every webhook, so you can match the payment to your order.

### Request fields

| **Field** | **Required** | **Description** |
| :- | :- | :- |
| `customerId` | Yes | The approved customer who receives the stablecoin |
| `rail` | Yes | `PIX` |
| `sourceCurrency` | Yes | `BRL` |
| `sourceAmount` | Yes | Amount in BRL, as a string |
| `targetCurrency` | Yes | `USDC` or `USDT` |
| `purpose` | Yes | End-use category of the funds. See [Transaction purpose](https://docs.lumx.io/concepts/transactions.md#transaction-purpose) |
| `blockchain` | No | `ETHEREUM`, `POLYGON`, `BASE`, or `TRON`. Defaults to the project's blockchain |
| `partnerFeeId` | No | [Partner fee](https://docs.lumx.io/concepts/partner-fees.md) added to the conversion. Without it, partner fees are zero |
| `metadata` | No | Any JSON object |

### Lock the rate

To quote a fixed amount of stablecoin, request a locked rate first with `POST /exchange-rates` (`type` set to `LOCKED`, `timelock` of `30s`, `1m`, or `5m`). Then pass the returned `id` as `exchangeRateId` in the on-ramp request, together with `customerId` and `purpose`. See [Exchange Rates](https://docs.lumx.io/concepts/exchange-rates.md).

### Expiry and late payments

An on-ramp has a payment window. A floating Pix on-ramp expires after 1 day, and a locked one expires with its quote. If the payer pays after that, Lumx does not process the transaction and refunds the sender on Pix. Create a new on-ramp instead. You get the `onramp.expired` webhook when the window closes.

## Track the payment with webhooks

Every Pix payment, from either method, runs as an on-ramp transaction. Subscribe to the `onramp.*` events:

| **Event** | **Triggered when** |
| :- | :- |
| `onramp.awaiting_funds` | Waiting for the Pix payment |
| `onramp.transferring_fiat` | Fiat transfer is in progress |
| `onramp.trading` | The conversion is being executed |
| `onramp.transferring_stablecoin` | The stablecoin is on its way to the wallet |
| `onramp.success` | Completed, with the receipt |
| `onramp.failed` | Failed |
| `onramp.expired` | The payment window closed |

The happy path is `AWAITING_FUNDS`, `TRANSFERRING_FIAT`, `TRADING`, `TRANSFERRING_STABLECOIN`, `SUCCESS`. Deduplicate events with the `webhook-id` header, and verify the signature as described in [Webhooks](https://docs.lumx.io/developer/webhooks.md#verifying-webhook-signatures).

## Confirm the on-chain delivery

`onramp.success` carries the receipt. The delivery is in `transactionHash` and `blockExplorerUrl`:

```json onramp.success (excerpt) theme={null}
{
  "eventId": "550e8400-e29b-41d4-a716-446655440000",
  "eventType": "onramp.success",
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "state": {
      "status": "SUCCESS",
      "receipt": {
        "sourceCurrency": "BRL",
        "sourceAmount": "10000.00",
        "targetCurrency": "USDC",
        "baseExchangeRate": "5.25",
        "baseTargetAmount": "1904.76",
        "finalTargetAmount": "1891.43",
        "finalExchangeRate": "5.29",
        "transactionHash": "0xabc123def456abc123def456abc123def456abc123def456abc123def456abc1",
        "blockExplorerUrl": "https://polygonscan.com/tx/0xabc123def456abc123def456abc123def456abc123def456abc123def456abc1"
      }
    }
  }
}
```

The `fees` object in the receipt breaks down the Lumx and partner fees, and `finalTargetAmount` is the amount delivered after them.

The stablecoin is delivered on the blockchain you chose, or on the project's default. An on-ramp credits the customer's wallet, and a rule credits the wallet of the customer who owns the account. Each customer has one wallet per network. `GET /customers/{id}?includeBalances=true` returns the balances. Which asset runs on which network:

| **Blockchain** | **USDC** | **USDT** |
| :- | :- | :- |
| `ETHEREUM` | Yes | Yes |
| `POLYGON` | Yes | Yes |
| `BASE` | Yes | No |
| `TRON` | No | Yes |

The wallet is a regular on-chain address, so you can move the balance on with a transfer or an off-ramp. See [Stablecoin Wallets](https://docs.lumx.io/concepts/wallets.md).

## Test in sandbox

A one-off on-ramp in sandbox completes on its own and credits the stablecoin to the customer's wallet, so you can test the full flow and then use that balance for off-ramps. Deposits cannot be made against sandbox accounts, so for a rule, call `POST /autoconversion-rules/simulate-deposit` with the `accountId`, an `amount`, and the rule's `depositIdentifier` as `reference`. The response is `{ "matchedRule": true }`, and your endpoint receives the `onramp.*` events. The endpoint returns `404` in production.

## Limits

An on-ramp counts against the customer's `onramp` limits. A transaction above a limit returns `422` with `TRANSACTION_LIMIT_EXCEEDED`. See [Transaction Limits](https://docs.lumx.io/compliance/transaction-limits.md).

## Related resources

> [card] [Autoconversion Rules](https://docs.lumx.io/guides/autoconversion-rules.md)
>
> Full reference for standing rules, in every currency.

> [card] [Named BRL account](https://docs.lumx.io/guides/named-brl-account-for-businesses.md)
>
> Open the BRL account that receives the Pix.

> [card] [Transactions](https://docs.lumx.io/concepts/transactions.md)
>
> On-ramp lifecycle and payment expiration.

> [card] [Stablecoin Wallets](https://docs.lumx.io/concepts/wallets.md)
>
> Networks, balances, and transfers out.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.