Skip to content
MyStocks Developers
API v1

API v1

Current stable contract

Versioning policyRelease changelog
Sandbox console
Broker API

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

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.

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.

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.

POST

/auto-register

Auto-register sub-account

Full endpoint documentation
Sandbox availablecreateAutoRegister

Single-call convenience endpoint that creates a sub-account and returns an API token for it. Idempotent on uid — calling twice with the same uid returns the existing sub-account and a fresh token. Equivalent to POST /users but returns auth context in one round trip.

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

uidstringRequired

Your internal user identifier. Idempotency key -- calling twice with the same uid returns the same sub-account.

Example: "user_42"

emailstring

Email address for the sub-account user.

Example: "alice@yourapp.com"

namestring

Full name shown in the MyStocks admin console.

Example: "Alice K."

phonestring

User phone number in E.164 format.

Example: "+254712345678"

countrystring

ISO 3166-1 alpha-2 country code.

Example: "KE"

Response fields

subAccountIdstring
tokenstring

Short-lived auth token for the sub-account.

isNewboolean

true if this call created the account, false if it already existed.

Response codes

200Sub-account created or retrieved.
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.

List & fetch

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.

GET

/users

List sub-accounts

Full endpoint documentation
Sandbox availablelistUsers

Returns all sub-accounts for your partner key. Supports pagination and status filtering. Status filters are applied before pagination. Follow nextCursor even for an empty filtered page with hasMore=true. Invalid or foreign cursors return 400.

Parameters

statusactive | frozen | closed | ALLquery
cursorstringquery

Opaque cursor from nextCursor of the previous response. Omit for the first page.

limitintegerquery

Example: 100

externalIdstringquery

Exact partner-owned external identifier lookup; combined with status when supplied.

Headers

AuthorizationstringRequired

Bearer sk_sandbox_<your_key> for sandbox requests.

Response fields

accountsobject[]
accounts[].subAccountIdstring

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

Example: "usr_abc123"

accounts[].userIdstring

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

accounts[].externalIdstring

Your own user identifier as set at creation.

Example: "usr_8821"

accounts[].displayNamestring | null

Example: "Alice K."

accounts[].emailstring | null

Example: "alice@yourapp.com"

accounts[].kycStatusNONE | PENDING | VERIFIED | REJECTED

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

accounts[].kycLevelNONE | BASIC | FULL

BASIC = ID verified. FULL = enhanced due diligence.

accounts[].kycRejectionCodestring | null

Stable rejection code when kycStatus is REJECTED.

accounts[].kycRejectionReasonstring | null

Customer-safe remediation guidance when kycStatus is REJECTED.

accounts[].kycReviewedAtstring | null

Timestamp of the rejection decision.

accounts[].statusactive | frozen | closed
accounts[].walletBalancenumber

Current USD wallet balance.

Example: 1250

usersobject[]

Backward-compatible alias of accounts.

users[].subAccountIdstring

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

Example: "usr_abc123"

users[].userIdstring

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

users[].externalIdstring

Your own user identifier as set at creation.

Example: "usr_8821"

users[].displayNamestring | null

Example: "Alice K."

users[].emailstring | null

Example: "alice@yourapp.com"

users[].kycStatusNONE | PENDING | VERIFIED | REJECTED

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

users[].kycLevelNONE | BASIC | FULL

BASIC = ID verified. FULL = enhanced due diligence.

users[].kycRejectionCodestring | null

Stable rejection code when kycStatus is REJECTED.

users[].kycRejectionReasonstring | null

Customer-safe remediation guidance when kycStatus is REJECTED.

users[].kycReviewedAtstring | null

Timestamp of the rejection decision.

users[].statusactive | frozen | closed
users[].walletBalancenumber

Current USD wallet balance.

Example: 1250

countinteger
hasMoreboolean
nextCursorstring

Response codes

200Sub-account list.
GET

/users/{userId}

Get sub-account

Full endpoint documentation
Sandbox availablegetUsers

Returns a single sub-account by its MyStocks subAccountId. Use this to check wallet balance, KYC status, and account state.

Parameters

userIdstringpathRequired

MyStocks sub-account ID (e.g. usr_abc123).

Example: usr_abc123

Headers

AuthorizationstringRequired

Bearer sk_sandbox_<your_key> for sandbox requests.

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

200Sub-account detail.
404Sub-account not found.

Update / freeze

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.

PATCH

/users/{userId}

Update sub-account

Full endpoint documentation
Sandbox availableupdateUsers

Updates mutable fields on a sub-account. All fields are optional — only provided fields are changed. Set status to frozen to immediately suspend all trading, deposits, and withdrawals for a user. Set back to active to restore access.

Parameters

userIdstringpathRequired

Example: usr_abc123

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

displayNamestring

New display name for the sub-account.

Example: "Alice Kamau"

emailstring

New email address.

statusactive | frozen

frozen suspends all trading, deposits and withdrawals. Set back to active to restore access.

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

200Updated sub-account.

Close / offboard

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.

Registered webhooks receive account.closed after a successful closure.

Sandbox closure and identifiers

Use the returned subAccountId consistently. Sandbox routes also resolve your tenant-scoped externalId to that same account and wallet; they do not create a second wallet under the alias.

Frozen and closed Sandbox accounts reject deposits, withdrawals, trades, subscriptions and redemptions with HTTP 422 (ACCOUNT_NOT_ACTIVE). Closing is terminal: metadata updates or attempts to reopen a closed account return HTTP 409 (ACCOUNT_CLOSED). Create a new customer account for a new relationship. Cash transfers recheck account state inside the wallet transaction.

DELETE

/users/{userId}

Close sub-account

Full endpoint documentation
Sandbox availablecloseUsers

Soft-closes/offboards a sub-account. This is a terminal state: closed sub-accounts cannot trade, receive deposits, or withdraw. The record is retained for audit, regulatory, and support purposes. Closure is blocked while the sub-account has open orders, positive holdings, or unsettled proceeds. If the USD wallet has residual cash, either withdraw it first or pass residualCashHandling: "transfer_to_partner" to atomically move the cash back to the partner master wallet during closure. Emits account.closed to registered webhooks. Requires Idempotency-Key.

Parameters

userIdstringpathRequired

Example: usr_abc123

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

residualCashHandlingrequire_zero | transfer_to_partner

How to handle a remaining USD wallet balance. require_zero blocks closure if cash remains. transfer_to_partner atomically moves residual cash to the partner master wallet before closing.

reasonstring

Partner-supplied closure reason stored for audit and support.

Example: "User requested account deletion in partner app."

Response fields

messagestring

Example: "Sub-account closed. Residual cash transferred to partner master wallet."

subAccountIdstring

Example: "usr_abc123"

externalIdstring

Example: "user_42"

statusclosed
residualTransferUsdnumber

USD cash moved back to the partner master wallet during closure.

Example: 42.5

currencyUSD
newMasterBalancenumber

Present when residual cash was transferred.

Example: 10042.5

alreadyClosedboolean

true when the sub-account was already closed.

Response codes

200Sub-account closed, or was already closed.
409Closure blocked by open orders, positions, unsettled proceeds, or residual cash.

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.

POST

/users/{userId}/deposit

Deposit to sub-account

Full endpoint documentation
Sandbox availablecreateDeposit

Native opt-in: ?walletContract=2 transfers actual specified currency between firm and customer wallets. Body contains only amount and currency. Requires traceable funding origin and settled available funds. Live requires approved currency capabilities and partner policy. No FX or external bank payout occurs. The v2 response contains transferId, direction, currency, amount, sourceBalance, targetBalance, simulationOnly, and externalPayout=false. Legacy v1 behavior below remains unchanged. Credits USD from your master wallet into a sub-account's wallet. Your master wallet must have sufficient balance — check via GET /account. Managed FX model — pass a USD ledger amount (amount or amountUsd) or pass amount with a non-USD currency such as KES. MyStocks converts supported non-USD amounts into the USD ledger using the managed conversion terms from the FX quote endpoints; bulk rate export is disabled. Sandbox uses the same conversion model but virtual balances only. Missing FX rates and unsupported currencies are rejected. Pass Idempotency-Key to make deposit retries safe on network failure.

Parameters

walletContract1 | 2query

Version 2 transfers actual currency without FX. Internal transfer only; body contains amount and currency.

Example: 1

userIdstringpathRequired

Example: usr_abc123

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

amountnumber

USD ledger amount to deposit, unless currency is a non-USD ISO code. If currency is non-USD, amount is interpreted in that currency and converted to USD by MyStocks managed FX.

Example: 500

amountUsdnumber

Explicit USD ledger amount. Use this when you also include local display fields.

Example: 500

currencystring

Currency of amount. Defaults to USD. Non-USD amounts are converted with MyStocks managed FX.

Example: "KES"

notestring

Optional description shown in the transaction history.

Example: "Mpesa STK push ref KE2482"

localAmountnumber

Equivalent amount in the user local currency. Stored for audit and compliance only.

Example: 65000

localCurrencystring

ISO 4217 code for the local amount.

Example: "KES"

fxRatenumber

Legacy partner-provided exchange rate. Omit this to use MyStocks managed FX.

Example: 130

Response fields

See the response format and API Reference for this endpoint.

Response codes

200Deposit processed.
400Master wallet has insufficient balance.
409Idempotency conflict.

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.

POST

/users/{userId}/withdraw

Withdraw from sub-account

Full endpoint documentation
Sandbox availablecreateWithdraw

Native opt-in: ?walletContract=2 transfers actual specified currency between firm and customer wallets. Body contains only amount and currency. Requires traceable funding origin and settled available funds. Live requires approved currency capabilities and partner policy. No FX or external bank payout occurs. The v2 response contains transferId, direction, currency, amount, sourceBalance, targetBalance, simulationOnly, and externalPayout=false. Legacy v1 behavior below remains unchanged. Moves USD from a sub-account's wallet back to your master wallet. Use this when your user requests a cash-out. The funds are immediately available in your master wallet. Pass a USD ledger amount or a supported local amount + currency; non-USD values are converted with MyStocks managed FX. Sandbox uses the same conversion model but virtual balances only. Missing FX rates and unsupported currencies are rejected. Pass Idempotency-Key to make withdrawals safe to retry.

Parameters

walletContract1 | 2query

Version 2 transfers actual currency without FX. Internal transfer only; body contains amount and currency.

Example: 1

userIdstringpathRequired

Example: usr_abc123

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

amountnumber

USD ledger amount to move, unless currency is a non-USD ISO code. If currency is non-USD, amount is interpreted in that currency and converted to USD by MyStocks managed FX.

Example: 200

amountUsdnumber

Explicit USD ledger amount. Use this when you also include local cash-out display fields.

Example: 200

currencystring

Currency of amount. Defaults to USD. Non-USD amounts are converted with MyStocks managed FX.

Example: "KES"

notestring

Optional description shown in transaction history.

localAmountnumber

Equivalent in local currency for the audit trail.

Example: 26000

localCurrencystring

ISO 4217 code.

Example: "KES"

fxRatenumber

Legacy partner-provided exchange rate. Omit this to use MyStocks managed FX.

Example: 130

Response fields

See the response format and API Reference for this endpoint.

Response codes

200Withdrawal processed.
400Sub-account has insufficient wallet balance.

Assert 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. Set status: "REJECTED", level: "NONE", and include both reasonCode and reason when your provider declines the customer. Rejected customers remain blocked from trading and money movement. This is a state-changing write, so a unique Idempotency-Key header is required (returns 400 MISSING_IDEMPOTENCY_KEY without it).

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.

POST

/users/{userId}/kyc

KYC assertion

Full endpoint documentation
Sandbox availablecreateKyc

Asserts the KYC status of a sub-account. MyStocks defers identity verification to your platform — you send us the result of your own KYC process. VERIFIED + BASIC is sufficient to unlock trading and asset subscriptions. FULL is required for higher transaction limits and private credit deals. REJECTED keeps the account gated and requires reasonCode plus customer-safe remediation text in reason; the response and kyc.updated webhook include reviewedAt. The reference field stores your internal KYC session ID for audit correlation. You may also attach an optional structured compliance profile (ID document type, date of birth, nationality, tax residency, PEP/sanctions screening result, risk rating, consent timestamp, evidence reference). Sensitive identifiers — idNumber and taxId — are stored as a sha256 fingerprint plus last-4 only and are never returned in full. All profile fields are optional and additive.

Parameters

userIdstringpathRequired

Example: usr_abc123

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

statusNONE | PENDING | VERIFIED | REJECTEDRequired

Overall KYC status of the user.

Example: "VERIFIED"

levelNONE | BASIC | FULLRequired

BASIC = government ID verified (sufficient for trading). FULL = address + enhanced due diligence.

Example: "BASIC"

providerstring

Name of the KYC provider that performed the verification (e.g. sumsub, smile_identity).

Example: "sumsub"

referencestring

Your internal KYC session reference for audit correlation.

Example: "kyc_session_88721"

reasonCodestring

Required when status is REJECTED. Stable machine-readable rejection code.

Example: "DOCUMENT_EXPIRED"

reasonstring

Required when status is REJECTED. Human-readable remediation guidance safe to show to the customer.

Example: "Submit a current government-issued identity document."

idDocumentTypePASSPORT | NATIONAL_ID | DRIVERS_LICENSE | VOTERS_CARD | RESIDENCE_PERMIT | OTHER

Type of identity document verified during your KYC process.

Example: "NATIONAL_ID"

idNumberstring

Identity document number. Stored as a sha256 fingerprint plus the last 4 characters only — never persisted or returned in full. The response and webhook echo back idNumberLast4.

Example: "24681012"

dateOfBirthstring

Date of birth in ISO YYYY-MM-DD format.

Example: "1990-04-17"

nationalitystring

Nationality as an ISO 3166-1 alpha-2 country code.

Example: "KE"

countryOfResidencestring

Country of residence as an ISO 3166-1 alpha-2 country code.

Example: "KE"

addressstring

Residential address (free-form, up to 500 characters).

Example: "12 Kenyatta Ave, Nairobi"

taxResidencystring

Country of tax residency as an ISO 3166-1 alpha-2 country code.

Example: "KE"

taxIdstring

Taxpayer identification number (TIN). Stored as a sha256 fingerprint plus the last 4 characters only — never persisted or returned in full. The response and webhook echo back taxIdLast4.

Example: "A012345678Z"

pepboolean

Whether the user is a politically exposed person.

Example: false

sanctionsResultCLEAR | FLAGGED | PENDING

Result of your sanctions/PEP screening.

Example: "CLEAR"

screeningProviderstring

Name of the sanctions/PEP screening provider.

Example: "comply_advantage"

riskRatingLOW | MEDIUM | HIGH

Risk rating assigned to the user by your onboarding process.

Example: "LOW"

consentAtstring

ISO 8601 timestamp when the user granted consent for processing.

Example: "2026-07-11T09:30:00Z"

evidenceReferencestring

Your reference/URL to the stored KYC evidence bundle for audit.

Example: "kyc_docs_88721"

employmentStatusEMPLOYED | SELF_EMPLOYED | UNEMPLOYED | STUDENT | RETIRED | OTHER

Employment status captured during onboarding.

Example: "EMPLOYED"

occupationstring

User occupation or role.

Example: "Software engineer"

employerNamestring

Employer or business name when available.

Example: "Acme Ltd"

sourceOfFundsunion

Source of funds used for investing.

Example: "SALARY"

sourceOfWealthunion

Source of accumulated wealth.

Example: "EMPLOYMENT_INCOME"

annualIncomeBandUNDER_10000 | 10000_50000 | 50000_100000 | 100000_250000 | 250000_1000000 | OVER_1000000

Annual income band in USD-equivalent.

Example: "50000_100000"

netWorthBandUNDER_25000 | 25000_100000 | 100000_500000 | 500000_1000000 | 1000000_5000000 | OVER_5000000

Net-worth band in USD-equivalent.

Example: "100000_500000"

investmentExperienceNONE | LIMITED | MODERATE | EXPERIENCED | PROFESSIONAL

User's investing experience level.

Example: "LIMITED"

investmentObjectivesstring[]

Investment objectives captured during suitability/appropriateness checks.

Example: ["GROWTH","RETIREMENT"]

riskToleranceLOW | MEDIUM | HIGH

User-declared or assessed risk tolerance.

Example: "MEDIUM"

suitabilityStatusNOT_ASSESSED | SUITABLE | UNSUITABLE | REVIEW_REQUIRED

Suitability outcome assigned by your onboarding process.

Example: "SUITABLE"

appropriatenessStatusNOT_ASSESSED | SUITABLE | UNSUITABLE | REVIEW_REQUIRED

Appropriateness outcome for execution-only brokerage products.

Example: "SUITABLE"

assessmentReferencestring

Your suitability/appropriateness assessment reference.

Example: "suitability_88721"

usPersonboolean

FATCA US-person declaration.

Example: false

fatcaStatusNOT_US_PERSON | US_PERSON | EXEMPT | UNKNOWN

FATCA classification asserted by your onboarding flow.

Example: "NOT_US_PERSON"

crsTaxResidenciesobject[]

CRS tax residencies. Tax IDs are stored as sha256 fingerprint plus last4 only.

crsTaxResidencies[].countrystringRequired

Example: "KE"

crsTaxResidencies[].taxIdstring

Stored as fingerprint + last4 only.

Example: "A012345678Z"

crsTaxResidencies[].reasonNoTinstring

Reason no TIN was supplied, if applicable.

marketAccountReferencesobject[]

Market-specific brokerage/CSD account references. Account numbers are stored as fingerprint plus last4 only.

marketAccountReferences[].marketstringRequired

Example: "NSE"

marketAccountReferences[].brokerstring

Example: "MyStocks Securities"

marketAccountReferences[].brokerAccountNumberstring

Stored as fingerprint + last4 only.

marketAccountReferences[].csdNumberstring

Stored as fingerprint + last4 only.

Response fields

messagestring
kycStatusNONE | PENDING | VERIFIED | REJECTED
kycLevelNONE | BASIC | FULL
reasonCodestring | null
reasonstring | null
reviewedAtstring | null
profileobject

Echo of the compliance fields asserted on this call (present only when a profile was supplied). Sensitive identifiers appear as idNumberLast4 / taxIdLast4 — never in full.

Response codes

200KYC status updated.

Notification devices

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.

GET

/users/{userId}/devices

List notification devices

Full endpoint documentation
Sandbox availablelistUserDevices

Lists mobile/web push devices registered for a sub-account. Tokens are never returned; only tokenLast4 is exposed for support correlation.

Parameters

userIdstringpathRequired

Example: usr_abc123

Headers

AuthorizationstringRequired

Bearer sk_sandbox_<your_key> for sandbox requests.

Response fields

devicesobject[]
devices[].deviceIdstring

Example: "dev_6f9a4d2c1b0e8a7c3d5f9012"

devices[].platformios | android | web
devices[].providerfcm | apns | expo | webpush
devices[].tokenLast4string

Last 4 characters of the token for support correlation.

devices[].appIdstring
devices[].localestring
devices[].timezonestring
devices[].externalDeviceIdstring
devices[].tagsstring[]
devices[].enabledboolean
devices[].statusactive | disabled | revoked
devices[].createdAtstring
devices[].updatedAtstring
devices[].lastSeenAtstring
countinteger

Response codes

200Registered notification devices.
POST

/users/{userId}/devices

Register notification device

Full endpoint documentation
Sandbox availableregisterUserDevice

Registers or updates a push-token record for your mobile/web app. MyStocks stores only a token hash and last4. This endpoint gives partners a durable device-token model for mobile notification fanout. Webhooks remain the server-side event source of truth; your backend should receive webhooks or SSE events and fan out user-visible notifications through APNs, FCM, Expo, or Web Push using the device records you maintain.

Parameters

userIdstringpathRequired

Example: usr_abc123

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

tokenstringRequired

Mobile/web push token from APNs, FCM, Expo, or Web Push. Stored as sha256 hash plus last4 only.

Example: "ExpoPushToken[xxxxxxxxxxxxxxxxxxxxxx]"

platformios | android | webRequired

Example: "ios"

providerfcm | apns | expo | webpushRequired

Example: "expo"

appIdstring

Partner app bundle/package ID.

Example: "com.afritrade.app"

deviceIdstring

Optional partner device identifier. Used to keep one stable MyStocks deviceId across token rotations.

Example: "afritrade-device-42"

localestring

Example: "en-KE"

timezonestring

Example: "Africa/Nairobi"

tagsstring[]

Example: ["retail","beta"]

enabledboolean

Response fields

See the response format and API Reference for this endpoint.

Response codes

200Existing device registration updated.
201Device registered.
DELETE

/users/{userId}/devices/{deviceId}

Revoke notification device

Full endpoint documentation
Sandbox availablerevokeUserDevice

Soft-revokes a registered push device. The record is retained for audit and support correlation.

Parameters

userIdstringpathRequired

Example: usr_abc123

deviceIdstringpathRequired

Example: dev_6f9a4d2c1b0e8a7c3d5f9012

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

Response fields

messagestring
subAccountIdstring
externalIdstring
deviceIdstring
statusstring

Example: "revoked"

Response codes

200Device revoked.
404Device not found.

Was this page useful?

Your signal helps us tighten partner onboarding docs.

Send note

Last updated on

On this page