Errors
Every MyStocks Partner API error carries a machine-readable error.code and a human-readable error.message. Full reference of HTTP status codes, error codes, and structured order-rejection codes.
Every error response carries a top-level error object with a machine-readable code string and a
human-readable message. This applies to all endpoints. Check error.code for programmatic handling;
use error.message for logging or UI display.
HTTP status codes
| Field | Type | Required | Description |
|---|---|---|---|
| 200 | OK | No | Request succeeded. |
| 201 | Created | No | Resource created (register, create sub-account). |
| 202 | Accepted | No | Order accepted into the live fill flow (trade, subscribe). Funds escrowed immediately; settlement is asynchronous. |
| 400 | Bad Request | No | Missing or invalid parameters, a missing idempotency key, or insufficient funds. Check error.code. |
| 401 | Unauthorized | No | API key missing, invalid, or expired. |
| 403 | Forbidden | No | Action not permitted: revoked/suspended key, missing scope, KYC required, frozen sub-account, or an operation outside your tier. |
| 404 | Not Found | No | Stock symbol, sub-account, holding, or instrument not found. |
| 409 | Conflict | No | Idempotency collision — a concurrent request with the same Idempotency-Key is still in progress. Retry after it resolves. |
| 422 | Unprocessable | No | Business-rule violation such as MARKET_CLOSED, a fund not being open, or requested units exceeding holdings. |
| 429 | Too Many Requests | No | Rate limit exceeded. Check X-RateLimit-Remaining and X-RateLimit-Reset headers. |
| 500 | Internal Server Error | No | Server-side failure — retry with exponential backoff or contact support. |
| 503 | Service Unavailable | No | Planned maintenance (MAINTENANCE) or an unplanned dependency outage (SERVICE_UNAVAILABLE). Always carries Retry-After. Never means your request was wrong — retry it unchanged. |
Machine-readable error codes
When the error field is an object, error.code is one of the values below.
| Field | Type | Required | Description |
|---|---|---|---|
| AUTH_MISSING | 401 | No | No API key supplied. Send Authorization: Bearer pk_live_... or X-Api-Key. |
| AUTH_INVALID | 401 | No | Key format is wrong or the key does not exist in the registry. |
| AUTH_SUSPENDED | 403 | No | Partner account temporarily suspended. Contact support@mystocks.africa. |
| AUTH_REVOKED | 403 | No | Key permanently revoked. A new key must be issued — revocation cannot be undone. |
| RATE_LIMITED | 429 | No | Too many requests. Back off and retry after X-RateLimit-Reset. |
| MISSING_PARAM | 400 | No | A required query/body parameter is absent. Check error.param or error.params[]. |
| MISSING_IDEMPOTENCY_KEY | 400 | No | An authenticated POST, PATCH, PUT, or DELETE was sent without the required Idempotency-Key header. The documented registration, reset, application, upgrade, and OAuth token endpoints are exempt. |
| INVALID_SYMBOL | 400 | No | Symbol fails format validation (2–20 alphanumerics, optionally dot-separated). Check error.invalid[] in a batch. |
| UNKNOWN_EXCHANGE | 400 | No | Exchange code not recognised. See the supported codes list. |
| INVALID_TYPE | 400 | No | A parameter has the wrong type. |
| VALIDATION_ERROR | 400 | No | Request body or query param failed validation. See error.message. |
| BATCH_LIMIT_EXCEEDED | 400 | No | Batch exceeds the max symbol count. Check error.max and error.received. |
| NOT_FOUND | 404 | No | Requested resource does not exist. |
| CONFLICT | 409 | No | Concurrent request conflict: idempotency collision or order state changed mid-operation. |
| QUOTE_REQUIRED | 400 | No | No quoteId supplied on a trade. Every trade needs a fresh single-use quoteId from GET /quote/{symbol}. |
| QUOTE_NOT_FOUND | 404 | No | quoteId never issued, or already expired and garbage-collected. Fetch a fresh quote. |
| QUOTE_SCOPE_MISMATCH | 403 | No | quoteId belongs to a different account context. Fetch with the same subAccountId you trade on. |
| STALE_QUOTE | 409 | No | quoteId expired (60s TTL) or already used. Fetch a fresh quote and retry. |
| QUOTE_ORDER_MISMATCH | 409 | No | quoteId does not match the submitted symbol/side/quantity/cashValue. Request a new quote. |
| INSUFFICIENT_FUNDS | 400 | No | Wallet balance too low. Top up the master wallet or deposit into the sub-account first. |
| KYC_REQUIRED | 403 | No | Sub-account KYC not verified. Assert via POST /users/{userId}/kyc then retry. |
| MARKET_CLOSED | 422 | No | The exchange is closed. Check GET /market/status and retry when the venue is open. |
| FORBIDDEN | 403 | No | Authenticated but not authorised (e.g. read-only data key on a write endpoint). |
| INTERNAL_ERROR | 500 | No | Unexpected server-side failure. Safe to retry with backoff. |
| MAINTENANCE | 503 | No | Planned maintenance window. Honour the Retry-After header. In read-only maintenance, GETs still succeed and only mutations return this. |
| SERVICE_UNAVAILABLE | 503 | No | Unplanned outage in a downstream dependency. Retry with exponential backoff; check the status page. |
Maintenance and downtime
During a maintenance window the Partner API returns 503 with a Retry-After header (in seconds).
There are two modes, reported as error.mode:
| Field | Type | Required | Description |
|---|---|---|---|
| full | mode | No | Every request is refused with 503 MAINTENANCE. |
| read_only | mode | No | GET and HEAD are served normally; every mutation (orders, payments, account changes) is refused with 503 MAINTENANCE. Used during a settlement or payment-rail incident so you can still read positions and reconcile while money movement is frozen. |
Do not treat a 503 as a rejected request — nothing was processed, and the same request is safe to
send again once Retry-After elapses. Keep your Idempotency-Key the same when you retry.
Live status, uptime, and incident history are published at
mystocks.africa/status (raw JSON: GET /api/v1/status). You do not
need to poll it: incidents are pushed to your webhooks as incident.declared / incident.resolved.
Order rejection codes
The codes above are returned synchronously — the HTTP call itself fails and no order is created.
A rejectionCode is different: it is attached asynchronously, when an order that was already
accepted (202, status PENDING) is later rejected by the MyStocks internal-book execution engine. You learn about it through
the order.rejected webhook, the execution report, or rejectionCode on GET /orders/{orderId} —
always alongside the free-text rejectionReason.
This is the exhaustive list. No other value is ever written.
retriable means resubmitting the same order unchanged could plausibly succeed later. not retriable
means something must change first — funds, KYC, the order itself — or the same rejection will repeat.
Order expiry is not a rejection. When a DAY or GTD order reaches its deadline it is
cancelled, carrying orderLifecycle: "EXPIRED" and a cancelReason — never a rejectionCode.
/orders/{orderId}
Get order
Full endpoint documentationgetOrderReturns a single order by ID.
Parameters
orderIdstringpathRequiredExample: ord_abc123xyz
Headers
AuthorizationstringRequiredBearer sk_sandbox_<your_key> for sandbox requests.
Response fields
orderIdstringUnique order ID. Use to poll status or cancel.
Example: "ord_abc123xyz"
symbolstringExample: "SCOM.KE"
namestringExample: "Safaricom PLC"
exchangestringExample: "NSE"
orderTypeMARKET | LIMIT | STOP | STOP_LIMITOrder type. MARKET orders are quote-gated; LIMIT/STOP/STOP_LIMIT rest as WORKING until triggered.
Example: "LIMIT"
limitPricenumber | nullLimit price in the stock's local currency (LIMIT / STOP_LIMIT only).
stopPricenumber | nullStop price in the stock's local currency (STOP / STOP_LIMIT only).
cancelablebooleanWhether the order can be cancelled now (DELETE). True while PENDING or WORKING.
replaceablebooleanWhether the order can be modified now (PATCH). True only for a WORKING resting order.
typeBUY | SELLstatusPENDING | WORKING | PARTIALLY_FILLED | PROCESSING | COMPLETED | FILLED | REJECTED | CANCELLED | EXPIREDPENDING after submission. WORKING = resting LIMIT/STOP/STOP_LIMIT order waiting for its trigger price (becomes PENDING on trigger). PARTIALLY_FILLED and FILLED are the canonical execution states. REJECTED, CANCELLED, and EXPIRED are terminal outcomes. PROCESSING is a legacy transition alias and COMPLETED is a v1 compatibility alias of FILLED; neither represents custody settlement. Settlement is tracked separately as PENDING, SETTLED, or FAILED.
quoteIdstring | nullPre-trade quote ID consumed by this order.
quoteExpiresAtstring | nullquoteUsdPricenumber | nullclientOrderIdstring | nullPartner-supplied order reference.
omsStatusstring | nullCanonical OMS lifecycle status.
timeInForcestring | nullfilledQuantitynumberremainingQuantitynumberaverageFillPricenumber | nullexecutionVenuestring | nulllastExecutionReportIdstring | nullexecutionSlaunionLive execution SLA clock for orders that have entered the PENDING dealing-desk queue. Null while a resting order is still WORKING.
quantityintegerpriceAtOrdernumberStock price in local currency at submission.
usdPriceAtOrdernumberUSD equivalent of priceAtOrder.
fxRateAtOrdernumber | nullManaged FX rate used for local-to-USD conversion at order submission.
fxSourcestring | nullfxRateAsOfstring | nullfxConversionunionfeenumberTotal fee in USD (base + partner markup).
baseFeenumberMyStocks base broker fee (0.75% of gross).
partnerMarkupFeenumberYour markup fee component. Zero if markupBps = 0.
totalAmountnumberBUY: gross + fee. SELL: gross - fee.
currencystringExample: "USD"
localCurrencystringExample: "KES"
rejectionCodestring | nullStructured rejection code. Populated when status = REJECTED.
rejectionReasonstring | nullFree-text rejection detail provided by the MyStocks internal-book execution service. Populated when status = REJECTED.
cancelledAtstring | nullsettledAtstring | nullSet when custody settlement completes; independent of the canonical FILLED execution state. Legacy completed records that pre-date this field return their immutable completion/creation timestamp as compatibility evidence.
createdAtstringcanonicalStatusPENDING | WORKING | PARTIALLY_FILLED | FILLED | REJECTED | CANCELLED | EXPIREDsettlementStatusPENDING | SETTLED | FAILEDorderLifecyclestring | nullEXPIRED for expiry; expiry is not a rejection.
cancelReasonstring | nullResponse codes
200Order detail.404Order not found.Was this page useful?
Your signal helps us tighten partner onboarding docs.
Last updated on