Executing a Trade
End-to-end walkthrough for executing a trade on behalf of a client — list asset pairs, calculate a quote, execute it, and retrieve the resulting order.
This guide walks you through running a single trade end-to-end — from discovering the right asset pair, to locking in a price with a quote, to executing the trade and retrieving the final order record. By the end, you will have a completed trade order on behalf of a funded client and the pattern you need to run trades at scale.
For the concepts behind the two-step quote-and-execute model, asset pairs, and the token lifecycle, see the Trading guide.
What You Will Have at the End
- A completed trade order with
type: buyortype: sellandstatus: completed - A client whose asset balances have been updated to reflect the trade
- The
partner_order_refyou tagged on the trade (if provided), ready for reconciliation - A working pattern for calculating and executing quotes at scale
Core Rules
Four rules to keep in mind before you run anything.
Quote → Execute — execute withinlifetimeA quote must be executed within the
lifetime(in seconds) returned in the calculate response, using thetokenalso returned there. If the quote expires, execution fails with4008and you must calculate a fresh quote. Tokens are single-use — once a token executes successfully, it cannot be reused.
Trade execution is synchronousA successful execute response means the order has been placed and is returned in a final status — typically
completed. No polling is required. The client's balances are updated on the response.
The order response is the source of truthFor the final trade result — execution price, amounts, fees — always rely on the order object returned by execute (or retrieved later). Do not recalculate values from the quote — use the order fields as authoritative.
Ifpartner_order_refis provided, it must be unique
partner_order_refis optional on trade execution, but if you provide it, the value must be unique across all orders under your partner account. Reusing a value returns2020(HTTP 409). Generate a fresh reference per trade.
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 - The client has sufficient balance in the asset they will spend — fund them first via the Funding & Reconciliation walkthrough if needed
- You have your Partner ID and can generate request signatures — see the Authentication guide
- You know which asset pair the client wants to trade (e.g.
BTC-USD) — or you will discover it in Step 1
Environment and signing
| Item | Details |
|---|---|
| Environment | Production: https://external-api.coinmena.comSandbox: contact [email protected] for credentials |
| Signed headers | All signed requests need X-Partner-ID, X-Timestamp, and X-Signature. See the Authentication guide to generate them |
Placeholders in the cURL examplesReplace
your_partner_idwith 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
- List asset pairs → find the pair to trade and confirm it is
tradable - Calculate a quote → receive a locked price and a short-lived
token - Execute the quote → place the order using the
tokenbeforelifetimeexpires - Retrieve the order (optional) → fetch by
idorpartner_order_reffor reconciliation
Step 1 — List Asset Pairs
Fetch the list of tradeable asset pairs to pick the one you want and to confirm it is currently tradeable.
curl -X GET "https://external-api.coinmena.com/v1/partner/asset-pairs" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654321000" \
-H "X-Signature: <your_generated_signature>"Response — 200 OK (trimmed)
200 OK (trimmed){
"items": [
{
"id": "BTC-USD",
"type": "crypto",
"base_id": "BTC",
"quote_id": "USD",
"decimal_places": 2,
"inv_decimal_places": 8,
"min_volume": "0.0001",
"max_volume": "100",
"trading_fee": "0.5",
"tradable": true,
"buy": "67550.75",
"sell": "67450.25",
"daily_change_pct": "2.35"
}
]
}What to Read
id— the pair identifier you will submit in Step 2 (e.g.BTC-USD)tradable— must betrue. Iffalse, quote calculation fails with4000min_volume/max_volume— yourbase_amountmust fall within these bounds or quote calculation fails with4003/4004buy/sell— current prices, useful for showing the client before calculating a quoteinv_decimal_places/decimal_places— precision for base and quote amounts respectively (forBTC-USDabove, base amounts allow up to 8 decimals, quote amounts allow up to 2)
Asset pair formatPair IDs follow
BASE-QUOTEformat. ForBTC-USD:BTCis the base asset (what is being bought or sold),USDis the quote asset (what it is priced in). See the Trading guide for the full breakdown.
Step 2 — Calculate a Quote
Calculate a quote for the trade. Submit the client, pair, side, and an amount — either base_amount (amount in the base asset, e.g. BTC) or quote_amount (amount in the quote asset, e.g. USD).
curl -X POST "https://external-api.coinmena.com/v1/partner/quotes" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654322000" \
-H "X-Signature: <your_generated_signature>" \
-H "Content-Type: application/json" \
-d '{
"partner_client_id": "user_12345",
"asset_pair": "BTC-USD",
"side": "buy",
"base_amount": "0.001"
}'Response — 200 OK
200 OK{
"result": {
"market_price": "67500.50",
"base_amount": "0.00100000",
"quote_amount": "67.50",
"fee_amount": "0.34",
"vat_amount": "0.00",
"vat_percentage": null,
"lifetime": 15,
"token": "eyJhbGciOiJIUzI1NiJ9..."
}
}What to Persist
| Field | Why You Need It |
|---|---|
token | The JWT you must send to execute. Bound to this quote, single-use |
lifetime | Seconds the token is valid. Start your execute call before this elapses |
market_price | The locked price for this quote. Useful to display to the client |
base_amount | Final base asset amount for the trade |
quote_amount | Final quote asset amount for the trade |
fee_amount | Fee the client will be charged |
base_amountorquote_amount— pick oneSubmit exactly one of the two. Use
base_amountwhen the client wants a specific quantity of the base asset (e.g. "buy 0.001 BTC"). Usequote_amountwhen the client wants to spend or receive a specific amount of the quote asset (e.g. "buy $100 of BTC"). Sending both, or neither, returns a validation error.
Show the client before you executeThe quote response contains everything needed to display the final price and fees to the client. Most integrations show these numbers on a confirmation screen, then trigger execute when the client confirms — making sure the total time from quote calculation to execute is less than
lifetimeseconds.
Step 3 — Execute the Quote
Place the order using the token from Step 2. partner_order_ref is optional but recommended — it lets you reconcile this trade by your own reference later.
curl -X POST "https://external-api.coinmena.com/v1/partner/quotes/execute" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654323000" \
-H "X-Signature: <your_generated_signature>" \
-H "Content-Type: application/json" \
-d '{
"partner_client_id": "user_12345",
"token": "eyJhbGciOiJIUzI1NiJ9...",
"partner_order_ref": "trade-abc-789"
}'Response — 200 OK
200 OK{
"result": {
"id": 67892,
"order_no": "CRB0000067892",
"partner_client_id": "user_12345",
"type": "buy",
"source": "market",
"status": "completed",
"price": "67500.50",
"credit": "67.50",
"credit_asset_id": "USD",
"debit": "0.00100000",
"debit_asset_id": "BTC",
"fee": "0.34",
"fee_asset_id": "USD",
"vat": "0.00",
"partner_order_ref": "trade-abc-789",
"created_at": "2024-06-01T10:10:00Z",
"transitioned_at": "2024-06-01T10:10:00Z",
"updated_at": "2024-06-01T10:10:00Z"
}
}What to Persist
| Field | Why You Need It |
|---|---|
id | CoinMENA's order ID |
partner_order_ref | Your own reference (if you provided one). Primary lookup key for reconciliation |
status | Should be completed. If failed or rejected, log and investigate |
price | Execution price — the locked price the trade was executed at |
credit / debit | See Reading the order on a trade |
fee / fee_asset_id | Fee charged for this trade, in the asset specified |
created_at | For audit trails |
Reading the Order on a Trade
On trade orders, credit and debit tell you what the client gave and received:
Order type | debit holds | credit holds |
|---|---|---|
buy | Base asset the client receives (e.g. 0.001 BTC) | Quote asset the client pays (e.g. 67.50 USD) |
sell | Quote asset the client receives (e.g. 82.11 USD) | Base asset the client gives (e.g. 0.0011 BTC) |
In the example above, the client paid 67.50 USD (credit) and received 0.001 BTC (debit) on a buy. See the Orders guide for the full mapping.
Step 4 — Retrieve the Order (Optional)
If you need to look up the order again later — for reconciliation, support, or your own reporting — use either the id from Step 3 or the partner_order_ref you submitted.
By partner_order_ref (recommended)
partner_order_ref (recommended)curl -X GET "https://external-api.coinmena.com/v1/partner/orders/ref/trade-abc-789" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654324000" \
-H "X-Signature: <your_generated_signature>"By id
idcurl -X GET "https://external-api.coinmena.com/v1/partner/orders/67892" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654325000" \
-H "X-Signature: <your_generated_signature>"Both return the same order object shape as in Step 3.
Usepartner_order_refif you provided oneLooking up by
partner_order_refmeans your own system stays the source of record — no mapping table needed between your IDs and CoinMENA's numericid. For bulk reconciliation patterns, see the Funding & Reconciliation walkthrough.
What Can Go Wrong
The most common errors during trade execution and what to do about them. A failed quote or execute never applies any balance change — retry logic can assume the client's state is unchanged on any error response.
| Error | Code | Likely Cause | Fix |
|---|---|---|---|
| Invalid client ID | 2008 | partner_client_id not found under your partner account | Verify the client was onboarded and the reference ID matches |
| Client not yet verified | 2009 | Client status is not verified | Complete onboarding — see the Onboarding a Client guide |
| Client is deactivated | 2010 | Client active is false | Reactivate via PUT /v1/partner/clients/{partner_client_id}/activation |
| Invalid asset pair | 2013 | asset_pair does not exist or is not available to your partner | Confirm the pair ID is correct. Fetch GET /v1/partner/asset-pairs for valid IDs |
Duplicate partner_order_ref | 2020 | You reused a reference value | Fetch the existing order via the ref lookup. Retry with a new reference only if needed |
| Insufficient funds | 3005 | Client's balance in the asset they spend is less than the trade amount | Fund the client first — see Funding & Reconciliation |
| Trading is not available | 4000 | Pair is not tradable | Filter pairs by tradable: true before quoting |
| Trading is temporarily unavailable | 4001 | Price feed is down for the pair | Retry after a delay |
| Amount exceeds the maximum allowed | 4003 | base_amount is above the pair's max_volume | Reduce the amount or split across multiple trades |
| Amount is below the minimum allowed | 4004 | base_amount is below the pair's min_volume | Increase the amount |
| Trading token is invalid | 4008 | Token expired, was already used, or was issued for a different client | Calculate a fresh quote and use the new token |
| Unauthorized | 401 | Bad signature, expired timestamp, or IP not whitelisted | Work through the Authentication troubleshooting checklist |
For the complete list, see the Error Codes guide.
Updated 1 day ago
| Next Step | Description |
|---|---|
| Trading | Concept reference for asset pairs, quotes, and the token lifecycle |
| Orders | Full reference for the order object, statuses, and retrieval |
| Funding & Reconciliation | Reconcile trade orders alongside deposits and withdrawals |
| Error Codes | Full reference for every error the API returns |
