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

# Merchant ramp

> Fiat onramp and offramp for registered merchants — quote, initiate, status, and webhooks.

Use the **merchant ramp API** for a simple server-to-server flow: quote amounts, initiate when the customer is ready, then poll status or use webhooks.

Base path: `/api/v1/merchant/ramp`

Auth matches [Merchant API v1](https://docs.morapay.io/getting-started/authentication.md): signed API key requests, or portal JWT with `X-Business-Id`.

> [!NOTE]
>
> This is separate from `POST /api/v1/merchant/quotes/ramp` (crypto swap-style quotes). Use **merchant ramp** for **fiat ↔ crypto** corridors supported on your account.

## Flow

1. **`POST /ramp/quote`** — amounts and fees (`customerAmount`, optional `merchantFee`).
2. **`POST /ramp/onramp`** or **`POST /ramp/offramp`** — same `amount` as the quote.
3. **`GET /ramp/transactions/:reference`** — status and payment or deposit instructions.
4. **Webhooks** — `ramp.created` and `ramp.status_updated` ([Webhooks](https://docs.morapay.io/api-reference/webhooks.md)).

## Endpoints

| Step | Method | Path |
| - | - | - |
| Quote | `POST` | `/ramp/quote` |
| Onramp | `POST` | `/ramp/onramp` |
| Offramp | `POST` | `/ramp/offramp` |
| Status | `GET` | `/ramp/transactions/:reference` |
| List | `GET` | `/ramp/transactions` |
| OTP | `POST` | `/ramp/transactions/:reference/otp` |
| Config | `GET` | `/ramp/config` |
| Limits | `GET` | `/ramp/limits?currency={code}` |
| Banks | `GET` | `/ramp/banks?currency={code}` |

## Rules

* **Initiate** and **OTP** are **LIVE-only** (`400`, `RAMP_LIVE_ONLY` in TEST).
* Transactions are scoped to your business; unknown references return **404**.
* **Offramp** requires completed owner KYC (same as withdrawals).

## Markup

* Markup is set in the **merchant portal** (owner), not in the API.
* **`customerAmount`** — customer pays (onramp) or receives in fiat (offramp) after markup.
* **`merchantFee`** — `{ percent, amountUsd, amountFiat }` when markup applies; otherwise `null`.

***

## Quote

`POST /api/v1/merchant/ramp/quote`

| Field | Description |
| - | - |
| `direction` | `onramp` or `offramp` |
| `currency` | Fiat corridor code |
| `amount` | Onramp: fiat to quote. Offramp: crypto amount the customer will send |

```bash cURL theme={null}
curl -s -X POST "https://api.morapay.io/api/v1/merchant/ramp/quote" \
  -H "Content-Type: application/json" \
  -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
  -H "Morapay-Timestamp: $TIMESTAMP" \
  -H "Morapay-Signature: v1=$SIGNATURE" \
  -d '{
    "direction": "onramp",
    "currency": "ghs",
    "amount": "200"
  }'
```

```json 200 OK theme={null}
{
  "success": true,
  "data": {
    "direction": "onramp",
    "currency": "ghs",
    "amount": "200",
    "customerAmount": "212.40",
    "quotedAmount": "200",
    "quotedCurrency": "ghs",
    "merchantFee": {
      "percent": "1.5",
      "amountUsd": "0.42",
      "amountFiat": "12.40"
    }
  }
}
```

***

## Onramp

`POST /api/v1/merchant/ramp/onramp`

Use the **same `amount`** as the quote.

| Field | Description |
| - | - |
| `currency` | Fiat corridor code |
| `amount` | Same as quoted |
| `destinationWallet` | EVM address that receives crypto after settlement |
| `paymentMethod` | `mobile_money` or `bank` |
| `phoneNumber`, `networkProvider` | Required when `paymentMethod` is `mobile_money` |

```bash cURL theme={null}
curl -s -X POST "https://api.morapay.io/api/v1/merchant/ramp/onramp" \
  -H "Content-Type: application/json" \
  -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
  -H "Morapay-Timestamp: $TIMESTAMP" \
  -H "Morapay-Signature: v1=$SIGNATURE" \
  -d '{
    "currency": "ghs",
    "amount": "200",
    "destinationWallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "paymentMethod": "mobile_money",
    "phoneNumber": "0244000000",
    "networkProvider": "MTN"
  }'
```

Response includes **`reference`**, **`payment`** instructions, and **`requiresOtp`** when the OTP endpoint is required.

***

## Offramp

`POST /api/v1/merchant/ramp/offramp`

| Field | Description |
| - | - |
| `currency` | Fiat corridor code |
| `amount` | Same as quoted (crypto) |
| `bankCode` | From `GET /ramp/banks` |
| `accountNumber` | Destination account |

```bash cURL theme={null}
curl -s -X POST "https://api.morapay.io/api/v1/merchant/ramp/offramp" \
  -H "Content-Type: application/json" \
  -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
  -H "Morapay-Timestamp: $TIMESTAMP" \
  -H "Morapay-Signature: v1=$SIGNATURE" \
  -d '{
    "currency": "ghs",
    "amount": "25",
    "bankCode": "058",
    "accountNumber": "0123456789"
  }'
```

Response includes **`deposit`** (crypto to send) and **`payout`** (fiat destination summary).

***

## OTP

`POST /api/v1/merchant/ramp/transactions/:reference/otp`

```json theme={null}
{ "otp": "123456" }
```

Use when onramp `requiresOtp` is true.

***

## Status and list

**`GET /api/v1/merchant/ramp/transactions/:reference`** — amounts, `customerAmount`, `merchantFee`, instructions.

**`GET /api/v1/merchant/ramp/transactions`** — `page`, `limit`.

Statuses: `INITIATED` → `PENDING` → `PROCESSING` → `COMPLETED` | `FAILED`.

***

## Webhooks

| Event | When |
| - | - |
| `ramp.created` | Ramp transaction created |
| `ramp.status_updated` | Status or settlement changed |

Payload `data`: `object: "ramp_transaction"`, `reference`, `direction`, `status`, amounts, `merchantFee` when applicable. Verify `Morapay-Signature` per [Webhooks](https://docs.morapay.io/api-reference/webhooks.md).

***

## Helpers

| Endpoint | Purpose |
| - | - |
| `GET /ramp/config` | Supported corridors and flags |
| `GET /ramp/limits?currency={code}` | Min/max amounts |
| `GET /ramp/banks?currency={code}` | Bank codes for offramp |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.