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

# Create Treasury Fiat-On-Demand Off-Ramp

> Creates an **OFF_RAMP_SELL** order with **`order_subtype` = `treasury_offramp`**.

This is the company cash-out path. No marketplace offer is required. Coinpool is the counterparty
(`vendor_id` is set from `TREASURY_USER_ID`). Customers can use this when no peer offers exist,
or when they prefer to sell crypto directly to the platform even if offers are available.

## Fiat payout destination

Customers must set `payout_method`:

- **`mpesa`**: Mobile money in Kenya. Requires `fiat_currency=KES` and `payout_phone` in MSISDN form (`2547XXXXXXXX`).
- **`bank`**: Bank transfer. Requires a nested `bank` object with bank name, branch name, physical address,
  account number, account name, and SWIFT code.

Flow:
1. Customer creates the order and receives a unique escrow address.
2. Customer sends USDT/USDC to escrow (`POST /orders/{id}/send-payment` for custodial wallets).
3. Escrow watcher confirms the deposit.
4. Platform pays fiat to the customer's M-Pesa or bank account.

Provide either `fiat_amount` (desired net payout) or `crypto_amount` (amount to sell). Pricing uses
an active `offramp` pricing profile and FX quote.




## OpenAPI

````yaml /openapi.yaml post /api/v1/auth/treasury/off-ramp/orders
openapi: 3.1.0
info:
  title: CoinPool API
  description: >
    CoinPool API reference. These APIs power cryptocurrency exchange between
    USDT and Fiat trading.


    - **On-Ramp**: Buy USDT with fiat (KES) via mobile money (STK Push for
    Kenya)

    - **Off-Ramp**: Sell USDT for KES with mobile money payout (Kenya)

    - **Ethereum, TRON, and Solana**: Multi-chain wallet support

    - **Merchant Offers**: Create and manage trading offers

    - **OTC Flows**: Bank and mobile money deposits/withdrawals for merchants

    - **Pricing engine**: FX quotes and fee profiles for quote-backed orders and
    transfers

    - **P2P/B2B transfers**: Internal and external stablecoin sends (USDT/USDC)
    with optional pricing snapshots

    - **Stablecoin swaps**: Treasury-backed two-leg USDT ↔ USDC conversion with
    BitGo confirmation, inventory reservation, and automatic refunds

    - **Multisig**: Collaborative and platform-managed multisig flows for
    high-value B2B
  version: 1.1.0
servers:
  - url: https://crypto.westminister.tech
    description: Production API (requires DNS for this hostname).
  - url: http://13.42.110.185:8080
    description: >-
      UAT on EC2 (direct). Use this base when building proof PDF URLs if the
      production hostname does not resolve.
security: []
tags:
  - name: Pricing
    description: >-
      Commercial pricing profiles and FX rate quotes (admin). Used with orders
      and transfers for auditable snapshots.
  - name: Transfers
    description: >-
      P2P and B2B stablecoin transfers (USDT/USDC). Optional fiat-equivalent
      pricing fields. B2B multisig behavior depends on wallet registration
      (synchronous completion vs proposal flow).
  - name: Stablecoin Swaps
    description: >-
      Treasury-backed USDT ↔ USDC conversions for BitGo provider-managed wallets
      on `tron`, `ethereum`, or `solana`. Collection confirms before treasury
      payout starts. Completion requires both legs and dual-asset balance
      synchronization.
  - name: Multisig
    description: >-
      Multisig wallet registration and TRON proposal/confirm flows
      (vendor/admin).
  - name: Escrow Wallets
    description: Escrow pool wallet metadata for off-ramp and operations.
  - name: Users
    description: >-
      User-related operations (registration, lookup, updates, counts, status
      changes)
  - name: Wallets-Users
    description: User wallet operations (create, manage, query balances)
  - name: Offers
    description: Offer operations (create, read, list, counts)
  - name: Orders
    description: Order operations (create, update, list, counts, stats)
  - name: Payment
    description: Payment initiation operations
  - name: Merchants
    description: >
      Merchant (vendor) onboarding and hierarchy operations.

      USE **GET /API/V1/AUTH/MERCHANTS** WITH **PAGE_ID** AND **PAGE_SIZE** TO
      PAGE MASTER VENDORS.

      USE **GET /API/V1/AUTH/MERCHANTS/{MERCHANT_ID}** FOR ONE MASTER VENDOR,
      **MERCHANT_WALLETS**, AND ALL **SUBVENDOR** ROWS WITH **WALLETS** (FULL
      TREE).
  - name: OTC Deposits
    description: >
      OTC fiat-to-crypto deposits (bank or mobile money). Rows live in
      **`otc_deposits`**. Merchants create drafts or one-shot deposits.
      **admin**, **otc_officer**, or **treasury** list all deposits.

      B2B bank flow uses draft, quote, submit, proof, assign, claim, settlement,
      and audit. **`credited_to_address`** is the merchant on-chain wallet
      treasury credits (resolved from the default wallet for
      **`requested_network`** on the master merchant ledger user or any
      **sub-vendor** under that merchant).

      **`GET /api/v1/auth/otc/deposits`** backfills missing
      **`credited_to_address`**/**`to_wallet_id`** when a wallet can be
      resolved. One-shot **`POST /api/v1/auth/otc/deposits`** persists the
      payout address when **`requested_network`** is sent.

      Bank proof PDFs upload via `POST .../proof` and are viewed at **`GET
      /otc-deposits-proof/{deposit_id}/{file}.pdf`** (relative
      **`proof_url`**/**`file_url`** plus API base URL).

      Merchants may edit tab-1 draft fields with **`PATCH
      /api/v1/auth/otc/deposits/{id}/draft`** while **`status`** is **`draft`**.
  - name: OTC Withdrawals
    description: >-
      OTC crypto-to-fiat withdrawals (bank or mobile money). Merchants create.
      Admin approves and executes.
  - name: OTC Config
    description: OTC display config (bank details, mobile money paybill) for merchant UI
  - name: Fiat Currencies
    description: >
      Shared platform **fiat_currencies** catalog. **GET
      /api/v1/auth/fiat-currencies** lists active rows for UI pickers. **GET
      /api/v1/auth/fiat-currencies/admin** lists all rows including inactive
      (admin). Admin manages rows with **GET
      /api/v1/auth/fiat-currencies/{id}**, **POST
      /api/v1/auth/fiat-currencies**, **PATCH
      /api/v1/auth/fiat-currencies/{id}**, and **DELETE
      /api/v1/auth/fiat-currencies/{id}**. Use for OTC, pricing, orders,
      remittance, and backoffice — not under **`/otc/...`**. Prefer **PATCH**
      with **`is_active: false`** over delete when a currency is referenced.
  - name: Countries
    description: >-
      Shared platform **countries** catalog. Public **GET /api/v1/countries**
      lists active rows for pickers. Auth **GET /api/v1/auth/countries** returns
      the same active catalog. Admin manages rows with **GET
      /api/v1/auth/countries/admin**, **GET /api/v1/auth/countries/{id}**,
      **POST /api/v1/auth/countries**, **PATCH /api/v1/auth/countries/{id}**,
      and **DELETE /api/v1/auth/countries/{id}**.
  - name: Files
    description: Authenticated file uploads for OTC receipts and proof artifacts.
paths:
  /api/v1/auth/treasury/off-ramp/orders:
    post:
      tags:
        - Orders
      summary: Create Treasury Fiat-On-Demand Off-Ramp
      description: >
        Creates an **OFF_RAMP_SELL** order with **`order_subtype` =
        `treasury_offramp`**.


        This is the company cash-out path. No marketplace offer is required.
        Coinpool is the counterparty

        (`vendor_id` is set from `TREASURY_USER_ID`). Customers can use this
        when no peer offers exist,

        or when they prefer to sell crypto directly to the platform even if
        offers are available.


        ## Fiat payout destination


        Customers must set `payout_method`:


        - **`mpesa`**: Mobile money in Kenya. Requires `fiat_currency=KES` and
        `payout_phone` in MSISDN form (`2547XXXXXXXX`).

        - **`bank`**: Bank transfer. Requires a nested `bank` object with bank
        name, branch name, physical address,
          account number, account name, and SWIFT code.

        Flow:

        1. Customer creates the order and receives a unique escrow address.

        2. Customer sends USDT/USDC to escrow (`POST /orders/{id}/send-payment`
        for custodial wallets).

        3. Escrow watcher confirms the deposit.

        4. Platform pays fiat to the customer's M-Pesa or bank account.


        Provide either `fiat_amount` (desired net payout) or `crypto_amount`
        (amount to sell). Pricing uses

        an active `offramp` pricing profile and FX quote.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customer_id
                - asset
                - fiat_currency
                - wallet_address
                - payout_method
                - expires_at
                - pricing_profile_id
                - fx_rate_quote_id
              properties:
                customer_id:
                  type: string
                  format: uuid
                asset:
                  type: string
                  enum:
                    - USDT
                    - USDC
                crypto_amount:
                  type: string
                  description: Amount of USDT/USDC the customer will send to escrow
                usdt_amount:
                  type: string
                  description: Deprecated alias for crypto_amount
                  deprecated: true
                fiat_amount:
                  type: string
                  description: Desired net fiat payout. If set
                  escrow crypto is derived from pricing: null
                fiat_currency:
                  type: string
                  example: KES
                wallet_address:
                  type: string
                  description: Customer custodial or verified external wallet
                payment_method:
                  type: string
                  description: Optional. Defaults to payout_method
                expires_at:
                  type: string
                  format: date-time
                payout_method:
                  type: string
                  enum:
                    - mpesa
                    - bank
                payout_phone:
                  type: string
                  description: Required for mpesa. Kenyan MSISDN such as 2547XXXXXXXX
                fee_bearer:
                  type: string
                  enum:
                    - sender
                    - receiver
                  default: sender
                bank:
                  type: object
                  description: Required when payout_method is bank
                  required:
                    - bank_name
                    - branch_name
                    - physical_address
                    - account_number
                    - account_name
                    - swift_code
                  properties:
                    bank_name:
                      type: string
                      example: Equity Bank
                    branch_name:
                      type: string
                      example: Westlands
                    physical_address:
                      type: string
                      example: Westlands Road
                      Nairobi: null
                    account_number:
                      type: string
                      example: '0123456789'
                    account_name:
                      type: string
                      example: Jane Doe
                    swift_code:
                      type: string
                      example: EQBLKENA
                    bank_code:
                      type: string
                      description: Optional local clearing or sort code
                pricing_profile_id:
                  type: string
                  format: uuid
                fx_rate_quote_id:
                  type: string
                  format: uuid
            examples:
              mpesa_kes:
                summary: Customer sells 100 USDT for KES via M-Pesa
                value:
                  customer_id: 8d09359f-325a-4ecf-998d-dbe5eda3a498
                  asset: USDT
                  crypto_amount: '100.00'
                  fiat_currency: KES
                  wallet_address: TPY7ewYk2eY9b4TTYkCHJH3Cqudh3NU6tM
                  payout_method: mpesa
                  payout_phone: '254727648169'
                  fee_bearer: sender
                  pricing_profile_id: 11111111-2222-3333-4444-555555555555
                  fx_rate_quote_id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
                  expires_at: '2026-07-22T18:00:00Z'
              bank_transfer:
                summary: Customer sells USDC for bank payout
                value:
                  customer_id: 8d09359f-325a-4ecf-998d-dbe5eda3a498
                  asset: USDC
                  fiat_amount: '10000.00'
                  fiat_currency: USD
                  wallet_address: TPY7ewYk2eY9b4TTYkCHJH3Cqudh3NU6tM
                  payout_method: bank
                  bank:
                    bank_name: Equity Bank
                    branch_name: Westlands
                    physical_address: Westlands Road, Nairobi
                    account_number: '0123456789'
                    account_name: Jane Doe
                    swift_code: EQBLKENA
                  pricing_profile_id: 11111111-2222-3333-4444-555555555555
                  fx_rate_quote_id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
                  expires_at: '2026-07-22T18:00:00Z'
      responses:
        '201':
          description: Treasury off-ramp order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Validation or pricing error
        '403':
          description: Wallet does not belong to customer or KYC not approved
        '500':
          description: Internal server error
      security:
        - bearerAuth: []
components:
  schemas:
    Order:
      type: object
      properties:
        id:
          type: string
          format: uuid
        customer_id:
          type: string
          format: uuid
        vendor_id:
          type: string
          format: uuid
          description: Liquidity provider (publisher). API name vendor_id.
        offer_id:
          type: string
          format: uuid
          nullable: true
          description: >-
            Liquidity listing id. API name offer_id. Nullable for custodial
            remittance orders.
        asset:
          type: string
          nullable: true
        crypto_amount:
          type: string
        usdt_amount:
          type: string
          nullable: true
          description: Backward-compatible alias for crypto_amount
        fiat_amount:
          type: string
        fiat_currency:
          type: string
        wallet_address:
          type: string
        status:
          type: string
          enum:
            - pending
            - processing
            - confirming
            - completed
            - cancelled
            - failed
        payment_method:
          type: string
          description: e.g., mpesa
        payment_txn_id:
          $ref: '#/components/schemas/NullableString'
        blockchain_txn_hash:
          $ref: '#/components/schemas/NullableString'
        expires_at:
          type: string
          format: date-time
        completed_at:
          $ref: '#/components/schemas/NullableTime'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        deleted_at:
          $ref: '#/components/schemas/NullableTime'
        merchant_request_id:
          $ref: '#/components/schemas/NullableString'
        checkout_request_id:
          $ref: '#/components/schemas/NullableString'
        mpesa_receipt_number:
          $ref: '#/components/schemas/NullableString'
        payment_phone_number:
          $ref: '#/components/schemas/NullableString'
        order_type:
          type: string
          enum:
            - ON_RAMP_BUY
            - ON_RAMP_SELL
            - OFF_RAMP_BUY
            - OFF_RAMP_SELL
        order_subtype:
          type: string
          enum:
            - standard_onramp
            - standard_offramp
            - remittance_offramp
            - custodial_remittance_offramp
            - treasury_offramp
          description: >
            Distinguishes marketplace, remittance, custodial remittance, and
            company fiat-on-demand off-ramp flows.

            Legacy rows are backfilled as `standard_onramp`/`standard_offramp`.

            `treasury_offramp` has no offer_id. Vendor is the platform treasury.
        sender_name:
          $ref: '#/components/schemas/NullableString'
        sender_country:
          $ref: '#/components/schemas/NullableString'
        sender_phone:
          $ref: '#/components/schemas/NullableString'
        beneficiary_bank_name:
          $ref: '#/components/schemas/NullableString'
        beneficiary_bank_code:
          $ref: '#/components/schemas/NullableString'
        beneficiary_bank_branch:
          $ref: '#/components/schemas/NullableString'
        beneficiary_bank_address:
          $ref: '#/components/schemas/NullableString'
        beneficiary_account_name:
          $ref: '#/components/schemas/NullableString'
        beneficiary_account_number:
          $ref: '#/components/schemas/NullableString'
        beneficiary_swift_code:
          $ref: '#/components/schemas/NullableString'
        escrow_wallet_address:
          $ref: '#/components/schemas/NullableString'
        escrow_network:
          $ref: '#/components/schemas/NullableString'
        escrow_reference:
          $ref: '#/components/schemas/NullableString'
        deposit_tx_hash:
          $ref: '#/components/schemas/NullableString'
        deposit_confirmations:
          type: integer
        deposit_detected_at:
          $ref: '#/components/schemas/NullableTime'
    NullableString:
      type: object
      description: Database-style nullable string wrapper
      properties:
        String:
          type: string
          nullable: true
        Valid:
          type: boolean
    NullableTime:
      type: object
      description: Database-style nullable time wrapper
      properties:
        Time:
          type: string
          format: date-time
          nullable: true
        Valid:
          type: boolean
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: PASETO

````