Make your first request
Search for a dataset first, inspect its schema, and only then choose filters. This avoids guessing slugs, columns, date fields, or point-in-time support.
- 1Create a key
Approved accounts create keys in the authenticated Data API console. Store the show-once secret in a secrets manager.
- 2Search, then inspect
Resolve a dataset with
GET /datasets?q=…, then read/schemabefore querying rows. - 3Query or export
Use bounded JSON for applications, complete-or-rejected CSV for filtered extracts, or checksummed Parquet for a full immutable version.
export TP_API_KEY="tp_live_..."
curl --fail-with-body \
--header "Authorization: Bearer $TP_API_KEY" \
"https://api.tradepolaris.com/platform/v1/datasets?q=apple&limit=10"import hashlib
import os
import requests
BASE_URL = "https://api.tradepolaris.com/platform/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['TP_API_KEY']}"
# Search first; do not page the full catalog.
catalog = session.get(
f"{BASE_URL}/datasets",
params={"q": "apple", "limit": 10},
)
catalog.raise_for_status()
dataset = catalog.json()[0]["name"]
# Inspect capabilities before choosing filters.
schema_response = session.get(f"{BASE_URL}/datasets/{dataset}/schema")
schema_response.raise_for_status()
schema = schema_response.json()
# JSON rows are paginated and DataFrame-ready.
rows_response = session.get(
f"{BASE_URL}/datasets/{dataset}/query",
params={"start": "2026-01-01", "limit": 5000},
)
rows_response.raise_for_status()
page = rows_response.json()
print(page["columns"], page["rows"], page["truncated"])
# For the immutable full version, verify the exported Parquet bytes.
export_response = session.get(f"{BASE_URL}/datasets/{dataset}/export")
export_response.raise_for_status()
artifact = export_response.json()
download = requests.get(artifact["url"]) # no API Authorization header
download.raise_for_status()
expected_sha256 = artifact.get("content_sha256")
if not expected_sha256:
raise RuntimeError("Export did not include a checksum")
assert hashlib.sha256(download.content).hexdigest() == expected_sha256Authentication and scopes
Send the key on every request. The secret begins with tp_live_, is shown once, and cannot be retrieved later.
Authorization: Bearer tp_live_...Curated scope
Reads the shared catalog and curated market datasets. The account's own uploads stay absent from search and return 404 on direct reads.
All-datasets scope
Adds datasets owned by the same account. Use it only for trusted internal services that genuinely need those rows.
- Keys expire after 1–365 days; the default is 90 days.
- Up to five keys can be active on one account.
- Optional IPv4 and IPv6 CIDRs restrict where a key may be used. An empty list means unrestricted.
- Rotation preserves the service-account identity and can keep the predecessor valid for a bounded handover.
- Revocation rejects the key immediately on every API endpoint.
Dataset endpoints
Every path below is relative to https://api.tradepolaris.com/platform/v1. The integration surface is structured and read-only; callers cannot submit SQL or arbitrary ordering.
/datasetsFind a dataset
Search the datasets visible to the key. The catalog is large and alphabetically paged, so search by name or label instead of walking every page.
| Parameter | Type | Meaning |
|---|---|---|
q | string | Search dataset names and human labels. For example, q=apple matches us-eq-aapl-1d. |
asset_class | enum | Optional family filter: equity, intl, futures, fx, crypto, fundamentals, options, news, positioning, or macro. |
limit | integer · 1–500default 200 | Maximum catalog rows in this page. |
offset | integer · ≥0default 0 | Zero-based catalog offset. |
Response
body- An array of dataset summaries: name, kind, latest_version, source, license, description, owned, updated_at, and asset.
X-Has-More- The reliable pagination signal. Do not infer completion from the returned row count.
/datasets/{name}/previewPreview its shape
Return a render-ready sample as line points, candles, or table rows. Use schema or query when a dataset is too large to preview.
| Parameter | Type | Meaning |
|---|---|---|
namerequired | string | Dataset slug returned by GET /datasets. |
version | integer · ≥1 | Pinned dataset version. Omit to use the latest version. |
max_points | integerdefault 500 | Requested preview density. Values are safely clamped to 10–2,000 points. |
Response
chart- line, candles, or table; identifies the populated payload field.
points / candles / rows- The render-ready preview payload.
total_rows / downsampled- Full version size and whether the preview was thinned.
/datasets/{name}/schemaInspect the schema
Read columns, dtypes, coverage, detected time and symbol fields, and the producer-declared capability contract before querying rows.
| Parameter | Type | Meaning |
|---|---|---|
namerequired | string | Dataset slug returned by GET /datasets. |
version | integer · ≥1 | Pinned dataset version. Omit to use the latest version. |
Response
columns[] / row_count- Column names and dtypes plus the version's total row count.
date_column / symbol_column- Detected effective-time and symbol fields when present.
date_min / date_max- Dataset- and version-specific coverage bounds.
capabilities- The source contract, including point_in_time_supported, time fields, revision_model, valid query operators, and provenance.
/datasets/{name}/queryQuery rows
Apply structured filters and column projection. This is not a SQL endpoint. JSON is paginated; CSV is complete-or-rejected up to 1,000,000 matching rows.
| Parameter | Type | Meaning |
|---|---|---|
namerequired | string | Dataset slug returned by GET /datasets. |
version | integer · ≥1 | Pinned dataset version. Omit to use the latest version. |
symbol | string · ≤32 chars | Exact symbol filter when the schema declares a symbol column. |
start | ISO date | Inclusive lower bound on the dataset's effective date field. |
end | ISO date | Inclusive upper bound on the dataset's effective date field. |
as_of | YYYY-MM-DD | Point-in-time knowledge bound. Use only when schema.capabilities.point_in_time_supported is true; unsupported datasets return 400. |
columns | comma-separated string | Projected column names. |
limit | integer · 1–5,000default 500 | Maximum rows in a JSON page. |
offset | integer · ≥0default 0 | JSON page offset. |
tail | booleandefault false | For JSON, keep the newest bounded window instead of the oldest one. CSV is already the complete filtered result. |
format | json | csvdefault json | JSON returns a bounded page. CSV returns the complete filtered result or rejects it before sending partial bytes. |
Response
columns / rows- Column names and row arrays, ready to construct a DataFrame.
total_matched / returned / truncated- Exact match count and page status for JSON responses.
as_of evidence- When applied: as_of, knowledge_time_column, knowledge_time_min, and knowledge_time_max.
CSV headers- X-Total-Rows is the emitted row count and X-Export-Complete: true confirms the body was not clipped.
/datasets/{name}/exportExport a pinned version
Mint a short-lived URL for the immutable Parquet artifact. Download the URL without an Authorization header and verify its SHA-256 checksum.
| Parameter | Type | Meaning |
|---|---|---|
namerequired | string | Dataset slug returned by GET /datasets. |
version | integer · ≥1 | Pinned dataset version. Omit to use the latest version. |
as_of | unsupported | Do not send this parameter. The endpoint returns 400 rather than silently exporting unfiltered history; use /query with as_of. |
Response
url / expires_in- A bearer download URL and its lifetime in seconds: 900 for curated datasets and 300 for account-owned uploads.
name / version / bytes / rows- Immutable artifact identity and size.
content_sha256- Checksum to verify after download.
Pagination without silent truncation
Increase offset while the response header X-Has-More is true. A short page can still have more results.
Increase offset while truncated is true. total_matched is the exact filtered count.
Set tail=true to keep the newest bounded window. It does not enable arbitrary sorting.
A successful CSV is complete and carries X-Export-Complete: true. Oversized results fail before any partial body is sent.
Point-in-time queries are capability-based
Use as_of=YYYY-MM-DD only when the resolved schema says capabilities.point_in_time_supported: true. The bound means “known by the end of that UTC date” on the declared availability field. Unsupported datasets return 400 instead of silently ignoring the bound.
Read time_field, availability_time_field, revision_model, and the response's knowledge_time_min / knowledge_time_max. An empty result before the retained floor is not evidence that no filing or disclosure existed.
| Catalog selector | Availability | Effective time | Revision model |
|---|---|---|---|
us-13f-hist-* | filing_date | period | filing_history_with_amendments |
us-form4-* | filing_date | transaction_date | filing_history_with_amendments |
house-ptr-* | filed_date | transaction_date | rolling_disclosure_history |
Coverage is dataset- and version-specific. Inspect date_min and date_max; Kappa makes no catalog-wide history promise. See the complete machine-readable capability matrix.
SEC 13F integration notes
History lanes retain accessions, including amendments; they are not amendment-resolved canonical portfolios. ADD-type amendments and firms that file through multiple entities require consumer-side interpretation. Do not infer a complete manager position unless an amendment-resolved portfolio is supplied.
Put, call, and unflagged positions remain distinct history rows. Use value_usd for normalized values; value preserves the raw SEC number and its unit changes across filing eras.
pct_of_filing_value is a weight within one accession. The legacy pct_of_portfolio field is a deprecated alias, not a canonical firm-level portfolio weight.
US equity reference data includes active and inactive/delisted symbols where supplied. That reduces survivorship bias but does not certify every dataset or historical universe as survivorship-free.
Handle exports as short-lived bearer artifacts
- Download the returned URL with a plain GET. Do not attach the TradePolaris API key to the object-storage request.
- Verify
content_sha256before accepting the file. Versions are immutable, so a pinned re-download should be byte-identical. - Do not log, share, or persist the URL. Anyone holding it can download until it expires.
- Revoking the API key does not invalidate URLs already issued; their TTL is the remaining exposure window.
- The URL-bearing response is
Cache-Control: no-store. - The export endpoint does not support
as_of. Use a point-in-time CSV query when the filtered result fits the documented row ceiling.
Errors and retries
The default normal-capacity budget is 120 requests per minute per key and can vary by plan. On 429, wait for Retry-After. Retry transient 503 responses with capped exponential backoff.
400- The request asks for unsupported semantics, such as as_of on a dataset that does not declare point-in-time support.
401- The bearer key is missing, malformed, expired, revoked, or unknown.
402 dataset_limit- The monthly distinct-dataset export meter is exhausted.
403- The account is not entitled to Data API access, or the key's source-CIDR policy denies the trusted client address.
404- The dataset does not exist or is outside this key's scope. Private datasets are concealed rather than disclosed with 403.
413- The preview is too large, or a CSV query matches more than 1,000,000 rows. Narrow the query or use Parquet export.
422- One or more parameters failed validation.
429- The per-key request budget is spent. Wait for Retry-After, then retry.
503- A transient fail-closed service guard rejected the request. Retry with backoff.
Key-management routes use account authentication
A Data API key cannot create, list, rotate, edit, or revoke other keys. These routes require an authenticated TradePolaris account session or account JWT. Ownership comes from that identity and cannot be supplied in the request body.
POST /api-keys- Create a key and return its secret once.
GET /api-keys- List credential history and metadata; never returns secrets.
POST /api-keys/{id}/rotate- Create a same-principal successor with a bounded overlap.
PATCH /api-keys/{id}- Update the label or source-CIDR policy.
DELETE /api-keys/{id}- Revoke immediately while retaining credential history.
One contract for people and machines
The page is server-rendered with semantic headings, tables, code, and stable fragment IDs. Parsers can use the same reference in two machine-oriented formats:
/data-api/openapi.jsonMarkdownGuide an integration with full context/data-api/docs.mdThe root llms.txt file links these artifacts so an agent discovering TradePolaris from the site index can reach the integration contract directly.