> For the complete documentation index, see [llms.txt](https://ivorypay.gitbook.io/ivorypay-on-off-ramp-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ivorypay.gitbook.io/ivorypay-on-off-ramp-documentation/api-reference-off-ramp/initiate-with-customer.md).

# Initiate Off-Ramp (with Customer)

Create a new customer and initiate a crypto-to-fiat off-ramp transaction.

Creates a new customer record (or retrieves an existing one by email) and initiates a crypto-to-fiat off-ramp transaction. The user will send crypto and receive fiat in their bank account or mobile money wallet.

## Endpoint

```
POST /v1/offramp
```

## Authentication

This endpoint accepts any one of three credentials in the `Authorization` header:

| Credential        | Header value                  |
| ----------------- | ----------------------------- |
| Merchant API key  | `Authorization: <api_key>`    |
| Business-user JWT | `Authorization: Bearer <jwt>` |
| Customer JWT      | `Authorization: Bearer <jwt>` |

## Request body

| Field                 | Type   | Required | Description                                                                                                                                                                        |
| --------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firstName`           | string | Yes      | Customer's first name (min 1 character)                                                                                                                                            |
| `lastName`            | string | Yes      | Customer's last name (min 1 character)                                                                                                                                             |
| `email`               | string | Yes      | Customer's email address                                                                                                                                                           |
| `phoneNumber`         | string | No       | Customer's phone number (E.164 format)                                                                                                                                             |
| `accountNumber`       | string | Yes      | Recipient bank account number or mobile money number                                                                                                                               |
| `bankCode`            | string | No       | Bank code for NGN bank payouts (use [List Banks](/ivorypay-on-off-ramp-documentation/api-reference-banks/list-banks.md) to get valid codes). Not required for mobile money payouts |
| `fiatCurrency`        | string | Yes      | Fiat currency for payout. See [Supported Currencies](/ivorypay-on-off-ramp-documentation/resources/supported-currencies.md)                                                        |
| `blockchain`          | string | Yes      | Blockchain network. See [Supported Blockchains](/ivorypay-on-off-ramp-documentation/resources/supported-blockchains.md)                                                            |
| `reference`           | string | Yes      | Your unique reference for this transaction. Validated as a string only (UUID not required on this variant)                                                                         |
| `token`               | string | Yes      | Cryptocurrency the user will send. See [Supported Networks & Tokens](/ivorypay-on-off-ramp-documentation/resources/supported-blockchains.md)                                       |
| `fiatAmount`          | number | No\*     | Fiat amount to be paid out                                                                                                                                                         |
| `cryptoAmount`        | number | No\*     | Crypto amount to be sent                                                                                                                                                           |
| `businessFeeInCrypto` | number | No       | Your business fee in crypto. Pair with `cryptoAmount`                                                                                                                              |
| `businessFeeInFiat`   | number | No       | Your business fee in fiat. Pair with `fiatAmount`                                                                                                                                  |
| `note`                | string | No       | Transaction note                                                                                                                                                                   |

{% hint style="warning" %}
**\*** Provide either `fiatAmount` + `businessFeeInFiat` OR `cryptoAmount` + `businessFeeInCrypto`. Mixing a fiat amount with a crypto fee (or vice versa) is rejected by validation.
{% endhint %}

## Example request

{% tabs %}
{% tab title="Bank (NGN)" %}

```bash
curl -X POST https://ramp-api.ivorypay.io/api/v1/offramp \
  -H "Authorization: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Chidi",
    "lastName": "Nwankwo",
    "email": "chidi@example.com",
    "phoneNumber": "+2348098765432",
    "accountNumber": "0123456789",
    "bankCode": "058",
    "blockchain": "BSC_MAINNET",
    "reference": "660e8400-e29b-41d4-a716-446655440001",
    "token": "USDT",
    "fiatCurrency": "NGN",
    "fiatAmount": 100000
  }'
```

{% endtab %}

{% tab title="Mobile Money (UGX)" %}

```bash
curl -X POST https://ramp-api.ivorypay.io/api/v1/offramp \
  -H "Authorization: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Chidi",
    "lastName": "Nwankwo",
    "email": "chidi@example.com",
    "phoneNumber": "+256772882926",
    "accountNumber": "256772882926",
    "blockchain": "STARKNET_MAINNET",
    "reference": "660e8410-f23c-41c4-a628-838625530891",
    "token": "USDT",
    "fiatCurrency": "UGX",
    "cryptoAmount": 1.5,
    "businessFeeInCrypto": 0.001
  }'
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const response = await fetch("https://ramp-api.ivorypay.io/api/v1/offramp", {
  method: "POST",
  headers: {
    "Authorization": "your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    firstName: "Chidi",
    lastName: "Nwankwo",
    email: "chidi@example.com",
    phoneNumber: "+2348098765432",
    accountNumber: "0123456789",
    bankCode: "058",
    blockchain: "BSC_MAINNET",
    reference: "660e8400-e29b-41d4-a716-446655440001",
    token: "USDT",
    fiatCurrency: "NGN",
    fiatAmount: 100000,
  }),
});

const data = await response.json();
console.log(data);
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.post(
    "https://ramp-api.ivorypay.io/api/v1/offramp",
    headers={
        "Authorization": "your_api_key",
        "Content-Type": "application/json",
    },
    json={
        "firstName": "Chidi",
        "lastName": "Nwankwo",
        "email": "chidi@example.com",
        "phoneNumber": "+2348098765432",
        "accountNumber": "0123456789",
        "bankCode": "058",
        "blockchain": "BSC_MAINNET",
        "reference": "660e8400-e29b-41d4-a716-446655440001",
        "token": "USDT",
        "fiatCurrency": "NGN",
        "fiatAmount": 100000,
    },
)

print(response.json())
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body, _ := json.Marshal(map[string]interface{}{
		"firstName":     "Chidi",
		"lastName":      "Nwankwo",
		"email":         "chidi@example.com",
		"phoneNumber":   "+2348098765432",
		"accountNumber": "0123456789",
		"bankCode":      "058",
		"blockchain":    "BSC_MAINNET",
		"reference":     "660e8400-e29b-41d4-a716-446655440001",
		"token":         "USDT",
		"fiatCurrency":  "NGN",
		"fiatAmount":    100000,
	})

	req, _ := http.NewRequest("POST", "https://ramp-api.ivorypay.io/api/v1/offramp", bytes.NewBuffer(body))
	req.Header.Set("Authorization", "your_api_key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)
	fmt.Println(string(respBody))
}
```

{% endtab %}
{% endtabs %}

## Example response

Returns HTTP `201 Created`.

```json
{
  "success": true,
  "message": "Query successful",
  "data": {
    "firstName": "Chidi",
    "lastName": "Nwankwo",
    "email": "chidi@example.com",
    "refCode": "xyz789abc0",
    "reference": "660e8400-e29b-41d4-a716-446655440001",
    "transferDetails": {
      "token": "USDT",
      "blockchain": "BSC_MAINNET",
      "amountPayable": 62.5,
      "businessFee": 0,
      "platformFee": 0.3,
      "walletAddress": "0xIvoryPayDepositAddress...",
      "createdAt": "2026-03-26T12:00:00.000Z",
      "fiatAmount": 100000,
      "expiresAt": "2026-03-26T13:00:00.000Z",
      "sessionId": "session_abc123",
      "duration": 3600,
      "status": "INITIATED"
    }
  }
}
```

## Response fields

| Field                           | Type   | Description                                       |
| ------------------------------- | ------ | ------------------------------------------------- |
| `refCode`                       | string | IvoryPay's unique customer reference              |
| `reference`                     | string | Your transaction reference                        |
| `transferDetails.token`         | string | Crypto token the user must send                   |
| `transferDetails.blockchain`    | string | Blockchain network                                |
| `transferDetails.amountPayable` | number | Exact crypto amount the user must send            |
| `transferDetails.walletAddress` | string | IvoryPay deposit address — user sends crypto here |
| `transferDetails.fiatAmount`    | number | Fiat amount the user will receive                 |
| `transferDetails.expiresAt`     | string | ISO 8601 session expiry time                      |
| `transferDetails.sessionId`     | string | Session identifier (used for refresh)             |
| `transferDetails.duration`      | number | Session duration in seconds                       |
| `transferDetails.businessFee`   | number | Your business fee                                 |
| `transferDetails.platformFee`   | number | IvoryPay platform fee                             |

## Related webhooks

* `offramp.cryptoPaymentReceived` — Crypto deposit detected on-chain
* `offramp.success` — Fiat payout sent to bank or mobile money wallet
* `offramp.failed` — Transaction failed
* `offramp.declined` — Transaction declined

## Error cases

| Error code      | Description                                                                              |
| --------------- | ---------------------------------------------------------------------------------------- |
| `ONOFFRAMP0033` | Invalid bank code                                                                        |
| `ONOFFRAMP0024` | Token not enabled for your account — contact support to enable the token/blockchain pair |

## Sandbox behaviour

{% hint style="info" %}
Off-ramp token access is provisioned per API key. If your sandbox key has not been enabled for a specific token/blockchain combination, you will receive `ONOFFRAMP0024`. Contact support with the token and network you need enabled.
{% endhint %}
