Skip to content
MyStocks Developers
API v1

API v1

Current stable contract

Versioning policyRelease changelog
Sandbox console
Start building

SDKs and Tools

MyStocks Partner API

MyStocks client source previews, multi-language examples, OpenAPI specifications, API Tester, and webhook utilities.

Explore endpoints

3 of 3
POST

/users

Create sub-account

Full endpoint documentation
Sandbox availablecreateUsers

Creates a new sub-account. Each sub-account has an isolated USD wallet, portfolio, and order book. The externalId is your own reference — it must be unique per partner and is used in all subsequent calls. Sub-accounts start with a walletBalance of $0 — fund them via POST /users/{userId}/deposit.

Parameters

This endpoint has no path or query parameters.

Headers

AuthorizationstringRequired

Bearer sk_sandbox_<your_key> for sandbox requests.

Idempotency-KeystringheaderRequired

Unique string that makes write calls safe to retry on network failure. Required for money movement, trading, KYC, subscriptions, and webhook creation. Deduplicated for 24 hours -- duplicate keys return the cached response. HTTP 409 if a concurrent request with the same key is still in progress.

Example: dep_user42_1743152580

Request body

externalIdstringRequired

Your internal user identifier. Must be unique per partner.

Example: "usr_8821"

displayNamestring

Full name shown in the MyStocks admin console.

Example: "Alice K."

emailstring

Email address for the sub-account user.

Example: "alice@yourapp.com"

phonestring

Customer phone number in international format when available.

Example: "+254712345678"

countrystring

ISO 3166-1 alpha-2 country code used for onboarding and compliance context.

Example: "KE"

Response fields

subAccountIdstring

MyStocks internal ID. Use in /users/{userId}/... paths.

Example: "usr_abc123"

userIdstring

Compatible alias of subAccountId. Use subAccountId as the canonical stored identifier.

externalIdstring

Your own user identifier as set at creation.

Example: "usr_8821"

displayNamestring | null

Example: "Alice K."

emailstring | null

Example: "alice@yourapp.com"

kycStatusNONE | PENDING | VERIFIED | REJECTED

VERIFIED required for trading and asset subscriptions. REJECTED remains gated until re-asserted.

kycLevelNONE | BASIC | FULL

BASIC = ID verified. FULL = enhanced due diligence.

kycRejectionCodestring | null

Stable rejection code when kycStatus is REJECTED.

kycRejectionReasonstring | null

Customer-safe remediation guidance when kycStatus is REJECTED.

kycReviewedAtstring | null

Timestamp of the rejection decision.

statusactive | frozen | closed
walletBalancenumber

Current USD wallet balance.

Example: 1250

Response codes

201Sub-account created.
409externalId already exists.

Use the client source previews for transport, structured errors, request IDs, timeouts, safe retries, and webhook verification. They do not replace understanding the API contract: always read the endpoint's authentication, scope, idempotency, and lifecycle requirements.

Registry publication pending

@mystocks-africa/partner-sdk is not currently published on npm and mystocks-partner is not currently published on PyPI. Do not put either registry install command into a production build. Approved controlled-pilot partners receive a versioned artifact and checksum directly from MyStocks. Registry availability will be announced in the changelog.

Both clients now have a version-locked release pipeline. A signed partner-sdk-vX.Y.Z tag runs the contract suites, builds the npm and Python distributions, verifies their metadata, produces SHA-256 checksums and build provenance, publishes through npm and PyPI trusted publishing, and attaches the same artifacts to a GitHub release. Registry install commands will be added here only after that release completes successfully.

Client availability

LanguagePackageStatus
TypeScript / JavaScript@mystocks-africa/partner-sdkSource preview; tested and buildable, registry release pending
Pythonmystocks-partnerSource preview; sync/async clients, registry release pending
Raw HTTPfetch, requests, or any OpenAPI clientPublic and recommended until the SDK registry releases

Initialize a client

The SDK examples below are for approved pilot artifacts. Everyone else can use the equivalent raw HTTP tab today.

javascript
const BASE = "https://mystocks.africa/api/sandbox/v1/partner";
const apiKey = process.env.MYSTOCKS_API_KEY;

async function api(path, init = {}) {
return fetch(BASE + path, {
  ...init,
  headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", ...init.headers },
}).then(async (res) => {
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.error?.message), body.error);
  return body;
});
}

Create a sub-account

bash
curl -X POST https://mystocks.africa/api/sandbox/v1/partner/users \
-H "Authorization: Bearer $MYSTOCKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"externalId":"user_42","displayName":"Jane Doe","email":"jane@example.com"}'

Quote and place a trade

javascript
const quote = await api("/quote/SCOM.KE?type=BUY&quantity=10&subAccountId=" + user.subAccountId);
const order = await api("/users/" + user.subAccountId + "/trade", {
method: "POST",
headers: { "Idempotency-Key": "trade_user42_scom_001" },
body: JSON.stringify({ symbol: "SCOM.KE", type: "BUY", quantity: 10, quoteId: quote.quoteId }),
});

Verify a webhook

Always verify the exact, unparsed request bytes before decoding JSON.

javascript
const rawBody = req.body; // Buffer from express.raw({ type: "*/*" })
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const supplied = req.headers["x-mystocks-signature"] ?? "";
const valid = supplied.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(supplied), Buffer.from(expected));

API tools

Operational awareness

You do not need to poll the status page. Incidents are pushed to your registered webhooks as incident.declared / incident.resolved and streamed on GET /stream. During planned maintenance the API returns 503 MAINTENANCE with a Retry-After header. See Errors for handling guidance, including read-only maintenance mode.

SDK behavior to rely on

  • Reads and idempotent writes may retry transient 429, 500, 502, 503, and 504 responses.
  • Non-idempotent writes are not automatically retried.
  • Preserve the same Idempotency-Key when retrying a write.
  • Capture X-Request-ID in logs and support tickets.
  • Verify webhooks using the raw body and the x-mystocks-signature header.

Begin with Authentication and the Broker API quickstart.

Catalogue, pagination and report contracts

The TypeScript SDK source uses the same filters and nullable catalogue fields as OpenAPI. Rebuild or upgrade the SDK before adopting these corrected types; documentation changes alone do not update an installed package.

const funds = await client.assetClasses.listFunds({ category: 'SPECIAL_FUND', currency: 'USD' });
const bonds = await client.assetClasses.listBonds({ instrumentType: 'TREASURY_BILL', currency: 'KES' });
const opportunities = await client.assetClasses.listOpportunities({ type: 'ALL' });
const accounts = await client.subAccounts.list({ status: 'active', externalId: 'customer-1' });
const orders = await client.trading.listOrders({ from: '2026-10-01', to: '2026-10-07', limit: 50 });
const articles = await client.assetClasses.listMarketIntel({ limit: 20 });
const aum = await client.reports.aum(); // current stored valuations only
const csv = await client.reports.aum({ format: 'csv' }); // string, not a JSON object

CSV-capable report methods return text when format: 'csv' is supplied. JSON calls retain typed objects. Follow nextCursor even when a filtered page is empty and hasMore is true. AUM does not accept historical asOf; the server explicitly rejects it with 422.

Was this page useful?

Your signal helps us tighten partner onboarding docs.

Send note

Last updated on

On this page