@0xarchive/sdk 0.9.1 → 1.2.0

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
@@ -4,7 +4,7 @@ Official TypeScript/JavaScript SDK for [0xarchive](https://0xarchive.io) - Histo
4
4
 
5
5
  Supports multiple exchanges:
6
6
  - **Hyperliquid** - Perpetuals data from April 2023
7
- - **Hyperliquid HIP-3** - Builder-deployed perpetuals (Pro+ only, February 2026+)
7
+ - **Hyperliquid HIP-3** - Builder-deployed perpetuals (February 2026+, free tier: km:US500, Build+: all symbols, Pro+: orderbook history)
8
8
  - **Lighter.xyz** - Perpetuals data (August 2025+ for fills, Jan 2026+ for OB, OI, Funding Rate)
9
9
 
10
10
  ## Installation
@@ -60,7 +60,7 @@ const client = new OxArchive({
60
60
 
61
61
  ## REST API Reference
62
62
 
63
- All examples use `client.hyperliquid.*` but the same methods are available on `client.lighter.*` for Lighter.xyz data.
63
+ Core resources (orderbook, trades, instruments, funding, openInterest, candles, freshness, summary, priceHistory) are available on both `client.hyperliquid.*` and `client.lighter.*`. Some resources are exchange-specific -- see each section for details.
64
64
 
65
65
  ### Order Book
66
66
 
@@ -232,7 +232,7 @@ while (result.nextCursor) {
232
232
  const recent = await client.lighter.trades.recent('BTC', 100);
233
233
  ```
234
234
 
235
- **Note:** The `recent()` method is only available for Lighter.xyz (`client.lighter.trades.recent()`). Hyperliquid does not have a recent trades endpoint - use `list()` with a time range instead.
235
+ **Note:** The `recent()` method is available for Lighter.xyz (`client.lighter.trades.recent()`) and HIP-3 (`client.hyperliquid.hip3.trades.recent()`). Hyperliquid does not have a recent trades endpoint -- use `list()` with a time range instead.
236
236
 
237
237
  ### Instruments
238
238
 
@@ -353,12 +353,12 @@ const hourly = await client.hyperliquid.openInterest.history('BTC', {
353
353
  | `limit` | `number` | No | Max results (default: 100, max: 1000) |
354
354
  | `interval` | `OiFundingInterval` | No | Aggregation interval: `'5m'`, `'15m'`, `'30m'`, `'1h'`, `'4h'`, `'1d'`. When omitted, raw ~1 min data is returned. |
355
355
 
356
- ### Liquidations (Hyperliquid only)
356
+ ### Liquidations
357
357
 
358
- Get historical liquidation events. Data available from May 2025 onwards.
358
+ Get historical liquidation events. Data available from May 2025 onwards for Hyperliquid, and from February 2026 for HIP-3.
359
359
 
360
360
  ```typescript
361
- // Get liquidation history for a coin
361
+ // Get liquidation history for a coin (Hyperliquid)
362
362
  const liquidations = await client.hyperliquid.liquidations.history('BTC', {
363
363
  start: Date.now() - 86400000,
364
364
  end: Date.now(),
@@ -383,14 +383,21 @@ const userLiquidations = await client.hyperliquid.liquidations.byUser('0x1234...
383
383
  end: Date.now(),
384
384
  coin: 'BTC' // optional filter
385
385
  });
386
+
387
+ // HIP-3 liquidations (case-sensitive coins)
388
+ const hip3Liquidations = await client.hyperliquid.hip3.liquidations.history('km:US500', {
389
+ start: Date.now() - 86400000,
390
+ end: Date.now(),
391
+ limit: 100
392
+ });
386
393
  ```
387
394
 
388
- ### Liquidation Volume (Hyperliquid only)
395
+ ### Liquidation Volume
389
396
 
390
397
  Get pre-aggregated liquidation volume in time-bucketed intervals. Returns total, long, and short USD volumes per bucket -- 100-1000x less data than individual liquidation records.
391
398
 
392
399
  ```typescript
393
- // Get hourly liquidation volume for the last week
400
+ // Get hourly liquidation volume for the last week (Hyperliquid)
394
401
  const volume = await client.hyperliquid.liquidations.volume('BTC', {
395
402
  start: Date.now() - 86400000 * 7,
396
403
  end: Date.now(),
@@ -400,11 +407,170 @@ const volume = await client.hyperliquid.liquidations.volume('BTC', {
400
407
  for (const bucket of volume.data) {
401
408
  console.log(`${bucket.timestamp}: total=$${bucket.totalUsd}, long=$${bucket.longUsd}, short=$${bucket.shortUsd}`);
402
409
  }
410
+
411
+ // HIP-3 liquidation volume (case-sensitive coins)
412
+ const hip3Volume = await client.hyperliquid.hip3.liquidations.volume('km:US500', {
413
+ start: Date.now() - 86400000 * 7,
414
+ end: Date.now(),
415
+ interval: '1h'
416
+ });
417
+ ```
418
+
419
+ ### Orders
420
+
421
+ Access order history, order flow aggregations, and TP/SL (take-profit/stop-loss) orders. Available for Hyperliquid and HIP-3.
422
+
423
+ ```typescript
424
+ // Get order history for a coin
425
+ const orders = await client.hyperliquid.orders.history('BTC', {
426
+ start: Date.now() - 86400000,
427
+ end: Date.now(),
428
+ limit: 1000,
429
+ user: '0x1234...', // optional: filter by user address
430
+ status: 'filled', // optional: filter by status
431
+ order_type: 'limit', // optional: filter by order type
432
+ });
433
+
434
+ // Paginate through all results
435
+ const allOrders = [...orders.data];
436
+ while (orders.nextCursor) {
437
+ const next = await client.hyperliquid.orders.history('BTC', {
438
+ start: Date.now() - 86400000,
439
+ end: Date.now(),
440
+ cursor: orders.nextCursor,
441
+ limit: 1000
442
+ });
443
+ allOrders.push(...next.data);
444
+ }
445
+
446
+ // Get order flow (aggregated order activity over time)
447
+ const flow = await client.hyperliquid.orders.flow('BTC', {
448
+ start: Date.now() - 86400000,
449
+ end: Date.now(),
450
+ interval: '1h', // optional aggregation interval
451
+ limit: 100
452
+ });
453
+
454
+ // Get TP/SL orders
455
+ const tpsl = await client.hyperliquid.orders.tpsl('BTC', {
456
+ start: Date.now() - 86400000,
457
+ end: Date.now(),
458
+ user: '0x1234...', // optional: filter by user
459
+ triggered: true, // optional: filter by triggered status
460
+ });
461
+
462
+ // HIP-3 orders (case-sensitive coins)
463
+ const hip3Orders = await client.hyperliquid.hip3.orders.history('km:US500', {
464
+ start: Date.now() - 86400000,
465
+ end: Date.now(),
466
+ limit: 1000
467
+ });
468
+
469
+ const hip3Flow = await client.hyperliquid.hip3.orders.flow('km:US500', {
470
+ start: Date.now() - 86400000,
471
+ end: Date.now(),
472
+ interval: '1h'
473
+ });
474
+
475
+ const hip3Tpsl = await client.hyperliquid.hip3.orders.tpsl('km:US500', {
476
+ start: Date.now() - 86400000,
477
+ end: Date.now()
478
+ });
479
+ ```
480
+
481
+ ### L4 Order Book
482
+
483
+ Access L4 orderbook snapshots, diffs, and history. L4 data includes user attribution (who placed each order). Available for Hyperliquid and HIP-3.
484
+
485
+ ```typescript
486
+ // Get current L4 orderbook snapshot
487
+ const l4Ob = await client.hyperliquid.l4Orderbook.get('BTC');
488
+
489
+ // Get L4 orderbook at a specific timestamp with custom depth
490
+ const l4Historical = await client.hyperliquid.l4Orderbook.get('BTC', {
491
+ timestamp: 1704067200000,
492
+ depth: 20
493
+ });
494
+
495
+ // Get L4 orderbook diffs (incremental updates)
496
+ const diffs = await client.hyperliquid.l4Orderbook.diffs('BTC', {
497
+ start: Date.now() - 3600000,
498
+ end: Date.now(),
499
+ limit: 1000
500
+ });
501
+
502
+ // Paginate through diffs
503
+ const allDiffs = [...diffs.data];
504
+ while (diffs.nextCursor) {
505
+ const next = await client.hyperliquid.l4Orderbook.diffs('BTC', {
506
+ start: Date.now() - 3600000,
507
+ end: Date.now(),
508
+ cursor: diffs.nextCursor,
509
+ limit: 1000
510
+ });
511
+ allDiffs.push(...next.data);
512
+ }
513
+
514
+ // Get L4 orderbook history (full snapshots over time)
515
+ const l4History = await client.hyperliquid.l4Orderbook.history('BTC', {
516
+ start: Date.now() - 86400000,
517
+ end: Date.now(),
518
+ limit: 1000
519
+ });
520
+
521
+ // HIP-3 L4 orderbook (case-sensitive coins)
522
+ const hip3L4 = await client.hyperliquid.hip3.l4Orderbook.get('km:US500');
523
+
524
+ const hip3L4Diffs = await client.hyperliquid.hip3.l4Orderbook.diffs('km:US500', {
525
+ start: Date.now() - 3600000,
526
+ end: Date.now(),
527
+ limit: 1000
528
+ });
529
+
530
+ const hip3L4History = await client.hyperliquid.hip3.l4Orderbook.history('km:US500', {
531
+ start: Date.now() - 86400000,
532
+ end: Date.now(),
533
+ limit: 1000
534
+ });
403
535
  ```
404
536
 
405
- ### Freshness (Hyperliquid only)
537
+ ### L3 Order Book (Lighter only)
406
538
 
407
- Check when each data type was last updated for a specific coin. Useful for verifying data recency before pulling it.
539
+ Access L3 orderbook snapshots and history from Lighter.xyz. L3 data includes individual order-level detail.
540
+
541
+ ```typescript
542
+ // Get current L3 orderbook
543
+ const l3Ob = await client.lighter.l3Orderbook.get('BTC');
544
+
545
+ // Get L3 orderbook at a specific timestamp with custom depth
546
+ const l3Historical = await client.lighter.l3Orderbook.get('BTC', {
547
+ timestamp: 1704067200000,
548
+ depth: 20
549
+ });
550
+
551
+ // Get L3 orderbook history
552
+ const l3History = await client.lighter.l3Orderbook.history('BTC', {
553
+ start: Date.now() - 86400000,
554
+ end: Date.now(),
555
+ limit: 1000
556
+ });
557
+
558
+ // Paginate through L3 history
559
+ const allL3 = [...l3History.data];
560
+ while (l3History.nextCursor) {
561
+ const next = await client.lighter.l3Orderbook.history('BTC', {
562
+ start: Date.now() - 86400000,
563
+ end: Date.now(),
564
+ cursor: l3History.nextCursor,
565
+ limit: 1000
566
+ });
567
+ allL3.push(...next.data);
568
+ }
569
+ ```
570
+
571
+ ### Freshness
572
+
573
+ Check when each data type was last updated for a specific coin. Useful for verifying data recency before pulling it. Available for all exchanges.
408
574
 
409
575
  ```typescript
410
576
  // Hyperliquid
@@ -636,6 +802,110 @@ const client = new OxArchive({
636
802
  });
637
803
  ```
638
804
 
805
+ ### Web3 Authentication
806
+
807
+ Get API keys programmatically using an Ethereum wallet — no browser or email required.
808
+
809
+ #### Free Tier (SIWE)
810
+
811
+ ```typescript
812
+ import { createWalletClient, http } from 'viem';
813
+ import { privateKeyToAccount } from 'viem/accounts';
814
+ import { mainnet } from 'viem/chains';
815
+
816
+ const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY');
817
+ const walletClient = createWalletClient({ account, chain: mainnet, transport: http() });
818
+
819
+ // 1. Get SIWE challenge
820
+ const challenge = await client.web3.challenge(account.address);
821
+
822
+ // 2. Sign with personal_sign (EIP-191)
823
+ const signature = await walletClient.signMessage({ message: challenge.message });
824
+
825
+ // 3. Submit → receive API key
826
+ const result = await client.web3.signup(challenge.message, signature);
827
+ console.log(result.apiKey); // "0xa_..."
828
+ ```
829
+
830
+ #### Paid Tier (x402 USDC on Base)
831
+
832
+ ```typescript
833
+ import { createWalletClient, http, encodePacked } from 'viem';
834
+ import { privateKeyToAccount } from 'viem/accounts';
835
+ import { base } from 'viem/chains';
836
+ import crypto from 'crypto';
837
+
838
+ const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY');
839
+ const walletClient = createWalletClient({ account, chain: base, transport: http() });
840
+
841
+ const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
842
+
843
+ // 1. Get pricing
844
+ const quote = await client.web3.subscribeQuote('build');
845
+ // quote.amount = "49000000" ($49 USDC), quote.payTo = "0x..."
846
+
847
+ // 2. Build & sign EIP-3009 transferWithAuthorization
848
+ const nonce = `0x${crypto.randomBytes(32).toString('hex')}` as `0x${string}`;
849
+ const validAfter = 0n;
850
+ const validBefore = BigInt(Math.floor(Date.now() / 1000) + 3600);
851
+
852
+ const signature = await walletClient.signTypedData({
853
+ domain: {
854
+ name: 'USD Coin',
855
+ version: '2',
856
+ chainId: 8453,
857
+ verifyingContract: USDC_ADDRESS,
858
+ },
859
+ types: {
860
+ TransferWithAuthorization: [
861
+ { name: 'from', type: 'address' },
862
+ { name: 'to', type: 'address' },
863
+ { name: 'value', type: 'uint256' },
864
+ { name: 'validAfter', type: 'uint256' },
865
+ { name: 'validBefore', type: 'uint256' },
866
+ { name: 'nonce', type: 'bytes32' },
867
+ ],
868
+ },
869
+ primaryType: 'TransferWithAuthorization',
870
+ message: {
871
+ from: account.address,
872
+ to: quote.payTo as `0x${string}`,
873
+ value: BigInt(quote.amount),
874
+ validAfter,
875
+ validBefore,
876
+ nonce,
877
+ },
878
+ });
879
+
880
+ // 3. Build x402 payment envelope and base64-encode
881
+ const paymentPayload = btoa(JSON.stringify({
882
+ x402Version: 2,
883
+ payload: {
884
+ signature,
885
+ authorization: {
886
+ from: account.address,
887
+ to: quote.payTo,
888
+ value: quote.amount,
889
+ validAfter: '0',
890
+ validBefore: validBefore.toString(),
891
+ nonce,
892
+ },
893
+ },
894
+ }));
895
+
896
+ // 4. Submit payment → receive API key + subscription
897
+ const sub = await client.web3.subscribe('build', paymentPayload);
898
+ console.log(sub.apiKey, sub.tier, sub.expiresAt);
899
+ ```
900
+
901
+ #### Key Management
902
+
903
+ ```typescript
904
+ // List and revoke keys (requires a fresh SIWE signature)
905
+ const keys = await client.web3.listKeys(challenge.message, signature);
906
+ await client.web3.revokeKey(challenge.message, signature, keys.keys[0].id);
907
+ ```
908
+
639
909
  ### Legacy API (Deprecated)
640
910
 
641
911
  The following legacy methods are deprecated and will be removed in v2.0. They default to Hyperliquid data:
@@ -650,7 +920,7 @@ const trades = await client.trades.list('BTC', { start, end });
650
920
 
651
921
  ## WebSocket Client
652
922
 
653
- The WebSocket client supports three modes: real-time streaming, historical replay, and bulk streaming.
923
+ The WebSocket client supports two modes: real-time streaming and historical replay. For bulk data downloads, use the S3 Parquet bulk export via the [Data Explorer](https://0xarchive.io/data).
654
924
 
655
925
  ```typescript
656
926
  import { OxArchiveWs } from '@0xarchive/sdk';
@@ -744,53 +1014,12 @@ ws.replaySeek(1704067200000); // Jump to timestamp
744
1014
  ws.replayStop();
745
1015
  ```
746
1016
 
747
- ### Bulk Streaming
748
-
749
- Fast bulk download for data pipelines. Data arrives in batches without timing delays.
750
-
751
- ```typescript
752
- const ws = new OxArchiveWs({ apiKey: 'ox_...' });
753
- ws.connect();
754
-
755
- const allData: OrderBook[] = [];
756
-
757
- // Handle batched data
758
- ws.onBatch((coin, records) => {
759
- allData.push(...records.map(r => r.data));
760
- });
761
-
762
- ws.onStreamProgress((snapshotsSent) => {
763
- console.log(`Progress: ${snapshotsSent} snapshots`);
764
- });
765
-
766
- ws.onStreamComplete((channel, coin, recordsSent) => {
767
- console.log(`Downloaded ${recordsSent} records`);
768
- });
769
-
770
- // Start bulk stream
771
- ws.stream('orderbook', 'ETH', {
772
- start: Date.now() - 3600000, // 1 hour ago
773
- end: Date.now(),
774
- batchSize: 1000 // Optional, defaults to 1000
775
- });
776
-
777
- // Lighter.xyz stream with granularity (tier restrictions apply)
778
- ws.stream('orderbook', 'BTC', {
779
- start: Date.now() - 3600000,
780
- end: Date.now(),
781
- granularity: '10s' // Options: 'checkpoint', '30s', '10s', '1s', 'tick'
782
- });
783
-
784
- // Stop if needed
785
- ws.streamStop();
786
- ```
787
-
788
1017
  ### Gap Detection
789
1018
 
790
- During historical replay and bulk streaming, the server automatically detects gaps in the data and notifies the client. This helps identify periods where data may be missing.
1019
+ During historical replay, the server automatically detects gaps in the data and notifies the client. This helps identify periods where data may be missing.
791
1020
 
792
1021
  ```typescript
793
- // Handle gap notifications during replay/stream
1022
+ // Handle gap notifications during replay
794
1023
  ws.onGap((channel, coin, gapStart, gapEnd, durationMinutes) => {
795
1024
  console.log(`Gap detected in ${channel}/${coin}:`);
796
1025
  console.log(` From: ${new Date(gapStart).toISOString()}`);
@@ -831,8 +1060,8 @@ const ws = new OxArchiveWs({
831
1060
  |---------|-------------|---------------|-------------------|
832
1061
  | `orderbook` | L2 order book updates | Yes | Yes |
833
1062
  | `trades` | Trade/fill updates | Yes | Yes |
834
- | `candles` | OHLCV candle data | Yes | Yes (replay/stream only) |
835
- | `liquidations` | Liquidation events (May 2025+) | Yes | Yes (replay/stream only) |
1063
+ | `candles` | OHLCV candle data | Yes | Yes (replay only) |
1064
+ | `liquidations` | Liquidation events (May 2025+) | Yes | Yes (replay only) |
836
1065
  | `open_interest` | Open interest snapshots | Yes | Replay/stream only |
837
1066
  | `funding` | Funding rate snapshots | Yes | Replay/stream only |
838
1067
  | `ticker` | Price and 24h volume | Yes | Real-time only |
@@ -847,6 +1076,7 @@ const ws = new OxArchiveWs({
847
1076
  | `hip3_candles` | HIP-3 OHLCV candle data | Yes | Yes |
848
1077
  | `hip3_open_interest` | HIP-3 open interest snapshots | Yes | Replay/stream only |
849
1078
  | `hip3_funding` | HIP-3 funding rate snapshots | Yes | Replay/stream only |
1079
+ | `hip3_liquidations` | HIP-3 liquidation events (Feb 2026+) | Yes | Yes (replay only) |
850
1080
 
851
1081
  > **Note:** HIP-3 coins are case-sensitive (e.g., `km:US500`, `xyz:XYZ100`). Do not uppercase them.
852
1082
 
@@ -859,6 +1089,7 @@ const ws = new OxArchiveWs({
859
1089
  | `lighter_candles` | Lighter OHLCV candle data | Yes | Yes |
860
1090
  | `lighter_open_interest` | Lighter open interest snapshots | Yes | Replay/stream only |
861
1091
  | `lighter_funding` | Lighter funding rate snapshots | Yes | Replay/stream only |
1092
+ | `lighter_l3_orderbook` | Lighter L3 order-level orderbook (Pro+) | Yes | Yes |
862
1093
 
863
1094
  #### Candle Replay/Stream
864
1095
 
@@ -871,14 +1102,6 @@ ws.replay('candles', 'BTC', {
871
1102
  interval: '15m' // 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w
872
1103
  });
873
1104
 
874
- // Bulk stream candles
875
- ws.stream('candles', 'ETH', {
876
- start: Date.now() - 3600000,
877
- end: Date.now(),
878
- batchSize: 1000,
879
- interval: '1h'
880
- });
881
-
882
1105
  // Lighter.xyz candles
883
1106
  ws.replay('lighter_candles', 'BTC', {
884
1107
  start: Date.now() - 86400000,
@@ -887,7 +1110,7 @@ ws.replay('lighter_candles', 'BTC', {
887
1110
  });
888
1111
  ```
889
1112
 
890
- #### HIP-3 Replay/Stream
1113
+ #### HIP-3 Replay
891
1114
 
892
1115
  ```typescript
893
1116
  // Replay HIP-3 orderbook at 50x speed
@@ -897,13 +1120,6 @@ ws.replay('hip3_orderbook', 'km:US500', {
897
1120
  speed: 50,
898
1121
  });
899
1122
 
900
- // Bulk stream HIP-3 trades
901
- ws.stream('hip3_trades', 'xyz:XYZ100', {
902
- start: Date.now() - 86400000,
903
- end: Date.now(),
904
- batchSize: 1000,
905
- });
906
-
907
1123
  // HIP-3 candles
908
1124
  ws.replay('hip3_candles', 'km:US500', {
909
1125
  start: Date.now() - 86400000,
@@ -958,42 +1174,7 @@ ws.replaySeek(1704067200000);
958
1174
  ws.replayStop();
959
1175
  ```
960
1176
 
961
- ### Multi-Channel Bulk Stream
962
-
963
- Stream multiple channels simultaneously for fast bulk download.
964
-
965
- ```typescript
966
- const ws = new OxArchiveWs({ apiKey: 'ox_...' });
967
- await ws.connect();
968
-
969
- // Handle initial snapshots
970
- ws.onReplaySnapshot((channel, coin, timestamp, data) => {
971
- console.log(`Initial ${channel} snapshot`);
972
- });
973
-
974
- // Handle batched data from all channels
975
- ws.onBatch((coin, records) => {
976
- for (const record of records) {
977
- // Process interleaved data from all channels
978
- }
979
- });
980
-
981
- ws.onStreamComplete((channel, coin, count) => {
982
- console.log(`Stream complete: ${count} records`);
983
- });
984
-
985
- // Start multi-channel stream
986
- ws.multiStream(['orderbook', 'trades', 'open_interest', 'funding'], 'ETH', {
987
- start: Date.now() - 3600000,
988
- end: Date.now(),
989
- batchSize: 1000
990
- });
991
-
992
- // Stop if needed
993
- ws.streamStop();
994
- ```
995
-
996
- **Channels available for multi-channel mode:** All historical channels can be combined in a single multi-channel replay or stream. This includes `orderbook`, `trades`, `candles`, `liquidations`, `open_interest`, `funding`, and their `lighter_*` and `hip3_*` variants.
1177
+ **Channels available for multi-channel replay:** All historical channels can be combined in a single multi-channel replay. This includes `orderbook`, `trades`, `candles`, `liquidations`, `open_interest`, `funding`, and their `lighter_*` and `hip3_*` variants.
997
1178
 
998
1179
  ### WebSocket Connection States
999
1180
 
@@ -1008,18 +1189,18 @@ The SDK accepts timestamps as Unix milliseconds or Date objects:
1008
1189
 
1009
1190
  ```typescript
1010
1191
  // Unix milliseconds (recommended)
1011
- client.orderbook.history('BTC', {
1192
+ client.hyperliquid.orderbook.history('BTC', {
1012
1193
  start: Date.now() - 86400000,
1013
1194
  end: Date.now()
1014
1195
  });
1015
1196
 
1016
1197
  // Date objects (converted automatically)
1017
- client.orderbook.history('BTC', {
1198
+ client.hyperliquid.orderbook.history('BTC', {
1018
1199
  start: new Date('2024-01-01'),
1019
1200
  end: new Date('2024-01-02')
1020
1201
  });
1021
1202
 
1022
- // WebSocket replay/stream also accepts both
1203
+ // WebSocket replay also accepts both
1023
1204
  ws.replay('orderbook', 'BTC', {
1024
1205
  start: Date.now() - 3600000,
1025
1206
  end: Date.now(),
@@ -1094,6 +1275,10 @@ const client = new OxArchive({
1094
1275
 
1095
1276
  When enabled, responses are validated against Zod schemas and throw `OxArchiveError` with status 422 if validation fails.
1096
1277
 
1278
+ ## Bulk Data Downloads
1279
+
1280
+ For large-scale data exports (full order books, complete trade history, etc.), use the S3 Parquet bulk export available at [0xarchive.io/data](https://0xarchive.io/data). The Data Explorer lets you select time ranges, symbols, and data types, then download compressed Parquet files directly.
1281
+
1097
1282
  ## Requirements
1098
1283
 
1099
1284
  - Node.js 18+ or modern browsers with `fetch` and `WebSocket` support