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

# Payroll

> Run global payroll by funding employers in stablecoin and paying employees in local fiat

Build a payroll product where your customers (employers) pay their employees and contractors anywhere in the world using stablecoin rails. Each employer is onboarded as a business customer. You register their payees as destinations and trigger payouts on their behalf; Lumx converts stablecoin to local fiat and settles into each payee's account.

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

For each employer using your product, create a business customer.

```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": "BUSINESS",
    "legalName": "Acme Inc.",
    "taxId": "42.887.120/0001-00",
    "incorporationDate": "2020-01-01",
    "country": "BRA",
    "email": "finance@acme.com",
    "accounts": ["USD"]
  }'
```

Before the employer can transact, they must accept Lumx's terms of service (`POST /customers/{id}/tos`) and complete KYB. See [Business verification](/guides/business-verification) for the full onboarding flow.

## Step 3: Fund the employer's wallet

Once the employer's USD account is `ACTIVE`, create an on-ramp transaction with the exact amount the employer plans to deposit. The response includes wire instructions for that specific deposit. Share them with the employer's finance team. When the wire lands matching the amount, Lumx converts USD to stablecoin and credits the employer'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": "FEDWIRE",
    "sourceCurrency": "USD",
    "sourceAmount": "50000.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>

If the employer already holds stablecoin on-chain, they can also transfer it directly to the wallet returned at customer creation, no on-ramp needed.

Subscribe to the `onramp.success` webhook to know the moment the wallet is funded and ready to run payouts. For the full deposit flow by rail, see [Global accounts](/guides/use-cases/global-accounts).

## Step 4: Register each payee's destination

For each employee or contractor the employer wants to pay, register a destination under the employer's customer record. Set `holder.relationship` to `EMPLOYEE` so the destination is correctly categorized for compliance. The `taxId` format varies by country; see [Tax IDs by country](/additional-information/tax-ids-by-country) and [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": "Maria Santos - Engineering",
        "rail": "PIX",
        "currency": "BRL",
        "identifier": {
          "keyType": "CPF",
          "keyValue": "123.456.789-00"
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "EMPLOYEE",
          "name": "Maria Santos",
          "taxId": "123.456.789-00",
          "birthDate": "1990-05-15",
          "email": "maria.santos@acme.com",
          "address": {
            "line1": "Rua Augusta 100",
            "city": "São Paulo",
            "state": "SP",
            "postalCode": "01304-000",
            "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": "Carlos Hernández - Operations",
        "rail": "SPEI",
        "currency": "MXN",
        "identifier": {
          "keyType": "CLABE",
          "keyValue": "012180001234567897"
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "EMPLOYEE",
          "name": "Carlos Hernández",
          "taxId": "HEGC900515ABC",
          "birthDate": "1990-05-15",
          "email": "carlos.hernandez@acme.com",
          "address": {
            "line1": "Calzada de Tlalpan 3465",
            "city": "Mexico City",
            "state": "CDMX",
            "postalCode": "04650",
            "country": "MEX"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="ACH (USD)">
    ```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": "Jane Doe - Marketing",
        "rail": "ACH",
        "currency": "USD",
        "identifier": {
          "type": "CHECKING",
          "accountNumber": "123456789012",
          "routingNumber": "021000021"
        },
        "bank": {
          "name": "JPMorgan Chase Bank",
          "address": {
            "line1": "383 Madison Avenue",
            "city": "New York",
            "state": "NY",
            "postalCode": "10179",
            "country": "USA"
          }
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "EMPLOYEE",
          "name": "Jane Doe",
          "taxId": "123-45-6789",
          "birthDate": "1985-09-12",
          "email": "jane.doe@acme.com",
          "address": {
            "line1": "350 5th Avenue",
            "city": "New York",
            "state": "NY",
            "postalCode": "10118",
            "country": "USA"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="FEDWIRE (USD)">
    ```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": "Sarah Lee - Executive",
        "rail": "FEDWIRE",
        "currency": "USD",
        "identifier": {
          "type": "CHECKING",
          "accountNumber": "987654321098",
          "routingNumber": "021000021"
        },
        "bank": {
          "name": "JPMorgan Chase Bank",
          "address": {
            "line1": "383 Madison Avenue",
            "city": "New York",
            "state": "NY",
            "postalCode": "10179",
            "country": "USA"
          }
        },
        "holder": {
          "type": "INDIVIDUAL",
          "relationship": "EMPLOYEE",
          "name": "Sarah Lee",
          "taxId": "234-56-7890",
          "birthDate": "1982-04-08",
          "email": "sarah.lee@acme.com",
          "address": {
            "line1": "1 Market Street",
            "city": "San Francisco",
            "state": "CA",
            "postalCode": "94105",
            "country": "USA"
          }
        }
      }'
    ```
  </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": "Lucas Martin - Engineering",
        "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": "EMPLOYEE",
          "name": "Lucas Martin",
          "taxId": "1850612345678",
          "birthDate": "1991-11-30",
          "email": "lucas.martin@acme.com",
          "address": {
            "line1": "45 Avenue Montaigne",
            "city": "Paris",
            "state": "IDF",
            "postalCode": "75008",
            "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": "John Doe - Design",
        "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": "EMPLOYEE",
          "name": "John Doe",
          "taxId": "AB123456C",
          "birthDate": "1988-03-22",
          "email": "john.doe@acme.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 payee is ready to receive payouts. See [Destinations](/concepts/destinations) for the full reference.

## Step 5: Run payroll

For each approved payee, create an off-ramp transaction debiting the employer's wallet. Use `purpose: "PROFESSIONAL_SERVICES"` for contractor and salary payments (the closest available code; there's no dedicated payroll purpose), or `EXPENSES_REIMBURSEMENT` for reimbursements. See [Purpose codes](/additional-information/purpose-codes) for the full list.

```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",
    "sourceCurrency": "USDC",
    "sourceAmount": "5000.00",
    "purpose": "PROFESSIONAL_SERVICES"
  }'
```

```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",
    "sourceCurrency": "USDC",
    "sourceAmount": "5000.00",
    "purpose": "PROFESSIONAL_SERVICES"
  },
  "state": {
    "status": "TRANSFERRING_STABLECOIN"
  }
}
```

Repeat the request per payee using a fresh `Idempotency-Key` each time. There's no batch endpoint, so run the calls in parallel from your job runner if you need to push a full payroll cycle at once.

<Tip>
  Lock in an exchange rate before the payout to guarantee the amount the payee receives. See [Exchange Rates](/concepts/exchange-rates).
</Tip>

## Step 6: Track payout status

Each off-ramp transaction follows this lifecycle:

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

Subscribe to the `offramp.success` and `offramp.failed` webhooks to reconcile payouts as they complete and surface status back to the employer in your product. See [Webhooks](/developer/webhooks) and the [Transactions](/concepts/transactions) lifecycle reference.

## Related resources

<CardGroup cols="2">
  <Card title="Global accounts" href="/guides/use-cases/global-accounts">
    Fund the employer's wallet via local fiat rails.
  </Card>

  <Card title="Destinations" href="/concepts/destinations">
    Holder relationships and verification.
  </Card>

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

  <Card title="Off-ramp API" href="/api-reference/transactions/off-ramp">
    Full API reference for off-ramp transactions.
  </Card>
</CardGroup>
