Skip to main content

Client

The Market Data JavaScript Client handles API requests, response parsing, rate-limit tracking, retries, and logging. The SDK supports stocks, options, funds, markets, and utility endpoints.

Get Started Quickly with the MarketDataClient

  1. Review the documentation on authentication to learn how to set your API token.
  2. Create a MarketDataClient instance and use it to make requests to the Market Data API.
  3. Make a test request and review the console output. The SDK includes logging capabilities to help you debug requests.
  4. Check the rate limit in the client to track credit usage and how many API credits remain.
  5. Configure Settings to customize output format, date format, and other universal parameters.

MarketDataClient

class MarketDataClient {
constructor(config?: MarketDataConfig);
readonly ready: Promise<void>;
}

interface MarketDataConfig {
token?: string;
baseUrl?: string;
apiVersion?: string;
maxRetries?: number;
retryInitialWait?: number;
retryMaxWait?: number;
retryFactor?: number;
skipStartupValidation?: boolean;
debug?: boolean;
logger?: Logger;
}

MarketDataClient is the main client class for interacting with the Market Data API. It provides access to all resources (stocks, options, funds, markets, utilities) and handles authentication, rate limiting, and request management.

Properties

  • token (string, optional): The authentication token for API requests. See authentication documentation for details.
  • rateLimits (UserRateLimits, optional): Current rate limit information. Populated by the startup /user/ call (see ready below) or by the first successful API request when startup validation is skipped.
  • ready (Promise<void>): Resolves when the eager /user/ validation completes. Rejects with AuthenticationError on bad tokens; transient errors are logged and swallowed. Await it if you need the fail-fast behaviour on construction.
  • baseUrl (string): The base URL for API requests (default: https://api.marketdata.app).
  • apiVersion (string): The API version to use (default: v1).
  • headers (Record<string, string>): HTTP headers including Authorization and User-Agent.
  • logger (Logger): The logger instance used for diagnostic output.
  • settings (MarketDataSettings): Resolved configuration including env-var defaults. See Settings for details.

Resources

  • stocks (StocksResource): Access to stocks endpoints (prices, quotes, candles, earnings, news)
  • options (OptionsResource): Access to options endpoints (chain, expirations, quotes, lookup)
  • funds (FundsResource): Access to funds endpoints (candles)
  • markets (MarketsResource): Access to markets endpoints (status)
  • utilities (UtilitiesResource): Access to utility endpoints (status, headers)

constructor

new MarketDataClient(config?: MarketDataConfig)

Creates and configures a new MarketDataClient instance. This initializes the client with the provided token (or reads it from the MARKETDATA_TOKEN environment variable), sets up HTTP headers, prepares the resource namespaces, and kicks off eager /user/ validation (unless skipStartupValidation: true).

Parameters

  • config (MarketDataConfig, optional)

    Configuration object. All properties are optional:

    • token (string): The authentication token. Falls back to MARKETDATA_TOKEN environment variable if not provided.
    • baseUrl (string): Override the API base URL. Defaults to https://api.marketdata.app.
    • apiVersion (string): Override the API version. Defaults to v1.
    • maxRetries (number): Maximum retry attempts for retriable errors. Defaults to 3.
    • retryInitialWait (number): Initial wait in seconds before the first retry. Defaults to 0.5.
    • retryMaxWait (number): Maximum wait in seconds between retries. Defaults to 10.
    • retryFactor (number): Exponential backoff factor. Defaults to 2.
    • skipStartupValidation (boolean): If true, skips the eager /user/ call the constructor makes to validate the token. Defaults to false. Use on serverless platforms where cold-start latency matters.
    • debug (boolean): If true, sets the default logger level to DEBUG. Defaults to false.
    • logger (Logger): A custom logger instance. If omitted, the SDK uses its built-in DefaultLogger.

Returns

  • MarketDataClient

    A new MarketDataClient instance ready to make API requests.

Notes

  • The client sets a User-Agent header of the form marketdata-sdk-js/{version} (e.g. marketdata-sdk-js/1.0.0).
  • All authenticated requests include an Authorization: Bearer {token} header.
  • The client reuses a single underlying fetch client, which benefits from Node's global connection pooling, and enforces a global 50-request concurrency pool across every endpoint.
  • Every request has a 99-second timeout; a timed-out fetch rejects with NetworkError.
  • Configuration properties can also be provided via environment variables — see Settings for the full list and their resolution order.

Example

import { MarketDataClient } from "@marketdata/sdk";

// Token will be read from MARKETDATA_TOKEN environment variable
const client = new MarketDataClient();

// Or provide the token explicitly
const clientWithToken = new MarketDataClient({ token: "your_token_here" });

// Fail fast on invalid tokens (default) — await readiness:
await client.ready;

// Skip the startup /user/ call (e.g. on Lambda cold starts)
const fast = new MarketDataClient({
token: "your_token_here",
skipStartupValidation: true,
});

// Enable debug logging for troubleshooting
const debugClient = new MarketDataClient({ debug: true });

// Provide a custom logger
import { DefaultLogger, LogLevel } from "@marketdata/sdk";
const logger = new DefaultLogger(LogLevel.WARN);
const quietClient = new MarketDataClient({ logger });

Error Handling

Resource methods return a MarketDataPromise<T> that resolves with the data on success and rejects with a subclass of MarketDataClientError on failure. Use standard JavaScript error-handling idioms.

The idiomatic approach.

import {
MarketDataClient,
AuthenticationError,
RateLimitError,
NotFoundError,
} from "@marketdata/sdk";

const client = new MarketDataClient();

try {
const prices = await client.stocks.prices("AAPL");
console.log("Success:", prices);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error("Bad token:", error.message);
} else if (error instanceof RateLimitError) {
console.error("Rate limit exceeded");
} else {
console.error("Failed:", error);
}
}

Every thrown error is a subclass of MarketDataClientError and carries HTTP context for support tickets:

try {
await client.stocks.prices("$$$");
} catch (err) {
// Base class — use `instanceof` to narrow to specific errors.
console.log(err.status_code); // 400
console.log(err.request_id); // cf-ray header, e.g. "8a1b2c-SJC"
console.log(err.request_url); // full URL that failed
console.log(err.timestamp); // Date of the request
console.log(err.support_info); // multi-line string to paste into tickets
}

Error classes

ClassWhen
AuthenticationError401 — token missing, invalid, or expired
BadRequestError400 — malformed request or invalid parameters
NotFoundError404 — exported but not thrown by default. The SDK translates 404 into an empty response with no_data: true; see no-data handling. The one exception is /user/, which opts into the throw path.
PaymentRequiredError402 — request denied by your plan (data older than your plan allows, premium endpoint on Free/Trial, or mode=cached on Free/Trial)
ForbiddenError403 — access denied. Typically the multi-IP block: the account is temporarily locked when used from more than one IP. Wait ~5 minutes and retry.
RateLimitError429 — per-minute/day rate limit exceeded
ServerError5xx — retriable, server-side failure
NetworkErrorTransport failure: DNS, connection, TLS, or 99s timeout
ParseErrorResponse body failed schema or JSON parsing
ValidationErrorClient-side input validation failure (before the network call)

No-data responses

When the server responds with 404 the SDK resolves the Promise with an empty array (or empty Blob for CSV) and flags the returned MarketDataPromise as no_data: true. Use hasData() to branch on it:

const pending = client.stocks.prices("UNKNOWN");
const prices = await pending;

if (!(await pending.hasData())) {
console.log("No data for that symbol");
} else {
console.log(prices);
}

MarketDataPromise

class MarketDataPromise<T> extends Promise<T> {
isJson(): boolean;
isCsv(): boolean;
isHtml(): boolean;
readonly no_data: boolean;
hasData(): Promise<boolean>;
save(filename?: string): Promise<string>;
saveToFile(filename?: string): Promise<string>;
blob(): Promise<Blob>;
}

Every resource method returns a MarketDataPromise<T>. It is a regular Promise<T> — you await it to get the data — with a few extra response-model methods available before you unwrap it:

  • isJson() / isCsv() / isHtml(): reports the requested format.
  • no_data: synchronous flag, true when the server returned 404.
  • hasData(): awaits and returns whether the resolved value carries any rows.
  • save(filename?) / saveToFile(filename?): persist the response to disk. Returns a Promise<string> resolving to the path written. Format is inferred from the extension when possible.
  • blob(): materialise the response as a Blob.

Chained saves work without an intermediate await:

const path = await client.stocks
.candles("AAPL", { resolution: "D", countback: 90 })
.saveToFile("aapl-90d.csv");

Accessing Rate Limits

The client tracks rate limits from the API by reading the X-Api-Ratelimit-* headers on every response. The client.rateLimits property is populated by the eager /user/ call during construction (awaited via client.ready).

const client = new MarketDataClient();
await client.ready; // ensures rateLimits is populated

if (client.rateLimits) {
console.log(`Limit: ${client.rateLimits.requestsLimit}`);
console.log(`Remaining: ${client.rateLimits.requestsRemaining}`);
console.log(`Consumed: ${client.rateLimits.requestsConsumed}`);
console.log(`Reset at: ${new Date(client.rateLimits.requestsReset * 1000)}`);
}

UserRateLimits

interface UserRateLimits {
requestsLimit: number; // Total API credits allowed
requestsRemaining: number; // API credits remaining
requestsConsumed: number; // API credits consumed
requestsReset: number; // Unix timestamp when the limit resets
}

Note: Rate limits are tracked via the following response headers:

  • x-api-ratelimit-limit: Total API credits allowed
  • x-api-ratelimit-remaining: Number of API credits remaining
  • x-api-ratelimit-consumed: Number of API credits consumed
  • x-api-ratelimit-reset: Unix timestamp when the rate limit resets

If rate limits have been fetched and requestsRemaining is 0, the next resource call will fail fast with a RateLimitError rather than hitting the API.

Logging

The SDK includes a built-in logger that outputs diagnostic information. You can pass a custom logger or use the default.

import { MarketDataClient, DefaultLogger, LogLevel } from "@marketdata/sdk";

// Default logger (INFO level)
const client1 = new MarketDataClient();

// Debug logging (more verbose — shows request URLs, response timings, token suffix)
const client2 = new MarketDataClient({ debug: true });

// Custom log level
const logger = new DefaultLogger(LogLevel.WARN);
const client3 = new MarketDataClient({ logger });

Log levels (in order of verbosity): DEBUG, INFO, WARN, ERROR.

You can also set the default level via the MARKETDATA_LOGGING_LEVEL environment variable.

The default logger obfuscates tokens in log output, showing only the last 4 characters.

Configuration

The SDK supports flexible configuration of universal parameters through environment variables, constructor arguments, and per-method overrides. See the Settings documentation for complete details on all available configuration options and how they interact.