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

# B2B OTC Desk Controls and Mobile Money C2B

> Maker-checker limits, quote enforcement, revenue reports, treasury liquidity, Pay Bill callbacks, and merchant settlement.

## Production Base URL

All paths below are rooted at:

```text theme={null}
https://crypto.westminister.tech
```

Authenticated routes use header `Authorization: Bearer <access_token>` unless noted as **public** (Safaricom callbacks).

Run migration **`000044_otc_desk_controls`** before using desk reports, C2B tables, or deposit pricing snapshot columns.

## Mobile Money C2B — Register with Safaricom (Public)

Register these **ConfirmationURL** and **ValidationURL** values in the Daraja portal for your pay bill/till:

| Purpose      | URL                                                              |
| ------------ | ---------------------------------------------------------------- |
| Validation   | `https://crypto.westminister.tech/api/v1/mpesa/c2b/validation`   |
| Confirmation | `https://crypto.westminister.tech/api/v1/mpesa/c2b/confirmation` |

`BillRefNumber` must match an active row in **`merchant_c2b_accounts`** (create via admin API below).

### Validation Callback (Safaricom → You)

**POST** `https://crypto.westminister.tech/api/v1/mpesa/c2b/validation`\
**Auth:** none

**Request body (example):**

```json theme={null}
{
  "TransactionType": "Pay Bill",
  "TransID": "QGH12345678",
  "TransTime": "20260601120000",
  "TransAmount": "5000.00",
  "BusinessShortCode": "174379",
  "BillRefNumber": "MERCHANT-ACME-001",
  "InvoiceNumber": "",
  "OrgAccountBalance": "100000.00",
  "ThirdPartyTransID": "",
  "MSISDN": "254712345678",
  "FirstName": "John",
  "MiddleName": "",
  "LastName": "Doe"
}
```

**Response (accepted):**

```json theme={null}
{
  "ResultCode": "0",
  "ResultDesc": "Accepted"
}
```

**Response (unknown account reference):**

```json theme={null}
{
  "ResultCode": "C2B00012",
  "ResultDesc": "Invalid Account Number"
}
```

### Confirmation Callback (Safaricom → You)

**POST** `https://crypto.westminister.tech/api/v1/mpesa/c2b/confirmation`\
**Auth:** none

Same request body shape as validation. On success the platform stores **`c2b_payments`** and, when `BillRefNumber` matches a merchant account, records merchant settlement (webhook `c2b.payment.settled` if `OTC_EVENTS_WEBHOOK_URL` is set).

**Response:**

```json theme={null}
{
  "ResultCode": 0,
  "ResultDesc": "Success"
}
```

## C2B Admin Configuration

### Create Merchant Account Reference

**POST** `https://crypto.westminister.tech/api/v1/auth/otc/c2b/accounts`\
**Roles:** **admin** or **treasury**

```json theme={null}
{
  "merchant_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "account_reference": "MERCHANT-ACME-001",
  "short_code": "174379"
}
```

### List C2B Payments

**GET** `https://crypto.westminister.tech/api/v1/auth/otc/c2b/payments?merchant_id=<uuid>&from=2026-06-01T00:00:00Z&to=2026-06-02T00:00:00Z`

## OTC Deposit Credit — Quote Enforcement

**POST** `https://crypto.westminister.tech/api/v1/auth/otc/deposits/{id}/credit`\
**Roles:** **admin**, **otc\_officer**, or **treasury** (with limits below)

`crypto_amount` must match `requested_crypto_amount` within **`OTC_CREDIT_QUOTE_TOLERANCE_BPS`** (default 10). Otherwise **422** with `requires_second_approval: true`. **admin** or **treasury** may pass **`override_reason`** to credit a different amount.

```json theme={null}
{
  "to_wallet_id": "09932418-5d29-4c40-955d-b291d695d999",
  "asset": "USDT",
  "crypto_amount": "766162.05000000",
  "network": "tron",
  "pricing_profile_id": "11111111-2222-3333-4444-555555555555",
  "fx_rate_quote_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "fiat_currency": "KES",
  "fiat_amount_equivalent": "100000000.00",
  "override_reason": ""
}
```

**422 example (quote mismatch):**

```json theme={null}
{
  "error": "credit amount 766000.00000000 does not match quoted 766162.05000000 (tolerance 10 bps)",
  "requires_second_approval": true
}
```

## Maker-Checker Limits (Env)

| Variable                         | Default | Meaning                                                                         |
| -------------------------------- | ------- | ------------------------------------------------------------------------------- |
| `OTC_OFFICER_MAX_USD`            | `10000` | Max USD notional per **otc\_officer** confirm/credit/withdrawal approve/execute |
| `OTC_CREDIT_QUOTE_TOLERANCE_BPS` | `10`    | Allowed deviation on credit vs quoted crypto                                    |

**admin** and **treasury** have no USD cap. **treasury** may confirm fiat and initiate credit.

## Revenue Reports

**GET** `https://crypto.westminister.tech/api/v1/auth/otc/reports/deposits?status=credited&limit=50&offset=0&from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z`

**GET** `https://crypto.westminister.tech/api/v1/auth/otc/reports/deposits/rollup?from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z`

**Response (rollup example):**

```json theme={null}
{
  "deal_count": 12,
  "total_fiat_in": "1200000000.00",
  "total_crypto_out": "9234567.89000000",
  "total_spread_amount": "27890.12000000",
  "total_fee_amount": "12.00000000"
}
```

## Treasury Desk Liquidity

**GET** `https://crypto.westminister.tech/api/v1/auth/treasury/desk-liquidity?network=tron&refresh=true`

```json theme={null}
{
  "network": "tron",
  "treasury_wallet_id": "...",
  "treasury_address": "T...",
  "treasury_usdt": "5000000.00000000",
  "pending_deposits": {
    "fiat_confirmed_not_credited": "250000000.00",
    "deal_count": 3
  },
  "pending_withdrawals": {
    "crypto_approved_or_processing": "100000.00000000",
    "fiat_total": "13000000.00",
    "deal_count": 2
  },
  "policy": {
    "officer_max_usd": "10000",
    "credit_quote_tolerance_bps": 10
  }
}
```

## Hedge Notes (Manual Register)

**POST** `https://crypto.westminister.tech/api/v1/auth/otc/hedge-notes`

```json theme={null}
{
  "otc_deposit_id": "deposit-uuid",
  "note_type": "hedge",
  "reference": "Binance spot buy TX123",
  "amount": "1000000.00000000",
  "currency": "USDT"
}
```

## Bank Withdrawal Payout Tracking

**POST** `https://crypto.westminister.tech/api/v1/auth/otc/withdrawals/{id}/record-bank-payout`

```json theme={null}
{
  "bank_payout_reference": "SWIFT-REF-2026-0601-001"
}
```
