> 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-on-ramp/initiate-with-customer.md).

# Initiate On-Ramp (with Customer)

Create a new customer and initiate an on-ramp transaction in a single call.

Creates a new customer record (or retrieves an existing one by email) and initiates a fiat-to-crypto on-ramp transaction.

{% hint style="info" %}
Use this endpoint when you don't have a pre-existing customer in IvoryPay. If the customer already exists, use [Initiate On-Ramp](/ivorypay-on-off-ramp-documentation/api-reference-on-ramp/initiate.md) instead.
{% endhint %}

## Endpoint

```
POST /v1/onramp
```

## Authentication

This endpoint is protected by the `HybridCheckoutHTTPAuthGuard`, which accepts any of the following credential types in the `Authorization` header:

| Credential type   | Header value                  | Use case                                               |
| ----------------- | ----------------------------- | ------------------------------------------------------ |
| Merchant API key  | `Authorization: <api_key>`    | Server-to-server calls from your backend               |
| Business-user JWT | `Authorization: Bearer <jwt>` | Calls made by an authenticated dashboard/business user |
| Customer JWT      | `Authorization: Bearer <jwt>` | Calls made by an authenticated end-customer            |

## 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)                                                                                               |
| `walletAddress`     | string | Yes      | Destination crypto wallet address                                                                                                    |
| `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                                                                                           |
| `token`             | string | Yes      | Cryptocurrency to receive. See [Supported Networks & Tokens](/ivorypay-on-off-ramp-documentation/resources/supported-blockchains.md) |
| `fiatCurrency`      | string | Yes      | Fiat currency to pay in. See [Supported Currencies](/ivorypay-on-off-ramp-documentation/resources/supported-currencies.md)           |
| `fiatAmount`        | number | No\*     | Amount in fiat the user will pay                                                                                                     |
| `cryptoAmount`      | number | No\*     | Amount in crypto the user will receive                                                                                               |
| `businessFeeInFiat` | number | No       | Your business fee in fiat. Omit or send `0` if you are not charging a fee                                                            |
| `redirectUrl`       | string | No       | URL to redirect user after checkout payment                                                                                          |
| `note`              | string | No       | Optional note attached to the transaction                                                                                            |

{% hint style="warning" %}
**\*** You must provide either `fiatAmount` or `cryptoAmount`, but not both.
{% endhint %}

## Example request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://ramp-api.ivorypay.io/api/v1/onramp \
  -H "Authorization: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Amina",
    "lastName": "Okafor",
    "email": "amina@example.com",
    "phoneNumber": "+2348012345678",
    "walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
    "blockchain": "BSC_MAINNET",
    "reference": "550e8400-e29b-41d4-a716-446655440000",
    "token": "USDT",
    "fiatCurrency": "NGN",
    "fiatAmount": 50000
  }'
```

{% endtab %}

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

```javascript
const response = await fetch("https://ramp-api.ivorypay.io/api/v1/onramp", {
  method: "POST",
  headers: {
    "Authorization": "your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    firstName: "Amina",
    lastName: "Okafor",
    email: "amina@example.com",
    phoneNumber: "+2348012345678",
    walletAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
    blockchain: "BSC_MAINNET",
    reference: "550e8400-e29b-41d4-a716-446655440000",
    token: "USDT",
    fiatCurrency: "NGN",
    fiatAmount: 50000,
  }),
});

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/onramp",
    headers={
        "Authorization": "your_api_key",
        "Content-Type": "application/json",
    },
    json={
        "firstName": "Amina",
        "lastName": "Okafor",
        "email": "amina@example.com",
        "phoneNumber": "+2348012345678",
        "walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
        "blockchain": "BSC_MAINNET",
        "reference": "550e8400-e29b-41d4-a716-446655440000",
        "token": "USDT",
        "fiatCurrency": "NGN",
        "fiatAmount": 50000,
    },
)

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":     "Amina",
		"lastName":      "Okafor",
		"email":         "amina@example.com",
		"phoneNumber":   "+2348012345678",
		"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
		"blockchain":    "BSC_MAINNET",
		"reference":     "550e8400-e29b-41d4-a716-446655440000",
		"token":         "USDT",
		"fiatCurrency":  "NGN",
		"fiatAmount":    50000,
	})

	req, _ := http.NewRequest("POST", "https://ramp-api.ivorypay.io/api/v1/onramp", 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 `201 Created` on success.

```json
{
  "success": true,
  "message": "Query successful",
  "data": {
    "firstName": "Amina",
    "lastName": "Okafor",
    "email": "amina@example.com",
    "refCode": "abc123def4",
    "reference": "550e8400-e29b-41d4-a716-446655440000",
    "transferDetails": {
      "accountName": "IvoryPay - Amina Okafor",
      "accountNumber": "1234567890",
      "bank": "Providus Bank",
      "amountPayable": 50000,
      "expiresAt": "2026-03-26T13:00:00.000Z",
      "currency": "NGN",
      "businessFee": 0,
      "platformFee": 250,
      "gasFee": 0.5,
      "createdAt": "2026-03-26T12:00:00.000Z",
      "checkoutUrl": null,
      "cryptoAmount": 31.25
    }
  }
}
```

{% hint style="info" %}
**`fiatCurrency: "ZAR"` behaves differently.** ZAR has no virtual account — the fiat-payment provider hands back a hosted checkout page instead. For ZAR, `accountName`/`accountNumber`/`bank` come back `null` and `transferDetails.checkoutUrl` is populated; redirect (or embed) the customer there to complete payment. See [Payment method types](/ivorypay-on-off-ramp-documentation/guides/hosted-checkout.md#payment-method-types-by-currency) for the full breakdown by currency.
{% endhint %}

## Response fields

| Field                           | Type           | Description                                                                                                                  |
| ------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `firstName`                     | string         | Customer's first name                                                                                                        |
| `lastName`                      | string         | Customer's last name                                                                                                         |
| `email`                         | string         | Customer's email address                                                                                                     |
| `refCode`                       | string         | IvoryPay's unique customer reference                                                                                         |
| `reference`                     | string         | Your transaction reference                                                                                                   |
| `transferDetails.accountName`   | string \| null | Virtual bank account name for payment (NGN/USD). `null` for ZAR and mobile-money currencies                                  |
| `transferDetails.accountNumber` | string \| null | Virtual bank account number (NGN/USD). `null` for ZAR and mobile-money currencies                                            |
| `transferDetails.bank`          | string \| null | Bank name for the virtual account (NGN/USD). `null` for ZAR and mobile-money currencies                                      |
| `transferDetails.amountPayable` | number         | Exact fiat amount the user must pay                                                                                          |
| `transferDetails.expiresAt`     | string         | ISO 8601 expiry time for the payment session                                                                                 |
| `transferDetails.currency`      | string         | Fiat currency                                                                                                                |
| `transferDetails.businessFee`   | number         | Your business fee                                                                                                            |
| `transferDetails.platformFee`   | number         | IvoryPay platform fee                                                                                                        |
| `transferDetails.gasFee`        | number         | Blockchain gas fee                                                                                                           |
| `transferDetails.createdAt`     | string         | ISO 8601 creation timestamp                                                                                                  |
| `transferDetails.checkoutUrl`   | string \| null | Hosted checkout page URL. **Populated for ZAR** (redirect the customer here) and mobile-money currencies; `null` for NGN/USD |
| `transferDetails.cryptoAmount`  | number         | Crypto amount the user will receive                                                                                          |
| `transferDetails.status`        | string         | Transaction status (only present on subsequent status lookups)                                                               |

## Related webhooks

* `onramp.fiatPaymentReceived` — Fiat payment confirmed
* `onramp.cryptoPayoutProcessing` — Crypto payout in progress
* `onramp.success` — Transaction completed
* `onramp.failed` — Transaction failed
