Sell crypto Coins Why Monica FAQ Get the app
Developers · Off-Ramp API · v1

Crypto in. Naira settled.
One API.

Issue a deposit wallet to any of your users. The moment their crypto confirms on-chain, Monica converts it at the locked rate and settles naira to your corporate account — in under 60 seconds — while a signed webhook tells your system exactly what happened.

BASE URLapi.monica.cash/v1 FORMATJSON over HTTPS AUTHBearer keys · HMAC webhooks SETTLEMENTNGN · under 60s after confirmation
01 · How settlement flows
1
You issue a wallet Call POST /v1/wallets with your user's reference. You get back a unique deposit address for the asset and network you chose. Show it to your user however you like.
2
Their deposit is detected Monica watches the chain. The moment a transaction touches the address you receive a deposit.detected webhook with the txid and amount — before it even confirms.
3
Confirmation locks the rate On the required confirmation, title to the crypto passes to Monica's treasury and the NGN rate is locked at that moment. You receive deposit.confirmed with the exact naira value. Monica is an off-ramp — deposit addresses are settlement endpoints, not custodial wallets.
4
Naira lands in your account The converted naira is paid to your registered corporate bank account in under 60 seconds, and settlement.paid closes the loop with the bank reference. Reconcile by customer_ref, deposit_id or settlement_id — your choice.
DETECTEDCONFIRMEDCONVERTEDSETTLED
02 · Access & authentication

API access is issued to registered businesses after a short due-diligence review (KYB). To request keys, write to [email protected] with your company name, RC number, website, expected monthly volume, and the corporate bank account that should receive settlements. Most reviews complete within two business days.

You'll receive two key pairs — sk_test_… for the sandbox and sk_live_… for production — plus a whsec_… webhook signing secret for each environment. Send your key on every request:

# Every request
Authorization: Bearer sk_live_9f2c7a1e4b8d…
Content-Type: application/json
Idempotency. Send an Idempotency-Key header on every POST. If a request is retried with the same key within 24 hours you get the original response back, never a duplicate wallet.
Keys are secrets. Server-side only — never in an app binary, never in the browser. A leaked live key can issue wallets against your account. Rotate immediately via [email protected] if exposed.
03 · Endpoints
POST/v1/walletsIssue a deposit wallet for one of your users
# Request
curl -X POST https://api.monica.cash/v1/wallets \
  -H "Authorization: Bearer sk_live_9f2c7a1e4b8d…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1e-user-8841-usdt" \
  -d '{
    "customer_ref": "user_8841",
    "asset":        "USDT",
    "network":      "TRC20",
    "label":        "Deposit wallet — user_8841"
  }'
# Response — 201 Created
{
  "id":           "wal_01JXK4N9Q2M7",
  "object":       "wallet",
  "customer_ref": "user_8841",
  "asset":        "USDT",
  "network":      "TRC20",
  "address":      "TWd2yzw5yFc9C3jn…",
  "status":       "active",
  "created_at":   "2026-07-06T09:41:02Z"
}
FieldTypeNotes
customer_refstring · requiredYour internal ID for the end user. Echoed on every deposit and webhook so you can reconcile without storing our IDs.
assetstring · requiredBTC, USDT, USDC, ETH, SOL, TRX, BNB
networkstring · requiredMust match the asset — e.g. TRC20, ERC20, BEP20, SPL, BITCOIN
labelstring · optionalFree text, ≤120 chars, shown in your dashboard exports.

Addresses are permanent. One user can hold one wallet per asset/network pair — repeat calls with the same customer_ref + pair return the existing wallet (200, not 201).

GET/v1/wallets/{wallet_id}Fetch one wallet
GET/v1/wallets?customer_ref=user_8841List a user's wallets
GET/v1/deposits/{deposit_id}Fetch one deposit
GET/v1/deposits?wallet_id=wal_01JXK4N9Q2M7List deposits on a wallet
# Deposit object
{
  "id":            "dep_01JXK7RQ83VD",
  "object":        "deposit",
  "wallet_id":     "wal_01JXK4N9Q2M7",
  "customer_ref":  "user_8841",
  "asset":         "USDT",
  "network":       "TRC20",
  "amount":        "150.000000",
  "txid":          "b2a4c9f7e1d8…",
  "confirmations": 1,
  "status":        "settled",
  "rate_ngn":      "1621.50",
  "ngn_amount":    "243225.00",
  "settlement_id": "set_01JXK7SM4T9A",
  "detected_at":   "2026-07-06T09:41:02Z",
  "confirmed_at":  "2026-07-06T09:41:19Z",
  "settled_at":    "2026-07-06T09:41:47Z"
}

status walks the lifecycle: detected → confirmed → converted → settled. Amounts are strings to preserve precision; never parse them as floats for accounting.

GET/v1/settlements/{settlement_id}Fetch one payout to your bank
GET/v1/settlements?from=2026-07-01&to=2026-07-06List settlements for reconciliation
# Settlement object
{
  "id":             "set_01JXK7SM4T9A",
  "object":         "settlement",
  "deposit_id":     "dep_01JXK7RQ83VD",
  "ngn_amount":     "243225.00",
  "bank_reference": "NIP/260706/094147/8823",
  "account_last4":  "7031",
  "status":         "paid",
  "paid_at":        "2026-07-06T09:41:47Z"
}
GET/v1/ratesCurrent NGN conversion rates for every supported asset

Indicative only — the binding rate is always the one locked at confirmation, returned on the deposit object and in deposit.confirmed.

04 · Webhooks

Register an HTTPS endpoint during onboarding (or change it later via [email protected]). Every event is a POST with a JSON body and two headers you must verify.

EventFires when
deposit.detectedA transaction to one of your wallets is seen in the mempool / first block. Unconfirmed — treat as informational.
deposit.confirmedRequired confirmations reached. Rate locked, naira value fixed. Safe to credit your user's ledger.
deposit.convertedThe crypto→NGN conversion executed on Monica's treasury.
settlement.paidNaira left for your corporate account. Carries the bank reference for reconciliation.
wallet.createdA wallet was issued (including via dashboard). Useful for audit trails.
# Delivery — example: deposit.confirmed
POST https://yourapp.com/webhooks/monica
X-Monica-Timestamp: 1783158079
X-Monica-Signature: 6e8c1d0a94b7f3…

{
  "id":         "evt_01JXK7RS0P2Q",
  "type":       "deposit.confirmed",
  "created_at": "2026-07-06T09:41:19Z",
  "data": {
    "deposit_id":    "dep_01JXK7RQ83VD",
    "wallet_id":     "wal_01JXK4N9Q2M7",
    "customer_ref":  "user_8841",
    "asset":         "USDT",
    "network":       "TRC20",
    "amount":        "150.000000",
    "txid":          "b2a4c9f7e1d8…",
    "confirmations": 1,
    "rate_ngn":      "1621.50",
    "ngn_amount":    "243225.00",
    "status":        "confirmed"
  }
}

Verifying signatures

Compute an HMAC-SHA256 over timestamp + "." + raw_body with your whsec_… secret and compare it, constant-time, to X-Monica-Signature. Reject anything older than 5 minutes.

# Pseudocode — any language
payload  = header("X-Monica-Timestamp") + "." + raw_request_body
expected = hex( hmac_sha256(key: WEBHOOK_SECRET, message: payload) )

if !constant_time_equals(expected, header("X-Monica-Signature")): reject 401
if abs(now() - header("X-Monica-Timestamp")) > 300:               reject 401
process(event)
respond 200
Delivery rules. Respond 2xx within 10 seconds — do your heavy work async. Failed deliveries retry with exponential backoff for 24 hours. Events can very occasionally arrive twice or out of order: key your handlers on event.id and treat them as idempotent.
05 · Errors
# Every error, same shape
{
  "error": {
    "code":    "unsupported_network",
    "message": "USDT is not available on network BITCOIN.",
    "param":   "network"
  }
}
StatusCodeMeaning
400validation_errorA field is missing or malformed. param names it.
401invalid_keyMissing, revoked, or wrong-environment API key.
403account_restrictedYour account is under review — check your inbox.
404not_foundNo such wallet / deposit / settlement on your account.
409idempotency_conflictSame Idempotency-Key reused with a different body.
422unsupported_networkThe asset/network pair isn't supported.
429rate_limitedOver 120 requests/minute. Honour Retry-After.
5xxinternalOur side. Safe to retry with the same idempotency key.
06 · Sandbox

Everything above works identically at https://sandbox.api.monica.cash/v1 with your sk_test_… key. Sandbox wallets accept testnet coins (TRC20 Shasta, Ethereum Sepolia, Bitcoin testnet3, Solana devnet), confirmations are accelerated, and settlements post to a virtual ledger you can inspect at GET /v1/settlements — no real bank movement, no real crypto. Webhooks fire exactly as in production, signed with your test whsec_….

07 · The fine print

Monica is a direct crypto-to-naira off-ramp operated by Monica Technologies Limited, Lagos, aligned with Nigeria's SEC VASP framework. We do not provide custodial wallet services: a deposit address issued through this API is a settlement endpoint, and on on-chain confirmation title to the crypto passes to Monica's treasury against our obligation to settle naira to your account. Partners must be registered businesses, complete KYB, and remain responsible for KYC on their own end users. Full terms are issued with your API agreement.

Request access

Ready to build on the off-ramp?

Tell us about your business and volumes — most integrations go live within a week of KYB approval.

[email protected] Include your company name, RC number, website, expected volume and settlement account.