# Swapping between Currency Pairs

Learn how to convert funds between supported currency pairs using the Atlas Swaps API.

A swap converts funds from one currency to another at the current exchange rate and credits the destination currency to your Atlas wallet. Use swaps to move funds across borders, settle international payments, or maintain balances in multiple currencies.

Before initiating a swap, check the current rate using the [Exchange Rates](https://docs.tryduplo.com/atlas/guides/rates) guide to display a live preview to your users.

> **Note**  
> Currently, all swaps must originate from `NGN`. You cannot initiate a swap from USD, GBP, or EUR.

## [Initiating a swap](https://docs.tryduplo.com/en/atlas/guides/swaps#initiating-a-swap)

To initiate a swap, make a POST request to the [Initiate FX Swap](https://docs.tryduplo.com/atlas/fx-swap/initiateFxSwap) endpoint with the following required fields:

- `source_amount`: The amount in NGN to swap. The minimum amount you can swap for each currency pair is `100` of the target currency.
- `target_currency`: The destination currency (`USD`, `GBP`, or `EUR`).
- `source_reference`: A unique string you assign to identify this swap on your system.

### cURL Example

```bash
curl -X POST "https://atlas.tryduplo.com/api/v1/fx/swap" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "source_amount": 500000,
    "target_currency": "USD",
    "source_reference": "SWP_SRC_001"
  }'
```

> **IMPORTANT**  
> Swap requests can only be initiated between **8AM and 5PM WAT (UTC+01:00)**. Any requests made outside the allowed window will not be processed.

On a successful request, you should receive a response similar to the one below:

### JSON Example

```json
{
  "requestId": "48ae6a61-a4e4-40af-bb53-e0ac03ed2929",
  "requestTimestamp": "2026-04-16 22:33:23.097",
  "message": "FX swap initiated successfully.",
  "statusCode": 201,
  "data": {
    "id": "019d986d-7353-725e-bbf0-9060fb2cf3c4",
    "destinationCurrency": "USD",
    "sourceCurrency": "NGN",
    "debitedAmount": {
      "value": 500000,
      "currency": "NGN",
      "formatted": "NGN500000"
    },
    "creditedAmount": {
      "value": 16666.666666666668,
      "currency": "USD",
      "formatted": "USD16666.666666667"
    },
    "status": "pending",
    "sourceReference": "SWP_SRC_001",
    "negotiatedRate": null,
    "createdAt": "2026-04-16T23:33:23+01:00"
  }
}
```

The `debitedAmount` is the amount taken from your NGN wallet. The `creditedAmount` is the equivalent amount credited to your destination currency wallet.

### [Lifecycle of an FX swap](https://docs.tryduplo.com/en/atlas/guides/swaps#lifecycle-of-an-fx-swap)

Once a swap is initiated, Atlas will send a `FX_SWAP_CREATED` webhook to notify your system that the request has been received and is now sitting in the `PENDING` state. This gives you an early signal to update your internal records or reflect the pending state to your users.

The swap request will remain in the pending state until the admin approves the swap request. Then, it will move to the `COMPLETED` state, and you will receive a `FX_SWAP_COMPLETED` webhook event. If the swap request is rejected, which can be due to compliance reasons or market volatility, you will get a `FX_SWAP_FAILED` event instead.

You can view the structure of the payload and learn how to handle webhooks from Atlas in our [webhook guide](https://docs.tryduplo.com/atlas/guides/webhooks#foreign-exchange-events).

## [Checking swap status](https://docs.tryduplo.com/en/atlas/guides/swaps#checking-swap-status)

After initiating a swap, use the [Get FX Swap](https://docs.tryduplo.com/atlas/fx-swap/getFxSwap) endpoint to poll for its current status and details. Pass the `id` returned in the `data.id` field of the initiation response.

### cURL Example

```bash
curl -X GET "https://atlas.tryduplo.com/api/v1/fx/swap/c42fd5b5-c3cf-4c95-aa66-3e3155f62968" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Accept: application/json"
```

On a successful request, you should receive a response similar to the one below:

### JSON Example

```json
{
    "requestId": "31c33e10-0088-4ebb-8686-1893ee7bee21",
    "requestTimestamp": "2026-04-16 22:44:35.413",
    "message": "FX swap fetched successfully.",
    "statusCode": 200,
    "data": {
        "id": "019d986d-7353-725e-bbf0-9060fb2cf3c4",
        "destinationCurrency": "USD",
        "sourceCurrency": "NGN",
        "debitedAmount": {
            "value": 500000,
            "currency": "NGN",
            "formatted": "NGN500000"
        },
        "creditedAmount": {
            "value": 16666.666666667,
            "currency": "USD",
            "formatted": "USD16666.666666667"
        },
        "status": "pending",
        "sourceReference": "SWP_SRC_001",
        "negotiatedRate": null,
        "createdAt": "2026-04-16T23:33:23+01:00"
    }
}
```

## [Listing your swap history](https://docs.tryduplo.com/en/atlas/guides/swaps#listing-your-swap-history)

Once you've been running swaps for a while, you'll need a way to review past activity: whether to audit recent conversions, surface transaction history for your users, or investigate a specific swap. The [List FX Swaps](https://docs.tryduplo.com/atlas/fx-swap/listFxSwaps) endpoint returns a paginated list of all swap requests on your account.

You can narrow results using the following query parameters:

- `status` - show only swaps with a specific state (`completed`, `pending`, or `failed`).
- `currency` - show only swaps that converted to a particular destination currency (`USD`, `GBP`, or `EUR`).
- `from_date` - the start of the date range to filter by (format: `YYYY-MM-DD`).
- `to_date` - the end of the date range to filter by (format: `YYYY-MM-DD`).
- `page` - the page number to retrieve (default: `1`).
- `limit` - the number of results per page (default: `10`).

All parameters are optional. Omitting them returns all swaps in reverse chronological order.

### cURL Example

```bash
curl -X GET "https://atlas.tryduplo.com/api/v1/fx/swaps?status=completed&currency=USD&from_date=2026-02-01&to_date=2026-02-28&page=1&limit=10" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Accept: application/json"
```

On a successful request, you should receive a response similar to the one below:

### JSON Example

```json
{
    "requestId": "45e55bb7-72d4-4e0c-95ed-e58773bc6d22",
    "requestTimestamp": "2026-04-16 22:52:40.874",
    "message": "FX swaps fetched successfully.",
    "statusCode": 200,
    "data": [
        {
            "id": "019d986d-7353-725e-bbf0-9060fb2cf3c4",
            "destinationCurrency": "USD",
            "sourceCurrency": "NGN",
            "debitedAmount": {
                "value": 500000,
                "currency": "NGN",
                "formatted": "NGN500000"
            },
            "creditedAmount": {
                "value": 16666.666666667,
                "currency": "USD",
                "formatted": "USD16666.666666667"
            },
            "status": "pending",
            "sourceReference": "SWP_SRC_001",
            "negotiatedRate": null,
            "createdAt": "2026-04-16T23:33:23+01:00"
        },
        {
            "id": "019d9872-0498-72c6-b234-995e53b91690",
            "destinationCurrency": "GBP",
            "sourceCurrency": "NGN",
            "debitedAmount": {
                "value": 400000,
                "currency": "NGN",
                "formatted": "NGN400000"
            },
            "creditedAmount": {
                "value": 8000,
                "currency": "GBP",
                "formatted": "GBP8000"
            },
            "status": "pending",
            "sourceReference": "SWP_SRC_001",
            "negotiatedRate": null,
            "createdAt": "2026-04-16T23:38:22+01:00"
        },
        {
            "id": "019d9872-a593-7171-a7a2-0a599d64e118",
            "destinationCurrency": "EUR",
            "sourceCurrency": "NGN",
            "debitedAmount": {
                "value": 300000,
                "currency": "NGN",
                "formatted": "NGN300000"
            },
            "creditedAmount": {
                "value": 6666.6666666667,
                "currency": "EUR",
                "formatted": "EUR6666.6666666667"
            },
            "status": "pending",
            "sourceReference": "SWP_SRC_001",
            "negotiatedRate": null,
            "createdAt": "2026-04-16T23:39:03+01:00"
        },
        {
            "id": "019d9874-262a-7184-9a7b-f976ed84e18e",
            "destinationCurrency": "EUR",
            "sourceCurrency": "NGN",
            "debitedAmount": {
                "value": 30,
                "currency": "NGN",
                "formatted": "NGN30"
            },
            "creditedAmount": {
                "value": 0.66666666666667,
                "currency": "EUR",
                "formatted": "EUR0.66666666666667"
            },
            "status": "pending",
            "sourceReference": "SWP_SRC_001",
            "negotiatedRate": null,
            "createdAt": "2026-04-16T23:40:42+01:00"
        }
    ],
    "links": {
        "first": "http://atlas.tryduplo.com/api/v1/fx/swaps?page=1",
        "last": "http://atlas.tryduplo.com/api/v1/fx/swaps?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "http://atlas.tryduplo.com/api/v1/fx/swaps?page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "http://atlas.tryduplo.com/api/v1/fx/swaps",
        "per_page": 10,
        "to": 4,
        "total": 4
    }
}
```

## [Reconciling swap transactions](https://docs.tryduplo.com/en/atlas/guides/swaps#reconciling-swap-transactions)

If you're building a reconciliation flow that needs to cover multiple transaction types (payouts, collections, and swaps) in a single view, the [List Transactions](https://docs.tryduplo.com/atlas/transactions/getTransactions) endpoint with `channel=swap` lets you pull swap activity in the same format as your other transactions.

### cURL Example

```bash
curl -X GET "https://atlas.tryduplo.com/api/v1/transaction?channel=swap&page=1&limit=10" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Accept: application/json"
```

On a successful request, you should receive a response similar to the one below:

### JSON Example

```json
{
  "requestId": "e6f7a8b9-c0d1-2345-abcd-ef6789012345",
  "requestTimestamp": "2026-02-28 14:30:00.000",
  "message": "Transactions retrieved successfully.",
  "statusCode": 200,
  "data": {
    "items": [
      {
        "id": "TXN_abc123def456",
        "channel": "swap",
        "reference": "d52ge6c6-d4dg-5d06-bb77-4f4266g73079",
        "sourceReference": "SWP_SRC_002",
        "fromCurrency": "NGN",
        "toCurrency": "USD",
        "amount": 1000000,
        "convertedAmount": 648.5,
        "status": "completed",
        "createdAt": "2026-04-14T09:45:12+00:00"
      },
      {
        "id": "TXN_789xyz012abc",
        "channel": "swap",
        "reference": "c42fd5b5-c3cf-4c95-aa66-3e3155f62968",
        "sourceReference": "SWP_SRC_001",
        "fromCurrency": "NGN",
        "toCurrency": "USD",
        "amount": 500000,
        "convertedAmount": 324.25,
        "status": "completed",
        "createdAt": "2026-04-10T10:15:30+00:00"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 2,
      "totalPages": 1
    }
  }
}
```

Each item includes a `reference` field that maps directly to the swap `id` from the FX swap endpoints, so you can cross-reference records between the two.

## [Fetching wallet balances](https://docs.tryduplo.com/en/atlas/guides/swaps#fetching-wallet-balances)

After a swap has been successfully processed, the swapped amount settles in the wallet with the corresponding destination currency. You can view the wallet balances of all available currencies using the [FX Wallet Balances](https://docs.tryduplo.com/atlas/fx-swap/getFxWalletBalances) endpoint.

### cURL Example

```bash
curl -X GET "https://atlas.tryduplo.com/api/v1/fx/wallet/balances" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Accept: application/json"
```

On a successful request, you should receive a response similar to the one below:

### JSON Example

```json
{
    "requestId": "34ec2faa-81c0-41e1-b5fd-f11a5a417cfe",
    "requestTimestamp": "2026-04-16 23:06:50.663",
    "message": "FX wallet balances fetched successfully.",
    "statusCode": 200,
    "data": [
        {
            "currency": "NGN",
            "ledgerBalance": {
                "value": 25199720,
                "currency": "NGN",
                "formatted": "NGN25199720"
            },
            "availableBalance": {
                "value": 25199720,
                "currency": "NGN",
                "formatted": "NGN25199720"
            },
            "businessState": "live"
        },
        {
            "currency": "EUR",
            "ledgerBalance": {
                "value": 0,
                "currency": "EUR",
                "formatted": "EUR0"
            },
            "availableBalance": {
                "value": 0,
                "currency": "EUR",
                "formatted": "EUR0"
            },
            "businessState": "live"
        },
        {
            "currency": "USD",
            "ledgerBalance": {
                "value": 0,
                "currency": "USD",
                "formatted": "USD0"
            },
            "availableBalance": {
                "value": 0,
                "currency": "USD",
                "formatted": "USD0"
            },
            "businessState": "live"
        },
        {
            "currency": "GBP",
            "ledgerBalance": {
                "value": 0,
                "currency": "GBP",
                "formatted": "GBP0"
            },
            "availableBalance": {
                "value": 0,
                "currency": "GBP",
                "formatted": "GBP0"
            },
            "businessState": "live"
        }
    ]
}
```
