Funding & Reconciliation

End-to-end walkthrough for funding a client and reconciling orders against your own records — create a deposit, check the balance, create a withdrawal, and look up orders by your own reference.

This guide walks you through funding a client with fiat, checking their balance, debiting them with a withdrawal, and reconciling those orders against your own records using partner_order_ref. By the end, you will have a client with a balance you can trade against and a reconciliation pattern you can apply in bulk.

For the concepts behind deposits, withdrawals, balances, and partner_order_ref, see the Funding guide.


What You Will Have at the End

  • A client with a funded fiat balance
  • Two orders on record — one deposit, one withdrawal — each tagged with your own partner_order_ref
  • A working reconciliation pattern: look up any order using your own reference, not CoinMENA's internal ID

Core Rules

Four rules to keep in mind before you run anything.

📘

The balance endpoint and order responses are the source of truth

Always rely on values returned by GET /v1/partner/balances and by the order endpoints for reconciliation. Do not recalculate amounts manually from your own system and assume they match — fetch CoinMENA's state and compare.

Funding is synchronous, and balances update on the response

A successful deposit or withdrawal response means the order is completed and the client's available_balance has already been updated. No polling, no settlement window. Every successful funding operation is fully applied before the response returns.

⚠️

If a request fails, no balance changes are applied

Any error response (4xx or 5xx) means the operation did not take effect. The client's balance is unchanged and no order was created. Safe to retry — with a new partner_order_ref if the original attempt produced a 2020 on its second try.

⚠️

Every partner_order_ref must be unique

Across your entire partner account — deposits, withdrawals, and trades share the same uniqueness namespace. Reusing a value returns 2020 (HTTP 409) and the API does not return the existing order. Always generate a fresh reference per order.


Before You Start

You need the following in place before running any of the calls below.

Prerequisites checklist

  • You have a verified, active client (status: verified, active: true). If not, complete the Onboarding a Client walkthrough first
  • You have your Partner ID and can generate request signatures — see the Authentication guide
  • You know the asset_id of the fiat asset you will deposit and withdraw — fetch from GET /v1/public/assets and check that published, depositable, and withdrawable are all true
  • You have a way to generate unique partner_order_ref values per order — use your own internal order IDs or a UUID

Environment and signing

ItemDetails
EnvironmentProduction: https://external-api.coinmena.com
Sandbox: contact [email protected] for credentials
Signed headersAll signed requests need X-Partner-ID, X-Timestamp, and X-Signature. See the Authentication guide to generate them
📘

Placeholders in the cURL examples

Replace your_partner_id with your actual Partner ID, and <your_generated_signature> with the Base64 signature you compute per the Authentication guide. Every request below needs its own fresh timestamp and signature.


The Flow at a Glance

  1. Deposit fiat → client's available_balance increases
  2. Check the balance → confirm the balance reflects the deposit
  3. Withdraw fiat → client's available_balance decreases
  4. Look up an order by your own reference → single-order reconciliation using partner_order_ref
  5. List orders in a date range → bulk reconciliation and audit pattern

Step 1 — Deposit Fiat

Credit a fiat balance to the client. The amount is a string decimal, greater than zero, with up to 8 decimal places.

curl -X POST "https://external-api.coinmena.com/v1/partner/deposits" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654321000" \
  -H "X-Signature: <your_generated_signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_client_id": "user_12345",
    "asset_id": "USD",
    "amount": "1000.00",
    "partner_order_ref": "deposit-abc-123"
  }'

Response — 200 OK

{
  "result": {
    "id": 67890,
    "order_no": "MND0000067890",
    "partner_client_id": "user_12345",
    "type": "deposit",
    "source": "bank",
    "status": "completed",
    "credit": null,
    "credit_asset_id": null,
    "debit": "1000.00",
    "debit_asset_id": "USD",
    "fee": "0",
    "fee_asset_id": "USD",
    "vat": "0",
    "partner_order_ref": "deposit-abc-123",
    "price": null,
    "created_at": "2024-06-01T10:00:00Z",
    "transitioned_at": "2024-06-01T10:00:00Z",
    "updated_at": "2024-06-01T10:00:00Z"
  }
}

What to Persist

FieldWhy You Need It
idCoinMENA's order ID. Useful as a secondary reference
partner_order_refYour own reference. Primary lookup key for reconciliation
statusShould be completed. If anything else, log and investigate
debitOn a deposit, this is the deposited amount. See Reading debit vs credit
created_atFor audit trails and time-range reconciliation later
📘

Why debit holds the deposit amount

On deposits and withdrawals, the debit and credit fields reflect CoinMENA's accounting convention, not the client's perspective. Read the type field first, then apply the mapping in the Funding guide. For deposits: debit is populated, credit is null.


Step 2 — Check the Client's Balance

Confirm the deposit updated the client's available_balance. Pass the client's ID as a query parameter to get client-scoped balances.

curl -X GET "https://external-api.coinmena.com/v1/partner/balances?partner_client_id=user_12345" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654322000" \
  -H "X-Signature: <your_generated_signature>"

Response — 200 OK

{
  "items": [
    {
      "asset_id": "USD",
      "balance": "1000.00",
      "available_balance": "1000.00",
      "balance_usd": "1000.00",
      "available_balance_usd": "1000.00"
    }
  ]
}

Check that available_balance on the USD record equals the deposit amount (plus any prior balance). This is the balance you check before calling any trading or withdrawal endpoint.

How Balance Changes Map to Operations

After any successful funding operation, the effect on available_balance is direct:

  • After a depositavailable_balance increases by the amount you submitted
  • After a withdrawalavailable_balance decreases by the amount you submitted
  • After a buy trade — quote asset balance decreases, base asset balance increases (see the Trading guide)
  • After a sell trade — base asset balance decreases, quote asset balance increases (see the Trading guide)
📘

Parse decimals with a decimal-aware type

Balance and amount fields are strings and may use scientific notation (e.g. "0E-8"). Never parse them as JavaScript Number or Python float — use Decimal in Python, decimal.js in JavaScript, or equivalent. Do not apply your own rounding to returned amounts; preserve the precision the API returns.

⚠️

Do not cache balances for long

Balances can change between calls — through your own operations, platform-side adjustments, or other activity on the account. Always fetch a fresh balance immediately before making a financial decision (e.g. before calculating a quote or submitting a withdrawal), rather than relying on a cached value from minutes earlier.

Retrieving a Single Asset Balance

If you only care about one asset, use the per-asset endpoint instead:

curl -X GET "https://external-api.coinmena.com/v1/partner/balances/USD?partner_client_id=user_12345" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654323000" \
  -H "X-Signature: <your_generated_signature>"

Returns a single balance object in result (not a list).


Step 3 — Withdraw Fiat

Debit fiat from the client. The withdrawal is rejected if available_balance is less than amount.

curl -X POST "https://external-api.coinmena.com/v1/partner/withdrawals" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654324000" \
  -H "X-Signature: <your_generated_signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "partner_client_id": "user_12345",
    "asset_id": "USD",
    "amount": "500.00",
    "partner_order_ref": "withdrawal-abc-456"
  }'

Response — 200 OK

{
  "result": {
    "id": 67891,
    "order_no": "MNW0000067891",
    "partner_client_id": "user_12345",
    "type": "withdrawal",
    "source": "bank",
    "status": "completed",
    "credit": "500.00",
    "credit_asset_id": "USD",
    "debit": null,
    "debit_asset_id": null,
    "fee": "0",
    "fee_asset_id": "USD",
    "vat": "0",
    "partner_order_ref": "withdrawal-abc-456",
    "price": null,
    "created_at": "2024-06-01T10:05:00Z",
    "transitioned_at": "2024-06-01T10:05:00Z",
    "updated_at": "2024-06-01T10:05:00Z"
  }
}

Reading debit vs credit

On funding orders, the debit / credit semantics are opposite between deposits and withdrawals:

Order typedebit holdscredit holdsEffect on client
depositThe deposited amountnullBalance increases by debit
withdrawalnullThe withdrawn amountBalance decreases by credit

Always check type first, then read the correct field. See the Orders guide for the full 4-way mapping (including trades).

Running Multiple Operations in Sequence

Funding operations are applied in the order you call them. If you run multiple deposits and withdrawals back to back, each one is fully applied before the response returns. If your logic depends on the current balance (for example, to decide whether a second withdrawal is safe), fetch a fresh balance between operations rather than computing it locally.


Step 4 — Look Up an Order by Your Reference

This is the reconciliation-friendly lookup path. Use the partner_order_ref you tagged at creation — no need to map CoinMENA's internal ID.

curl -X GET "https://external-api.coinmena.com/v1/partner/orders/ref/deposit-abc-123" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654325000" \
  -H "X-Signature: <your_generated_signature>"

Response — 200 OK

{
  "result": {
    "id": 67890,
    "order_no": "MND0000067890",
    "partner_client_id": "user_12345",
    "type": "deposit",
    "status": "completed",
    "debit": "1000.00",
    "debit_asset_id": "USD",
    "partner_order_ref": "deposit-abc-123",
    "created_at": "2024-06-01T10:00:00Z"
  }
}

Match the returned fields against your internal record:

  • status — should be completed for a successful funding order
  • debit / credit — match against your expected amount (based on type)
  • partner_order_ref — confirms the echo of your reference
⚠️

Handling a 409 on creation

If Step 1 or Step 3 returned 2020 with HTTP 409 (duplicate partner_order_ref), the original order already exists. Do not retry with the same reference — call GET /v1/partner/orders/ref/{partner_order_ref} (this step) to fetch the existing order. If its status is completed, the original succeeded; if failed or rejected, retry with a new partner_order_ref.

Looking Up by CoinMENA's Order ID

If you need to look up an order using CoinMENA's numeric id instead, use:

curl -X GET "https://external-api.coinmena.com/v1/partner/orders/67890" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654326000" \
  -H "X-Signature: <your_generated_signature>"

Returns the same order object.


Step 5 — Audit Orders in a Date Range

Use order listing to audit every funding operation in a time window and verify that each one matches your expected results. Filter aggressively before paginating — combine partner_client_id, from_datetime, and status to keep result sets small.

curl -X GET "https://external-api.coinmena.com/v1/partner/orders?partner_client_id=user_12345&from_datetime=2024-06-01T00:00:00Z&to_datetime=2024-06-01T23:59:59Z&status=completed&page=1&page_size=100" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654327000" \
  -H "X-Signature: <your_generated_signature>"

Response — 200 OK

{
  "items": [
    {
      "id": 67890,
      "partner_client_id": "user_12345",
      "type": "deposit",
      "status": "completed",
      "debit": "1000.00",
      "debit_asset_id": "USD",
      "partner_order_ref": "deposit-abc-123",
      "created_at": "2024-06-01T10:00:00Z"
    },
    {
      "id": 67891,
      "partner_client_id": "user_12345",
      "type": "withdrawal",
      "status": "completed",
      "credit": "500.00",
      "credit_asset_id": "USD",
      "partner_order_ref": "withdrawal-abc-456",
      "created_at": "2024-06-01T10:05:00Z"
    }
  ],
  "total": 2,
  "page": 1,
  "page_size": 100
}

Iterate pages until page >= ceil(total / page_size) or the current page returns fewer than page_size items. See the Pagination guide for the full pattern.

Reconciliation Checklist

For each order in the response:

  • Match partner_order_ref against your internal record
  • Confirm status: completed (or flag failed / rejected for investigation)
  • Confirm the amount field (debit or credit based on type) matches your expected value
  • Flag any orders in CoinMENA's response that are not in your system
  • Flag any orders in your system that are not in CoinMENA's response

What Can Go Wrong

The most common errors during funding and reconciliation. A failed funding request never applies any balance change — retry logic can assume the client's state is unchanged on any error response.

ErrorCodeLikely CauseFix
Invalid client ID2008partner_client_id not found under your partner accountVerify the client was onboarded and the reference ID matches
Client not yet verified2009Client status is not verifiedComplete onboarding — see the Onboarding a Client guide
Client is deactivated2010Client active is falseReactivate via PUT /v1/partner/clients/{partner_client_id}/activation
Invalid asset2012Asset is not published, not depositable (for deposits), or not withdrawable (for withdrawals)Fetch GET /v1/public/assets and pick an asset with all required flags
Duplicate partner_order_ref2020You reused a reference valueFetch the existing order via the ref lookup. Retry with a new reference only if needed
Insufficient funds3005available_balance is less than the withdrawal amountCheck the balance before withdrawing. Deposit more first if needed
Order not found404Wrong order ID or reference, or the order belongs to a different partnerDouble-check the reference. A partner cannot retrieve another partner's orders
Unauthorized401Bad signature, expired timestamp, or IP not whitelistedWork through the Authentication troubleshooting checklist

For the complete list, see the Error Codes guide.


What’s Next
Next StepDescription
Executing a TradeUse the funded balance to run a trade end-to-end
FundingConcept reference for deposits, withdrawals, and balances
OrdersFull reference for the order object, statuses, and retrieval
PaginationHow to iterate through paginated lists like GET /v1/partner/orders