{"_id":"@agrigoryan/questrade-api","name":"@agrigoryan/questrade-api","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agrigoryan/questrade-api","version":"0.1.0","description":"TypeScript client for the Questrade API. Zero dependencies.","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"bun":"./src/index.ts","import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"typecheck":"tsc --noEmit","build":"tsc -p tsconfig.build.json","prepublishOnly":"tsc -p tsconfig.build.json"},"devDependencies":{"@types/bun":"latest","typescript":"^5.7"},"author":{"name":"Aram Grigoryan"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/agrigoryan/questrade-api.git"},"sideEffects":false,"_id":"@agrigoryan/questrade-api@0.1.0","gitHead":"df4d3ea97bccc7639d9713015ff7eeb2e9da68e9","bugs":{"url":"https://github.com/agrigoryan/questrade-api/issues"},"homepage":"https://github.com/agrigoryan/questrade-api#readme","_nodeVersion":"24.7.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-8hijfhALv8uixX9/cFPfBUXCi1sr5ArEH9YK4LDyrc2Traq2bdTZKi7v1AY+p5jAKnPGILgxh/mCZ1LspGKBog==","shasum":"756e6e7b767fe0a39bcbd0fade120dfcdcd864e9","tarball":"https://registry.npmjs.org/@agrigoryan/questrade-api/-/questrade-api-0.1.0.tgz","fileCount":68,"unpackedSize":107305,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICRAxFkZD5I8kcyt/bVmwSw4ZAzXQ6jlr1qXOavjiilDAiBCe11J3B65BHN+chvuWCVzpmAAczVzSK3vSptKvpQTkw=="}]},"_npmUser":{"name":"agrigoryan","email":"aram.grigoryan@gmail.com"},"directories":{},"maintainers":[{"name":"agrigoryan","email":"aram.grigoryan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/questrade-api_0.1.0_1770772115078_0.263187312553814"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-11T01:08:34.957Z","0.1.0":"2026-02-11T01:08:35.238Z","modified":"2026-02-11T01:08:35.442Z"},"maintainers":[{"name":"agrigoryan","email":"aram.grigoryan@gmail.com"}],"description":"TypeScript client for the Questrade API. Zero dependencies.","homepage":"https://github.com/agrigoryan/questrade-api#readme","repository":{"type":"git","url":"git+https://github.com/agrigoryan/questrade-api.git"},"author":{"name":"Aram Grigoryan"},"bugs":{"url":"https://github.com/agrigoryan/questrade-api/issues"},"license":"MIT","readme":"# questrade-api\n\nTypeScript client for the [Questrade REST & WebSocket API](https://www.questrade.com/api/documentation). Zero runtime dependencies.\n\n## Features\n\n- Full coverage of Questrade's v1 REST API (accounts, markets, orders, symbols)\n- Real-time L1 quote and notification streaming via WebSocket\n- OAuth2 authentication (refresh-token and auth-code flows)\n- Automatic token refresh on 401 via callback\n- Automatic rate-limit retry on 429\n- Typed responses with string-union enums\n- Works with Bun and Node.js (ESM)\n\n## Install\n\n```sh\nbun add questrade-api\n# or\nnpm install questrade-api\n```\n\n## Quick Start\n\n```typescript\nimport {\n  exchangeRefreshToken,\n  ApiClient,\n  getAccounts,\n  getPositions,\n  getQuotes,\n} from \"questrade-api\";\n\n// 1. Authenticate with a refresh token\nconst creds = await exchangeRefreshToken(\"your_refresh_token\");\n\n// 2. Create a client with automatic token refresh\nconst client = new ApiClient({\n  accessToken: creds.accessToken,\n  apiServer: creds.apiServer,\n  onTokenExpired: async () => {\n    const fresh = await exchangeRefreshToken(creds.refreshToken);\n    creds.accessToken = fresh.accessToken;\n    creds.refreshToken = fresh.refreshToken;\n    creds.apiServer = fresh.apiServer;\n    return { accessToken: fresh.accessToken, apiServer: fresh.apiServer };\n  },\n});\n\n// 3. Use the API\nconst { accounts } = await getAccounts(client);\nconst { positions } = await getPositions(client, accounts[0].number);\nconst { quotes } = await getQuotes(client, [8049]); // AAPL\n```\n\n## Authentication\n\nQuestrade uses OAuth2. You'll need a refresh token from the [Questrade API Hub](https://www.questrade.com/api).\n\n### Refresh Token Flow\n\n```typescript\nimport { exchangeRefreshToken } from \"questrade-api\";\n\nconst creds = await exchangeRefreshToken(\"your_refresh_token\");\n// creds.accessToken, creds.refreshToken, creds.apiServer, creds.expiresIn\n```\n\n### Authorization Code Flow\n\n```typescript\nimport { exchangeAuthCode } from \"questrade-api\";\n\nconst creds = await exchangeAuthCode(code, clientId, redirectUri);\n```\n\n### Practice (Demo) Account\n\nPass `true` as the last argument to use the practice login server:\n\n```typescript\nconst creds = await exchangeRefreshToken(\"your_refresh_token\", true);\n```\n\n### Token Revocation\n\n```typescript\nimport { revokeToken } from \"questrade-api\";\n\nawait revokeToken(creds.refreshToken);\n```\n\n## API Reference\n\nAll API functions take an `ApiClient` as the first argument.\n\n### Accounts\n\n```typescript\nimport {\n  getTime,\n  getAccounts,\n  getPositions,\n  getBalances,\n  getExecutions,\n  getOrders,\n  getActivities,\n} from \"questrade-api\";\n\nawait getTime(client);\nawait getAccounts(client);\nawait getPositions(client, accountId);\nawait getBalances(client, accountId);\nawait getExecutions(client, accountId, startTime, endTime);\nawait getOrders(client, accountId, { stateFilter: \"All\" });\nawait getActivities(client, accountId, startTime, endTime);\n```\n\n### Market Data\n\n```typescript\nimport {\n  getMarkets,\n  getQuotes,\n  getOptionQuotes,\n  getStrategyQuotes,\n  getCandles,\n} from \"questrade-api\";\n\nawait getMarkets(client);\nawait getQuotes(client, [8049, 9291]);\nawait getOptionQuotes(client, { optionIdFilter: [...], filters: [...] });\nawait getStrategyQuotes(client, { variants: [...] });\nawait getCandles(client, symbolId, startTime, endTime, \"OneDay\");\n```\n\n### Symbols\n\n```typescript\nimport {\n  getSymbolsByIds,\n  getSymbolsByNames,\n  searchSymbols,\n  getOptionChain,\n} from \"questrade-api\";\n\nawait getSymbolsByIds(client, [8049]);\nawait getSymbolsByNames(client, [\"AAPL\", \"MSFT\"]);\nawait searchSymbols(client, \"AAPL\");\nawait getOptionChain(client, symbolId);\n```\n\n### Orders\n\n```typescript\nimport {\n  createOrder,\n  updateOrder,\n  cancelOrder,\n  getOrderImpact,\n} from \"questrade-api\";\n\nconst order = await createOrder(client, accountId, {\n  symbolId: 8049,\n  quantity: 10,\n  orderType: \"Limit\",\n  timeInForce: \"GoodTillCanceled\",\n  limitPrice: 150.0,\n  action: \"Buy\",\n});\n\nawait updateOrder(client, accountId, orderId, { limitPrice: 155.0 });\nawait cancelOrder(client, accountId, orderId);\nawait getOrderImpact(client, accountId, orderRequest);\n```\n\n### Streaming\n\n```typescript\nimport { streamQuotes, streamNotifications } from \"questrade-api\";\n\n// L1 quote stream (note: may freeze market data in other IQ platforms)\nconst quoteStream = await streamQuotes(client, [8049], {\n  onQuote: (quote) => console.log(quote),\n  onError: (err) => console.error(err),\n  onClose: () => console.log(\"closed\"),\n});\n\n// Notification stream (order fills, executions)\nconst notifStream = await streamNotifications(client, {\n  onNotification: (event) => console.log(event),\n  onError: (err) => console.error(err),\n  onClose: () => console.log(\"closed\"),\n});\n\n// Clean up\nquoteStream.close();\nnotifStream.close();\n```\n\n## Error Handling\n\nAPI errors throw a `QuestradeError` with structured fields:\n\n```typescript\nimport { QuestradeError } from \"questrade-api\";\n\ntry {\n  await createOrder(client, accountId, orderRequest);\n} catch (err) {\n  if (err instanceof QuestradeError) {\n    console.log(err.httpStatus); // 400\n    console.log(err.code);       // error code from Questrade\n    console.log(err.message);    // human-readable message\n    console.log(err.orderId);    // present on order errors\n  }\n}\n```\n\n## Development\n\n```sh\nbun install\nbun run typecheck   # type-check only\nbun run build       # compile to dist/\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-0ddf7798b63f3b95a6b8007ebc6f3b7a"}