# Changelog

> All notable MyStocks Partner API changes by version, from the v1.0 initial release through v2.9. Entries marked Deprecated are removed on the date in the Sunset header — see API Versioning for the deprecation policy.

## v3.0 — August 2026

- **Clarified** — African equity data is exchange-supplied and 15-minute delayed, not real-time. `delayMinutes: 15` identifies the exchange latency class; `refreshIntervalSeconds: 900` identifies the API ingestion target. MyStocks holds full data rights for every supported exchange.
- **Clarified** — Every listed African equity has EOD data for a line chart; complete reported OHLCV remains instrument-dependent and is governed by candle quality metadata.
- **Corrected** — MyStocks holds full market-data rights for every supported exchange. Provider-tier errors are ingestion/configuration incidents, not exchange-licensing gaps.

- **Fixed** — `GET /users/{userId}/orders?symbol=SCOM.KE` now filters reliably in production and sandbox without requiring a Firestore composite index.
- **Fixed** — Stock, quote, company, and ETF responses derive `changePct` from `price` and `previousClose` when the ingest row omits it; sector labels and filters are normalized at the partner boundary.
- **Fixed** — Completed legacy transactions expose settlement evidence, and filled legacy orders return an explicitly marked synthetic FILL when they pre-date the immutable execution journal.
- **Fixed** — Sandbox MARKET quotes are claimed atomically only after funds/holdings validation; reuse returns `STALE_QUOTE`, while insufficient funds returns the canonical structured error without consuming the quote.
- **Added** — Sandbox LIMIT/STOP/STOP_LIMIT placement and cancellation parity, including reserved-cash/unit release and lifecycle webhooks.

- **Added** — `GET /stocks/{symbol}/candles`, the canonical chart contract, accepts sparse delayed `15m` and `1h` buckets alongside `1d`, `1w`, and `1mo`; observed cadence metadata prevents partners from mistaking coarse capture for complete intraday coverage.
- **Fixed** — Chart recommendations now use price quality independently of volume: incomplete/highly-flat OHLC and sparse intraday data fall back to EOD lines, while complete OHLC may remain candlestick-capable when only volume is incomplete.
- **Fixed** — Canonical GSE/BRVM examples now use `GCB.GH` and `SNTS.CI`; legacy `GCBBANK.GH` and `SNTS.BF` remain accepted as compatibility aliases.
- **Added** — Candle responses include the instrument `name`, per-candle `volumeAvailable`, and series-level `volumeCoveragePct` and `volumeStatus`.
- **Deprecated** — Stock `/chart` and `/history` compatibility routes; migrate to `/candles` before 2026-10-01. Guessed `/prices` and `/ohlc` paths are not API routes.
- **Fixed** — Sandbox `/history` and `/chart` now preserve stored OHLCV instead of forcing close-only candles and zero volume.
- **Added** — Candle-level `ohlcAvailable` plus `ohlcCoveragePct`, `flatCandlePct`, `zeroVolumePct`, `qualityStatus`, and `qualityIssues` for deterministic chart fallbacks.
- **Fixed** — Market-data writers no longer convert missing provider volume into a fabricated reported zero.
- **Added** — Production and sandbox parity plus API Tester, OpenAPI, Postman, TypeScript SDK, and sync/async Python SDK coverage for stock candles.
- **Clarified** — Candles are delayed, pull-based, and unadjusted. Sparse minute/hour buckets are available, but continuous intraday coverage, live WebSocket candle updates, and server-side technical indicators are not currently offered.
- **Clarified** — In-app chart display is included under the Partner Agreement; raw redistribution, standalone feeds, and bulk historical exports require separate data rights.
- **Fixed** — Removed the inaccurate claim that the legacy stock-history route automatically aggregates weekly and monthly candles, and corrected its Postman path.

## v2.9 — July 2026

- **Added** — Maker-checker approval policies, thresholds, multi-approver decisions, expiry, cancellation, delegation, immutable evidence, payload fingerprints, and idempotent execution binding.
- **Changed** — Organization policies may now require independent approval for material payouts, API-key lifecycle operations, webhook changes, security policy, corporate-action elections, and proxy votes.
- **Added** — Enterprise SAML/OIDC configuration with platform activation and enforced federated console login.
- **Added** — Organization-scoped SCIM 2.0 Users, Groups, and ServiceProviderConfig resources with hashed bearer tokens and immediate deprovisioning.
- **Added** — Manual and scheduled access certifications with confirm, change-required, and revoke decisions.
- **Added** — Downloadable security/compliance evidence bundles with credential redaction and SHA-256 integrity evidence.

## v2.8 — July 2026

- **Added** — Partner-console RBAC with organization membership, ten default roles, custom roles, verified-email invitations, immediate permission changes, last-owner protection, and revocable human sessions. Machine credentials remain governed separately by API scopes.
- **Added** — **Team & Access** console operations under `/team`, `/team/invites`, `/team/members/{memberId}`, `/team/roles`, and `/sessions`.
- **Added** — Organization-scoped **Help & Support** cases under `/support`, including P0–P3 severity, acknowledgement and update clocks, operational references, partner-visible messages, escalation, assignment, resolution, and closure.
- **Added** — Optional privileged-role MFA enforcement for Owner, Administrator, Treasury, and Compliance console sessions.

All notable API changes. Entries marked **Deprecated** will be removed on the date listed in the
`Sunset` header — see [API Versioning](/partners/docs/versioning) for the deprecation policy.

## v2.7 — July 2026

- **Added** — Resting orders on the **master account**. `POST /trade` now accepts `orderType: LIMIT | STOP | STOP_LIMIT` (previously master orders could only be MARKET). Like sub-account resting orders, they are not quote-gated, may be placed while the market is closed, and escrow at the trigger price.
- **Added** — `PATCH /orders/{orderId}` modifies a resting master order in place (`limitPrice`, `stopPrice`, `quantity`), matching the existing `PATCH /users/{userId}/orders/{orderId}`. Requires `Idempotency-Key`; emits `order.replaced`.
- **Changed** — `DELETE /orders/{orderId}` now cancels `WORKING` resting master orders as well as `PENDING` market orders, refunding BUY escrow and releasing SELL unit reservations.
- **Added** — **Price alerts**: `POST/GET /price-alerts` and `GET/DELETE /price-alerts/{alertId}`, backing a new `price.alert` webhook event. Thresholds are in the instrument's local trading currency and are evaluated against the latest delayed price observation while the exchange is open.
- **Added** — **Quote freshness contract.** Every quote now carries `asOf` (when the price was captured upstream), `stale`, and a `dataQuality` block (`delayMode`, `delayMinutes`, `refreshIntervalSeconds`, `provider`). `GET /market/exchanges` publishes the same policy per exchange. Quotes are **delayed** — polled every 15 minutes between 08:00–16:00 UTC on weekdays — and were never real-time; this makes the existing behaviour explicit. Price your trades against `asOf`.
- **Added** — `503` maintenance handling: `MAINTENANCE` and `SERVICE_UNAVAILABLE` error codes, always with `Retry-After`. A `read_only` mode serves GETs normally while refusing mutations, so you can reconcile during a settlement incident.
- **Added** — Public status page at [mystocks.africa/status](https://mystocks.africa/status), rendering the existing `GET /api/v1/status` registry.
- **Added** — Concurrent `GET /stream` connection cap, published per tier (Starter 2, Growth 5, Enterprise 20). Exceeding it returns `429` rather than opening a stream that immediately dies.
- **Changed** — Order rejection codes are now documented with retry semantics (which are safe to resubmit and which are not) and validated against a single source of truth. The set is unchanged and exhaustive: `INSUFFICIENT_FUNDS`, `KYC_REQUIRED`, `MARKET_CLOSED`, `COMPLIANCE_HOLD`, `TECHNICAL_ISSUE`, `OTHER`.

## v2.6 — July 2026

- **Fixed** — Asset-detail endpoints (`GET /bonds/{id}`, `/funds/{id}`, `/opportunities/{id}`, `/market-intel/{id}`) now return a clean 404 for any unresolvable id, including Firestore-reserved patterns (e.g. `__x__`) that previously threw a 500.
- **Added** — Sandbox parity: `PATCH /settings` and the SMTP test now work in sandbox, and `POST /api-keys/rotate` rotates your sandbox key in place. Both were previously 422 stubs.
- **Changed** — Enterprise scoped-key enforcement is now enforced, not advisory. With `scopedKeysRequired` enabled, a key with no scopes is denied (403); a full-access key must hold the `"*"` scope.
- **Changed** — Signed requests now cover the query string: `HMAC-SHA256(apiKey, "{timestamp}.{METHOD}.{path}{?query}.{sha256(body)}")`. Signing without the query string is deprecated.
- **Fixed** — mTLS verification is stricter: a bare or spoofed `x-forwarded-client-cert` no longer counts as a verified certificate. Use `x-client-cert-verified: success` or a genuine Envoy XFCC with a `Hash=`.
- **Fixed** — API reference corrected: data keys access market data via `/market/*`; the deprecated `/market-data/*` aliases are not in the data-key allowlist.

## v2.5 — July 2026

- **Changed** — Integration test tools renamed: `POST /test-tools/deposit`, `POST /test-tools/trade`, `GET /test-tools/orders` are the new canonical live-key testing paths. The old `/sandbox/*` paths remain supported aliases but are deprecated.
- **Added** — Security guidance: avoid embedding API keys (including `pk_data_`) in production bundles; proxy through your backend or mint short-lived tokens via `POST /oauth/token`.
- **Fixed** — OpenAPI spec: the data-key prefix is `pk_data_` (earlier text showed `dk_`).
- **Changed** — Market data unified under `/market/*`: `GET /market/exchanges` and `GET /market/ohlcv` are the new canonical paths; `/market-data/*` remain deprecated aliases.
- **Added** — camelCase pagination meta on `GET /market/movers` (`totalCount`, `perPage`, `hasNext`); snake_case aliases deprecated, removal 2026-10-01.
- **Added** — Typed response-header components in the spec (`X-RateLimit-*`, `Retry-After`) and documented webhook request headers.
- **Added** — Webhook delivery semantics documented: at-least-once, possible duplicates/out-of-order, dedupe-by-eventId, gap reconciliation.
- **Added** — Retry-guidance table in Authentication.
- **Fixed** — Webhook retry policy corrected to the actual scheduler: up to 6 attempts with exponential back-off (immediate, 5 s, 30 s, 5 min, 30 min, 2 h).
- **Added** — Concepts & Glossary (15 terms with stable `#term-<slug>` anchors), Architecture & Custody, and Order & Money Lifecycles sections.
- **Added** — Recipes: eight implementation guides at `/partners/docs/recipes`, each on its own shareable URL.
- **Fixed** — Build a Trading App guide now shows the correct two-step `GET /quote/{symbol}` → `POST /trade` sequence.
- **Fixed** — Cash-mode (fractional) trading now works with the quote gate: `GET /quote/{symbol}` accepts `cashValue`.
- **Fixed** — Sandbox `GET /buying-power` endpoints now exist; quote quantities accept fractional values.
- **Added** — Sandbox webhooks reach full production parity (real endpoints, HMAC signing, retries, delivery log, test-fire).
- **Fixed** — Sandbox parity sweep: duplicate `externalId` returns the existing sub-account (200); structured batch/validation errors.
- **Added** — Sandbox top-ups (`POST /topup`) auto-approve and fire `topup.confirmed`.
- **Added** — OpenAPI: `GET /dividends/{symbol}/history` documented.
- **Fixed** — `GET /stocks` documented as a full, non-paginated filtered list with a `search` param.
- **Fixed** — Quick Start step 1 corrected: `POST /register` authenticates with a Firebase ID token.

## v2.4 — July 2026

- **Added** — Real-time event stream: `GET /stream` (Server-Sent Events) — every webhook event, also streamed, with resume via `Last-Event-ID` / `?since=`.
- **Added** — Self-serve pricing: `GET /pricing` + `PATCH /pricing` (default markup bps + per-symbol/exchange/asset-class overrides + promo window).
- **Added** — Webhook `corporateaction.declared` (split, rights issue, bonus, merger, delisting, symbol change) with `affectedSubAccounts[]`.
- **Added** — Tax lots + realized-gain reporting: `GET /users/{userId}/tax-lots` and `GET /users/{userId}/gains`.
- **Added** — `GET /float` + `PATCH /float` (master funding headroom); webhooks `topup.confirmed` and `float.low`; optional credit line.
- **Added** — Native LIMIT / STOP / STOP_LIMIT orders on sub-account trades (rest in `WORKING`, fire `order.triggered`).
- **Added** — `GET /buying-power` endpoints — settlement-aware balances (`withdrawableUsd` excludes unsettled SELL proceeds).
- **Changed** — Sub-account withdrawals can enforce a settlement hold: over-withdrawal returns `400 UNSETTLED_FUNDS`.
- **Changed** — Unified stock/quote response shape across `/market/quotes`, `/market/movers`, `/stocks`.
- **Deprecated** — snake_case aliases on `/market/quotes` and `/market/movers`; removal 2026-10-01.
- **Added** — `price` returned alongside deprecated `currentPrice` on `/stocks/{symbol}` and `/companies/{symbol}`.

## v2.3 — June 2026

- **Added** — `GET /market/movers` — paginated top gainers/losers per exchange.
- **Changed** — List endpoints use cursor pagination (`cursor` + `nextCursor` + `hasMore`).
- **Fixed** — Batch-quote `volume` returns integer `0` (not `null`); overflow returns `BATCH_LIMIT_EXCEEDED`; malformed symbols return `400 INVALID_SYMBOL`.
- **Fixed** — `?symbols[]=` array bracket notation returns a clear `VALIDATION_ERROR` pointing to `?symbols=A,B,C`.
- **Changed** — Error-codes table expanded (`MISSING_PARAM`, `INVALID_SYMBOL`, `UNKNOWN_EXCHANGE`, `INVALID_TYPE`, `BATCH_LIMIT_EXCEEDED`).

## v2.2 — June 2026

- **Added** — OHLCV in chart endpoints: `open`, `high`, `low`, `close`, `volume` on every candle plus parallel arrays.
- **Added** — `open` field on stock and ETF detail responses.
- **Fixed** — Missing logo SVGs return a branded placeholder instead of an error page.

## v2.1 — May 2026

- **Added** — ETF support: `GET /etfs`, `/etfs/{symbol}`, `/etfs/{symbol}/history`, `/etfs/{symbol}/chart`.
- **Added** — Price charts: `GET /stocks/{symbol}/chart` and `/etfs/{symbol}/chart`.
- **Added** — Multi-symbol batch quotes (up to 50 symbols).
- **Added** — Sandbox simulation headers `X-Sandbox-Force-Status` / `X-Sandbox-Force-Error`.
- **Changed** — Structured error model `{"error": {"code", "message"}}`.
- **Added** — Timing-safe HMAC signature-verification examples (Express, FastAPI).

## v2.0 — May 2026

- **Added** — Sandbox endpoints: `POST /sandbox/deposit`, `POST /sandbox/trade`, `GET /sandbox/orders`.
- **Added** — All sandbox webhook payloads include `isSandbox: true`.
- **Added** — Sandbox tab in the Partner Dashboard; cheat codes (quantity 100 → auto-fill, 999 → auto-reject).

## v1.9 — May 2026

- **Added** — `POST /auto-register`, `GET /quote/{symbol}`, `GET /market/status`, `GET /webhooks/{id}/deliveries`.
- **Added** — Webhook events `wallet.credited`, `incident.declared`, `incident.resolved`.
- **Changed** — Deposit body accepts `localAmount`, `localCurrency`, `fxRate`.
- **Fixed** — Webhook signature example uses `timingSafeEqual`.

## v1.8 — April 2026

- **Added** — Company endpoints; `GET /usage`; `GET /audit`; partner `markupBps`; SMTP settings.

## v1.7 — March 2026

- **Added** — `GET /report/revenue`, `GET /report/invoice`, `POST /api-keys/rotate` & `revoke`, `GET /api-keys/data-key`.
- **Changed** — Trade body accepts optional `stopLoss` and `takeProfit`.

## v1.6 — January 2026

- **Added** — `POST /users/{userId}/subscribe` & `redeem`, `GET /dividends/calendar`, `GET /report/dividends`, webhook `dividend.paid`.

## v1.5 — November 2025

- **Added** — Bonds & fixed income, funds & ETFs, private credit & pre-IPO, `POST /users/{userId}/kyc`.

## v1.0 — September 2025

- **Added** — Initial release: equity trading, sub-accounts, USD wallets, deposits, withdrawals, webhooks, core stock/portfolio/user/trade/webhook endpoints.
