> For the complete documentation index, see [llms.txt](https://docs.fonbnk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fonbnk.com/server-to-server/integration-guide/flow-examples/crypto-to-fiat.md).

# Crypto to Fiat

A POLYGON\_USDT (crypto) deposit paying out NGN (fiat) — the classic off-ramp.

{% hint style="info" %}
Every response on this page is a **sandbox** capture, so the contract address, the bank list and the rates are sandbox values. Production addresses are on [Supported countries and cryptocurrencies](/supported-countries-and-cryptocurrencies.md); read yours from [Get available currencies](/server-to-server/api-endpoints/get-available-currencies.md) rather than either.
{% endhint %}

{% stepper %}
{% step %}

#### Call [Get available currencies](/server-to-server/api-endpoints/get-available-currencies.md)

{% code title="Example response (trimmed to the two entries we need)" overflow="wrap" expandable="true" %}

```json
[
  {
    "currencyType": "crypto",
    "currencyCode": "POLYGON_USDT",
    "paymentChannels": [
      {
        "name": "Crypto",
        "type": "crypto",
        "transferTypes": ["manual"],
        "isDepositAllowed": true,
        "isPayoutAllowed": true
      }
    ],
    "currencyDetails": {
      "network": "POLYGON",
      "asset": "USDT",
      "contractAddress": "0x3b3a06b48119c035a2e86afdb69d9ad930643b3d"
    },
    "pairs": ["fiat", "merchant_balance"]
  },
  {
    "currencyType": "fiat",
    "currencyCode": "NGN",
    "paymentChannels": [
      {
        "name": "Bank transfer",
        "type": "bank",
        "transferTypes": ["manual"],
        "isDepositAllowed": true,
        "isPayoutAllowed": true
      },
      {
        "name": "Airtime",
        "type": "airtime",
        "transferTypes": [],
        "isDepositAllowed": false,
        "isPayoutAllowed": true,
        "carriers": [
          { "code": "ng_mtn", "name": "MTN Nigeria" },
          { "code": "ng_airtel", "name": "Airtel Nigeria" },
          { "code": "ng_glo", "name": "Glo Mobile Nigeria" },
          { "code": "ng_9mobile", "name": "9Mobile Nigeria" }
        ]
      }
    ],
    "currencyDetails": { "countryIsoCode": "NG" },
    "pairs": ["crypto", "merchant_balance"]
  }
]
```

{% endcode %}

POLYGON\_USDT allows deposits, and NGN's `bank` channel has `isPayoutAllowed: true`. So POLYGON\_USDT → NGN over `bank` is legal. `airtime` would work as a payout too — add a `carrierCode` if you use it.
{% endstep %}

{% step %}

#### Call [Get order limits](/server-to-server/api-endpoints/get-order-limits.md)

* depositPaymentChannel: "<mark style="color:yellow;">crypto</mark>"
* depositCurrencyType: "<mark style="color:yellow;">crypto</mark>"
* depositCurrencyCode: "<mark style="color:yellow;">POLYGON\_USDT</mark>"
* payoutPaymentChannel: "<mark style="color:yellow;">bank</mark>"
* payoutCurrencyType: "<mark style="color:yellow;">fiat</mark>"
* payoutCurrencyCode: "<mark style="color:yellow;">NGN</mark>"
* payoutCountryIsoCode: "<mark style="color:yellow;">NG</mark>"

{% code title="Example response" overflow="wrap" %}

```json
{
    "deposit": {
        "min": 1,
        "max": 500,
        "minUsd": 1,
        "maxUsd": 500,
        "step": 0.000001,
        "supportsDecimals": true
    },
    "payout": {
        "min": 1409,
        "max": 704460,
        "minUsd": 1,
        "maxUsd": 500,
        "step": 1,
        "supportsDecimals": false
    }
}
```

{% endcode %}

The user can send 1 to 500 POLYGON\_USDT and receive 1,409 to 704,460 NGN. Note that the NGN leg is whole units only — `supportsDecimals: false`, `step: 1`.

The user wants 30,000 NGN. Check their KYC tier with the [KYC flow](/server-to-server/kyc-flow.md), passing the amounts. Off-ramp KYC is a per-country switch and South Africa is currently the only country where it is on, so a Nigerian off-ramp needs none — but read `offrampKycRequired` rather than assuming. See [KYC](/kyc.md).
{% endstep %}

{% step %}

#### Call [Create quote](/server-to-server/api-endpoints/create-quote.md)

The amount goes on the payout leg, because the user asked for an NGN figure.

{% code title="Example request" %}

```json
{
    "deposit": {
        "paymentChannel": "crypto",
        "currencyType": "crypto",
        "currencyCode": "POLYGON_USDT"
    },
    "payout": {
        "paymentChannel": "bank",
        "currencyType": "fiat",
        "currencyCode": "NGN",
        "countryIsoCode": "NG",
        "amount": 30000
    }
}
```

{% endcode %}

{% code title="Example response" overflow="wrap" expandable="true" %}

```json
{
    "quoteId": "692d9874a60e2135463730cf",
    "quoteExpiresAt": "2025-12-01T14:00:28.208Z",
    "deposit": {
        "paymentChannel": "crypto",
        "currencyType": "crypto",
        "currencyCode": "POLYGON_USDT",
        "currencyDetails": {
            "network": "POLYGON",
            "asset": "USDT",
            "contractAddress": "0x3b3a06b48119c035a2e86afdb69d9ad930643b3d"
        },
        "cashout": {
            "amountBeforeFees": 21.272315,
            "amountAfterFees": 21.272315,
            "amountBeforeFeesUsd": 21.272315,
            "amountAfterFeesUsd": 21.272315,
            "chargedFees": [],
            "chargedFeesUsd": [],
            "totalChargedFees": 0,
            "totalChargedFeesUsd": 0,
            "exchangeRate": 1,
            "exchangeRateAfterFees": 1,
            "chargedFeesPerRecipient": {},
            "chargedFeesPerRecipientUsd": {},
            "feeSettings": []
        },
        "fieldsToCreateOrder": [
            {
                "key": "blockchainWalletAddress",
                "type": "string",
                "label": "Your wallet address",
                "required": false
            },
            {
                "key": "depositSandboxForcedFlow",
                "type": "enum",
                "label": "Sandbox deposit forced flow",
                "required": false,
                "defaultValue": "deposit_success",
                "options": [
                    { "label": "Deposit success", "value": "deposit_success" },
                    { "label": "Deposit invalid", "value": "deposit_invalid" }
                ]
            }
        ],
        "transferType": "manual"
    },
    "payout": {
        "paymentChannel": "bank",
        "currencyType": "fiat",
        "currencyCode": "NGN",
        "currencyDetails": { "countryIsoCode": "NG" },
        "cashout": {
            "amountBeforeFees": 31088,
            "amountAfterFees": 30000,
            "amountBeforeFeesUsd": 21.272315,
            "amountAfterFeesUsd": 20.527839,
            "chargedFees": [
                { "id": "service_fee", "type": "percentage", "recipient": "platform", "amount": 777.2 },
                { "id": "merchant_fee", "type": "percentage", "recipient": "merchant", "amount": 310.88 }
            ],
            "chargedFeesUsd": [
                { "id": "service_fee", "type": "percentage", "recipient": "platform", "amount": 0.531808 },
                { "id": "merchant_fee", "type": "percentage", "recipient": "merchant", "amount": 0.212723 }
            ],
            "totalChargedFees": 1088.08,
            "totalChargedFeesUsd": 0.744531,
            "exchangeRate": 1461.43,
            "exchangeRateAfterFees": 1514.4312,
            "chargedFeesPerRecipient": { "platform": 777.2, "merchant": 310.88 },
            "chargedFeesPerRecipientUsd": { "platform": 0.531808, "merchant": 0.212723 },
            "feeSettings": [
                { "id": "service_fee", "recipient": "platform", "type": "percentage", "value": 2.5, "min": 0, "max": "Infinity" },
                { "id": "merchant_fee", "recipient": "merchant", "type": "percentage", "value": 1, "min": 0, "max": "Infinity" }
            ]
        },
        "fieldsToCreateOrder": [
            { "key": "phoneNumber", "label": "Phone Number", "required": true, "type": "phone" },
            {
                "key": "bankCode",
                "label": "Bank name",
                "required": true,
                "type": "enum",
                "options": [
                    { "label": "Sandbox Bank", "value": "1" },
                    { "label": "Sandbox Bank 2", "value": "2" },
                    { "label": "Sandbox Bank 3", "value": "3" }
                ]
            },
            { "key": "bankAccountNumber", "label": "Bank Account Number", "required": true, "type": "string" },
            {
                "key": "payoutSandboxForcedFlow",
                "type": "enum",
                "label": "Sandbox payout forced flow",
                "required": false,
                "defaultValue": "payout_success",
                "options": [
                    { "label": "Payout success", "value": "payout_success" },
                    { "label": "Payout failed", "value": "payout_failed" }
                ]
            }
        ]
    }
}
```

{% endcode %}

To receive 30,000 NGN the user must deposit **21.272315** POLYGON\_USDT — that is `deposit.cashout.amountBeforeFees`. Collect the fields marked `required` on both legs:

* `phoneNumber`
* `bankCode` (from the enum options)
* `bankAccountNumber`

{% hint style="info" %}
`blockchainWalletAddress` is **not** required on a crypto *deposit* leg — it is `required: false` there, and `required: true` only when crypto is the payout. Send it anyway if you know it: it comes back in the transfer details as `senderWalletAddress`, which is what the user sees as "your wallet address". It is a display value, not a filter — the deposit is recognised from the transaction hash you confirm with.
{% endhint %}
{% endstep %}

{% step %}

#### Call [Create order](/server-to-server/api-endpoints/create-order.md)

{% code title="Example request" overflow="wrap" expandable="true" %}

```json
{
    "quoteId": "692d9874a60e2135463730cf",
    "userCountryIsoCode": "NG",
    "userEmail": "someuser@example.com",
    "userIp": "223.134.123.12",
    "deposit": {
        "paymentChannel": "crypto",
        "currencyType": "crypto",
        "currencyCode": "POLYGON_USDT"
    },
    "payout": {
        "paymentChannel": "bank",
        "currencyType": "fiat",
        "currencyCode": "NGN",
        "countryIsoCode": "NG",
        "amount": 30000
    },
    "fieldsToCreateOrder": {
        "blockchainWalletAddress": "0x5b7ae3c6c87f4a3f94b35c77233b13191ebfad20",
        "phoneNumber": "2348012345678",
        "bankCode": "1",
        "bankAccountNumber": "1234567890"
    }
}
```

{% endcode %}

{% code title="Example response (transfer instructions excerpt)" overflow="wrap" expandable="true" %}

```json
{
    "quoteUsed": true,
    "order": {
        "_id": "692d98b0a60e21354637311a",
        "countryIsoCode": "NG",
        "userId": "686671f07730d8d1a9b2260a",
        "userEmail": "someuser@example.com",
        "status": "deposit_awaiting",
        "deposit": {
            "paymentChannel": "crypto",
            "currencyType": "crypto",
            "currencyCode": "POLYGON_USDT",
            "currencyDetails": {
                "network": "POLYGON",
                "asset": "USDT",
                "contractAddress": "0x3b3a06b48119c035a2e86afdb69d9ad930643b3d"
            },
            "providedFieldsToCreateOrder": {
                "blockchainWalletAddress": "0x5b7ae3c6c87f4a3f94b35c77233b13191ebfad20"
            },
            "transferInstructions": {
                "type": "manual",
                "instructionsText": "Please send the exact amount of crypto to the address below. Make sure to send only USDT on the Polygon network. Sending any other assets or using a different network may result in loss of funds.",
                "transferDetails": [
                    { "id": "recipientWalletAddress", "label": "Wallet address to send", "value": "0xdc9cbad0c43f912a66cd44cd22a15c04368e659f" },
                    { "id": "senderWalletAddress", "label": "Your wallet address", "value": "0x5b7ae3c6c87f4a3f94b35c77233b13191ebfad20" },
                    { "id": "amountToSend", "label": "Amount to send", "value": "21.272315" },
                    { "id": "cryptoTransactionRequestAdditionalData", "label": "Crypto transaction additional data", "value": "" }
                ],
                "fieldsToConfirmOrder": [
                    { "key": "blockchainTransactionHash", "type": "string", "label": "Transaction hash", "required": true }
                ]
            }
        },
        "payout": {
            "paymentChannel": "bank",
            "currencyType": "fiat",
            "currencyCode": "NGN",
            "currencyDetails": { "countryIsoCode": "NG" },
            "providedFieldsToCreateOrder": {
                "phoneNumber": "2348012345678",
                "bankCode": "1",
                "bankAccountNumber": "1234567890"
            }
        },
        "statusChangeLogs": [],
        "createdAt": "2025-12-01T13:31:28.372Z",
        "updatedAt": "2025-12-01T13:31:28.372Z",
        "expiresAt": "2025-12-01T14:01:28.156Z"
    }
}
```

{% endcode %}

From `transferInstructions` and `fieldsToConfirmOrder` we know:

* The user sends <mark style="color:yellow;">21.272315</mark> Polygon USDT to <mark style="color:yellow;">0xdc9cbad0c43f912a66cd44cd22a15c04368e659f</mark>. Send the exact amount, on that network, to that address.
* `senderWalletAddress` echoes the wallet address you passed, for the user to check against their own wallet.
* Confirming the order needs <mark style="color:yellow;">blockchainTransactionHash</mark>.
  {% endstep %}

{% step %}

#### The user sends the exact amount to that address

{% endstep %}

{% step %}

#### Call [Confirm order](/server-to-server/api-endpoints/confirm-order.md) with the transaction hash

{% code title="Example request" %}

```json
{
  "orderId": "692d98b0a60e21354637311a",
  "fieldsToConfirmOrder": {
     "blockchainTransactionHash": "0xe168c39bf7165c0eaa88e4df1e21e987666e44f11f2bea6f9be1c145f382dade"
  }
}
```

{% endcode %}
{% endstep %}

{% step %}

#### We confirm the transaction on-chain and send the NGN payout

{% endstep %}

{% step %}

#### Wait for "<mark style="color:yellow;">payout\_successful</mark>"

Handle the `order-status-change` [webhook](/server-to-server/webhooks.md), or poll [Get order](/server-to-server/api-endpoints/get-order.md).
{% endstep %}
{% endstepper %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fonbnk.com/server-to-server/integration-guide/flow-examples/crypto-to-fiat.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
