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

# Initiate a crypto ramp

> Initiate an on-ramp (fiat → crypto) or off-ramp (crypto → fiat) conversion. PCX acts as the orchestrator — your users send or receive fiat, and PCX handles the crypto settlement automatically.

**On-ramp**: the customer pays in fiat using their preferred payment method. Once the fiat collection is confirmed, the crypto is settled directly to the `wallet_address` you provide. No further action is needed after a successful initiation.

**Off-ramp**: the customer sends crypto and receives fiat to a registered beneficiary's bank or mobile money account.

You must fetch a fresh rate from `GET /organizations/admin/exchange-rate` immediately before presenting it to the user and before submitting this request. The rate must be fetched in the same direction the funds flow — `fromCurrency=fiat&toCurrency=crypto` for `on_ramp`, and `fromCurrency=crypto&toCurrency=fiat` for `off_ramp`. The `client_rate` you send is validated against the current live rate for that direction — if it has drifted more than 0.5% (or was fetched in the wrong direction), the request is rejected with `RATE_STALE` and you must re-fetch.




## OpenAPI

````yaml /api-reference/external/openapi.yaml post /payments-init/ramp
openapi: 3.0.3
info:
  title: PCX API
  description: >
    The PCX integration API. Every request requires two headers: `Authorization`
    (Bearer JWT for user-facing flows, or the literal string `NONE`) and
    `X-Api-Key` (your API key for server-to-server calls, or the literal string
    `NONE`). Pass `NONE` for whichever header you are not using.
  version: '1.0'
servers:
  - url: https://prod-api.pcxpay.com/v1
    description: Production
  - url: https://devs.pcxpay.com/v1
    description: Development
security: []
tags:
  - name: Payment Initiation
    description: Initiate payments and poll for status
  - name: API Keys
    description: Create and manage API keys for programmatic access
  - name: Webhooks
    description: Register endpoints and receive transaction notifications
  - name: Beneficiaries
    description: Manage payment recipients
  - name: Payments
    description: Initiate and track payments
  - name: Bank Validation
    description: Validate bank accounts before initiating a payment
  - name: Transactions
    description: Query the financial transaction ledger
  - name: Virtual Accounts
    description: Multi-currency virtual account provisioning and fund operations
  - name: Payment Links
    description: Generate shareable payment links for customer checkout
paths:
  /payments-init/ramp:
    parameters:
      - $ref: '#/components/parameters/AuthorizationHeader'
      - $ref: '#/components/parameters/XApiKeyHeader'
    post:
      tags:
        - Payment Initiation
      summary: Initiate a crypto ramp
      description: >
        Initiate an on-ramp (fiat → crypto) or off-ramp (crypto → fiat)
        conversion. PCX acts as the orchestrator — your users send or receive
        fiat, and PCX handles the crypto settlement automatically.


        **On-ramp**: the customer pays in fiat using their preferred payment
        method. Once the fiat collection is confirmed, the crypto is settled
        directly to the `wallet_address` you provide. No further action is
        needed after a successful initiation.


        **Off-ramp**: the customer sends crypto and receives fiat to a
        registered beneficiary's bank or mobile money account.


        You must fetch a fresh rate from `GET
        /organizations/admin/exchange-rate` immediately before presenting it to
        the user and before submitting this request. The rate must be fetched in
        the same direction the funds flow —
        `fromCurrency=fiat&toCurrency=crypto` for `on_ramp`, and
        `fromCurrency=crypto&toCurrency=fiat` for `off_ramp`. The `client_rate`
        you send is validated against the current live rate for that direction —
        if it has drifted more than 0.5% (or was fetched in the wrong
        direction), the request is rejected with `RATE_STALE` and you must
        re-fetch.
      operationId: initiateRamp
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RampRequest'
      responses:
        '200':
          description: Ramp initiated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RampResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          description: Rate has drifted beyond the 0.5% tolerance
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 422
                  error:
                    type: string
                    example: RATE_STALE
                  message:
                    type: string
                    example: Rate has drifted. Please re-fetch the exchange rate.
components:
  parameters:
    AuthorizationHeader:
      name: Authorization
      in: header
      required: true
      description: >-
        Bearer JWT for user-facing flows (`Bearer eyJraWQ...`), or the literal
        string `NONE` when authenticating via API key.
      schema:
        type: string
        default: NONE
        example: Bearer eyJraWQ...
    XApiKeyHeader:
      name: X-Api-Key
      in: header
      required: true
      description: >-
        API key for server-to-server flows, or the literal string `NONE` when
        authenticating via JWT.
      schema:
        type: string
        default: NONE
        example: pcx_abc123_xxxx
  schemas:
    RampRequest:
      type: object
      required:
        - direction
        - user_id
        - org_id
        - fiat_currency
        - fiat_amount
        - client_rate
        - crypto_currency
        - crypto_network
        - payment_method
        - country
        - payer_details
      properties:
        direction:
          type: string
          enum:
            - on_ramp
            - off_ramp
          description: >
            `on_ramp` — customer pays fiat, receives crypto to `wallet_address`.
            `off_ramp` — customer sends crypto, receives fiat to beneficiary.
        user_id:
          type: string
          description: ID of the initiating user.
        org_id:
          type: string
          description: Your organisation ID.
        fiat_currency:
          type: string
          description: ISO 4217 fiat currency code (e.g. `NGN`, `KES`, `GHS`).
          example: NGN
        fiat_amount:
          type: number
          format: float
          description: >-
            Amount in fiat currency — what the customer pays (on-ramp) or
            receives (off-ramp).
          example: 10000
        client_rate:
          type: number
          format: float
          description: >
            The rate you fetched from `GET /organizations/admin/exchange-rate`
            and showed to the user. Validated against the current live rate on
            submission — must be within 0.5% or the request is rejected with
            `RATE_STALE`.
          example: 0.00000645
        crypto_currency:
          type: string
          description: Crypto asset code (e.g. `USDC`, `USDT`, `EURC`, `BTC`, `ETH`).
          example: USDC
        crypto_network:
          type: string
          description: Blockchain network (e.g. `ethereum`, `polygon`, `tron`).
          example: ethereum
        payment_method:
          type: string
          enum:
            - mobile_money
            - bank_transfer
          description: Fiat payment method.
        country:
          type: string
          description: ISO alpha-2 country code of the fiat side (e.g. `NG`, `KE`).
          example: NG
        payer_details:
          type: object
          required:
            - email
          properties:
            name:
              type: string
              example: Jane Kamau
            email:
              type: string
              format: email
              example: jane@example.com
            phone:
              type: string
              example: '+2348122603628'
        customer_type:
          type: string
          enum:
            - retail
            - institution
          default: retail
          description: >-
            Use `institution` for business customers. Requires `business_id` and
            `business_name`.
        business_id:
          type: string
          description: Required when `customer_type` is `institution`.
        business_name:
          type: string
          description: Required when `customer_type` is `institution`.
        wallet_address:
          type: string
          description: >-
            On-ramp only. The destination crypto wallet address. PCX settles
            crypto here directly after fiat collection.
          example: 0xABC123...your-wallet-address
        mobile_money_details:
          type: object
          description: Required for `mobile_money` payment method.
          properties:
            provider:
              type: string
              description: Network name as returned by `POST /externals/networks`.
              example: MTN
            phone_number:
              type: string
              example: '+2348122603628'
        bank_details:
          type: object
          description: On-ramp bank transfer — payer's source bank account.
          properties:
            account_number:
              type: string
            bank_code:
              type: string
            bank_name:
              type: string
        beneficiary_id:
          type: string
          description: >-
            Off-ramp only. ID of the registered beneficiary receiving the fiat
            payout.
        beneficiary_name:
          type: string
          description: Off-ramp only. Full name of the beneficiary.
        destination:
          type: object
          description: Off-ramp only. Destination routing details for the fiat payout.
          properties:
            accountNumber:
              type: string
            bankCode:
              type: string
            bankName:
              type: string
        metadata:
          type: object
          description: Arbitrary key-value pairs included in webhook payloads.
          additionalProperties: true
    RampResponse:
      type: object
      properties:
        statusCode:
          type: integer
          example: 200
        response:
          type: object
          properties:
            success:
              type: boolean
              example: true
            payment_id:
              type: string
              example: ea5965e4-1432-40ef-bccf-cb51455a935a
            transaction_id:
              type: string
              example: 2a679c96-69bf-424c-89cb-c2f4a90a2738
            direction:
              type: string
              enum:
                - on_ramp
                - off_ramp
            status:
              type: string
              description: Initial status of the ramp (e.g. `pending`).
              example: pending
            fiat_currency:
              type: string
              example: NGN
            fiat_amount:
              type: number
              format: float
              example: 10000
            crypto_currency:
              type: string
              example: USDC
            crypto_network:
              type: string
              example: ethereum
            crypto_amount:
              type: number
              format: float
              description: >-
                Amount of crypto the customer will receive (on-ramp) or send
                (off-ramp) at the locked spread-adjusted rate.
              example: 6.45
            expires_at:
              type: string
              format: date-time
              description: >-
                When the collection window closes. Prompt the user to complete
                payment before this time.
            next_action:
              type: string
              nullable: true
              enum:
                - make_transfer
                - approve_prompt
                - send_crypto
                - wait
              description: >
                What the client should do next to complete the ramp:

                  - `make_transfer` — on-ramp bank transfer. Display the bank account
                    details in `payment_instructions` so the customer can send the funds.
                  - `approve_prompt` — on-ramp mobile money. The provider has pushed
                    a prompt (e.g. STK push) to the customer's phone — instruct them
                    to approve it.
                  - `send_crypto` — off-ramp. Display `payment_instructions` so the
                    customer can send the required crypto amount to the PCX-provided
                    wallet address. Fiat payout to the registered beneficiary starts
                    once the deposit is confirmed.
                  - `wait` — any flow where no further client action is required
                    (e.g. off-ramp where the provider did not return settlement details).
                    PCX continues processing in the background.

                May be `null` if the provider response did not include the data
                needed to populate instructions (for example, an on-ramp bank
                transfer where `bankInfo` was missing).
              example: make_transfer
            payment_instructions:
              type: object
              nullable: true
              description: >
                Action-specific details the client should display to the
                customer. Shape depends on `next_action`:

                  - When `next_action` is `make_transfer`, the object has
                    `type: "bank_transfer"` plus `account_name`, `account_number`,
                    `bank_name`, `amount`, `currency`, and `reference`.
                  - When `next_action` is `approve_prompt`, the object has
                    `type: "mobile_money"`, a human-readable `message`, `amount`,
                    and `currency`.
                  - When `next_action` is `send_crypto`, the object has
                    `type: "crypto_transfer"` plus `wallet_address`, `crypto_amount`,
                    `crypto_currency`, `crypto_network`, and `expires_at`.
                  - `null` when `next_action` is `wait` or when no instructions are
                    available.
              properties:
                type:
                  type: string
                  enum:
                    - bank_transfer
                    - mobile_money
                    - crypto_transfer
                  description: Discriminates the instruction shape.
                account_name:
                  type: string
                  description: Bank transfer only. Beneficiary account name to display.
                account_number:
                  type: string
                  description: Bank transfer only. Beneficiary account number to display.
                bank_name:
                  type: string
                  description: Bank transfer only. Name of the receiving bank.
                reference:
                  type: string
                  description: >-
                    Bank transfer only. Reference the customer must include with
                    the transfer.
                message:
                  type: string
                  description: >-
                    Mobile money only. Human-readable message describing the
                    prompt sent to the customer.
                amount:
                  type: number
                  format: float
                  description: Amount the customer should pay, in `currency`.
                currency:
                  type: string
                  description: ISO 4217 currency code for `amount`.
                wallet_address:
                  type: string
                  description: >-
                    Crypto transfer only. PCX-provided wallet address the
                    customer must send crypto to.
                crypto_amount:
                  type: number
                  format: float
                  description: >-
                    Crypto transfer only. Exact crypto amount the customer must
                    send.
                crypto_currency:
                  type: string
                  description: Crypto transfer only. Crypto asset code (e.g. `USDC`).
                crypto_network:
                  type: string
                  description: >-
                    Crypto transfer only. Blockchain network the deposit must be
                    made on (e.g. `ethereum`).
                expires_at:
                  type: string
                  format: date-time
                  description: >-
                    Crypto transfer only. When the deposit window closes — the
                    customer must complete the transfer before this time.
              example:
                type: bank_transfer
                account_name: PCX Collections
                account_number: '0123456789'
                bank_name: Access Bank
                amount: 10000
                currency: NGN
                reference: PCX-ea5965e4
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
        status:
          type: string
          enum:
            - error
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Missing or invalid credentials
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

````