Skip to content

Toss Invest

Emulated Toss Invest (토스증권) Open API for local development and testing.

Emulates all 41 operations of the Toss Invest Open API. Accounts, holdings, orders, and conditional orders are stateful; market and reference data are generated deterministically from the seeded prices.

Included now:

  • POST /oauth2/token (client credentials; form body or HTTP Basic). Issuing a new token revokes the previous one (token-revoked).
  • Market data: /api/v1/prices, /orderbook, /trades, /price-limits, /candles
  • Stock info: /api/v1/stocks, /stocks/all, warnings, and KR investor trends
  • Market info: exchange rate, KR/US market calendars, rankings, market indicators
  • Sectors: list, rankings, detail, member stocks and ETFs
  • Accounts: /api/v1/accounts, /api/v1/holdings
  • Orders: create, modify, cancel, list (OPEN / CLOSED with cursor), detail
  • Conditional orders (SINGLE / OCO / OTO): create, list, detail, modify, delete
  • Buying power, sellable quantity, commissions
  • Emulator control: POST /_emulator/prices moves a price, filling resting limit orders and firing conditional orders

Account-scoped endpoints need the X-Tossinvest-Account: <accountSeq> header. Responses are wrapped in { "result": ... }; errors are { "error": { "requestId", "code", "message", "data"? } }. The exception is POST /oauth2/token, which answers in the plain OAuth2 shape ({ "access_token", "token_type", "expires_in" }, or { "error", "error_description" }).

Start

# From this repo (after `bun install && bun run build`)
bun packages/emulate/dist/index.js --service tossinvest

# Or from the published package
npx @pleaseai/emulate --service tossinvest

A single service starts on the base port (default 4000). Use -p <port> to change it. When started alongside other services, ports are assigned sequentially from the base port.

Auth

curl -X POST http://localhost:4000/oauth2/token \
  -d grant_type=client_credentials \
  -d client_id=tsck_example_client_id \
  -d client_secret=tsck_example_client_secret

Trading Example

# Current price
curl "http://localhost:4000/api/v1/prices?symbols=005930" \
  -H "Authorization: Bearer <access_token>"

# Market buy; fills immediately at the current price
curl -X POST http://localhost:4000/api/v1/orders \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tossinvest-Account: 1" \
  -H "content-type: application/json" \
  -d '{"symbol":"005930","side":"BUY","orderType":"MARKET","quantity":"10"}'

# Move the price to fill a resting limit order
curl -X POST http://localhost:4000/_emulator/prices \
  -H "content-type: application/json" \
  -d '{"symbol":"005930","price":70000}'

Seed Config

Add a tossinvest: section to emulate.config.yaml (or pass --seed <file>):

tossinvest:
  holidays: # optional; a listed country (KR or US) replaces its built-in 2026 holiday set; null or [] clears it
    KR: [2026-05-05, 2026-10-09]
    US: [2026-07-03]
  clients:
    - client_id: tsck_example_client_id
      client_secret: tsck_example_client_secret
      name: Demo App
  stocks:
    - symbol: '005930'
      name: 삼성전자
      market: KOSPI
      price: 72000
  accounts:
    - account_seq: 1
      cash:
        krw: 10000000
        usd: 10000
      commission:
        kr: '0.00015'
        us: '0.001'
        kr_start_date: 2026-01-01 # KR startDate in GET /commissions
      holdings:
        - symbol: '005930'
          quantity: 100
          average_price: 65000
Navigation

Type to search…

↑↓ navigate↵ selectEsc close