Sub-Accounts
Create and manage end-user sub-accounts — each with an isolated USD wallet, portfolio, and order history. Covers create/auto-register, list/fetch, freeze, deposit, withdraw, and the KYC assertion API with an optional structured compliance profile.
Each of your end-users gets an isolated sub-account with its own USD wallet, portfolio, and order history. All write operations (deposit, withdraw, trade) are scoped to a single sub-account. The master wallet is the funding source for sub-account deposits.
Examples use the production base. Swap /api/v1/partner for /api/sandbox/v1/partner (and an
sk_sandbox_ key) to run against the sandbox.
Create a sub-account
POST /users
Create a sub-account for one of your end-users. Returns HTTP 201. Use externalId to map MyStocks
sub-account IDs back to your own user table.
| Field | Type | Required | Description |
|---|---|---|---|
| externalId | string | Yes | Your internal user ID. Must be unique per partner — the natural idempotency key. |
| displayName | string | No | Full name shown in the MyStocks admin console. |
| string | No | User email address. |
curl -X POST "https://mystocks.africa/api/v1/partner/users" \
-H "Authorization: Bearer pk_live_<key>" \
-H "Content-Type: application/json" \
-d '{"externalId":"user_42","displayName":"Jane Doe","email":"jane@example.com"}'Auto-register
POST /auto-register
Idempotent sub-account creation — safe to call on every user login. If a sub-account already exists for
the given uid it is returned unchanged (no duplicate). Same response shape as POST /users.
| Field | Type | Required | Description |
|---|---|---|---|
| uid | string | Yes | Your internal user identifier. Acts as the idempotency key. |
| string | No | Email address. | |
| name | string | No | Display name. |
| phone | string | No | Phone in E.164 format, e.g. +254712345678. |
| country | string | No | ISO 3166-1 alpha-2 country code. |
List & fetch
GET /users · GET /users/{userId}
List all sub-accounts (cursor-paginated, default 100/page, max 500) or fetch a single one by its
subAccountId. Filter by ?externalId= to look up using your own ID.
Update / freeze
PATCH /users/{userId}
Update display name or email. Set status: "frozen" to suspend all trading, deposits, and withdrawals
for the sub-account; set back to status: "active" to restore access.
Close / offboard
DELETE /users/{userId}
Soft-close a sub-account when your user leaves your product or asks to terminate their investing account. Closure is terminal: the sub-account is retained for audit and regulatory history, but it can no longer trade, receive deposits, or withdraw.
Closure is blocked if the account has open orders, positive holdings, or unsettled proceeds. If the USD
wallet still has cash, either call /withdraw first or pass residualCashHandling: "transfer_to_partner" to move the remaining cash to your master wallet during closure.
| Field | Type | Required | Description |
|---|---|---|---|
| residualCashHandling | string | No | require_zero (default) | transfer_to_partner. |
| reason | string | No | Closure reason stored in the audit trail. |
Registered webhooks receive account.closed after a successful closure.
Deposit
POST /users/{userId}/deposit
Credit a sub-account wallet. Send a USD amount, or send a supported local-currency amount with
currency and MyStocks will calculate the USD ledger credit using managed FX. Always set
Idempotency-Key.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | number | Yes | Amount in currency; defaults to USD. |
| amountUsd | number | No | Exact USD ledger amount for direct-USD integrations. |
| currency | string | No | ISO 4217 code for amount, e.g. KES, NGN, GHS. |
| fxRate | number | No | Deprecated legacy partner rate; omit for managed FX. |
| note | string | No | Reference string shown in transaction history. |
curl -X POST "https://mystocks.africa/api/v1/partner/users/usr_abc123/deposit" \
-H "Authorization: Bearer pk_live_<key>" \
-H "Idempotency-Key: dep_user42_001" \
-H "Content-Type: application/json" \
-d '{"amount":65000,"currency":"KES","note":"mpesa_QHJ29SK"}'Withdraw
POST /users/{userId}/withdraw
Debit a sub-account wallet and return the USD ledger amount to your master wallet. For supported
non-USD requests, MyStocks converts amount in currency; your payout rail then delivers the local
currency to the user. The sub-account must have sufficient uninvested balance. Always set
Idempotency-Key.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | number | Yes | Amount in currency; defaults to USD. |
| amountUsd | number | No | Exact USD ledger amount for direct-USD integrations. |
| currency | string | No | ISO 4217 code for amount. |
| fxRate | number | No | Deprecated legacy partner rate; omit for managed FX. |
| note | string | No | Reference for transaction history. |
Assert KYC
POST /users/{userId}/kyc
Assert the KYC result you obtained using your own provider. Set status: "VERIFIED" and
level: "BASIC" to unlock trading; FULL unlocks enhanced limits and higher-value subscriptions.
This is a state-changing write, so a unique Idempotency-Key header is required (returns
400 MISSING_IDEMPOTENCY_KEY without it).
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | Yes | NONE | PENDING | VERIFIED |
| level | string | Yes | NONE | BASIC (ID verified) | FULL (enhanced due diligence) |
| provider | string | No | KYC provider that performed the verification (e.g. sumsub). |
| reference | string | No | Your KYC session ID for audit correlation. |
You may also attach an optional structured compliance profile — all fields below are optional and
additive. The two sensitive identifiers, idNumber and taxId, are stored as a sha256 fingerprint
plus the last 4 characters only; they are never persisted or returned in full. The response and the
kyc.updated webhook echo back idNumberLast4 / taxIdLast4.
| Field | Type | Required | Description |
|---|---|---|---|
| idDocumentType | string | No | PASSPORT | NATIONAL_ID | DRIVERS_LICENSE | VOTERS_CARD | RESIDENCE_PERMIT | OTHER |
| idNumber | string | No | ID document number. Stored as fingerprint + last4 only; never returned in full. |
| dateOfBirth | string | No | ISO date, YYYY-MM-DD. |
| nationality | string | No | ISO 3166-1 alpha-2 country code (e.g. KE). |
| countryOfResidence | string | No | ISO 3166-1 alpha-2 country code. |
| address | string | No | Residential address, up to 500 characters. |
| taxResidency | string | No | ISO 3166-1 alpha-2 country code of tax residency. |
| taxId | string | No | TIN. Stored as fingerprint + last4 only; never returned in full. |
| pep | boolean | No | Politically exposed person flag. |
| sanctionsResult | string | No | CLEAR | FLAGGED | PENDING — your sanctions/PEP screening result. |
| screeningProvider | string | No | Sanctions/PEP screening provider name. |
| riskRating | string | No | LOW | MEDIUM | HIGH. |
| consentAt | string | No | ISO 8601 timestamp of user consent. |
| evidenceReference | string | No | Your reference/URL to the stored KYC evidence bundle. |
| employmentStatus | string | No | EMPLOYED | SELF_EMPLOYED | UNEMPLOYED | STUDENT | RETIRED | OTHER. |
| sourceOfFunds | string/array | No | SALARY | BUSINESS_INCOME | INVESTMENTS | INHERITANCE | SAVINGS | PENSION | GIFT | OTHER. |
| sourceOfWealth | string/array | No | BUSINESS_OWNERSHIP | EMPLOYMENT_INCOME | INVESTMENTS | INHERITANCE | PROPERTY | SAVINGS | PENSION | OTHER. |
| annualIncomeBand | string | No | USD-equivalent income band, e.g. 50000_100000. |
| netWorthBand | string | No | USD-equivalent net-worth band, e.g. 100000_500000. |
| investmentExperience | string | No | NONE | LIMITED | MODERATE | EXPERIENCED | PROFESSIONAL. |
| investmentObjectives | array | No | CAPITAL_PRESERVATION | INCOME | GROWTH | SPECULATION | HEDGING | RETIREMENT | OTHER. |
| suitabilityStatus | string | No | NOT_ASSESSED | SUITABLE | UNSUITABLE | REVIEW_REQUIRED. |
| appropriatenessStatus | string | No | NOT_ASSESSED | SUITABLE | UNSUITABLE | REVIEW_REQUIRED. |
| fatcaStatus | string | No | NOT_US_PERSON | US_PERSON | EXEMPT | UNKNOWN. |
| crsTaxResidencies | array | No | Array of country/taxId declarations. Tax IDs are stored as fingerprint + last4 only. |
| marketAccountReferences | array | No | Market-specific broker/CSD references. Account numbers are stored as fingerprint + last4 only. |
Notification devices
GET /users/{userId}/devices · POST /users/{userId}/devices · DELETE /users/{userId}/devices/{deviceId}
Register mobile/web push tokens for a sub-account so your app can fan out user-visible notifications
after receiving MyStocks webhooks or SSE events. MyStocks stores only a token hash plus tokenLast4;
raw APNs/FCM/Expo/Web Push tokens are never returned.
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | APNs, FCM, Expo, or Web Push token. Stored as fingerprint + last4 only. |
| platform | string | Yes | ios | android | web. |
| provider | string | Yes | apns | fcm | expo | webpush. |
| appId | string | No | Bundle/package/app identifier. |
| deviceId | string | No | Your stable device identifier; keeps the same MyStocks deviceId across token rotations. |
| locale | string | No | Locale such as en-KE. |
| timezone | string | No | IANA timezone such as Africa/Nairobi. |
| tags | array | No | Optional partner tags for segmentation. |
Was this page useful?
Your signal helps us tighten partner onboarding docs.
Last updated on