> ## 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.

# Remittances

> Send money cross-border by funding senders in local currency and paying recipients on local rails

Build a P2P remittance product where individuals send money to family and friends abroad. Each sender is onboarded as an individual customer who funds their wallet in local currency. To send, you register the recipient's destination under the sender and trigger a payout. Lumx converts stablecoin to the recipient's local fiat and delivers it on local rails.

## Step 1: Generate your API key

Head over to [dashboard.lumx.io](https://dashboard.lumx.io). Once logged in, generate a new API key and store it securely. See [Authentication](/get-started/authentication) for details.

## Step 2: Onboard the sender

For each sender using your product, create an individual customer. Provision an account in their home currency so they can fund the wallet via a local rail. Senders must accept Lumx's terms of service (`POST /customers/{id}/tos`) and complete KYC before they can move funds.

```bash Request theme={null}
curl -X POST https://api-sandbox.lumx.io/customers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "type": "INDIVIDUAL",
    "name": "Lucia Pereira",
    "taxId": "123-45-6789",
    "birthDate": "1985-09-12",
    "country": "USA",
    "email": "lucia.pereira@example.com",
    "accounts": ["USD"]
  }'
```

See [Individual verification](/guides/individual-verification) for the full onboarding flow.

## Step 3: Fund the sender's wallet

Once the sender's account is `ACTIVE`, create an on-ramp transaction for the exact amount the sender plans to deposit. The response includes the rail-specific payment details: ACH/wire for USD, PIX `brCode` for BRL, SPEI CLABE for MXN, IBAN for EUR. Show them in your app for the sender to pay; when the deposit matches, Lumx converts the fiat to stablecoin and credits the sender's wallet.

```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": "ACH",
    "sourceCurrency": "USD",
    "sourceAmount": "500.00",
    "targetCurrency": "USDC",
    "purpose": "PERSONAL_ACCOUNT"
  }'
```

<Info>
  Each deposit must be matched to an on-ramp transaction created in advance with the exact amount.
</Info>

Subscribe to the `onramp.success` webhook to know the moment the wallet is funded and the sender can confirm the remittance. For the full deposit flow by rail, see [Global accounts](/guides/use-cases/global-accounts). If the sender pays after the on-ramp expires, Lumx refunds them on the same rail. See [Late deposits](/concepts/transactions#late-deposits).

## Step 4: Register the recipient's destination

Register a destination for the recipient under the sender. Use `holder.relationship` of `RELATIVE` for family or `FRIEND` for friends. This is how the recipient is categorized for compliance. See [Coverage](/get-started/coverage) for the full list of supported rails and currencies.

<Tabs>
  <Tab title="PIX (BRL)">
    ```bash Request theme={null}
    curl -X POST https://api-sandbox.lumx.io/destinations \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "name": "Mother - Brazil",
        "rail": "PIX",
        "currency": "BRL",
        "identifier": {
          "keyType": "CPF",
          "keyValue": "123.456.789-00"
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "RELATIVE",
          "name": "Ana Pereira",
          "taxId": "123.456.789-00",
          "birthDate": "1960-04-22",
          "email": "ana.pereira@example.com",
          "address": {
            "line1": "Rua das Flores 250",
            "city": "Belo Horizonte",
            "state": "MG",
            "postalCode": "30130-110",
            "country": "BRA"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="SPEI (MXN)">
    ```bash Request theme={null}
    curl -X POST https://api-sandbox.lumx.io/destinations \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "name": "Sister - Mexico",
        "rail": "SPEI",
        "currency": "MXN",
        "identifier": {
          "keyType": "CLABE",
          "keyValue": "012180001234567897"
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "RELATIVE",
          "name": "Sofia Hernández",
          "taxId": "HEHS920811XYZ",
          "birthDate": "1992-08-11",
          "email": "sofia.hernandez@example.com",
          "address": {
            "line1": "Av. Reforma 500",
            "city": "Mexico City",
            "state": "CDMX",
            "postalCode": "06600",
            "country": "MEX"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="SEPA (EUR)">
    ```bash Request theme={null}
    curl -X POST https://api-sandbox.lumx.io/destinations \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "name": "Cousin - France",
        "rail": "SEPA",
        "currency": "EUR",
        "identifier": {
          "iban": "FR1420041010050500013M02606",
          "bic": "BNPAFRPP"
        },
        "bank": {
          "name": "BNP Paribas",
          "address": {
            "line1": "16 Boulevard des Italiens",
            "city": "Paris",
            "state": "IDF",
            "postalCode": "75009",
            "country": "FRA"
          }
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "RELATIVE",
          "name": "Emma Martin",
          "taxId": "1850612345678",
          "birthDate": "1985-06-12",
          "email": "emma.martin@example.com",
          "address": {
            "line1": "12 Rue de Rivoli",
            "city": "Paris",
            "state": "IDF",
            "postalCode": "75004",
            "country": "FRA"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="SWIFT (international)">
    ```bash Request theme={null}
    curl -X POST https://api-sandbox.lumx.io/destinations \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "name": "Friend - UK",
        "rail": "SWIFT",
        "currency": "USD",
        "identifier": {
          "iban": "GB29NWBK60161331926819",
          "bic": "NWBKGB2L"
        },
        "bank": {
          "name": "NatWest Bank",
          "address": {
            "line1": "250 Bishopsgate",
            "city": "London",
            "postalCode": "EC2M 4AA",
            "country": "GBR"
          }
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "FRIEND",
          "name": "Oliver Smith",
          "taxId": "AB123456C",
          "birthDate": "1990-03-22",
          "email": "oliver.smith@example.com",
          "address": {
            "line1": "10 Downing Street",
            "city": "London",
            "postalCode": "SW1A 2AA",
            "country": "GBR"
          }
        }
      }'
    ```
  </Tab>
</Tabs>

Destinations go through verification before they can be used. Subscribe to the `destinations.approved` webhook to know when a recipient is ready to receive funds. See [Destinations](/concepts/destinations) for the full reference.

## Step 5: Lock an exchange rate

Senders want to know exactly how much the recipient will receive before confirming the transfer. Fetch a locked exchange rate first and reference its `id` in the off-ramp request to guarantee the conversion price.

```bash Request theme={null}
curl -X POST https://api-sandbox.lumx.io/exchange-rates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "type": "LOCKED",
    "rail": "PIX",
    "sourceCurrency": "USDC",
    "targetCurrency": "BRL",
    "sourceAmount": "500.00",
    "timelock": "1m"
  }'
```

```json Response theme={null}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "type": "LOCKED",
  "rail": "PIX",
  "sourceCurrency": "USDC",
  "sourceAmount": "500.00",
  "targetCurrency": "BRL",
  "baseTargetAmount": "2587.50",
  "baseExchangeRate": "5.1750",
  "finalTargetAmount": "2581.81",
  "finalExchangeRate": "5.1636",
  "expiresAt": "2026-05-16T15:45:00Z"
}
```

Show the resulting `finalTargetAmount` to the sender. If they confirm before `expiresAt`, the off-ramp will settle at `finalExchangeRate`. See [Exchange Rates](/concepts/exchange-rates).

## Step 6: Send the remittance

Create an off-ramp transaction debiting the sender's wallet. Reference the locked `exchangeRateId` and use `purpose: "BILLS"` (the closest available code for P2P remittances; see [Purpose codes](/additional-information/purpose-codes)).

```bash Request theme={null}
curl -X POST https://api-sandbox.lumx.io/transactions/off-ramp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "destinationId": "e80d3137-eddd-4791-b9b8-6e36b289f284",
    "exchangeRateId": "123e4567-e89b-12d3-a456-426614174000",
    "purpose": "BILLS"
  }'
```

```json Response theme={null}
{
  "id": "9b1c5b8a-3d1f-4a8f-b6e0-2c1b6a7e9f33",
  "customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "type": "OFF_RAMP",
  "request": {
    "destinationId": "e80d3137-eddd-4791-b9b8-6e36b289f284",
    "exchangeRateId": "123e4567-e89b-12d3-a456-426614174000",
    "purpose": "BILLS"
  },
  "state": {
    "status": "TRANSFERRING_STABLECOIN"
  }
}
```

## Step 7: Notify the sender on completion

Each off-ramp follows this lifecycle:

`TRANSFERRING_STABLECOIN` → `TRADING` → `TRANSFERRING_FIAT` → `SUCCESS`

Subscribe to `offramp.success` and `offramp.failed` webhooks to push a confirmation back to the sender in your app the moment the recipient receives the funds. See [Webhooks](/developer/webhooks).

## Related resources

<CardGroup cols="2">
  <Card title="Global accounts" href="/guides/use-cases/global-accounts">
    Provision the sender's funding account.
  </Card>

  <Card title="Exchange Rates" href="/concepts/exchange-rates">
    Lock FX rates for predictable payouts.
  </Card>

  <Card title="Destinations" href="/concepts/destinations">
    Holder relationships and rail-specific identifiers.
  </Card>

  <Card title="Transactions" href="/concepts/transactions">
    Off-ramp lifecycle and purpose codes.
  </Card>
</CardGroup>
