Skip to content
Partner API Docs

Trading

Place BUY and SELL orders for your master account or any sub-account. MARKET orders use quoteId; LIMIT/STOP orders rest without quotes. Covers order types, time-in-force, history, cancellation, ledger, and portfolio.

Place BUY and SELL orders on behalf of your master account or any sub-account. MARKET orders use a two-step quote -> trade flow in both sandbox and production: fetch a quote, then place the order with that quoteId within 60 seconds. Resting LIMIT, STOP, and STOP_LIMIT orders are placed without a quoteId because your request supplies the trigger price; they rest as WORKING until activated. Sandbox market orders fill instantly; live production market orders submitted during exchange hours target PENDING → FILLED / REJECTED within 5 minutes. v1 may emit legacy COMPLETED as an alias of FILLED. Always use Idempotency-Key on trade calls.

Quote
GET /quote/{symbol}
PENDING
POST /trade — escrowed
FILLED
order.filled

The full state machine — including LIMIT/STOP, cancellation, and expiry — is in Order & Money Lifecycles.

Get a quote

GET /quote/{symbol}

Try in API Tester

Step 1 of every MARKET trade (sandbox and production). Returns the fee breakdown -- gross value, base fee (0.75%), optional partner markup, total cost (BUY) or estimated proceeds (SELL), sufficient-funds check -- and a quoteId that the subsequent MARKET /trade call requires. Resting LIMIT/STOP orders skip this endpoint. Quotes are single-use and expire after 60 seconds (quoteExpiresAt); a stale or reused quoteId returns 409 STALE_QUOTE, and a quoteId whose symbol/side/quantity does not match the order returns 409 QUOTE_ORDER_MISMATCH. Quotes are indicative, not binding: settlement executes at the market price, protected by a deviation band (default +/-10% of the quoted price).

FieldTypeRequiredDescription
typestringYesBUY or SELL.
quantitynumberNoNumber of whole shares (positive integer) — the order placed against this quote must match it. For fractional investing use cashValue instead. Mutually exclusive with cashValue.
cashValuenumberNoUSD amount for cash-mode (fractional) investing. Mutually exclusive with quantity. The trade must use the SAME cashValue.
subAccountIdstringNoSub-account ID. Omit to quote against the master wallet. The quoteId is bound to this account context, symbol, side, and sizing mode.
bash
curl "https://mystocks.africa/api/v1/partner/quote/SCOM.KE?type=BUY&quantity=500&subAccountId=usr_abc123" -H "Authorization: Bearer pk_live_<key>"
{ "quoteId": "qt_9f2c81d4b7a3", "quoteExpiresAt": "2026-07-07T09:46:00Z", "quoteTtlSeconds": 60, "symbol": "SCOM.KE", "exchange": "NSE", "currency": "KES", "type": "BUY", "quantity": 500, "localPrice": 16.5, "usdPrice": 0.127306, "gross": 63.65, "baseFee": 0.48, "partnerMarkupFee": 0.0, "fee": 0.48, "totalCost": 64.13, "sufficientFunds": true, "feeRate": 0.75, "note": "Pass quoteId to POST /trade within 60 seconds. No order has been placed." }

Place a trade

POST /trade (master) · POST /users/{userId}/trade (sub-account)

Try in API Tester

Place a BUY or SELL order. BUY escrows the cost (gross + fee) from the wallet immediately; SELL checks that the sub-account holds the required units. The symbol accepts exchange-qualified (SCOM.KE) or bare ticker (SCOM).

FieldTypeRequiredDescription
symbolstringYesExchange-qualified ticker or unambiguous bare ticker.
quantitynumberNoShare-sized order quantity. Use either quantity or cashValue, never both. Whole-share markets require integers; fractional-enabled markets allow decimals.
cashValuenumberNoUSD notional for cash-mode fractional investing. Use either cashValue or quantity, never both. MARKET trades must match the quoted cashValue.
quoteIdstringNoRequired only for MARKET orders, including when orderType is omitted. Must come from GET /quote/{symbol}; single-use, expires after 60s. Do not send for LIMIT/STOP/STOP_LIMIT.
orderTypestringNoMARKET (default) | LIMIT | STOP | STOP_LIMIT. Resting order types do not use quoteId and return status WORKING.
limitPricenumberNoLocal-currency limit price. Required for LIMIT and STOP_LIMIT.
stopPricenumberNoLocal-currency trigger price. Required for STOP and STOP_LIMIT.
clientOrderIdstringNoYour internal order reference (<=80 chars). Unique per partner -- a safe retry/dedupe handle alongside Idempotency-Key.
timeInForcestringNoGTC (default), DAY (auto-cancelled after 24h), or GTD (auto-cancelled at expiresAt). Expiry refunds BUY escrow / releases SELL reservations and fires order.cancelled. IOC is not supported.
expiresAtstringNoISO-8601. Required when timeInForce is GTD.
stopLossnumberNoAuto-sell price floor (USD). Optional.
takeProfitnumberNoAuto-sell price ceiling (USD). Optional.
takeProfitnumberNoAuto-sell price ceiling (USD). Optional.
bash
# Step 1 - quote (quoteId expires in 60s)
curl "https://mystocks.africa/api/v1/partner/quote/SCOM.KE?type=BUY&quantity=1000&subAccountId=usr_abc123" -H "Authorization: Bearer pk_live_<key>"

# Step 2 - place the order with that quoteId
curl -X POST "https://mystocks.africa/api/v1/partner/users/usr_abc123/trade" -H "Authorization: Bearer pk_live_<key>" -H "Idempotency-Key: trade_user42_001" -H "Content-Type: application/json" -d '{"symbol":"SCOM.KE","type":"BUY","quantity":1000,"quoteId":"qt_9f2c81d4b7a3","clientOrderId":"my-ord-10001"}'
{ "status": "PENDING", "orderId": "ord_abc123", "quoteId": "qt_9f2c81d4b7a3", "clientOrderId": "my-ord-10001", "timeInForce": "GTC", "subAccountId": "usr_abc123", "type": "BUY", "symbol": "SCOM.KE", "quantity": 1000, "priceAtOrder": 16.5, "usdPriceAtOrder": 0.0126, "gross": 12.6, "fee": 0.09, "totalCost": 12.69, "note": "Order is pending. Funds reserved from sub-account wallet." }

Production returns PENDING with the reserved price as priceAtOrder (local) and usdPriceAtOrder. In sandbox the same call resolves instantly to FILLED and instead carries usdPrice, localPrice, currency, and the post-trade newSubBalance.

Sandbox cheat codes. Quantity 100 → instant auto-fill (FILLED). Quantity 999 → instant auto-reject (REJECTED). Use them to test your webhook handlers without waiting for the admin queue.

Production execution behavior

Production orders are operationally constrained by the exchange, the broker, and the available market data. Treat these guarantees as part of your client-state model:

FieldTypeRequiredDescription
partial fillsbehaviorNoOrders may fill partially. Use order status plus execution reports to show filledQuantity, remainingQuantity, and averageFillPrice when present.
average pricefieldNoaverageFillPrice is the weighted average of fills, not necessarily the quote price or the last market price.
slippageguardrailNoMARKET orders execute at available market prices inside the configured deviation band (default +/-10%). Orders outside that band are rejected or left pending for manual handling.
halts and auctionsmarket stateNoIf an exchange is halted, in auction, closed, or missing a valid market price, MARKET orders are rejected or held pending; resting orders remain WORKING until normal trading resumes and their trigger is crossed.
order book depthcoverageNoThe Partner API does not contractually expose Level-2 depth. Use quoted/last prices for retail UX, and design advanced depth views only after a market-data vendor agreement is in place.

List & fetch orders

GET /orders · GET /orders/{orderId} · GET /users/{userId}/orders

Try in API Tester

List orders for the master account or a specific sub-account (cursor-paginated), or fetch a single order by ID to poll status. Order fields include status, rejectionCode, rejectionReason, fee, baseFee, partnerMarkupFee, and timestamps. Filter by ?status=PENDING, ?symbol=, or ?from=/?to= date range.

{ "orders": [{ "id": "ord_abc123", "symbol": "SCOM.KE", "type": "BUY", "status": "FILLED", "quantity": 1000, "priceAtOrder": 16.5, "totalAmount": 12.69, "feeAmount": 0.09, "currency": "USD", "rejectionCode": null, "settledAt": "2026-06-04T11:30:00Z", "createdAt": "2026-06-04T09:45:00Z" }], "count": 1, "hasMore": false, "nextCursor": null }

Cancel an order

DELETE /orders/{orderId} · DELETE /users/{userId}/orders/{orderId}

Try in API Tester

Cancel an order while it is still PENDING (market orders awaiting fill) or WORKING (resting limit/stop orders). BUY escrow is refunded atomically. Returns HTTP 409 once the order has reached a terminal state (FILLED, CANCELLED, EXPIRED, or REJECTED). A successful cancellation fires an order.cancelled webhook.

Transaction ledger

GET /users/{userId}/transactions

Full wallet ledger for a sub-account — every credit and debit in chronological order: deposits, withdrawals, trade escrows (INVEST), trade proceeds (SELL), dividend distributions (DISTRIBUTION), fund redemptions (REDEEM), and fees. Cursor-paginated.

FieldTypeRequiredDescription
typestringNoDEPOSIT | WITHDRAWAL | INVEST | SELL | DISTRIBUTION | REDEEM | FEE | TRANSFER_IN | TRANSFER_OUT
fromdateNoOn or after this date (YYYY-MM-DD, UTC).
todateNoOn or before this date (YYYY-MM-DD, UTC).
cursorstringNoOpaque cursor from nextCursor. Omit for first page.
limitintegerNoPage size, default 50, max 200.
{ "transactions": [{ "id": "txn_abc123", "type": "DEPOSIT", "status": "COMPLETED", "direction": "CREDIT", "amount": 500, "currency": "USD", "reference": "dep_riven_user_42_1743152580", "createdAt": "2026-06-01T10:00:00Z" }, { "id": "txn_xyz789", "type": "INVEST", "status": "PENDING", "direction": "DEBIT", "amount": 64.13, "currency": "USD", "description": "BUY SCOM.KE x500", "reference": "ord_def456" }], "count": 2, "hasMore": false, "nextCursor": null }

Portfolio

GET /portfolio (master) · GET /users/{userId}/portfolio (sub-account)

Holdings with current market value, cost basis, unrealized P&L, and currency. Also includes fund and bond positions if the account holds subscriptions.

{ "walletBalance": 487.31, "totalValue": 512.31, "holdings": [{ "symbol": "SCOM.KE", "name": "Safaricom PLC", "quantity": 1000, "avgCostUsd": 0.01269, "currentPriceUsd": 0.0126, "marketValue": 12.6, "unrealizedPnl": -0.09, "currency": "KES" }] }

Was this page useful?

Your signal helps us tighten partner onboarding docs.

Last updated on

On this page