Skip to content
Partner API Docs

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.

FieldTypeRequiredDescription
externalIdstringYesYour internal user ID. Must be unique per partner — the natural idempotency key.
displayNamestringNoFull name shown in the MyStocks admin console.
emailstringNoUser 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"}'
{ "subAccountId": "usr_abc123", "externalId": "user_42", "displayName": "Jane Doe", "email": "jane@example.com", "kycStatus": "NONE", "kycLevel": "NONE", "status": "active", "walletBalance": 0 }

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.

FieldTypeRequiredDescription
uidstringYesYour internal user identifier. Acts as the idempotency key.
emailstringNoEmail address.
namestringNoDisplay name.
phonestringNoPhone in E.164 format, e.g. +254712345678.
countrystringNoISO 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.

curl -X PATCH "https://mystocks.africa/api/v1/partner/users/usr_abc123" \
  -H "Authorization: Bearer pk_live_<key>" \
  -H "Content-Type: application/json" \
  -d '{"status":"frozen"}'

Deposit

POST /users/{userId}/deposit

Credit a sub-account wallet. The USD amount is deducted from your master wallet and added to the sub-account. Pass localAmount, localCurrency, and fxRate for the audit trail — they do not affect how much USD is credited. Always set Idempotency-Key.

FieldTypeRequiredDescription
amountnumberYesUSD to credit. Deducted from your master wallet.
localAmountnumberNoLocal-currency equivalent (audit trail only).
localCurrencystringNoISO 4217 code, e.g. KES, NGN, GHS.
fxRatenumberNoLocal units per USD that you applied.
notestringNoReference 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":500,"localAmount":655000,"localCurrency":"KES","fxRate":1310,"note":"mpesa_QHJ29SK"}'
{ "message": "Deposit successful.", "subAccountId": "usr_abc123", "amount": 500, "currency": "USD", "newSubBalance": 500, "newMasterBalance": 99500 }

Withdraw

POST /users/{userId}/withdraw

Debit a sub-account wallet and return the funds to your master wallet. You are responsible for paying the user in their local currency at the rate you applied. The sub-account must have sufficient uninvested balance. Always set Idempotency-Key.

FieldTypeRequiredDescription
amountnumberYesUSD to move to your master wallet.
localAmountnumberNoLocal equivalent for audit trail.
localCurrencystringNoISO 4217 code.
fxRatenumberNoRate you applied.
notestringNoReference for transaction history.
{ "message": "Withdrawal successful.", "subAccountId": "usr_abc123", "amount": 200, "currency": "USD", "newSubBalance": 300, "newMasterBalance": 99700 }

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).

FieldTypeRequiredDescription
statusstringYesNONE | PENDING | VERIFIED
levelstringYesNONE | BASIC (ID verified) | FULL (enhanced due diligence)
providerstringNoKYC provider that performed the verification (e.g. sumsub).
referencestringNoYour 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.

FieldTypeRequiredDescription
idDocumentTypestringNoPASSPORT | NATIONAL_ID | DRIVERS_LICENSE | VOTERS_CARD | RESIDENCE_PERMIT | OTHER
idNumberstringNoID document number. Stored as fingerprint + last4 only; never returned in full.
dateOfBirthstringNoISO date, YYYY-MM-DD.
nationalitystringNoISO 3166-1 alpha-2 country code (e.g. KE).
countryOfResidencestringNoISO 3166-1 alpha-2 country code.
addressstringNoResidential address, up to 500 characters.
taxResidencystringNoISO 3166-1 alpha-2 country code of tax residency.
taxIdstringNoTIN. Stored as fingerprint + last4 only; never returned in full.
pepbooleanNoPolitically exposed person flag.
sanctionsResultstringNoCLEAR | FLAGGED | PENDING — your sanctions/PEP screening result.
screeningProviderstringNoSanctions/PEP screening provider name.
riskRatingstringNoLOW | MEDIUM | HIGH.
consentAtstringNoISO 8601 timestamp of user consent.
evidenceReferencestringNoYour reference/URL to the stored KYC evidence bundle.
curl -X POST "https://mystocks.africa/api/v1/partner/users/usr_abc123/kyc" \
  -H "Authorization: Bearer pk_live_<key>" \
  -H "Idempotency-Key: kyc_usr_abc123_001" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "VERIFIED",
    "level": "BASIC",
    "provider": "sumsub",
    "reference": "kyc_session_88721",
    "idDocumentType": "NATIONAL_ID",
    "idNumber": "24681012",
    "dateOfBirth": "1990-04-17",
    "nationality": "KE",
    "taxResidency": "KE",
    "sanctionsResult": "CLEAR",
    "riskRating": "LOW",
    "consentAt": "2026-07-11T09:30:00Z"
  }'
{ "message": "KYC status updated.", "subAccountId": "usr_abc123", "kycStatus": "VERIFIED", "kycLevel": "BASIC", "profile": { "idDocumentType": "NATIONAL_ID", "idNumberLast4": "1012", "nationality": "KE", "taxResidency": "KE", "sanctionsResult": "CLEAR", "riskRating": "LOW" } }

On this page