Introduction

The PublicOptions API is a REST interface to historical price data for US equity options. All responses are JSON. All endpoints are versioned under /v1.

Servers

All traffic goes through a single production base URL.

EnvironmentBase URLUse for
Productionhttps://api.czar28.com/v1All live traffic.

Quickstart

Create an API key in your dashboard, then pull a year of daily quotes for AAPL Jan-2026 $180 calls.

bash
export API_KEY="sopk_live_..."
curl https://api.czar28.com/v1/options/quote/eod \
  -H "Authorization: Bearer $API_KEY" \
  -G --data-urlencode "root=AAPL" \
      --data-urlencode "exp=20250117" \
      --data-urlencode "strike=180" \
      --data-urlencode "right=C" \
      --data-urlencode "start_date=20240101" \
      --data-urlencode "end_date=20240601"

Authentication

Every request must include an Authorization header with your API key. Keys are scoped to your account and can be rotated or revoked instantly from the dashboard.

http
Authorization: Bearer sopk_live_xxxxxxxxxxxxxxxx

Key types

  • sopk_live_… — production keys, count against your monthly quota.
  • sopk_test_… — test keys, separate quota, safe to embed in CI.

Rotation

Rotating a key issues a new secret and keeps the old one alive for a 24-hour grace window, so you can deploy without downtime. Revoking a key takes effect immediately.

Security

  • Treat the key like a password. Never commit it or expose it in browser code.
  • API keys are hashed at rest; the full value is shown exactly once at creation.
  • All traffic must be TLS — plain HTTP is rejected.

Errors

Failed requests return a JSON body with stable error and message fields. Validation errors include a details object listing the offending parameters.

json
{
  "error": "invalid_parameters",
  "message": "exp must be YYYYMMDD",
  "details": { "fieldErrors": { "exp": ["exp must be YYYYMMDD"] } }
}
StatusError codeMeaning
400invalid_parametersQuery parameters missing, malformed, or out of range.
401unauthorizedMissing, malformed, revoked, or expired API key.
402subscription_inactiveAccount has no active subscription. Visit billing to resume.
404not_foundContract or date range produced no data.
429quota_exceededMonthly request quota exhausted. Resets at the date in X-RateLimit-Reset.
502upstream_unavailableThetaData upstream timed out or returned 5xx. Safe to retry with backoff.
503circuit_openUpstream is failing repeatedly; circuit breaker is open. Retry in 30–60s.

Retry guidance

  • 502 / 503 — retry with exponential backoff (250 ms × 2ⁿ, max 5 attempts).
  • 429 — stop, upgrade your plan, or wait until X-RateLimit-Reset.
  • 400 / 401 / 402 — never retry; fix the request or account first.

Rate limits & quotas

Every successful response carries the following headers so clients can self-throttle without polling:

HeaderValue
X-RateLimit-LimitYour plan's monthly request quota.
X-RateLimit-RemainingRequests remaining in the current period.
X-RateLimit-ResetUnix timestamp (seconds) when the quota resets.
Retry-AfterOn 429 / 503 only — seconds to wait before retrying.

Quotas are tracked per account, not per key, and reset at 00:00 UTC on the first of each month. Per-minute rate limits also apply (Free 60/min burst 20, Pro 600/min burst 100, Business 3000/min burst 500). Responses include X-RateLimit-Limit-Minute, X-RateLimit-Burst, and Retry-After headers. See pricing for plan limits.

Idempotency

Every endpoint accepts an optional Idempotency-Key request header. When two requests arrive within 24 hours with the same key and the same body, the second request returns the original cached response — without re-hitting the upstream provider and without consuming additional monthly quota. This is the recommended pattern for safely retrying after a timeout or network error.

Rules

  • Key is an opaque client-generated string, ≤ 255 characters. UUIDs work well.
  • Scope is per API key. Two different keys may reuse the same value without collision.
  • Replays return the original status code and body, plus Idempotent-Replayed: true.
  • Reusing a key with a different request body returns 409 idempotency_conflict.
  • 5xx responses are not cached, so transient upstream failures are safe to retry with the same key.
  • Entries expire after 24 hours.
bash
curl "https://api.czar28.com/v1/options/quote/eod?root=AAPL&exp=20260116&strike=180&right=C&start_date=20250601&end_date=20250701" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: 8e3b5c0a-2f4a-4b9d-9a8e-1c2d3f4a5b6c"

CORS

Every /v1 endpoint allows cross-origin GET from any origin and exposes the rate-limit headers, so you can call the API directly from a browser app running on your own domain.

http
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, Idempotency-Key
Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Burst, Retry-After, API-Version, Idempotent-Replayed

Heads-up: anything you ship to the browser is publicly visible. Don't embed a high-volume key in a public site — proxy through your own backend instead.

Response envelope

All data endpoints return the same shape: a header with metadata and a response array of rows. The header.format array names each column, in order, for the rows in response.

json
{
  "header": {
    "latency_ms": 47,
    "format": ["ms_of_day", "bid", "ask", "bid_size", "ask_size", "date"]
  },
  "response": [
    [34200000, 6.85, 7.05, 12, 9, 20240102],
    [34260000, 6.80, 7.00, 14, 11, 20240102]
  ]
}

Loading into pandas:

python
import pandas as pd
df = pd.DataFrame(body["response"], columns=body["header"]["format"])

API reference

Every endpoint below is generated directly from our OpenAPI 3.1 spec — the same file our SDKs and Postman collection consume. If the spec changes, this page changes with it.

End-of-day quotes for a single contract

GET/v1/options/quote/eod

Query parameters

NameTypeDescription
rootrequiredstringUnderlying ticker (uppercase).
exprequiredYYYYMMDDExpiration date YYYYMMDD.
strikerequirednumberStrike price in dollars.
rightrequired"C" | "P"Option right (C=call, P=put).
start_daterequiredYYYYMMDDStart date YYYYMMDD.
end_daterequiredYYYYMMDDEnd date YYYYMMDD.

Response fields

Columns appear in header.format in this order; rows are arrays in response.

FieldTypeDescription
dateint (YYYYMMDD)Trading date.
opennumberOpening trade price.
highnumberSession high.
lownumberSession low.
closenumberClosing trade price.
bidnumberClosing best bid.
asknumberClosing best ask.
volumeintContracts traded.

Example

bash
curl https://czar28.com/v1/options/quote/eod
  -H "Authorization: Bearer $API_KEY" \
  -G --data-urlencode "root=AAPL" \
     --data-urlencode "exp=20260619" \
     --data-urlencode "strike=200" \
     --data-urlencode "right=C" \
     --data-urlencode "start_date=20260101" \
     --data-urlencode "end_date=20260131"

Intraday quotes for a single contract

GET/v1/options/quote/intraday

Query parameters

NameTypeDescription
rootrequiredstringUnderlying ticker (uppercase).
exprequiredYYYYMMDDExpiration date YYYYMMDD.
strikerequirednumberStrike price in dollars.
rightrequired"C" | "P"Option right (C=call, P=put).
start_daterequiredYYYYMMDDStart date YYYYMMDD.
end_daterequiredYYYYMMDDEnd date YYYYMMDD.
ivlintegerBar interval in milliseconds (1000 – 3600000). Default 60000.
rth"true" | "false"Regular trading hours only.

Response fields

Columns appear in header.format in this order; rows are arrays in response.

FieldTypeDescription
ms_of_dayintMilliseconds since midnight (US/Eastern).
bidnumberBest bid at end of interval.
asknumberBest ask at end of interval.
bid_sizeintContracts at the best bid.
ask_sizeintContracts at the best ask.
dateint (YYYYMMDD)Trading date.

Example

bash
curl https://czar28.com/v1/options/quote/intraday
  -H "Authorization: Bearer $API_KEY" \
  -G --data-urlencode "root=AAPL" \
     --data-urlencode "exp=20260619" \
     --data-urlencode "strike=200" \
     --data-urlencode "right=C" \
     --data-urlencode "start_date=20260101" \
     --data-urlencode "end_date=20260131" \
     --data-urlencode "ivl=60000" \
     --data-urlencode "rth=true"

Historical trades for a single contract

GET/v1/options/trades

Query parameters

NameTypeDescription
rootrequiredstringUnderlying ticker (uppercase).
exprequiredYYYYMMDDExpiration date YYYYMMDD.
strikerequirednumberStrike price in dollars.
rightrequired"C" | "P"Option right (C=call, P=put).
start_daterequiredYYYYMMDDStart date YYYYMMDD.
end_daterequiredYYYYMMDDEnd date YYYYMMDD.

Response fields

Columns appear in header.format in this order; rows are arrays in response.

FieldTypeDescription
ms_of_dayintMilliseconds since midnight (US/Eastern).
sequenceintExchange sequence number.
sizeintTrade size in contracts.
conditionintOPRA condition code.
pricenumberTrade price.
exchangeintOPRA exchange code.
dateint (YYYYMMDD)Trading date.

Example

bash
curl https://czar28.com/v1/options/trades
  -H "Authorization: Bearer $API_KEY" \
  -G --data-urlencode "root=AAPL" \
     --data-urlencode "exp=20260619" \
     --data-urlencode "strike=200" \
     --data-urlencode "right=C" \
     --data-urlencode "start_date=20260101" \
     --data-urlencode "end_date=20260131"

List option contracts for a root + expiration

GET/v1/options/chain

Query parameters

NameTypeDescription
rootrequiredstringUnderlying ticker (uppercase).
exprequiredYYYYMMDDExpiration date YYYYMMDD.

Response fields

Columns appear in header.format in this order; rows are arrays in response.

FieldTypeDescription
rootstringUnderlying ticker.
expirationint (YYYYMMDD)Expiration date.
strikeint (1/10¢)Strike in tenths of a cent. Divide by 1000 for dollars.
rightC | PCall or put.

Example

bash
curl https://czar28.com/v1/options/chain
  -H "Authorization: Bearer $API_KEY" \
  -G --data-urlencode "root=AAPL" \
     --data-urlencode "exp=20260619"

Health check

GET/v1/options/health

Response fields

FieldTypeDescription
statusstring"ok" when healthy, "degraded" otherwise.
upstream.mdds_statusstring"CONNECTED" | "DISCONNECTED" | "UNKNOWN".
upstream.upstream_msintRound-trip latency to upstream in ms.

Example

bash
curl https://czar28.com/v1/options/health

Versioning & deprecation policy

The API is versioned in the URL path. The current stable version is /v1. We will never make a backwards-incompatible change to a released version — breaking changes ship as a new major version (/v2) alongside the old one.

What counts as a breaking change

  • Removing or renaming an endpoint, field, parameter, or error code
  • Changing the type or semantics of an existing field
  • Making a previously optional parameter required
  • Tightening validation in a way that rejects previously valid input

What is not breaking (safe to add anytime)

  • New endpoints, optional parameters, or response fields
  • New optional response headers
  • New enum values returned by the server (clients must tolerate unknown values)
  • Bug fixes that align behavior with the documented contract

Deprecation timeline

  • Day 0 — deprecation announced via email and on this page. Successor version is generally available.
  • Day 0 onward — deprecated endpoints return a Deprecation: true header (RFC 9745) and a Sunset header (RFC 8594) with the removal date. A Link header points to the successor.
  • 12 months minimum — deprecated version continues to work unchanged. Paid plans get a written 12-month commitment from announcement to sunset.
  • Sunset date — deprecated version returns 410 Gone with { "error": "version_sunset" }.

Currently active versions

VersionStatusSunset
v1Stable

Changelog

Notable changes to the public API. Additive changes (new endpoints, optional parameters, new response fields) ship without notice; anything breaking follows the deprecation policy above.

DateVersionChange
2026-05-21v1.1Added Idempotency-Key header support on every endpoint; added API-Version response header; documented Deprecation/Sunset/Link headers.
2026-05-20v1.0Per-minute token-bucket rate limiting (Free 60/min burst 20, Pro 600/min burst 100, Business 3000/min burst 500).
2026-05-19v1.0Per-API-key monthly quotas and usage analytics in the dashboard.
2026-05-18v1.0Initial public release: EOD, intraday, trades, chain, and health endpoints.

OpenAPI & Postman

Machine-readable spec and a ready-to-import Postman collection. Set the apiKey variable to your sopk_… key after importing.