JavaScript Examples
This page provides JavaScript examples using the nativefetch API for all major API operations.
Setup
Create a utility module for API requests:Copy
// ticksupply.js
const API_KEY = process.env.TICKSUPPLY_API_KEY;
const BASE_URL = "https://api.ticksupply.com";
async function apiRequest(method, path, options = {}) {
const headers = {
"X-Api-Key": API_KEY,
...options.headers
};
const response = await fetch(`${BASE_URL}${path}`, {
method,
headers,
...options
});
// Handle rate limiting
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "30");
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await sleep(retryAfter * 1000);
return apiRequest(method, path, options);
}
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.error.code} - ${error.error.message}`);
}
if (response.status === 204) {
return null;
}
return response.json();
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export { apiRequest, sleep };
Catalog operations
List exchanges
Copy
async function listExchanges() {
return apiRequest("GET", "/v1/exchanges");
}
// Usage
const exchanges = await listExchanges();
exchanges.forEach(exchange => {
console.log(`${exchange.code}: ${exchange.display_name}`);
});
List instruments
Copy
async function listInstruments(exchange, search = null, limit = null) {
const params = new URLSearchParams();
if (search) params.set("search", search);
if (limit) params.set("limit", limit);
const queryString = params.toString();
const path = `/v1/exchanges/${exchange}/instruments${queryString ? `?${queryString}` : ""}`;
return apiRequest("GET", path);
}
// Usage
const result = await listInstruments("binance", "BTC", 10);
result.items.forEach(pair => {
console.log(`${pair.symbol}: ${pair.base}/${pair.quote}`);
});
Get datastreams
Copy
async function getDatastreams(exchange, instrument, streamType) {
const params = new URLSearchParams({
exchange,
instrument,
stream_type: streamType
});
return apiRequest("GET", `/v1/datastreams?${params}`);
}
// Usage
const result = await getDatastreams("binance", "BTCUSDT", "trade");
result.items.forEach(ds => {
console.log(`Datastream ${ds.datastream_id}: ${ds.wire_format}`);
});
Subscription operations
Create a subscription
Copy
async function createSubscription(datastreamId, options = {}) {
const { idempotencyKey } = options;
const payload = { datastream_id: datastreamId };
const headers = { "Content-Type": "application/json" };
if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;
return apiRequest("POST", "/v1/subscriptions", {
headers,
body: JSON.stringify(payload)
});
}
// Usage
const subscription = await createSubscription(123, {
idempotencyKey: crypto.randomUUID()
});
console.log(`Created subscription: ${subscription.id}`);
console.log(`Status: ${subscription.status}`);
List subscriptions with pagination
Copy
async function* iterateSubscriptions(limit = 50) {
let pageToken = null;
while (true) {
const params = new URLSearchParams({ limit: String(limit) });
if (pageToken) params.set("page_token", pageToken);
const result = await apiRequest("GET", `/v1/subscriptions?${params}`);
for (const item of result.items) {
yield item;
}
pageToken = result.next_page_token;
if (!pageToken) break;
}
}
async function listAllSubscriptions() {
const subscriptions = [];
for await (const sub of iterateSubscriptions()) {
subscriptions.push(sub);
}
return subscriptions;
}
// Usage
const subscriptions = await listAllSubscriptions();
subscriptions.forEach(sub => {
console.log(`${sub.id}: ${sub.status}`);
});
Subscription lifecycle management
Copy
async function getSubscription(subscriptionId) {
return apiRequest("GET", `/v1/subscriptions/${subscriptionId}`);
}
async function pauseSubscription(subscriptionId) {
await apiRequest("POST", `/v1/subscriptions/${subscriptionId}/pause`);
console.log(`Paused subscription: ${subscriptionId}`);
}
async function resumeSubscription(subscriptionId) {
await apiRequest("POST", `/v1/subscriptions/${subscriptionId}/resume`);
console.log(`Resumed subscription: ${subscriptionId}`);
}
async function deleteSubscription(subscriptionId, idempotencyKey = null) {
const headers = {};
if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;
await apiRequest("DELETE", `/v1/subscriptions/${subscriptionId}`, { headers });
console.log(`Deleted subscription: ${subscriptionId}`);
}
async function getSubscriptionSpans(subscriptionId) {
return apiRequest("GET", `/v1/subscriptions/${subscriptionId}/spans`);
}
// Usage
const subId = "sub_550e8400e29b41d4a716446655440000";
const sub = await getSubscription(subId);
console.log(`Status: ${sub.status}`);
await pauseSubscription(subId);
const spans = await getSubscriptionSpans(subId);
spans.forEach(span => {
console.log(`Span: ${span.started_at} - ${span.ended_at || "ongoing"}`);
});
await resumeSubscription(subId);
Export operations
Create an export
Copy
async function createExport(datastreamId, startTimeNs, endTimeNs, idempotencyKey = null) {
const payload = {
datastream_id: datastreamId,
start_time: String(startTimeNs),
end_time: String(endTimeNs)
};
const headers = { "Content-Type": "application/json" };
if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;
return apiRequest("POST", "/v1/exports", {
headers,
body: JSON.stringify(payload)
});
}
// Usage - export last 24 hours
const nowNs = BigInt(Date.now()) * 1_000_000n;
const dayAgoNs = nowNs - (86400n * 1_000_000_000n);
const exportJob = await createExport(
123,
dayAgoNs,
nowNs,
crypto.randomUUID()
);
console.log(`Created export: ${exportJob.id}`);
Wait for export completion
Copy
async function waitForExport(exportId, pollInterval = 5000, timeout = 300000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const result = await apiRequest("GET", `/v1/exports/${exportId}`);
const status = result.status;
console.log(`Status: ${status}`);
if (status === "succeeded") {
return result;
} else if (status === "failed") {
throw new Error(`Export failed: ${result.reason || "Unknown error"}`);
}
await sleep(pollInterval);
}
throw new Error(`Export did not complete within ${timeout}ms`);
}
// Usage
const completedExport = await waitForExport(exportJob.id);
console.log(`Export completed at: ${completedExport.finished_at}`);
Download export
Copy
import { writeFile } from "fs/promises";
async function downloadExport(exportId, outputDir = ".") {
// Get presigned URLs for all artifacts
const result = await apiRequest("GET", `/v1/exports/${exportId}/download`);
console.log(`Downloading ${result.count} file(s), ${result.total_bytes.toLocaleString()} bytes total...`);
const downloadedFiles = [];
for (const artifact of result.artifacts) {
const outputPath = `${outputDir}/${artifact.filename}`;
console.log(` Downloading ${artifact.filename} (${artifact.bytes.toLocaleString()} bytes)...`);
const response = await fetch(artifact.url);
if (!response.ok) {
throw new Error(`Download failed: ${response.status}`);
}
const buffer = await response.arrayBuffer();
await writeFile(outputPath, Buffer.from(buffer));
downloadedFiles.push(outputPath);
}
console.log(`Downloaded ${downloadedFiles.length} file(s)`);
return downloadedFiles;
}
// Usage
const files = await downloadExport(exportJob.id, "./exports");
Availability
Check data availability
Copy
async function getAvailability(datastreamId) {
const params = new URLSearchParams({ datastream_id: String(datastreamId) });
return apiRequest("GET", `/v1/availability?${params}`);
}
// Usage
const availability = await getAvailability(123);
console.log(`Datastream ID: ${availability.datastream.datastream_id}`);
console.log(`Last updated: ${availability.updated_at}`);
availability.ranges.forEach(range => {
console.log(` ${range.from} - ${range.to}: ~${range.rows_estimate.toLocaleString()} rows`);
});
Complete workflow example
Copy
// complete-example.js
import { writeFile } from "fs/promises";
const API_KEY = process.env.TICKSUPPLY_API_KEY;
const BASE_URL = "https://api.ticksupply.com";
async function apiRequest(method, path, options = {}) {
const headers = { "X-Api-Key": API_KEY, ...options.headers };
const response = await fetch(`${BASE_URL}${path}`, { method, headers, ...options });
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "30");
await new Promise(r => setTimeout(r, retryAfter * 1000));
return apiRequest(method, path, options);
}
if (!response.ok) {
const error = await response.json();
throw new Error(`${error.error.code}: ${error.error.message}`);
}
return response.status === 204 ? null : response.json();
}
async function main() {
// 1. Find BTCUSDT trade datastream
console.log("Finding BTCUSDT trade datastream...");
const datastreamResult = await apiRequest("GET",
"/v1/datastreams?exchange=binance&instrument=BTCUSDT&stream_type=trade"
);
const datastreamId = datastreamResult.items[0].datastream_id;
console.log(`Found datastream ID: ${datastreamId}`);
// 2. Create subscription
console.log("Creating subscription...");
const subscription = await apiRequest("POST", "/v1/subscriptions", {
headers: {
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({ datastream_id: datastreamId })
});
console.log(`Subscription created: ${subscription.id}`);
// 3. Wait for data collection
console.log("Waiting 60 seconds for data collection...");
await new Promise(r => setTimeout(r, 60000));
// 4. Create export
const nowNs = BigInt(Date.now()) * 1_000_000n;
const hourAgoNs = nowNs - (3600n * 1_000_000_000n);
console.log("Creating export...");
const exportJob = await apiRequest("POST", "/v1/exports", {
headers: {
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
datastream_id: datastreamId,
start_time: String(hourAgoNs),
end_time: String(nowNs)
})
});
console.log(`Export created: ${exportJob.id}`);
// 5. Wait for completion
console.log("Waiting for export to complete...");
while (true) {
const status = (await apiRequest("GET", `/v1/exports/${exportJob.id}`)).status;
console.log(`Status: ${status}`);
if (status === "succeeded") break;
if (status === "failed") throw new Error("Export failed!");
await new Promise(r => setTimeout(r, 5000));
}
// 6. Download all artifacts
console.log("Downloading...");
const downloadResult = await apiRequest("GET", `/v1/exports/${exportJob.id}/download`);
for (const artifact of downloadResult.artifacts) {
console.log(` Downloading ${artifact.filename}...`);
const downloadResponse = await fetch(artifact.url);
const buffer = await downloadResponse.arrayBuffer();
await writeFile(artifact.filename, Buffer.from(buffer));
}
console.log(`Downloaded ${downloadResult.count} file(s)`);
}
main().catch(console.error);
Copy
TICKSUPPLY_API_KEY=your_key node complete-example.js