Error Codes
Complete reference for all error codes returned by the CoinMENA Partner API.
The CoinMENA Partner API uses two layers of error information to help you identify and handle failures precisely:
- HTTP status codes indicate the broad category of failure (authentication, validation, not found, etc.)
- Application error codes (
codefield) explain the exact business or validation reason for the failure
Always handle errors using the application code field — it is stable and intended for programmatic use. The msg field is human-readable and may change over time. Multiple errors can share the same HTTP status code but have different application codes — always rely on code for precise handling.
Error Response Structure
Every error response returns a JSON object with the following fields:
{
"code": 2008,
"msg": "Invalid client ID",
"msg_detail": null
}| Field | Type | Description |
|---|---|---|
code | integer | Application-level error code. Use this for programmatic error handling |
msg | string | Human-readable error message. May change — do not rely on it for logic |
msg_detail | object, array, or null | Additional error context. Present on validation errors and some trading errors. Null otherwise |
How to Interpret an Error Response
When you receive an error, follow this order:
- Check the HTTP status — determines the broad failure category
- Check
code— identifies the exact error reason - Check
msg— provides a human-readable description for logging or display - Inspect
msg_detail— if present, contains field-level validation errors or trading context
Common debugging flowIf you receive an unexpected error:
- Check the HTTP status first
- Review the application
codeagainst this reference- Use
msg_detailto identify which field or value caused a validation failure- Compare your request payload with the documented trigger for that error code
Decimal Fields and Scientific Notation
Decimal fields are returned as JSON strings and may use scientific notation when the value is very small or zero (e.g. "0E-8", "1e-8"). Always parse decimal fields using a decimal-aware type.
ImportantDo not parse decimal fields as JavaScript
numberor Pythonfloat— these types lose precision with financial values. UseDecimalin Python or a library likedecimal.jsin JavaScript.
HTTP Status Codes
| Status | Meaning |
|---|---|
200 / 201 | Request succeeded |
204 | Request succeeded, no response body (e.g. client activation) |
400 | Application-level error — check code for the exact reason |
401 | Authentication failed — check the 401 section below |
404 | Resource not found |
409 | Conflict — duplicate partner_order_ref |
422 | Request validation failed — check msg_detail for field-level errors |
401 — Unauthorized
A 401 response can be returned for multiple reasons — invalid signature, expired timestamp, missing headers, or IP not whitelisted. All triggers return the same response body, so you cannot distinguish the cause from the response alone.
{
"code": 401,
"msg": "Unauthorized",
"msg_detail": null
}| Trigger |
|---|
Missing X-Partner-ID, X-Timestamp, or X-Signature headers |
Invalid X-Partner-ID format |
Invalid X-Timestamp format |
| Timestamp outside the 60-second validity window |
| Partner not found or inactive |
| Partner has no public key configured |
| Client IP not in the partner's IP whitelist |
| Ed25519 signature verification failed |
Debugging 401 errorsSince all 401 triggers look identical, work through the Authentication guide's troubleshooting checklist systematically. See the Authentication guide for the full checklist, and the IP Whitelisting guide if IP issues are suspected.
422 — Validation Error
Returned when the request body or parameters fail schema validation. The msg_detail field contains an array of field-level errors.
{
"code": 422,
"msg": "Validation Error",
"msg_detail": [
{
"type": "email_parsing",
"loc": ["body", "email"],
"msg": "Input should be a valid email"
}
]
}Each object in msg_detail contains:
| Field | Description |
|---|---|
loc | Location of the invalid field as an array — tells you exactly where the validation failed (e.g. ["body", "email"]) |
msg | Human-readable description of what is wrong with that field |
type | Classifies the validation failure type (e.g. email_parsing, greater_than, missing) |
Common 422 Triggers
| Trigger | Affected Endpoints |
|---|---|
| Invalid JSON body | All endpoints that accept a request body |
| Missing or invalid required fields | POST /v1/partner/clients, PUT /v1/partner/clients/{id}, POST /v1/partner/deposits, POST /v1/partner/withdrawals, POST /v1/partner/quotes, POST /v1/partner/quotes/execute |
| Invalid email format | POST /v1/partner/clients, PUT /v1/partner/clients/{id} |
| Invalid phone format | POST /v1/partner/clients, PUT /v1/partner/clients/{id} |
| Employment fields missing for status | POST /v1/partner/clients, PUT /v1/partner/clients/{id} |
| Forbidden employment fields for status | POST /v1/partner/clients, PUT /v1/partner/clients/{id} |
account_purpose is empty | POST /v1/partner/clients, PUT /v1/partner/clients/{id} |
| Invalid or negative amount | POST /v1/partner/deposits, POST /v1/partner/withdrawals |
| Invalid amount for quotes | POST /v1/partner/quotes |
page < 1, page_size < 1, or page_size > 100 | GET /v1/partner/clients, GET /v1/partner/orders, GET /v1/partner/clients/{id}/documents |
| Invalid enum value for filters | GET /v1/partner/clients, GET /v1/partner/orders, POST /v1/partner/clients, POST /v1/partner/quotes |
| Invalid datetime format | GET /v1/partner/clients, GET /v1/partner/orders |
| Invalid token format | POST /v1/partner/quotes/execute |
| Field-level validation on any request schema | All endpoints with request bodies or query parameters |
Application Error Codes
Client Status Errors
Errors related to existing clients — identity, verification status, and activity state.
| Code | HTTP | Message | Trigger | Endpoints |
|---|---|---|---|---|
2008 | 400 | Invalid client ID | partner_client_id does not exist or does not belong to this partner | All endpoints that accept partner_client_id |
2009 | 400 | The client is not yet verified | Client is not in verified status | POST /v1/partner/deposits, POST /v1/partner/withdrawals, POST /v1/partner/quotes, POST /v1/partner/quotes/execute |
2010 | 400 | The client is deactivated | Client active is false | POST /v1/partner/deposits, POST /v1/partner/withdrawals, POST /v1/partner/quotes, POST /v1/partner/quotes/execute |
Client Onboarding Errors
Returned by POST /v1/partner/clients (create) and PUT /v1/partner/clients/{id} (update) when client payload validation fails.
| Code | HTTP | Message | Trigger | Applies To |
|---|---|---|---|---|
2016 | 400 | Government ID is already being used by another approved client | Duplicate government_id_number already registered for another client | Create, Update |
2021 | 400 | Client is under the legal age | birth_date below the legal age threshold | Create only |
2022 | 400 | Invalid residency country | residency_id is not a supported or acceptable residency country | Create, Update |
2023 | 400 | Invalid citizenship country | citizenship_id is not a supported or acceptable citizenship country | Create, Update |
2024 | 400 | Invalid place of birth country | place_of_birth_id is not a supported country | Create only |
2025 | 400 | Residency visa number and expiry are required | residency_visa_number or residency_visa_doe missing when required | Create, Update |
2026 | 400 | A client with this partner_client_id already exists | Duplicate partner_client_id already registered under this partner | Create only |
2027 | 400 | A client with this email already exists | Duplicate email already registered under this partner | Create, Update |
2028 | 400 | A client with this phone already exists | Duplicate phone already registered under this partner | Create, Update |
2024and2026on update
place_of_birth_idandpartner_client_idare immutable after client creation — they cannot be modified viaPUT /v1/partner/clients/{id}. Errors2024and2026can only occur on client creation.
Asset Errors
| Code | HTTP | Message | Trigger | Endpoints |
|---|---|---|---|---|
2012 | 400 | Invalid asset | Asset not found, not published, not fiat, or not depositable | POST /v1/partner/deposits |
2012 | 400 | Invalid asset | Asset not found, not published, not fiat, or not withdrawable | POST /v1/partner/withdrawals |
2012 | 400 | Invalid asset | Asset not found or not supported | GET /v1/partner/balances/{asset_id} |
2013 | 400 | Invalid asset pair | Asset pair not found or not available to this partner | POST /v1/partner/quotes |
GET /v1/partner/balances/{asset_id}— two possible 400 errorsThis endpoint can return either
2012(invalid asset) or2008(invalid client) when apartner_client_idquery parameter is supplied and doesn't match. Check thecodefield to determine which.
Order and Funds Errors
| Code | HTTP | Message | Trigger | msg_detail | Endpoints |
|---|---|---|---|---|---|
2020 | 409 | An order with this partner_order_ref already exists | Duplicate partner_order_ref for the same partner | null | POST /v1/partner/quotes/execute, POST /v1/partner/deposits, POST /v1/partner/withdrawals |
3005 | 400 | Insufficient funds | Client balance is insufficient for the trade | {"quote": {...}} | POST /v1/partner/quotes |
3005 | 400 | Insufficient funds for payment | Client balance is insufficient for the withdrawal | null | POST /v1/partner/withdrawals |
3005on quotesWhen returned on
POST /v1/partner/quotes, the response includes aquoteobject inmsg_detailwith the calculated price and amounts. You can use this to show the client the current market rate even when the trade cannot be executed.
{
"code": 3005,
"msg": "Insufficient funds",
"msg_detail": {
"quote": {
"market_price": "74100.4093",
"base_amount": "0.13000000",
"quote_amount": "9633.15",
"fee_amount": "0.09",
"vat_percentage": null,
"vat_amount": "0.00",
"lifetime": 15,
"token": null
}
}
}Trading Errors
| Code | HTTP | Message | Trigger | msg_detail |
|---|---|---|---|---|
4000 | 400 | Trading is not available | Asset pair is not tradable | {"quote": {...}} |
4001 | 400 | Trading is temporarily unavailable | Price feed is down for this asset pair | {"quote": {...}} |
4003 | 400 | Amount exceeds the maximum allowed | Requested amount is above the asset pair's maximum volume | {"limit": "...", "quote": {...}} |
4004 | 400 | Amount is below the minimum allowed | Requested amount is below the asset pair's minimum volume | {"limit": "...", "quote": {...}} |
4008 | 400 | Trading token is invalid | Token expired, client mismatch, or invalid/corrupted token | null |
Trading errors 4000, 4001, 4003, 4004 apply to POST /v1/partner/quotes. Error 4008 applies to POST /v1/partner/quotes/execute.
Trading errors andmsg_detailErrors
4000,4001,4003, and4004return aquoteobject inmsg_detaileven on failure. For4003and4004, alimitfield is also returned showing the applicable minimum or maximum volume. Use this to show the user the current market price and explain why their trade was rejected.
{
"code": 4004,
"msg": "Amount is below the minimum allowed",
"msg_detail": {
"limit": "0.00020000",
"quote": {
"market_price": "74815.8482",
"base_amount": "0.00000200",
"quote_amount": "0.15",
"fee_amount": "0.00",
"vat_percentage": null,
"vat_amount": "0.00",
"lifetime": 15,
"token": null
}
}
}Not Found Errors
{
"code": 404,
"msg": "Not Found",
"msg_detail": null
}| Code | HTTP | Message | Trigger | Endpoints |
|---|---|---|---|---|
404 | 404 | Not Found | Asset not found | GET /v1/public/assets/{asset_id} |
404 | 404 | Not Found | Country not found | GET /v1/public/countries/{country_id} |
404 | 404 | Not Found | Asset pair not found or not available to this partner | GET /v1/partner/asset-pairs/{asset_pair_id} |
404 | 404 | Not Found | Order not found or does not belong to this partner | GET /v1/partner/orders/{order_id}, GET /v1/partner/orders/ref/{partner_order_ref} |
404 | 404 | Not Found | Document not found or does not belong to this client | GET /v1/partner/clients/{id}/documents/{document_id} |
Recommended Error Handling
| Scenario | Recommendation |
|---|---|
401 errors | Do not retry without fixing the signature, timestamp, or IP. Check the Authentication and IP Whitelisting guides |
422 errors | Do not retry without fixing the request — use msg_detail to identify which field failed |
409 errors (2020) | Do not retry — use a new unique partner_order_ref or check whether the order already succeeded |
404 errors | Verify the resource ID is correct and belongs to your partner account |
400 client onboarding errors | Do not retry — fix the duplicate or invalid field identified by the error code |
400 trading errors (4000–4004) | Use msg_detail to surface context to the user — the quote object contains the current market price |
400 3005 | Client has insufficient funds — fund the client via POST /v1/partner/deposits or reduce trade amount |
500 errors | Unexpected server errors — retry with exponential backoff and contact support if persistent |
Integration best practices
- Always use the application
codefor programmatic error handling — notmsg- Log both the HTTP status and the application
codefor every error- Surface user-friendly messages in your app rather than raw API error messages
- Never retry
422,409, or client onboarding400errors without modifying the request first
Updated 2 days ago
| Next Step | Description |
|---|---|
| Authentication | Full breakdown of the signing algorithm, rules, and troubleshooting |
| IP Whitelisting | Add a second security layer to your integration |
| Pagination | How to work with paginated list endpoints |
