Hosted API operational handoff
Coordinate hosted approval, funding, execution, payouts and reconciliation with MyStocks operations.
How does my trading app connect to MyStocks operations?
Sandbox is an isolated simulation. Hosted Live approval, API credentials, installation licensing and external settlement are separate states. A successful Sandbox journey never approves a production organization or moves real funds.
| Partner action | Admin task | Shared state and evidence |
|---|---|---|
| Submit hosted application | Review identity and business, approve the organization and production access | Application and organization status, authorized decision, notification and audit |
| Remit firm funding | Match payment reference, currency and actual receipt before crediting float | One canonical ledger credit, reference, reviewer and available firm balance |
| Fund a customer | Review exceptions and available firm float | Atomic firm-to-customer transfer, customer wallet and ledger entries |
| Submit a stock order | Review partner-attributed order in /admin/dealing-room | Order ID, partner business name, reserved cash/units, executions and remainder |
| Subscribe to a fund or bond | Review the corresponding pending investment order and allocation | Reserved USD, NAV/FX, approved allocation, holding and transaction |
| Return customer cash to firm | Review account restrictions and settlement holds | Customer debit and firm credit; this is not an external payout |
| Request an external payout | Authorize treasury decision and confirm provider outcome | Beneficiary, reserved amount, approval, provider reference and ledger |
| Reconcile a period | Compare the canonical ledger with independent payment/custody records | As-of period, discrepancies, evidence and signed review |
| Report a delivery problem | Review webhook attempts and an owned support case | Event ID, signature, retries, communication and audit |
What should I show my customer while an order is pending?
Show the actual API order status, reserved balance and filled versus remaining quantity. Request acceptance is not execution. A fill is not independent settlement. Do not enable withdrawals against unsettled proceeds when settlement holds apply. Use event IDs and idempotent handlers; reconnect an event stream with its last event ID.
How do I safely retry money movement?
Use the same canonical subAccountId, endpoint, payload and Idempotency-Key for the same logical operation. A changed payload is a new intent and must not be retried under the old key. Inspect wallet, order and ledger state before resolving an uncertain outcome. Use canonical IDs consistently even when an external-ID alias is supported.
Can a closed account be reopened?
No. A closed account is terminal and cannot be changed back to active through metadata updates. Frozen accounts can be restored through the authorized lifecycle. Money-moving handlers recheck ownership and active state inside their transaction. Create a new account for a new customer relationship; retain the old account's records for review.
What evidence completes an acceptance test?
Partner action → admin task → authorized decision → shared state → notification → audit evidence → automated test. Email queue insertion proves notification intent, not inbox delivery. Dealing-room tests prove the internal handoff, not execution at an external exchange. A reconciliation response without independent custody/payment data remains incomplete.
Operations can use admin readiness to find required decisions and their workspaces. Production-only checks need an isolated approved test integration; the public Sandbox reference app does not execute treasury or dealing-room decisions.
Currency closure and frozen customer orders
The organization currency workspace shows customer currency closure blockers and next actions. These are currency snapshots: no blockers does not confirm that orders, holdings or settlement checks pass. Closure rechecks all obligations atomically. A frozen customer's pending order can be rejected in the dealing room, but approval cannot create a new fill. Currency policy approval does not bypass customer account status.
How do I read across my customers?
Use GET /orders/blotter for owned customer orders. The master GET /orders remains a master-account endpoint. The blotter orders customers by customer ID, then orders by newest createdAt within each customer; it is not a globally chronological feed. Each request scans at most 20 customers and 1,000 orders and returns up to 200 matching orders (default 50). Follow nextCursor while hasMore is true, even when a filtered page is empty. Keep the same filters and environment on continuation.
Use GET /users/summary?userIds=customer-1,external-2 for 1–20 distinct owned customer IDs or external IDs. Unknown and foreign customers receive the same per-item NOT_FOUND error. Each account includes its canonical identity, actual currency wallets, USD buying power, currency closure blockers and read timestamp. The request reads each account independently and reuses the wallet accounting checks; it is not an atomic consolidated statement or a replacement for final closure checks. Wallet read cost depends on each customer's wallet, entitlement and order history. Do not add USD and KES balances together.
Set API_BASE=https://partners.mystocks.africa/api/sandbox/v1/partner for virtual Sandbox accounts, or /api/v1/partner for approved Live access. Customer reads appear in the partner currency workspace and /admin/partners currency workspace. Admin reads require ledger-view permission; hosted API reads require the relevant scoped credential.
/orders/blotter
List orders across owned customer accounts
Full endpoint documentationlistCustomerOrderBlotterCustomer ID ascending, then createdAt descending within each customer; not global chronological ordering. Scans at most 20 customers and 1,000 orders per request. Continue using nextCursor even when orders is empty. Cursors are scoped to partner, environment and filters. This does not change the master-account /orders endpoint.
Parameters
limitintegerqueryPage size, default 50.
Example: 50
cursorstringqueryOpaque continuation from this endpoint.
symbolstringqueryInstrument symbol.
statusALL | PENDING | WORKING | PARTIALLY_FILLED | FILLED | REJECTED | CANCELLED | EXPIRED | COMPLETEDqueryCanonical execution status; COMPLETED aliases FILLED.
fromstringqueryInclusive ISO date or timezone-aware timestamp.
tostringqueryInclusive ISO date (through 23:59:59.999 UTC) or timezone-aware timestamp.
Headers
AuthorizationstringRequiredBearer sk_sandbox_<your_key> for sandbox requests.
Response fields
ordersobject[]Requiredorders[].orderIdstringorders[].subAccountIdstringorders[].externalIdstring | nullorders[].symbolstringorders[].typestringorders[].statusstringorders[].canonicalStatusstringorders[].settlementStatusstringorders[].quantitynumberorders[].filledQuantitynumberorders[].remainingQuantitynumberorders[].currencystringorders[].createdAtstring | nullorders[].filledAtstring | nullorders[].settledAtstring | nullorders[].rejectionCodestring | nullorders[].orderLifecyclestring | nullEXPIRED for expiry; expiry is not a rejection.
orders[].cancelReasonstring | nullcountintegerRequiredhasMorebooleanRequirednextCursorstring | nullRequiredorderingstringRequiredscopestringsnapshotModelstringscannedOrdersintegersandboxbooleanResponse codes
200Owned customer results with explicit read and continuation limits.400Invalid bounds, identifiers or cursor.401Valid environment-specific API key required.403Required read permission is missing.429Partner request rate limit exceeded./orders
List orders
Full endpoint documentationlistOrdersReturns your partner order history. Filter by status, symbol, or date range. Filters from/to are enforced against createdAt. ISO dates cover full UTC days. Sparse matches may yield an empty page with hasMore=true; follow nextCursor. Each call scans at most 1000 source records. Invalid limits, dates and cursors return 400.
Parameters
statusPENDING | WORKING | PARTIALLY_FILLED | PROCESSING | COMPLETED | FILLED | REJECTED | CANCELLED | EXPIREDquerysymbolstringqueryExample: SCOM.KE
fromstringqueryISO date (whole UTC day) or timezone-qualified ISO date-time; invalid or reversed bounds return 400.
Example: 2026-01-01
tostringqueryISO date (whole UTC day) or timezone-qualified ISO date-time; invalid or reversed bounds return 400.
Example: 2026-03-31
cursorstringqueryOpaque cursor from nextCursor of the previous response. Omit for the first page.
limitintegerqueryExample: 50
Headers
AuthorizationstringRequiredBearer sk_sandbox_<your_key> for sandbox requests.
Response fields
ordersobject[]Requiredorders[].orderIdstringUnique order ID. Use to poll status or cancel.
Example: "ord_abc123xyz"
orders[].symbolstringExample: "SCOM.KE"
orders[].namestringExample: "Safaricom PLC"
orders[].exchangestringExample: "NSE"
orders[].orderTypeMARKET | LIMIT | STOP | STOP_LIMITOrder type. MARKET orders are quote-gated; LIMIT/STOP/STOP_LIMIT rest as WORKING until triggered.
Example: "LIMIT"
orders[].limitPricenumber | nullLimit price in the stock's local currency (LIMIT / STOP_LIMIT only).
orders[].stopPricenumber | nullStop price in the stock's local currency (STOP / STOP_LIMIT only).
orders[].cancelablebooleanWhether the order can be cancelled now (DELETE). True while PENDING or WORKING.
orders[].replaceablebooleanWhether the order can be modified now (PATCH). True only for a WORKING resting order.
orders[].typeBUY | SELLorders[].statusPENDING | 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.
orders[].quoteIdstring | nullPre-trade quote ID consumed by this order.
orders[].quoteExpiresAtstring | nullorders[].quoteUsdPricenumber | nullorders[].clientOrderIdstring | nullPartner-supplied order reference.
orders[].omsStatusstring | nullCanonical OMS lifecycle status.
orders[].timeInForcestring | nullorders[].filledQuantitynumberorders[].remainingQuantitynumberorders[].averageFillPricenumber | nullorders[].executionVenuestring | nullorders[].lastExecutionReportIdstring | nullorders[].executionSlaunionLive execution SLA clock for orders that have entered the PENDING dealing-desk queue. Null while a resting order is still WORKING.
orders[].quantityintegerorders[].priceAtOrdernumberStock price in local currency at submission.
orders[].usdPriceAtOrdernumberUSD equivalent of priceAtOrder.
orders[].fxRateAtOrdernumber | nullManaged FX rate used for local-to-USD conversion at order submission.
orders[].fxSourcestring | nullorders[].fxRateAsOfstring | nullorders[].fxConversionunionorders[].feenumberTotal fee in USD (base + partner markup).
orders[].baseFeenumberMyStocks base broker fee (0.75% of gross).
orders[].partnerMarkupFeenumberYour markup fee component. Zero if markupBps = 0.
orders[].totalAmountnumberBUY: gross + fee. SELL: gross - fee.
orders[].currencystringExample: "USD"
orders[].localCurrencystringExample: "KES"
orders[].rejectionCodestring | nullStructured rejection code. Populated when status = REJECTED.
orders[].rejectionReasonstring | nullFree-text rejection detail provided by the MyStocks internal-book execution service. Populated when status = REJECTED.
orders[].cancelledAtstring | nullorders[].settledAtstring | 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.
orders[].createdAtstringorders[].canonicalStatusPENDING | WORKING | PARTIALLY_FILLED | FILLED | REJECTED | CANCELLED | EXPIREDorders[].settlementStatusPENDING | SETTLED | FAILEDorders[].orderLifecyclestring | nullEXPIRED for expiry; expiry is not a rejection.
orders[].cancelReasonstring | nullcountintegerRequiredhasMorebooleanRequirednextCursorstring | nullRequiredResponse codes
200Order list./users/summary
Read up to 20 customer wallet summaries
Full endpoint documentationgetCustomerWalletSummariesSupply 1–20 distinct owned customer IDs or external IDs, separated by commas. Unknown and foreign IDs return the same NOT_FOUND item error. Actual currency wallets, USD buying power and currency closure blockers are returned per account. Accounts are read independently, not as an atomic consolidated statement. Open orders, positions and settlements still require closure-time checks.
Parameters
userIdsstringqueryRequired1–20 distinct comma-separated customer IDs or external IDs.
Headers
AuthorizationstringRequiredBearer sk_sandbox_<your_key> for sandbox requests.
Response fields
accountsobject[]Requiredaccounts[].requestedIdstringaccounts[].subAccountIdstringaccounts[].userIdstringaccounts[].externalIdstringaccounts[].statusstringaccounts[].asOfstringaccounts[].currencyWalletsobject[]accounts[].buyingPowerobjectaccounts[].currencyClosureBlockersobject[]accounts[].errorobjectcountintegerRequiredasOfstringRequiredsnapshotModelstringRequiredsandboxbooleanResponse codes
200Owned customer results with explicit read and continuation limits.400Invalid bounds, identifiers or cursor.401Valid environment-specific API key required.403Required read permission is missing.429Partner request rate limit exceeded.Was this page useful?
Your signal helps us tighten partner onboarding docs.
Last updated on