> ## 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.

# Orders and Payments

> Creating Quote-Backed Orders, Off-Ramp Flow, Fees, and Payment-Screen Endpoints

## Terminology (Avoid “Taking an Offer” Confusion)

The JSON fields keep historical names. Product language should be:

| Concept                | API field                     | Meaning                                                                                                                                                                              |
| ---------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Customer**           | `customer_id`                 | The user placing the order (for off-ramp remittance: already holds USDT/USDC in custody).                                                                                            |
| **Liquidity provider** | `vendor_id`                   | The account that **published** the marketplace line—not “who gave the customer their crypto.”                                                                                        |
| **Liquidity listing**  | `offer_id`                    | The **published terms row** (asset, fiat pair, limits, active status) the order and pricing attach to for validation and lifecycle—not the funding source of the customer’s balance. |
| **Beneficiary**        | `beneficiary_*`, payout phone | Who receives fiat (e.g. Mobile Money). **Not** required to be the liquidity provider.                                                                                                |

For **off-ramp remittance**, John selects a **liquidity listing** so the platform has a consistent **conversion anchor**. He is **not** “obtaining USDT” from that listing.

## Creating an Order

`POST /api/v1/auth/orders`

* **`offer_id`** — Required. Must reference an existing **liquidity listing** for the chosen **`vendor_id`** (liquidity provider).
* **`pricing_profile_id`** and **`fx_rate_quote_id`** — Required for commercial enforcement. Must match **`order_type`**, asset (**USDT**), **`fiat_currency`**, and network implied by **`wallet_address`** (Tron-style `T...` vs Ethereum `0x...`) for pricing validation. **`fiat_currency`** must be an active code from the shared catalog. LIST OPTIONS WITH **`GET /api/v1/auth/fiat-currencies`** (SAME CATALOG AS OTC, REMITTANCE, AND ADMIN TOOLING — NOT UNDER **`/otc/...`**).
* **`order_type`** - `ON_RAMP_BUY` (default) or `OFF_RAMP_SELL`.
* **Off-Ramp**: provide **`payout_phone`**. Escrow and network detection use the customer’s validated **`wallet_address`**.

## Recommended Mobile Sequence

For app clients, resolve commercial IDs first, then create the order:

1. **`POST /api/v1/auth/pricing/resolve`** with `flow_type`, `network`, `asset`, `fiat_currency`, `amount_in`, and `amount_in_type` (plus optional **`vendor_id`**/**`offer_id`** to pin the preview to a specific **liquidity listing**).
2. Read **`pricing_profile_id`** and **`fx_rate_quote_id`** from the response.
3. **`POST /api/v1/auth/orders`** with those IDs plus order amounts and routing fields.

This keeps pricing selection logic on the backend and avoids client-side mismatches.

## Recommended Web Sequence

For web dashboards/backoffice tools, use an explicit quote-review-confirm pattern:

1. **`POST /api/v1/auth/pricing/resolve`** with full context (`flow_type`, `network`, `asset`, `fiat_currency`, amount, and selected **liquidity listing** `offer_id` + **liquidity provider** `vendor_id`).
2. Render a review panel showing rates, spread, and total fees from the resolve response.
3. On operator confirmation, **`POST /api/v1/auth/orders`** with the returned `pricing_profile_id` and `fx_rate_quote_id`.
4. Continue with payment or escrow steps (order-type specific) and track status via order endpoints.

For consistency, web should follow the same server-resolved pricing path as mobile rather than hard-coding commercial IDs in the UI.

## Web Complete Flow (All Operations)

Use this sequence for web portals that support customer checkout, operations, and treasury actions.

### 1) User Setup (Email-First on Web)

1. Register user: **`POST /api/v1/users/register`**
2. Login: **`POST /api/v1/users/login`** (or **`/login-pin`** if enabled)
3. Load user wallets: **`GET /api/v1/auth/wallets/user`**
4. Optionally set preferred default network wallet: **`PUT /api/v1/auth/wallet/id/{wallet_id}/set-default-network`**

Default Ethereum, TRON, and Solana wallets are best-effort provisioned at registration. Duplicate **email** or **phone\_number** returns **409** with no user or wallets created. If one chain fails, others may still be created and **`wallet_errors`** is returned. Set default wallet/network to avoid forcing `from_wallet_id` on every transfer path.

### 1.1 Merchant Registration (Web BackOffice)

Use merchant onboarding endpoints for treasury and OTC operations:

1. Create master merchant: **`POST /api/v1/auth/merchants`**
2. Create sub-merchant under a master: **`POST /api/v1/auth/merchants/{merchant_id}/sub-merchants`**
3. Create master + branches in one request: **`POST /api/v1/auth/merchants/with-sub-merchants`**
4. List master merchants only (paginated): **`GET /api/v1/auth/merchants`** with **`page_id`** and **`page_size`**
5. View one master, its wallets, and every sub-merchant with wallets: **`GET /api/v1/auth/merchants/{merchant_id}`** ( **`merchant_id`** must be the **master vendor** user id, not a sub-merchant id)
6. Update merchant or sub-merchant profile/status: **`PATCH /api/v1/auth/merchants/{merchant_id}`**

For offer and settlement operations, the web app should use the merchant `id` as `vendor_id` in offer/order/transfer contexts.

### 1.2 Merchant Operations Surface (Web)

After onboarding, merchant operators typically use:

* Offer management:
  * **`POST /api/v1/auth/offers`**
  * **`GET /api/v1/auth/offers/vendor/{vendor_id}`**
  * **`GET /api/v1/auth/offers/active`**, search and count variants
  * **`PUT /api/v1/auth/customer/offers/{id}`** (edit own offer)
  * **`DELETE /api/v1/auth/customer/offers/{id}`** (delete/cancel own offer)
* Order operations:
  * **`GET /api/v1/auth/orders/vendor/{vendor_id}`**
  * **`GET /api/v1/auth/orders/recent/vendor/{vendor_id}`**
  * **`GET /api/v1/auth/orders/stats/vendor/{vendor_id}`**
* Wallet operations (if extra wallets are required beyond defaults):
  * **`POST /api/v1/auth/wallets`**
  * **`GET /api/v1/auth/wallets/user`**
  * **`GET /api/v1/auth/wallets/user-network`**
  * **`PUT /api/v1/auth/wallet/id/{id}/set-default-network`**
  * **`PUT /api/v1/auth/wallet/id/{id}/active-status`**
* Liquidity and reconciliation:
  * **`GET /api/v1/auth/vendors/{vendor_id}/liquidity`**
  * **`GET /api/v1/auth/transactions/completed`**
* Customer history surface:
  * **`GET /api/v1/auth/customer/transactions`** (returns only authenticated customer's created offers + orders)
* OTC queues:
  * deposits:
    * **`POST /api/v1/auth/otc/deposits`**
    * **`GET /api/v1/auth/otc/deposits/{id}`**
    * **`POST /api/v1/auth/otc/deposits/{id}/confirm`**
    * **`POST /api/v1/auth/otc/deposits/{id}/reject`**
    * **`POST /api/v1/auth/otc/deposits/{id}/credit`**
    * **`GET /api/v1/auth/otc/deposits/queue/pending-bank`**
    * **`GET /api/v1/auth/otc/deposits/queue/ready-to-credit`**
  * withdrawals:
    * **`POST /api/v1/auth/otc/withdrawals`**
    * **`GET /api/v1/auth/otc/withdrawals/{id}`**
    * **`POST /api/v1/auth/otc/withdrawals/{id}/approve`**
    * **`POST /api/v1/auth/otc/withdrawals/{id}/reject`**
    * **`POST /api/v1/auth/otc/withdrawals/{id}/execute`**
    * **`GET /api/v1/auth/otc/withdrawals/queue/pending`**
    * **`GET /api/v1/auth/otc/withdrawals/queue/approved`**

### 2) on-Ramp (Fiat -> USDT, C2B)

1. List offers: **`GET /api/v1/auth/offers/active?page_id=1&page_size=20`**
2. Resolve pricing (flow=`onramp`): **`POST /api/v1/auth/pricing/resolve`**
3. Create order with resolved IDs: **`POST /api/v1/auth/orders`** (`order_type=ON_RAMP_BUY`)
4. Trigger STK push: **`POST /api/v1/auth/orders/payment`**
5. Poll status: **`GET /api/v1/auth/order/id/{order_id}`**

Typical progression: `pending` -> `processing` -> `completed` (or `payment_failed`/`failed`).

### 3) Off-Ramp (USDT -> Fiat, B2C)

1. Resolve pricing (flow=`offramp`): **`POST /api/v1/auth/pricing/resolve`** (optionally pass **`vendor_id`** + **`offer_id`** to align with the chosen **liquidity listing**)
2. Create order with payout phone: **`POST /api/v1/auth/orders`** (`order_type=OFF_RAMP_SELL`)
3. Read escrow fields from response (`escrow_wallet_address`, `escrow_network`, `escrow_reference`)
4. Fund escrow:
   * in-app wallet route: **`POST /api/v1/auth/orders/{order_id}/send-payment`**, or
   * external chain transfer to escrow wallet
5. Poll status: **`GET /api/v1/auth/order/id/{order_id}`**

Typical progression: `awaiting_crypto` -> `awaiting_confirmations` -> `crypto_received` -> `payout_pending` -> `completed` (or `failed`).

#### Off-Ramp Remittance (Third-Party Fiat Payout)

Use **`POST /api/v1/auth/remittance/off-ramp/orders`** when the customer sends crypto to escrow but **mobile money (or bank) pays someone else**. Same **`vendor_id`** (liquidity provider) and **`offer_id`** (liquidity listing) semantics. They anchor **pricing and validation**, not the beneficiary’s identity. The request uses **`beneficiary_fiat_amount`** plus pricing IDs to derive **escrow crypto**. See OpenAPI for the full body.

Use the shared **countries** catalog when collecting remittance country fields. **`GET /api/v1/countries`** returns active rows for public pickers. **`GET /api/v1/auth/countries`** returns the same active catalog for authenticated apps. Prefer ISO 3166-1 alpha-3 values like **`KEN`** and **`GBR`** for **`sender_country`**, **`beneficiary_country`**, **`source_country`**, and **`destination_country`**. The backend still accepts legacy alpha-2 input and normalizes it to alpha-3.

For **custodial** send-money with a **corridor** only, use **`POST /api/v1/auth/remittance/custodial/drafts`**, and **`POST /api/v1/auth/remittance/custodial/drafts/{id}/confirm`**. See **Custodial Corridor Remittance**.

#### Domestic vs Cross-Border Off-Ramp

When the fiat beneficiary is in a **different country** than the customer who sends crypto from their wallet, you are in a **cross-border remittance** scenario (different compliance and commercial treatment than a **domestic** payout where both sides share the same country).

**Identification:** Identify domestic vs cross-border by comparing **customer (KYC) country** to **`beneficiary_country`** on the order (use ISO 3166-1 alpha-3 codes, e.g. `KEN`, `GBR`). If they match, treat the flow as domestic. However, if they differ, we treat it as cross-border remittance.

The API persists **`beneficiary_country`** on off-ramp orders. Your integration must supply a reliable **customer country** from KYC (or an explicit field collected at quote time) so this comparison is possible before you choose pricing profiles, FX quotes, or copy for the checkout screen.

### 4) P2P (Customer -> Customer USDT)

1. Ensure sender has a funded wallet on selected network.
2. Create transfer from web wallet/send UI using P2P transfer endpoint.
3. Poll transfer detail/status endpoint until terminal state.

Use P2P for customer-to-customer USDT movement only (not fiat conversion).

### 5) B2B (Merchant -> Merchant Settlement)

1. Select merchant source wallet (typically treasury wallet policy).
2. Submit transfer: **`POST /api/v1/auth/transfers/b2b`**
3. If collaborative signing is required, follow proposal confirm endpoints.
4. Poll transfer: **`GET /api/v1/auth/transfers/{id}`**

Use B2B for merchant settlement and treasury balancing between businesses.

### 5.1 Merchant Treasury Transfers (External/Internal)

Merchant web treasury screens may use:

1. Internal merchant transfer: **`POST /api/v1/auth/transfers/b2b`**
2. External destination transfer: **`POST /api/v1/auth/transfers/b2b/external`**
3. List and inspect transfer lifecycle:
   * **`GET /api/v1/auth/transfers`**
   * **`GET /api/v1/auth/transfers/{id}`**
   * **`GET /api/v1/auth/transfers/{id}/pricing`**

For high-value flows, pair this with multisig wallet registration and proposal confirmation endpoints when policy requires collaborative signing.

### 6) B2B2C (Merchant-Funded Customer Settlement)

Treat B2B2C as two linked rails:

1. **B2B Funding Leg**: merchant treasury movement to payout context.
2. **B2C Customer Leg**: off-ramp style payout execution to beneficiary phone/account.

Track each leg with its own IDs and statuses for reconciliation, support, and dispute handling.

## Off-Ramp vs on-Ramp

|                     | On-Ramp              | Off-Ramp                                                 |
| ------------------- | -------------------- | -------------------------------------------------------- |
| **order\_type**     | `ON_RAMP_BUY`        | `OFF_RAMP_SELL`                                          |
| **status**          | `pending` → pay fiat | `awaiting_crypto` → customer sends USDT to escrow        |
| **wallet\_address** | Delivery wallet      | Used to detect **TRON vs Ethereum** for pricing + escrow |

## Payment Screen (in-App Wallet Send)

| Method                                             | Purpose                                                                                                                                       |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /api/v1/auth/orders/{order_id}/estimate-fee` | Estimate network fee. Body includes **`wallet_id`** and **`network`** (must match order network).                                             |
| `POST /api/v1/auth/orders/{order_id}/send-payment` | Send USDT from the user’s platform wallet to escrow (off-ramp) or destination (on-ramp pattern). Requires `{ "wallet_id", "confirm": true }`. |
| `GET /api/v1/auth/orders/{order_id}/qr-code`       | QR/URI payload for display.                                                                                                                   |

## Fiat Payment (Mobile Money)

`POST /api/v1/auth/orders/payment` - STK push with **`order_id`** and **`phone_number`**.

## Pricing on the Order

`GET /api/v1/auth/order/id/{id}/pricing` returns the stored snapshot (rates, fees, net amounts) when present.

## Callbacks (Server-to-Server)

* `POST /api/v1/payment/callback` — mobile money. Configured for Daraja validation.
* `POST /api/v1/mpesa/b2c/result` and **`.../queue`** - B2C payout callbacks.

These endpoints are **not** authenticated with a user PASETO. We secure them at the network and payload-validation layer.
