Skip to content
Partner API Docs

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.

// 401 auth error
{ "error": { "code": "AUTH_MISSING", "message": "Provide a valid partner API key via Authorization: Bearer pk_live_... or X-Api-Key header." } }
 
// 400 validation error
{ "error": { "code": "VALIDATION_ERROR", "message": "Ambiguous symbol \"MTN\" matches multiple listings: MTN.GH, MTN.NG. Use an exchange-qualified symbol." } }

HTTP status codes

FieldTypeRequiredDescription
200OKNoRequest succeeded.
201CreatedNoResource created (register, create sub-account).
202AcceptedNoOrder accepted into the live fill flow (trade, subscribe). Funds escrowed immediately; settlement is asynchronous.
400Bad RequestNoMissing or invalid parameters, a missing idempotency key, or insufficient funds. Check error.code.
401UnauthorizedNoAPI key missing, invalid, or expired.
403ForbiddenNoAction not permitted: revoked/suspended key, missing scope, KYC required, frozen sub-account, or an operation outside your tier.
404Not FoundNoStock symbol, sub-account, holding, or instrument not found.
409ConflictNoIdempotency collision — a concurrent request with the same Idempotency-Key is still in progress. Retry after it resolves.
422UnprocessableNoBusiness-rule violation such as MARKET_CLOSED, a fund not being open, or requested units exceeding holdings.
429Too Many RequestsNoRate limit exceeded. Check X-RateLimit-Remaining and X-RateLimit-Reset headers.
500Internal Server ErrorNoServer-side failure — retry with exponential backoff or contact support.
503Service UnavailableNoPlanned 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.

FieldTypeRequiredDescription
AUTH_MISSING401NoNo API key supplied. Send Authorization: Bearer pk_live_... or X-Api-Key.
AUTH_INVALID401NoKey format is wrong or the key does not exist in the registry.
AUTH_SUSPENDED403NoPartner account temporarily suspended. Contact support@mystocks.africa.
AUTH_REVOKED403NoKey permanently revoked. A new key must be issued — revocation cannot be undone.
RATE_LIMITED429NoToo many requests. Back off and retry after X-RateLimit-Reset.
MISSING_PARAM400NoA required query/body parameter is absent. Check error.param or error.params[].
MISSING_IDEMPOTENCY_KEY400NoAn 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_SYMBOL400NoSymbol fails format validation (2–20 alphanumerics, optionally dot-separated). Check error.invalid[] in a batch.
UNKNOWN_EXCHANGE400NoExchange code not recognised. See the supported codes list.
INVALID_TYPE400NoA parameter has the wrong type.
VALIDATION_ERROR400NoRequest body or query param failed validation. See error.message.
BATCH_LIMIT_EXCEEDED400NoBatch exceeds the max symbol count. Check error.max and error.received.
NOT_FOUND404NoRequested resource does not exist.
CONFLICT409NoConcurrent request conflict: idempotency collision or order state changed mid-operation.
QUOTE_REQUIRED400NoNo quoteId supplied on a trade. Every trade needs a fresh single-use quoteId from GET /quote/{symbol}.
QUOTE_NOT_FOUND404NoquoteId never issued, or already expired and garbage-collected. Fetch a fresh quote.
QUOTE_SCOPE_MISMATCH403NoquoteId belongs to a different account context. Fetch with the same subAccountId you trade on.
STALE_QUOTE409NoquoteId expired (60s TTL) or already used. Fetch a fresh quote and retry.
QUOTE_ORDER_MISMATCH409NoquoteId does not match the submitted symbol/side/quantity/cashValue. Request a new quote.
INSUFFICIENT_FUNDS400NoWallet balance too low. Top up the master wallet or deposit into the sub-account first.
KYC_REQUIRED403NoSub-account KYC not verified. Assert via POST /users/{userId}/kyc then retry.
MARKET_CLOSED422NoThe exchange is closed. Check GET /market/status and retry when the venue is open.
FORBIDDEN403NoAuthenticated but not authorised (e.g. read-only data key on a write endpoint).
INTERNAL_ERROR500NoUnexpected server-side failure. Safe to retry with backoff.
MAINTENANCE503NoPlanned maintenance window. Honour the Retry-After header. In read-only maintenance, GETs still succeed and only mutations return this.
SERVICE_UNAVAILABLE503NoUnplanned 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:

FieldTypeRequiredDescription
fullmodeNoEvery request is refused with 503 MAINTENANCE.
read_onlymodeNoGET 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.
// 503 during a read-only window
{
  "error": {
    "code": "MAINTENANCE",
    "message": "The Partner API is in read-only maintenance: reads are being served normally, but order, payment, and account mutations are temporarily refused.",
    "mode": "read_only",
    "endsAt": "2026-07-14T02:00:00.000Z",
    "statusPage": "https://mystocks.africa/status"
  }
}

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 dealing desk. 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.

FieldTypeRequiredDescription
INSUFFICIENT_FUNDSretriableNoThe account lacked settled balance at settlement time. Top up and resubmit.
MARKET_CLOSEDretriableNoThe exchange was closed when the desk attempted execution. Orders placed outside market hours are normally queued rather than rejected, so this usually indicates an unscheduled closure. Check GET /market/status, then resubmit.
TECHNICAL_ISSUEretriableNoExecution failed for an operational reason at the venue or on the desk. Safe to resubmit; if it recurs, check /status for an open incident.
KYC_REQUIREDnot retriableNoThe account is not KYC-approved. Complete KYC via POST /users/{userId}/kyc, wait for kyc.updated, then resubmit. Retrying as-is will be rejected again.
COMPLIANCE_HOLDnot retriableNoBlocked by compliance review (sanctions, market-abuse check, restricted security, or an account hold). Do not resubmit — contact support@mystocks.africa.
OTHERnot retriableNoDoes not fit a category above. rejectionReason always carries the specific explanation.

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.

Was this page useful?

Your signal helps us tighten partner onboarding docs.

Last updated on

On this page