Funding
Funding covers how fiat money moves in and out of a client's account — deposits credit a client's balance, withdrawals debit it. This page explains the funding model, asset eligibility, reconciliation, and how balances behave.
Funding is how fiat money moves in and out of your clients' accounts on CoinMENA. You create deposits to credit a client's balance and withdrawals to debit it. Both are bank-based, both are scoped per client, and both create order records you can reconcile against your own internal references.
Overview
The Partner API supports two funding operations:
| Operation | Endpoint | What It Does |
|---|---|---|
| Deposit | POST /v1/partner/deposits | Credit fiat to a client's available balance |
| Withdrawal | POST /v1/partner/withdrawals | Debit fiat from a client's available balance |
Both operations:
- Are scoped to a single client via
partner_client_id - Accept only published fiat assets (e.g.
USD) - Require a unique
partner_order_reffor reconciliation - Create an order record that you can retrieve later (see Orders)
- Are synchronous and immediate — the balance updates in the same call
Funding is bank-basedThe Partner API funding endpoints book bank-based fiat deposits and withdrawals on behalf of your clients. Crypto deposits and withdrawals are not supported through this API.
Core Rules
Three rules govern every funding call. All three are hard constraints — violating any one of them rejects the request.
Funding is synchronous and immediateA successful deposit or withdrawal call returns an order with
status: completed. The transaction has been created and completed in the same call — there is no pending/processing state to poll. The client's balance is updated on the response, not later.
partner_order_refmust be unique per partnerEvery funding call requires a
partner_order_refthat has never been used before under your partner account. Reusing one returns error2020with HTTP409 Conflict. This prevents duplicate order creation. It is not silent retry — a conflict means you must fetch the existing order and decide what to do, not retry with the same ref. See Handling a2020Conflict.
Withdrawals require sufficient available balanceA withdrawal is rejected with error
3005— Insufficient funds for payment — if the client'savailable_balanceis less than the requested amount. No partial withdrawal is ever performed. Check the balance before calling if the amount is close to the available total.
Funding Flow
Every funding call follows the same shape:
- Submit — Call
POST /v1/partner/depositsorPOST /v1/partner/withdrawalswith the client, asset, amount, andpartner_order_ref. - Validate — CoinMENA checks client eligibility, asset eligibility, balance (for withdrawals), and
partner_order_refuniqueness. - Execute — The order is created and the client's balance is updated in the same call.
- Respond — The response contains the created order object with
status: completed. Persist the order ID and yourpartner_order_ref.
No polling. No second call. The response is final.
Asset Eligibility
Not every asset can be used for funding. Each asset has three flags on the asset object that control eligibility:
| Flag | Meaning |
|---|---|
published | The asset is visible on the platform. Required for both deposits and withdrawals |
depositable | The asset can be deposited. Required for POST /v1/partner/deposits |
withdrawable | The asset can be withdrawn. Required for POST /v1/partner/withdrawals |
The rule: the asset submitted in a funding request must be published and have the correct flag for the operation (depositable for deposits, withdrawable for withdrawals). Funding is for fiat assets only (e.g. USD).
Submitting a crypto asset, an unpublished asset, or an asset missing the correct flag returns error 2012 — Invalid asset.
You can discover which assets are eligible by calling GET /v1/public/assets and filtering on these flags.
Deposits
Credit fiat to a client's account.
Request
Submit to POST /v1/partner/deposits:
| Field | Required | Constraints | Description |
|---|---|---|---|
partner_client_id | Yes | max 255 | The client whose balance is being credited |
asset_id | Yes | max 10, must be a published, depositable fiat asset | Fiat asset identifier (e.g. USD) |
amount | Yes | string decimal, > 0, max 8 decimal places | Amount to deposit |
partner_order_ref | Yes | max 255, unique per partner | Your own unique reference for this order. Used for reconciliation |
Request Example
{
"partner_client_id": "user_12345",
"asset_id": "USD",
"amount": "1000.00",
"partner_order_ref": "deposit-abc-123"
}Response
The deposit call returns the created order object. On a deposit, the debit field holds the deposited amount and credit is null:
{
"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"
}
}The client's USD available balance increases on return. See Reading the Response below for how to interpret the debit and credit fields.
Withdrawals
Debit fiat from a client's account.
Request
Submit to POST /v1/partner/withdrawals:
| Field | Required | Constraints | Description |
|---|---|---|---|
partner_client_id | Yes | max 255 | The client whose balance is being debited |
asset_id | Yes | max 10, must be a published, withdrawable fiat asset | Fiat asset identifier (e.g. USD) |
amount | Yes | string decimal, > 0, max 8 decimal places | Amount to withdraw |
partner_order_ref | Yes | max 255, unique per partner | Your own unique reference for this order. Used for reconciliation |
Request Example
{
"partner_client_id": "user_12345",
"asset_id": "USD",
"amount": "500.00",
"partner_order_ref": "withdrawal-abc-456"
}Response
The withdrawal call returns the created order object. On a withdrawal, the credit field holds the withdrawn amount and debit is null:
{
"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"
}
}The client's USD available balance decreases on return.
Reading the Response — debit vs credit
debit vs creditDeposits and withdrawals use debit and credit fields in different ways. Read them by looking at the order's type field first.
Order type | debit holds | credit holds |
|---|---|---|
deposit | The deposited amount (e.g. USD) | null |
withdrawal | null | The withdrawn amount (e.g. USD) |
How to tell if a balance went up or down — don't rely on the field name. Use type:
type: deposit→ client's balance increased bydebittype: withdrawal→ client's balance decreased bycredit
Why does a deposit populatedebit?The
debitandcreditfields reflect CoinMENA's internal accounting convention, not the client's perspective. From CoinMENA's books, a deposit means CoinMENA records a debit entry (an asset received on its side), and a withdrawal means CoinMENA records a credit entry. You do not need to understand the accounting — just follow the mapping table above.
The same fields appear on trade orders (buy / sell) but with different semantics. See the Orders guide for the full mapping across all four order types.
Fee Fields in the Response
Every funding order response includes fee-related fields:
| Field | Description |
|---|---|
fee | Fee amount recorded for this order |
fee_asset_id | Asset ID in which the fee is denominated |
vat | VAT amount recorded for this order |
Always read these fields from the response rather than assuming a value. Record them on your side for accounting and reconciliation.
partner_order_ref — The Reconciliation Key
partner_order_ref — The Reconciliation Keypartner_order_ref is required for both deposits and withdrawals. It is your system's reference ID for the order, used to reconcile CoinMENA's order records against your own books.
Why It Matters
- Your system of record stays yours. Store your internal ID as
partner_order_ref. Later, fetch the order withGET /v1/partner/orders/ref/{partner_order_ref}— no mapping table needed between your IDs and CoinMENA's numericid. - Duplicate protection. If your system accidentally submits the same funding call twice with the same
partner_order_ref, the second call is rejected with2020. This protects against duplicate order creation — but see the handling rules below. - Reconciliation. Every order response echoes back the
partner_order_refyou submitted, so you can match CoinMENA's books to yours line by line.
Handling a 2020 Conflict
2020 ConflictIf you receive 2020 on a funding call:
- Do not retry with the same
partner_order_ref. The original order already exists. - Fetch the existing order with
GET /v1/partner/orders/ref/{partner_order_ref}. - Inspect the order's
status:- If
completed— the original succeeded; treat this as done. - If
failed/rejected— the original did not succeed; retry with a newpartner_order_ref.
- If
- Update your internal state to reflect the actual outcome.
2020is not silent idempotencyA
2020response does not return the existing order's data. You must callGET /v1/partner/orders/ref/{partner_order_ref}yourself to retrieve it.
Balances After Funding
Funding directly affects the client's asset balance. To understand the effect, you need two fields from the balance object:
| Field | What It Represents |
|---|---|
balance | Total balance, including any amounts reserved or locked |
available_balance | Balance available for trading or withdrawal — this is what you check before acting |
Effect of Each Operation
| Operation | Effect on available_balance |
|---|---|
| Deposit | Increases by the deposited amount (the debit value on the order response) |
| Withdrawal | Decreases by the withdrawn amount (the credit value on the order response) |
Trade (buy) | Decreases the quote asset (e.g. USD), increases the base asset (e.g. BTC) |
Trade (sell) | Decreases the base asset, increases the quote asset |
Deposited funds are immediately usable for tradingOnce a deposit response returns, the deposited amount is reflected in
available_balanceand can be used to calculate and execute quotes. There is no settlement window between depositing and trading.
Retrieving Balances
Two endpoints are available:
| Endpoint | Returns |
|---|---|
GET /v1/partner/balances | All balances for the partner account, or for a specific client with ?partner_client_id= |
GET /v1/partner/balances/{asset_id} | Balance for one asset, partner-level or client-scoped |
To retrieve a client's balance, pass ?partner_client_id=<your_client_ref>. Omitting it returns the partner-level balance.
Balance Response Example
{
"items": [
{
"asset_id": "USD",
"balance": "1000.00",
"available_balance": "1000.00",
"balance_usd": "1000.00",
"available_balance_usd": "1000.00"
},
{
"asset_id": "BTC",
"balance": "0.00100000",
"available_balance": "0.00100000",
"balance_usd": "67.50",
"available_balance_usd": "67.50"
}
]
}
Decimal parsingBalance fields are returned as strings and may use scientific notation (e.g.
"0E-8"). Parse with a decimal-aware type —Decimalin Python,decimal.jsin JavaScript — never as afloatornumber.
Why Funding Can Fail
Beyond transport-level errors (timeouts, 5xx, etc.), a funding call can fail for these business reasons:
| Reason | Error Code | Applies To | Fix |
|---|---|---|---|
| Invalid client ID | 2008 | Deposits, Withdrawals | Verify partner_client_id exists under your partner account |
| Client is not verified | 2009 | Deposits, Withdrawals | Only verified clients can be funded |
| Client is deactivated | 2010 | Deposits, Withdrawals | Reactivate the client via the activation endpoint |
| Asset not found, not published, or not depositable | 2012 | Deposits | Submit a published, depositable fiat asset |
| Asset not found, not published, or not withdrawable | 2012 | Withdrawals | Submit a published, withdrawable fiat asset |
Duplicate partner_order_ref | 2020 | Deposits, Withdrawals | Use a new unique reference — see Handling a 2020 Conflict |
| Insufficient balance | 3005 | Withdrawals | Check available_balance before calling |
Schema validation failure (invalid amount, missing field, etc.) | 422 | Deposits, Withdrawals | Review msg_detail to identify the failing field |
Common Mistakes
The most frequent issues partners hit when implementing funding:
| Mistake | Fix |
|---|---|
Reusing partner_order_ref across orders | Each reference must be unique per partner. Duplicates return 2020 |
Retrying a failed funding call with the same partner_order_ref | Look up the existing order first — retry with a new reference only if the original truly failed |
Submitting a crypto asset_id | Funding endpoints accept fiat assets only |
| Submitting an asset without the correct eligibility flag | Check depositable for deposits and withdrawable for withdrawals on the asset object |
Assuming credit always means "client received" | Field meaning depends on order type — use the mapping table in Reading the Response |
Parsing amount or balance fields as float / Number | Use a decimal-aware type — scientific notation breaks float parsing |
Sending amount as a JSON number | Submit as a string (e.g. "1000.00") to preserve precision |
Withdrawing without checking available_balance | For edge-case amounts, check balance first to avoid a 3005 |
| Assuming completion is async | Funding is synchronous — the returned order is final on response |
Expecting 2020 to return the existing order | 2020 only signals the conflict; fetch the existing order separately |
Related Error Codes
The errors you are most likely to see during funding:
| Code | Trigger | Endpoint |
|---|---|---|
2008 | Invalid client ID | Deposits, Withdrawals |
2009 | Client is not yet verified | Deposits, Withdrawals |
2010 | Client is deactivated | Deposits, Withdrawals |
2012 | Invalid asset (not found, not published, or wrong flag) | Deposits, Withdrawals, GET /v1/partner/balances/{asset_id} |
2020 | Duplicate partner_order_ref | Deposits, Withdrawals (also Execute) |
3005 | Insufficient funds for payment | Withdrawals |
See the Error Codes guide for the full reference.
Updated 1 day ago
| Next Step | Description |
|---|---|
| Orders | The order object, statuses, and retrieval patterns |
| Trading | How to execute trades on behalf of a client |
| Error Codes | Full reference for every error the API returns |
