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

# Quickstart

> Fund a sandbox wallet, register a payee and send your first payout, end to end, in about 10 minutes.

This guide walks through a complete payout in the sandbox: you top up a wallet, register Maria Lopez with her Dutch bank account, price a EUR 500 payout, send it and confirm it was paid. Every request below runs as-is with curl, and no real funds move.

```mermaid theme={null}
sequenceDiagram
  participant You as Your server
  participant API as Infinity API
  You->>API: GET /wallets
  You->>API: POST /test/deposits
  You->>API: POST /payees, then POST /payees/{id}/addresses
  You->>API: POST /quotes
  You->>API: POST /payouts
  API-->>You: payout.paid (about 30 s later)
```

## Before you begin

You need a sandbox secret key, which starts with `sk_test_`.

Sandbox keys are issued by our team. [Contact us](mailto:support@infinityapp.in?subject=Sandbox%20API%20key) with your company name and we'll set up your sandbox account and send you an `sk_test_` key.

Export the key and the sandbox base URL so the examples can use them:

```bash theme={null}
export INFINITY_KEY="sk_test_..."
export BASE="https://sandbox-api.infinityapp.in/v1"
```

**1. Find your wallet**

Payouts are paid from a wallet, and every sandbox account starts with a USD wallet. List your wallets and note the `id`; you'll pass it when you fund the wallet and when you pay.

```bash theme={null}
curl "$BASE/wallets" -H "Authorization: Bearer $INFINITY_KEY"
```

```json Response theme={null}
{
  "data": [
    {
      "id": "wallet_7t4m9k2qx8d3hn5r",
      "currency": "usd",
      "total": "0.00",
      "reserved": "0.00",
      "available": "0.00"
    }
  ],
  "has_more": false
}
```

A `401` with the code `wrong_environment` means the key is a live key; the sandbox only accepts `sk_test_` keys.

**2. Fund the wallet**

In live, you fund a wallet with a bank transfer to your funding address. The sandbox replaces that with a test deposit:

```bash theme={null}
curl "$BASE/test/deposits" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "wallet_id": "wallet_7t4m9k2qx8d3hn5r", "amount": "10000.00" }'
```

The deposit is credited immediately, the wallet's `available` amount becomes `10000.00`, and Infinity emits a `deposit.created` event.

Two conventions show up here that apply across the API. Amounts are decimal strings, so values are never rounded through floating point. And any request that moves money requires an `Idempotency-Key`: if the request is retried with the same key, Infinity returns the original result instead of crediting twice. See [Idempotency](https://docs.infinityapp.in/guides/idempotency.md).

**3. Register a payee**

A payee is anyone you pay. Create one with a name and an email address:

```bash theme={null}
curl "$BASE/payees" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Maria",
    "last_name": "Lopez",
    "email": "maria@example.com",
    "send_invite": false,
    "reference": "vendor-829"
  }'
```

```json Response (abridged) theme={null}
{
  "id": "payee_c8pnahcrxqzd3z8d",
  "first_name": "Maria",
  "last_name": "Lopez",
  "email": "maria@example.com",
  "currency": null,
  "status": "invited",
  "send_invite": false,
  "reference": "vendor-829"
}
```

`send_invite: false` stops Infinity from emailing Maria, because you'll submit her bank details yourself in the next step. `reference` holds your own identifier for her and is returned on every read and event. `currency` stays `null` until her bank account determines it.

**4. Add the payee's bank account**

Maria banks in the Netherlands, so she is paid in EUR over SEPA. Submit her account as a payee address:

```bash theme={null}
curl "$BASE/payees/payee_c8pnahcrxqzd3z8d/addresses" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "bank_account",
    "currency": "eur",
    "rail": "sepa",
    "owner_type": "individual",
    "beneficiary_name": "Maria Lopez",
    "bank_name": "ABN AMRO",
    "account_number": "NL91ABNA0417164300",
    "beneficiary_address": { "line1": "Damrak 1", "city": "Amsterdam", "postal_code": "1012", "country": "NL" }
  }'
```

```json Response (abridged) theme={null}
{
  "id": "address_7m3kq9xwd2hr5tna",
  "payee_id": "payee_c8pnahcrxqzd3z8d",
  "currency": "eur",
  "rail": "sepa",
  "account_number_last4": "4300",
  "status": "active"
}
```

Infinity validates the details against the SEPA rules and registers the account with the payout network. Maria's status is now `active`, which means payouts to her are sent immediately. Each currency and rail requires different fields; `GET /bank-requirements` returns them so your forms can stay in sync with the validation.

> [!TIP]
>
> In the sandbox, any account number ending in `0000` is rejected with `400 bank_details_invalid`, which lets you exercise your error handling.

**5. Price the payout**

A quote prices payouts exactly as a create would, without saving or reserving anything:

```bash theme={null}
curl "$BASE/quotes" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
    "items": [ { "payee_id": "payee_c8pnahcrxqzd3z8d", "amount": "500.00", "currency": "eur" } ]
  }'
```

```json Response theme={null}
{
  "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
  "debit_currency": "usd",
  "fee_bearer": "account",
  "items": [
    {
      "payee_id": "payee_c8pnahcrxqzd3z8d",
      "amount": "500.00",
      "currency": "eur",
      "rate": "0.8955",
      "debit_amount": "568.35",
      "fee": "10.00",
      "payee_amount": "500.00",
      "payee_currency": "eur"
    }
  ],
  "total_debit": "568.35",
  "total_fee": "10.00",
  "available_balance": "10000.00",
  "sufficient_balance": true
}
```

With `fee_bearer: account`, you pay the fee on top: the wallet is debited USD 568.35, which is USD 558.35 converted at 0.8955 plus a USD 10.00 fee, and Maria receives exactly EUR 500.00. Rates aren't locked, so the payout is priced again at the moment you create it.

**6. Create the payout**

`POST /payouts` creates a batch of payouts in one call; here the batch holds a single payout. The `Idempotency-Key` is required:

```bash theme={null}
curl "$BASE/payouts" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv-1042" \
  -d '{
    "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
    "name": "October invoices",
    "description": "Design work, October",
    "items": [
      { "payee_id": "payee_c8pnahcrxqzd3z8d", "amount": "500.00", "currency": "eur", "reference": "inv-1042" }
    ]
  }'
```

```json Response (abridged) theme={null}
{
  "id": "batch_fcb4cuwtd6fcbmwr",
  "number": "PB-2026-21",
  "name": "October invoices",
  "status": "pending",
  "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
  "total_debit": "568.35",
  "payouts": [
    {
      "id": "payout_4kz9xq7m2w8dn3ra",
      "payee_id": "payee_c8pnahcrxqzd3z8d",
      "amount": "500.00",
      "currency": "eur",
      "debit_amount": "568.35",
      "status": "pending",
      "reference": "inv-1042"
    }
  ]
}
```

Infinity priced the payout, reserved USD 568.35 in the wallet and handed the payout to the network. If the request times out, repeat it with the same `Idempotency-Key`: you receive this same batch, and no second payout is created.

**7. Confirm it was paid**

Sandbox payouts move to `processing` after about 5 seconds and to `paid` after about 30. Retrieve the payout:

```bash theme={null}
curl "$BASE/payouts/payout_4kz9xq7m2w8dn3ra" -H "Authorization: Bearer $INFINITY_KEY"
```

```json Response (abridged) theme={null}
{ "id": "payout_4kz9xq7m2w8dn3ra", "status": "paid", "payee_amount": "500.00", "payee_currency": "eur" }
```

In production, don't poll for status. Register a [webhook endpoint](https://docs.infinityapp.in/guides/webhooks.md) and handle `payout.paid`, `payout.failed` and `payout.returned` as they arrive.

## Simulate a failure

A paid payout can still be returned by the payee's bank days later, and your integration needs to handle that. The sandbox can trigger it on demand:

```bash theme={null}
curl "$BASE/test/payouts/payout_4kz9xq7m2w8dn3ra/advance" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "returned" }'
```

The call returns `202 Accepted`. Within a couple of seconds the payout moves to `returned` with `failure_code: returned_by_bank`, and Infinity emits `payout.returned`. [Sandbox](https://docs.infinityapp.in/guides/sandbox.md) lists every outcome you can simulate.

## Go live

Switch the key and the base URL; no other code changes:

```bash theme={null}
export INFINITY_KEY="sk_live_..."
export BASE="https://api.infinityapp.in/v1"
```

In live, you fund wallets by bank transfer to your [funding addresses](https://docs.infinityapp.in/guides/funding-your-wallets.md), and payees can enter their own bank details through the hosted page instead of you submitting them.

## Next steps

> [card] [Payouts](https://docs.infinityapp.in/guides/payouts.md)
>
> Statuses, payouts on hold, editing and failures.

> [card] [Webhooks](https://docs.infinityapp.in/guides/webhooks.md)
>
> Receive and verify events.


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