# Paper and Demo Trading

> Use the MyStocks sandbox and integration test tools to validate trading workflows without moving real money.

MyStocks calls its non-production environment **Sandbox**. It is the equivalent of a paper/demo environment for partner integration testing, but it has its own key prefix and base URL.

| Surface                            | Key           | Base URL                               | Purpose                                                                                     |
| ---------------------------------- | ------------- | -------------------------------------- | ------------------------------------------------------------------------------------------- |
| Sandbox environment                | `sk_sandbox_` | `/api/sandbox/v1/partner`              | Isolated virtual accounts and accelerated trading workflows                                 |
| Canonical deterministic test tools | `sk_sandbox_` | `/api/sandbox/v1/partner/test-tools/*` | Simulated order, wallet, holding, execution, and webhook scenarios for new integrations     |
| Restricted legacy compatibility    | `pk_live_`    | `/api/v1/partner/test-tools/*`         | Virtual-event testing against approved live webhook configuration; never production trading |

The production-base compatibility surface is not the isolated sandbox. Deprecated `/sandbox/*` aliases remain only for existing integrations and must not be used in new examples.

## What to test

- account creation and auto-registration;
- deposits, withdrawals, and idempotent retries;
- KYC-required and frozen-account behavior;
- quote expiry and mismatched quote rejection;
- market, limit, stop, and cancellation lifecycles;
- insufficient funds and holdings errors;
- webhook signatures, duplicates, ordering, and retry leases;
- SSE reconnect and `Last-Event-ID` replay;
- daily reconciliation and statement generation.

## Sandbox parity boundaries

The sandbox mirrors the partner-facing treasury and revenue workflows needed for product design:
`GET/PATCH/POST /float`, `GET/PATCH /pricing`, and master or sub-account `GET /tax-lots` and
`GET /gains`. Pricing and treasury updates are virtual and never alter production settings. Tax lots
and gains are derived from sandbox instant-fill orders using the same FIFO reporting model as production.

The following controls remain production-only and appear as non-executable reference entries in the
API Tester: OAuth client credentials, enterprise security policy, go-live certification, reconciliation
packs, OMS execution reports, SSE streaming, and resting-order replacement. OpenAPI operations declare
this boundary with `x-sandbox: false`, and CI fails if the route, specification, and tester disagree.

## Deterministic execution certification

List a customer's simulated orders with their actual sub-account ID:

```bash
curl "https://mystocks.africa/api/sandbox/v1/partner/test-tools/orders?subAccountId=usr_abc123&status=FILLED" \
  -H "Authorization: Bearer sk_sandbox_KEY"
```

Replace `usr_abc123` with the ID returned by `POST /users`. Omitting `subAccountId` in sandbox
returns `400 MISSING_PARAM`; the production compatibility route treats it as an optional filter.

## Expected restrictions and test outcomes

| Request                                                                 | Expected result and correct test setup                                                                                                                                                           |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST /trade`                                                           | Master-account trading is unavailable in sandbox and returns 422. Use `POST /users/{userId}/trade` for a successful virtual trade.                                                               |
| `POST /payout`                                                          | Sandbox returns 422 because virtual funds cannot be paid out. `GET /payout` remains available.                                                                                                   |
| Enterprise, team, security, approvals, sessions, and support operations | Production-only operations are marked `x-sandbox: false` and disabled for sandbox keys in the API Tester. An authenticated request to an absent sandbox route returns `404 SANDBOX_UNSUPPORTED`. |
| Schema discovery                                                        | Fetch [OpenAPI JSON](/openapi.json) or [OpenAPI YAML](/openapi.yaml) from the site root, without the sandbox API prefix or credentials.                                                          |
| Corporate-action election                                               | Read the action first and select a valid option. See [election options](/partners/docs/corporate-governance-api#choosing-a-valid-election-option).                                               |

Exclude production-only operations from sandbox happy-path coverage. Test expected restrictions separately,
asserting the response status and error payload. A correct rejection is a passing negative test, not a
successful trade or payout. Unknown paths also use the sandbox fallback, so a 404 alone does not establish
that the requested operation exists in production.

For replay tests, use a supported mutation, the **same idempotency key and identical body** (including
`clientOrderId`), and verify that the wallet/order changes only once. Test changed-body rejection separately.

## Advancing a deterministic scenario

Use `POST /test-tools/trade` on the sandbox base URL to create an isolated lifecycle scenario. Set
`outcome` to `PENDING`, `FILL`, `PARTIAL_FILL`, `REJECT`, `CANCEL`, or `FAIL_SETTLEMENT` and provide a
deterministic `unitPriceUsd`. The simulator updates virtual wallet reservations, holdings, execution
records, and the same signed order webhooks used by production.

Advance pending and partially filled scenarios without MyStocks staff:

```bash
curl -X PATCH "$BASE/test-tools/orders/$ORDER_ID" \
  -H "Authorization: Bearer $MYSTOCKS_API_KEY" \
  -H "Idempotency-Key: scenario-step-2" \
  -H "Content-Type: application/json" \
  -d '{"subAccountId":"usr_abc123","action":"PARTIAL_FILL","quantity":5,"unitPriceUsd":10}'
```

Repeat with `FILL` for the remainder, then `SETTLE`. Use `REJECT`, `CANCEL`, or `FAIL_SETTLEMENT` to
certify terminal failure handling. Every instruction requires an idempotency key so retries cannot
apply the same wallet or holding movement twice.

Sandbox trades may settle instantly and do not reproduce every production timing characteristic. Always run the [go-live certification](/partners/docs/going-live) checks before requesting production access.
