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

# Onramping

> Create on-ramp pay-links that let your customers buy crypto with fiat (card or bank transfer) and send it directly to an invoice address.

# Onramping API

This document covers the **Onramping** endpoint used to create **pay-links** that redirect your customers to our on-ramp checkout where they can purchase crypto with fiat and have it sent directly to a deposit address.

It includes:

* Create a pay-link (`POST /api/ramping/links`)

> This endpoint is protected, you must be authenticated.

***

## Base URL

All examples use:

* `https://www.niftipay.com`

If you're running locally, replace with your own base URL.

***

## Authentication

This endpoint supports **two authentication methods** (depending on your integration setup):

### 1) API Key (recommended for server-to-server integrations)

Send your API key in the `x-api-key` header.

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/ramping/links" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ ... }'
```

### 2) Session cookie (browser / dashboard usage)

If you are authenticated via the dashboard.

> For browser calls, you usually don't need to add headers manually — the cookie is sent automatically.

***

## How it works

1. You call `POST /api/ramping/links` with your customer's details and the fiat amount.
2. The API creates an underlying crypto invoice order and generates a signed pay-link token.
3. You redirect your customer to the returned `url`.
4. The customer lands on the Niftipay on-ramp page, selects a payment method (card or bank transfer), completes KYC if needed, and pays.
5. The purchased crypto is sent directly to the invoice deposit address.
6. Once the on-chain deposit is detected, the invoice is marked as `paid` and your webhook fires.

***

## Create a pay-link

`POST /api/ramping/links`

### Request body

| Field          | Type             | Required | Notes                                                                                                                                                      |
| -------------- | ---------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firstName`    | string           | Yes      | Customer's first name.                                                                                                                                     |
| `lastName`     | string           | Yes      | Customer's last name.                                                                                                                                      |
| `email`        | string           | Yes      | Customer's email. Used for verification and KYC.                                                                                                           |
| `fiatAmount`   | string or number | Yes      | The fiat amount the merchant wants to receive (net). Must be a valid decimal.                                                                              |
| `network`      | string           | No       | Blockchain network: `BTC`, `LTC`, `ETH`, `SOL`, or `XRP`. Falls back to your saved defaults if omitted.                                                    |
| `asset`        | string           | No       | Crypto asset: `BTC`, `LTC`, `ETH`, `SOL`, `XRP`, `USDT`, or `USDC`. USDT/USDC require `network` to be `ETH`. Falls back to your saved defaults if omitted. |
| `fiatCurrency` | string           | No       | Fiat currency code. Defaults to `EUR` if not provided and no saved default. See [supported currencies](#supported-fiat-currencies) below.                  |
| `reference`    | string           | No       | Your own unique reference for this order. If provided, must be unique across your orders.                                                                  |
| `merchantId`   | string           | No       | Optional merchant identifier for multi-merchant setups.                                                                                                    |
| `provider`     | string           | No       | Optional provider preference. If omitted, the provider is chosen automatically based on customer geolocation.                                              |

> If `network` and `asset` are not provided, the API will use your saved defaults from `/api/ramping/settings-token`. If no defaults are saved either, the request will fail with a 400 error.

### Query parameters

| Param              | Type  | Notes                                                                                       |
| ------------------ | ----- | ------------------------------------------------------------------------------------------- |
| `replaceCancelled` | `"1"` | If set, allows re-creating a link for a previously cancelled order with the same reference. |

***

### Success response (200)

```json theme={null}
{
  "url": "https://www.niftipay.com/ramping/pay/eyJhbG...",
  "token": "eyJhbG...",
  "order": {
    "id": "clxyz123...",
    "reference": "INV-001",
    "network": "ETH",
    "asset": "USDT",
    "amountCrypto": "105.26",
    "fiatCurrency": "EUR",
    "fiatAmount": "100.00",
    "depositAddress": "0xabc123...",
    "destinationTag": null,
    "paymentUri": "ethereum:0xabc123...?value=105260000",
    "qrUrl": "https://...",
    "status": "pending",
    "createdAt": "2026-03-26T10:00:00.000Z",
    "expiresAt": "2026-03-27T10:00:00.000Z",
    "merchantId": null
  },
  "link": {
    "orderId": "clxyz123...",
    "reference": "INV-001",
    "fiat": "EUR",
    "fiatAmount": "100.00",
    "crypto": "USDT",
    "blockchain": "ETH",
    "expiresAt": "2026-03-27T10:00:00.000Z",
    "invoiceExpiresAt": "2026-03-27T10:00:00.000Z",
    "invoiceStatus": "pending",
    "providerHint": null,
    "fiatAmountNet": null,
    "fiatAmountGross": null,
    "feePercent": null
  }
}
```

### Response fields

#### `url`

The full public URL to redirect your customer to. This is the on-ramp checkout page.

#### `order`

| Field            | Type           | Notes                                           |
| ---------------- | -------------- | ----------------------------------------------- |
| `id`             | string         | Internal order ID.                              |
| `reference`      | string         | Your reference (or auto-generated).             |
| `network`        | string         | Blockchain network.                             |
| `asset`          | string         | Crypto asset.                                   |
| `amountCrypto`   | string         | The crypto amount the customer needs to send.   |
| `fiatCurrency`   | string         | Fiat currency code.                             |
| `fiatAmount`     | string         | Net fiat amount.                                |
| `depositAddress` | string         | The on-chain address the customer will send to. |
| `destinationTag` | string or null | XRP destination tag (only for XRP).             |
| `paymentUri`     | string         | Payment URI for wallet apps.                    |
| `qrUrl`          | string         | QR code image URL.                              |
| `status`         | string         | Order status (starts as `pending`).             |
| `createdAt`      | string         | ISO 8601 creation timestamp.                    |
| `expiresAt`      | string         | ISO 8601 expiration timestamp.                  |
| `merchantId`     | string or null | Your merchant ID if provided.                   |

#### `link`

| Field              | Type           | Notes                                                |
| ------------------ | -------------- | ---------------------------------------------------- |
| `orderId`          | string         | Same as `order.id`.                                  |
| `reference`        | string         | Same as `order.reference`.                           |
| `fiat`             | string         | Fiat currency.                                       |
| `fiatAmount`       | string         | Net fiat amount.                                     |
| `crypto`           | string         | Crypto asset.                                        |
| `blockchain`       | string         | Blockchain network.                                  |
| `expiresAt`        | string         | When the pay-link token expires.                     |
| `invoiceExpiresAt` | string         | When the underlying invoice expires.                 |
| `invoiceStatus`    | string         | Current invoice status.                              |
| `providerHint`     | string or null | Provider hint if specified.                          |
| `fiatAmountNet`    | string or null | Net fiat amount (provider prefill).                  |
| `fiatAmountGross`  | string or null | Gross fiat amount including fees (provider prefill). |
| `feePercent`       | number or null | Fee percentage applied (provider prefill).           |

***

## Supported fiat currencies

The following fiat currencies are supported for on-ramping:

| Code  | Currency           |
| ----- | ------------------ |
| `USD` | US Dollar          |
| `EUR` | Euro               |
| `GBP` | British Pound      |
| `AUD` | Australian Dollar  |
| `AED` | UAE Dirham         |
| `BRL` | Brazilian Real     |
| `CAD` | Canadian Dollar    |
| `CHF` | Swiss Franc        |
| `CZK` | Czech Koruna       |
| `DKK` | Danish Krone       |
| `HKD` | Hong Kong Dollar   |
| `IDR` | Indonesian Rupiah  |
| `INR` | Indian Rupee       |
| `JPY` | Japanese Yen       |
| `MXN` | Mexican Peso       |
| `NOK` | Norwegian Krone    |
| `NZD` | New Zealand Dollar |
| `PHP` | Philippine Peso    |
| `PLN` | Polish Zloty       |
| `QAR` | Qatari Riyal       |
| `RON` | Romanian Leu       |
| `SAR` | Saudi Riyal        |
| `SEK` | Swedish Krona      |
| `SGD` | Singapore Dollar   |
| `THB` | Thai Baht          |
| `TRY` | Turkish Lira       |
| `TWD` | New Taiwan Dollar  |
| `VND` | Vietnamese Dong    |
| `ZAR` | South African Rand |

> Availability of specific currencies may vary depending on the customer's country and the on-ramp provider selected.

***

## Bank approval rates

On-ramping is limited by the customer's card-issuing bank. Each bank has a historic approval rate that determines how likely a card transaction is to succeed.

See the full [Bank Approval Rates](/api/bank-approvals) reference for all supported banks and their approval percentages by region.

***

## Error responses

| Status | Condition                              | Example                                                                                                                              |
| ------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| 400    | Missing required fields                | `{ "error": "firstName, lastName, email are required" }`                                                                             |
| 400    | Invalid fiat amount                    | `{ "error": "fiatAmount is required and must be a number (string or number)" }`                                                      |
| 400    | Missing network/asset with no defaults | `{ "error": "network and asset are required. Either provide them in the request or set defaults via /api/ramping/settings-token." }` |
| 400    | Unsupported network                    | `{ "error": "Unsupported network: ABC" }`                                                                                            |
| 400    | Asset/network mismatch                 | `{ "error": "USDC/USDT require ETH" }`                                                                                               |
| 403    | Crypto not enabled for ramping         | `{ "error": "Crypto not enabled for ramping" }`                                                                                      |
| 409    | Duplicate reference                    | `{ "error": "Reference already exists" }`                                                                                            |
| 409    | No available deposit addresses         | `{ "error": "No available addresses" }`                                                                                              |

***

## Examples

### Example 1 — Basic pay-link (EUR, ETH network)

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/ramping/links" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "fiatAmount": "100",
    "network": "ETH",
    "asset": "USDT",
    "fiatCurrency": "EUR"
  }'
```

### Example 2 — With reference and merchant ID

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/ramping/links" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane@example.com",
    "fiatAmount": "250.50",
    "network": "BTC",
    "asset": "BTC",
    "fiatCurrency": "USD",
    "reference": "ORDER-2026-001",
    "merchantId": "shop-london-01"
  }'
```

### Example 3 — Using saved defaults (no network/asset/fiat)

If you have already configured defaults via the dashboard or `/api/ramping/settings-token`:

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/ramping/links" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Alex",
    "lastName": "Johnson",
    "email": "alex@example.com",
    "fiatAmount": "50"
  }'
```

### Example 4 — Replace a cancelled order

If a previous order with the same reference was cancelled and you want to create a new one:

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/ramping/links?replaceCancelled=1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "fiatAmount": "100",
    "network": "SOL",
    "asset": "SOL",
    "reference": "ORDER-2026-001"
  }'
```

***

## Customer flow after redirect

Once your customer opens the `url` returned by this endpoint:

1. They see the on-ramp checkout page with the invoice details pre-filled.
2. They enter their email (used for verification code and KYC).
3. They select a payment method: **Debit/Credit Card** or **Bank Transfer**.
4. They are redirected to complete KYC and payment.
5. The crypto is purchased and sent to the invoice deposit address.
6. Once the on-chain deposit is confirmed, the invoice status changes to `paid`.

> The on-ramp provider is automatically selected based on the customer's geolocation. You can override this with the `provider` field in the API request.

***

## Node.js Example

A complete Node.js example showing how to create an onramping pay-link, including all optional fields and response parsing.

```javascript theme={null}
const result = await apiRequest("POST", "/api/ramping/links", {
  // Customer details — used for checkout flow and KYC
  firstName: "John",
  lastName: "Smith",
  email: "john.smith@example.com",

  // Net fiat amount you (the merchant) want to receive
  fiatAmount: 100,

  // Blockchain network (optional — falls back to dashboard defaults)
  network: "ETH",

  // Crypto asset (optional — falls back to dashboard defaults)
  asset: "USDT",

  // Fiat currency (defaults to "EUR")
  fiatCurrency: "EUR",

  // Your unique reference (optional)
  reference: "RAMP-ORDER-001",
});

// Key response fields:
// result.url                  — redirect customer here (checkout page)
// result.token                — signed token in the URL
// result.order.id             — underlying crypto invoice ID
// result.order.depositAddress — on-chain deposit address
// result.order.amountCrypto   — crypto amount
// result.order.status         — "pending" initially
// result.link.fiatAmountNet   — net fiat amount
// result.link.fiatAmountGross — gross fiat amount (with fees)
// result.link.feePercent      — fee percentage
```

> See the full working script with setup and helper function: [API Examples (Node.js)](/api/examples#example-2-create-an-onramping-pay-link)

***

## Webhooks

Ramping orders fire events on **two channels**, both delivered to your merchant webhook URL with the same HMAC signing scheme:

* **Core order events** (`pending`, `paid`, `cancelled`, `expired`, `refunded`) track the underlying crypto invoice — the same events you receive for direct crypto orders.
* **Ramping events** (`ramping.status_changed`, `ramping.kyc_pending`) track the onramp provider's own lifecycle (KYC, fiat capture, status transitions).

### Expiry behavior for Banxa orders

Crypto invoices created through the ramping flow get an initial `expiresAt = createdAt + 12 hours`, the same as direct invoices. **Onramp orders behave differently when KYC is in progress:**

* If the linked Banxa order is still in a non-terminal status (e.g. `extraVerification`, `pendingPayment`, `waitingPayment`, `paymentReceived`) as the 12h mark approaches, Niftipay automatically extends the invoice's `expiresAt` up to a **72-hour hard cap from the ramping order's creation time** and emits a `ramping.kyc_pending` event.
* If KYC clears within 72h, funds are delivered on-chain and you receive the normal `paid` event.
* If KYC does not clear within 72h, the invoice is force-cancelled and you receive an `expired` event with `reason: "ramping_kyc_timeout"` plus a final `ramping.status_changed` with `reason: "kyc_timeout_72h"`.

See the full event reference and payload examples in the [Webhooks documentation](/api/webhooks#ramping-webhooks-onramp-lifecycle).
