Introduction to On/Off-Ramping

This guide provides an overview of how to integrate fiat-to-crypto (On-ramp) and crypto-to-fiat (Off-ramp) conversions using the Centiiv Protocol API.

The Centiiv Protocol is a decentralized liquidity aggregation platform. It connects applications with liquidity providers (LPs) to facilitate cross-border and regional conversions between stablecoins and fiat currencies.


Key Concepts

  • On-ramp (Fiat → Stablecoin): The user pays in local fiat currency (e.g., Nigerian Naira, NGN) to a virtual bank account and receives stablecoin (e.g., USDC) in their specified blockchain wallet.
  • Off-ramp (Stablecoin → Fiat): The user sends stablecoin to a temporary deposit wallet and receives local fiat currency directly in their bank account, mobile money wallet, or digital payment app (Alipay/WeChat).
  • Aggregator Key: Your credentials determine which environment you interact with. Keys starting with sandbox_ target our testing environment, while keys starting with live_ target production.
  • Active Endpoint vs. Deprecated Endpoints: Always use the /requests endpoint for creating transactions. The /public/order endpoint is deprecated.

1. Authentication and Environments

All requests to the ramping endpoints require authentication. You must supply your aggregator API key in the request header:

x-api-key: your_api_key_here

Environment Routing

The environment is determined automatically based on your API key prefix (sandbox_ or live_). You can also explicitly set or override this behavior by providing the optional X-Environment header:

  • sandbox: To test integrations with mock nodes and testnet assets.
  • live: For real-time, production transactions.

2. Step 1: Getting a Real-Time Quote

Before initiating an on-ramp or off-ramp request, obtain a real-time exchange rate quote. This endpoint selects an optimal LP using our selection algorithms and applies the relevant LP and aggregator fee configurations.

Request

Endpoint: POST /public/quote

{
  "fromAsset": "USDC",
  "toAsset": "NGN",
  "amount": 100,
  "network": "STELLAR"
}

Response

The response provides the LP rate, the estimated receivable amount after fees, and the gross amount the payer needs to deposit.

{
  "rate": "1485.50",
  "estimatedReceivableAmount": "148550.00",
  "fees": "1500.00",
  "totalToPay": "100.00"
}

3. Step 2: Processing an On-Ramp (Fiat → Crypto)

An on-ramp flow allows users to deposit fiat and receive stablecoins.

Step-by-Step Flow

  1. Initiate Request: Your application submits an on-ramp request to /requests.
  2. Retrieve Virtual Account: The API returns details for a temporary virtual bank account.
  3. User Deposit: The user transfers the required fiat amount to the provided virtual account.
  4. Fulfillment: The protocol detects the deposit, and the LP releases the equivalent stablecoins to the user's destinationAddress.

On-Ramp Request

Endpoint: POST /requests

{
  "fromAsset": "NGN",
  "toAsset": "USDC",
  "amount": 150000,
  "destinationAddress": "GCFXH5C3YQBAW7OKL2AVZFYJ6IHLZN4SXKTWRVQPQG3E5QJWZ7M2UW3K",
  "network": "STELLAR",
  "sender": {
    "externalId": "user_67890",
    "fullName": "Jane Smith",
    "email": "[email protected]",
    "phone": "+2348012345678"
  }
}

On-Ramp Response (Abridged)

Observe the temporaryWallet object, which contains the virtual account details your user needs to pay into.

{
  "id": "e0b82146-5f11-477c-bc24-811c750e42d7",
  "status": "PENDING",
  "type": "ONRAMP",
  "fromAsset": "NGN",
  "toAsset": "USDC",
  "amount": 150000,
  "temporaryWallet": {
    "virtualAccountNumber": "8012345678",
    "virtualAccountName": "Cent Protocol / Jane Smith",
    "virtualBankName": "Wema Bank",
    "virtualBankCode": "035"
  },
  "createdAt": "2026-07-29T10:00:00.000Z",
  "updatedAt": "2026-07-29T10:00:00.000Z"
}

4. Step 3: Processing an Off-Ramp (Crypto → Fiat)

An off-ramp flow allows users to send stablecoin and receive fiat in their bank account or mobile money wallet.

Step-by-Step Flow

  1. Initiate Request: Submit a request to /requests specifying the destination details.
  2. Retrieve Deposit Wallet: The API returns a temporary blockchain address (publicAddress).
  3. User Transfer: The user transfers stablecoins to the provided deposit address.
  4. Fulfillment: Once the blockchain deposit is confirmed, the LP routes the fiat payout to the beneficiary.

Polymorphic Beneficiaries

Off-ramp beneficiaries vary significantly by region. The API supports structured polymorphic payloads under beneficiary.destination. Select the schema matching your target channel:

  • Nigeria (BANK): Standard 10-digit NUBAN and bank code.
  • Ghana/Kenya/Uganda (MOBILEMONEY): Phone number and network operator (MTN, Airtel, M-Pesa).
  • Kenya (PAYBILL/PAYTILL): M-Pesa business Paybill or Till number.
  • China (ALIPAY/WECHATPAY): Structured phone number, full account name, remittance purpose, and sender details required for regional compliance.

Example: Off-ramp Request to Nigerian Bank

Endpoint: POST /requests

{
  "fromAsset": "USDC",
  "toAsset": "NGN",
  "amount": 100,
  "network": "STELLAR",
  "refundAddress": "GCFXH5C3YQBAW7OKL2AVZFYJ6IHLZN4SXKTWRVQPQG3E5QJWZ7M2UW3K",
  "beneficiary": {
    "externalId": "user_ng_991",
    "destination": {
      "type": "BANK",
      "bankCode": "044",
      "accountNumber": "0123456789"
    }
  }
}

Example: Off-ramp Request to Kenya Mobile Money (M-Pesa)

{
  "fromAsset": "USDC",
  "toAsset": "KES",
  "amount": 50,
  "network": "STELLAR",
  "refundAddress": "GCFXH5C3YQBAW7OKL2AVZFYJ6IHLZN4SXKTWRVQPQG3E5QJWZ7M2UW3K",
  "beneficiary": {
    "externalId": "user_ke_401",
    "destination": {
      "type": "MOBILEMONEY",
      "network": "MPESA",
      "accountNumber": "254712200002",
      "accountName": "Jane Doe"
    }
  }
}

Off-Ramp Response (Abridged)

Observe the temporaryWallet object, which contains the deposit address where the user must send their crypto.

{
  "id": "c9a41982-d28f-49ff-a18a-fbc86a687cfc",
  "status": "PENDING",
  "type": "OFFRAMP",
  "fromAsset": "USDC",
  "toAsset": "NGN",
  "amount": 100,
  "temporaryWallet": {
    "publicAddress": "GCFXH5C3YQBAW7OKL2AVZFYJ6IHLZN4SXKTWRVQPQG3E5QJWZ7M2UW3K",
    "network": "STELLAR",
    "isTestnet": false,
    "expiresAt": "2026-07-29T10:30:00.000Z"
  },
  "createdAt": "2026-07-29T10:00:00.000Z",
  "updatedAt": "2026-07-29T10:00:00.000Z"
}

5. Checking Request Status

Since deposits and banking networks are asynchronous, requests status transitions from PENDING to PROCESSING and ultimately FULFILLED (or FAILED / EXPIRED).

Request

Endpoint: GET /requests/{id}

GET /requests/c9a41982-d28f-49ff-a18a-fbc86a687cfc

Key Lifecycle Statuses

  • PENDING: Request created; awaiting deposit from the user.
  • PROCESSING: Deposit detected; payout or conversion is currently in progress.
  • FULFILLED: Transaction completed successfully.
  • FAILED: The conversion or payout encountered an issue.
  • EXPIRED: No deposit was received within the 30-minute timeout limit.
  • REFUNDED: Conversion failed, and funds were returned to the refund address.

6. Verification and Utility Endpoints

To avoid payout failures, verify beneficiary details beforehand.

Supported Banks

Retrieve the list of supported banking institutions and their codes for the target region.

  • Endpoint: GET /banking/banks

Account Verification

Verify that a bank account number and bank code match the beneficiary's registered name.

  • Endpoint: POST /banking/verify-account
  • Payload:
    {
      "bankCode": "044",
      "accountNumber": "0123456789"
    }


Did this page help you?