@structbuild/sdk 0.2.11 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,8 +7,6 @@ TypeScript SDK for prediction market data via [api.struct.to](https://api.struct
7
7
  ```bash
8
8
  npm install @structbuild/sdk
9
9
  # or
10
- pnpm add @structbuild/sdk
11
- # or
12
10
  bun add @structbuild/sdk
13
11
  ```
14
12
 
@@ -45,64 +43,113 @@ const client = new StructClient({
45
43
 
46
44
  ```typescript
47
45
  const markets = await client.markets.getMarkets({ limit: 10 });
48
- const market = await client.markets.getMarket({ condition_id: "0x..." });
49
- const marketBySlug = await client.markets.getMarketBySlug({ slug: "will-x-happen" });
50
- const trades = await client.markets.getTrades({ condition_id: "0x..." });
51
- const candles = await client.markets.getCandlestick({ condition_id: "0x...", timeframe: "1d", interval: "1h" });
46
+ const market = await client.markets.getMarket({ conditionId: "0x..." });
47
+ const marketBySlug = await client.markets.getMarketBySlug({ marketSlug: "will-x-happen" });
48
+ const trades = await client.markets.getTrades({ condition_ids: "0x..." });
49
+ const candles = await client.markets.getCandlestick({ condition_id: "0x...", resolution: "1h" });
50
+ const chart = await client.markets.getMarketChart({ condition_id: "0x..." });
52
51
  const metrics = await client.markets.getMarketMetrics({ condition_id: "0x..." });
53
52
  const volumeChart = await client.markets.getMarketVolumeChart({ condition_id: "0x..." });
53
+ const priceJumps = await client.markets.getPriceJumps();
54
54
  ```
55
55
 
56
56
  ### Events
57
57
 
58
58
  ```typescript
59
59
  const events = await client.events.getEvents({ limit: 10 });
60
- const event = await client.events.getEvent({ id: "123" });
60
+ const event = await client.events.getEvent({ identifier: "123" });
61
61
  const eventBySlug = await client.events.getEventBySlug({ slug: "us-election" });
62
- const eventMetrics = await client.events.getEventMetrics({ event_id: "123" });
62
+ const eventMetrics = await client.events.getEventMetrics({ event_slug: "us-election", timeframe: "24h" });
63
+ const outcomes = await client.events.getEventOutcomes({ event_slug: "us-election" });
64
+ const chart = await client.events.getEventChart({ event_slug: "us-election" });
63
65
  ```
64
66
 
65
67
  ### Trader / Portfolio
66
68
 
67
69
  ```typescript
68
- const portfolio = await client.trader.getPortfolio({ address: "0x..." });
69
- const positions = await client.trader.getPortfolioPositions({ address: "0x..." });
70
70
  const trades = await client.trader.getTraderTrades({ address: "0x..." });
71
71
  const profile = await client.trader.getTraderProfile({ address: "0x..." });
72
+ const profiles = await client.trader.getTraderProfilesBatch({ addresses: "0x...,0x..." });
72
73
  const pnl = await client.trader.getTraderPnl({ address: "0x..." });
73
- const pnlByMarket = await client.trader.getTraderMarketPnl({ address: "0x..." });
74
- const pnlByEvent = await client.trader.getTraderEventPnl({ address: "0x..." });
74
+ const marketPnl = await client.trader.getTraderMarketPnl({ address: "0x..." });
75
+ const eventPnl = await client.trader.getTraderEventPnl({ address: "0x..." });
76
+ const outcomePnl = await client.trader.getTraderOutcomePnl({ address: "0x..." });
75
77
  const pnlCandles = await client.trader.getTraderPnlCandles({ address: "0x..." });
78
+ const pnlCalendar = await client.trader.getTraderPnlCalendar({ address: "0x..." });
76
79
  const volumeChart = await client.trader.getTraderVolumeChart({ address: "0x..." });
80
+ const leaderboard = await client.trader.getGlobalPnl();
77
81
  ```
78
82
 
79
83
  ### Holders
80
84
 
81
85
  ```typescript
82
86
  const marketHolders = await client.holders.getMarketHolders({ condition_id: "0x..." });
83
- const eventHolders = await client.holders.getEventHolders({ event_slug: "us-election" });
84
- const positionHolders = await client.holders.getPositionHolders({ position_id: "123" });
87
+ const positionHolders = await client.holders.getPositionHolders({ positionId: "123" });
85
88
  const history = await client.holders.getMarketHoldersHistory({ condition_id: "0x..." });
89
+ const posHistory = await client.holders.getPositionHoldersHistory({ positionId: "123" });
86
90
  ```
87
91
 
88
- ### Series
92
+ ### Order Book
89
93
 
90
94
  ```typescript
91
- const series = await client.series.getSeriesList();
92
- const outcomes = await client.series.getSeriesOutcomes({ series_slug: "my-series" });
95
+ const orderBook = await client.orderBook.getOrderBook({ asset_id: "0x..." });
96
+ const history = await client.orderBook.getOrderBookHistory();
97
+ const marketBook = await client.orderBook.getMarketOrderBook();
98
+ const spreads = await client.orderBook.getSpreadHistory();
93
99
  ```
94
100
 
95
- ### Search, Tags, Bonds
101
+ ### Series, Search, Tags, Assets, Bonds
96
102
 
97
103
  ```typescript
104
+ const series = await client.series.getSeriesList();
105
+ const outcomes = await client.series.getSeriesOutcomes({ series_slug: "my-series" });
106
+ const assetHistory = await client.assets.getAssetHistory({ symbol: "BTC", variant: "1d" });
98
107
  const results = await client.search.search({ query: "election" });
99
108
  const tags = await client.tags.getTags();
109
+ const tag = await client.tags.getTag({ identifier: "politics" });
100
110
  const bonds = await client.bonds.getBonds();
101
111
  ```
102
112
 
113
+ ### Trade Types
114
+
115
+ Trade endpoints (`getTrades`, `getTraderTrades`) return a discriminated union of all on-chain event types. Use the `trade_type` field to narrow:
116
+
117
+ ```typescript
118
+ import type { Trade, MarketTrade, OracleEvent, TradeEventType } from "@structbuild/sdk";
119
+
120
+ const { data: trades } = await client.markets.getTrades();
121
+
122
+ for (const trade of trades) {
123
+ switch (trade.trade_type) {
124
+ case "OrderFilled":
125
+ case "OrdersMatched":
126
+ console.log(trade.price, trade.usd_amount, trade.shares_amount);
127
+ break;
128
+ case "Redemption":
129
+ console.log(trade.winning_outcome_index, trade.position_details);
130
+ break;
131
+ case "Merge":
132
+ case "Split":
133
+ console.log(trade.usd_amount, trade.position_details);
134
+ break;
135
+ case "Resolution":
136
+ console.log(trade.payout_numerators);
137
+ break;
138
+ }
139
+ }
140
+ ```
141
+
142
+ The SDK exports convenience sub-unions for common filtering:
143
+
144
+ - **`MarketTrade`** — actual on-chain trades: `OrderFilled`, `OrdersMatched`, `Redemption`, `Merge`, `Split`, `PositionsConverted`, `Cancelled`, `RegisterToken`, `Approval`
145
+ - **`OracleEvent`** — protocol lifecycle events: `Initialization`, `Proposal`, `Dispute`, `Settled`, `Resolution`, `ConditionResolution`, `Reset`, `Flag`, `Unflag`, `Pause`, `Unpause`, `ManualResolution`, `NegRiskOutcomeReported`
146
+ - **`TradeEventType`** — string literal union of all `trade_type` values for autocomplete
147
+
148
+ Individual schemas are also exported: `OrderFilledTrade`, `RedemptionTrade`, `MergeTrade`, `SplitTrade`, `CancelledTrade`, `PositionsConvertedTrade`, `RegisterTokenTrade`, `ApprovalTrade`, and all oracle event types.
149
+
103
150
  ### Webhooks
104
151
 
105
- Manage webhook subscriptions for real-time event notifications. Webhook endpoints are platform-level (not venue-scoped).
152
+ Manage webhook subscriptions for real-time event notifications:
106
153
 
107
154
  ```typescript
108
155
  const webhooks = await client.webhooks.list();
@@ -114,30 +161,129 @@ const webhook = await client.webhooks.create({
114
161
  min_usd_value: 100,
115
162
  },
116
163
  });
117
- const detail = await client.webhooks.getWebhook({ webhookId: webhook.data.id });
118
- await client.webhooks.update({ webhookId: webhook.data.id, events: ["first_trade"] });
119
164
  await client.webhooks.test({ webhookId: webhook.data.id });
165
+ await client.webhooks.rotateSecret({ webhookId: webhook.data.id });
120
166
  await client.webhooks.deleteWebhook({ webhookId: webhook.data.id });
167
+ const events = await client.webhooks.listEvents();
121
168
  ```
122
169
 
123
- #### Webhook Payload Types
170
+ ## WebSocket API
124
171
 
125
- The SDK exports typed payload schemas for building webhook receivers:
172
+ Real-time streaming via room-based subscriptions with fully typed filters, responses, and events.
126
173
 
127
174
  ```typescript
128
- import type {
129
- FirstTradePayload,
130
- ProbabilitySpikePayload,
131
- GlobalPnlPayload,
132
- VolumeMilestonePayload,
133
- } from "@structbuild/sdk";
175
+ import { StructWebSocket } from "@structbuild/sdk";
134
176
 
135
- function handleWebhook(payload: FirstTradePayload) {
136
- console.log(payload.trader, payload.price, payload.side);
137
- }
177
+ const ws = new StructWebSocket({ apiKey: "your-api-key" });
178
+ await ws.connect();
179
+ ```
180
+
181
+ ### Subscribing to rooms
182
+
183
+ Each room has typed filters and a typed subscribe response:
184
+
185
+ ```typescript
186
+ const res = await ws.subscribe("polymarket_trades", {
187
+ condition_ids: ["0xabc123"],
188
+ });
189
+
190
+ await ws.subscribe("polymarket_order_book", {
191
+ asset_ids: ["0xabc123"],
192
+ });
193
+
194
+ // Some rooms have optional filters
195
+ await ws.subscribe("polymarket_asset_prices");
196
+ await ws.subscribe("polymarket_clob_rewards", { subscribe_all: true });
197
+ ```
198
+
199
+ ### Listening for events
200
+
201
+ ```typescript
202
+ ws.on("trade_stream_update", (event) => {
203
+ event.condition_id;
204
+ event.price;
205
+ event.size;
206
+ event.side;
207
+ });
208
+
209
+ ws.on("order_book_update", (event) => {
210
+ event.asset_id;
211
+ event.bids;
212
+ event.asks;
213
+ });
214
+
215
+ ws.on("clob_rewards_update", (event) => {
216
+ event.event_type; // "added" | "removed" | "updated"
217
+ event.condition_id;
218
+ event.reward;
219
+ });
220
+ ```
221
+
222
+ ### Alerts
223
+
224
+ Alerts use a separate client with per-event typed filters and payloads:
225
+
226
+ ```typescript
227
+ import { StructAlertsWebSocket } from "@structbuild/sdk";
228
+
229
+ const alerts = new StructAlertsWebSocket({ apiKey: "your-api-key" });
230
+ await alerts.connect();
231
+
232
+ await alerts.subscribe("trader_whale_trade", {
233
+ wallet_addresses: ["0xd91..."],
234
+ min_usd_value: 10000,
235
+ });
236
+
237
+ await alerts.subscribe("probability_spike", {
238
+ spike_direction: "up",
239
+ min_probability_change_pct: 5,
240
+ });
241
+
242
+ alerts.on("trader_whale_trade", (payload) => {
243
+ payload.data.trader;
244
+ payload.data.amount_usd;
245
+ });
246
+
247
+ alerts.on("probability_spike", (payload) => {
248
+ payload.data.spike_direction;
249
+ payload.data.spike_pct;
250
+ });
138
251
  ```
139
252
 
140
- Available payload types: `FirstTradePayload`, `GlobalPnlPayload`, `MarketPnlPayload`, `EventPnlPayload`, `PositionPnlPayload`, `ConditionMetricsPayload`, `EventMetricsPayload`, `PositionMetricsPayload`, `VolumeMilestonePayload`, `EventVolumeMilestonePayload`, `PositionVolumeMilestonePayload`, `ProbabilitySpikePayload`.
253
+ ### Available rooms
254
+
255
+ | Room | Filters | Event |
256
+ |------|---------|-------|
257
+ | `polymarket_trades` | `condition_ids` | `trade_stream_update` |
258
+ | `polymarket_asset_prices` | `condition_ids?` | `asset_price_tick`, `asset_price_window_update` |
259
+ | `polymarket_asset_window_updates` | `condition_ids` | `asset_window_update` |
260
+ | `polymarket_market_metrics` | `condition_ids` | `market_metrics_update` |
261
+ | `polymarket_event_metrics` | `event_slugs` | `event_metrics_update` |
262
+ | `polymarket_position_metrics` | `position_ids` | `position_metrics_update` |
263
+ | `polymarket_trader_pnl` | `addresses` | `trader_global_pnl_update`, `trader_market_pnl_update`, `trader_event_pnl_update` |
264
+ | `polymarket_trader_positions` | `addresses` | `trader_position_update` |
265
+ | `polymarket_accounts` | `wallets` | `accounts_update`, `usdce_update`, `matic_update` |
266
+ | `polymarket_order_book` | `asset_ids` | `order_book_update` |
267
+ | `polymarket_clob_rewards` | `condition_ids?`, `subscribe_all?` | `clob_rewards_update` |
268
+
269
+ ### Lifecycle events
270
+
271
+ ```typescript
272
+ ws.on("connected", () => {});
273
+ ws.on("disconnected", ({ code, reason }) => {});
274
+ ws.on("reconnecting", ({ attempt }) => {});
275
+ ws.on("reconnect_failed", (err) => {});
276
+ ws.on("auth_failed", (err) => {});
277
+ ws.on("warning", (warning) => {});
278
+ ws.on("error", (err) => {});
279
+ ```
280
+
281
+ ### Cleanup
282
+
283
+ ```typescript
284
+ ws.unsubscribe("polymarket_trades");
285
+ ws.disconnect();
286
+ ```
141
287
 
142
288
  ## JWT Auth
143
289
 
@@ -161,6 +307,15 @@ const ws = new StructWebSocket({
161
307
 
162
308
  The `pk_jwt_*` key is safe to hardcode in frontend bundles — it is useless without a valid JWT from your configured auth provider.
163
309
 
310
+ If your JWT can rotate while a socket stays alive, prefer `getJwt` so reconnects always rebuild the URL with a fresh token:
311
+
312
+ ```typescript
313
+ const ws = new StructWebSocket({
314
+ apiKey: "pk_jwt_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
315
+ getJwt: () => userAccessToken,
316
+ });
317
+ ```
318
+
164
319
  ## Pagination
165
320
 
166
321
  Use the `paginate` helper to iterate through all results:
@@ -184,7 +339,7 @@ for await (const market of paginate(
184
339
  import { HttpError, TimeoutError, NetworkError } from "@structbuild/sdk";
185
340
 
186
341
  try {
187
- await client.markets.getMarket({ condition_id: "0x..." });
342
+ await client.markets.getMarket({ conditionId: "0x..." });
188
343
  } catch (error) {
189
344
  if (error instanceof HttpError) {
190
345
  console.log(error.status, error.body);