FOUNDER PRICINGSee what it covers →

API reference

Everything is one REST call away.

One base URL, one header, JSON everywhere. The catalog and the coverage ledger are open without a key; data access signs short-lived URLs over object storage so bulk downloads never pass through the API.

base https://api.probnode.comv1OpenAPI 3.1

Quickstart

Get a key, list the catalog, sign a URL, read the file. The free plan covers the sample surface across every market, so nothing below needs a paid plan.

first_book.py
1import pmd
2
3book = pmd.books("btc-updown-5m-1762598700-up",
4 start="2026-11-08T12:05:00Z",
5 end="2026-11-08T12:10:00Z")
6print(book.head(3))
Output

Authentication

A key looks like pmd_a1b2c3d4_... and travels in the Authorization header. We store only a sha256 hash and a clear-text prefix, so a key is displayed once at creation and can never be read back - revoke and mint a new one instead.

Authorization: Bearer pmd_a1b2c3d4_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Endpoints

MethodPathWhat it doesAccess
Catalog - open, no key
GET/v1/catalog/seriesList seriesfree
GET/v1/catalog/marketsList markets, filtered by seriesfree
GET/v1/catalog/markets/{slug}One market with its tokensfree
GET/v1/catalog/coverageCoverage ledger per market-hourfree
Data - key required
POST/v1/data/urlsSign short-lived download URLsplan
GET/v1/data/usageQuota used today, entitlements, reset timekey
Account
POST/v1/auth/registerCreate an account and mint the first keyopen
POST/v1/auth/loginSign in and mint a keyopen
GET/v1/meThe current accountkey
GET/v1/keysList keys by prefixkey
POST/v1/keysMint an additional keykey
DELETE/v1/keys/{prefix}Revoke a keykey
Billing
GET/v1/plansPrice list, entitlements and licence per planopen
POST/v1/ordersOrder a plan; we invoice, nothing is chargedkey
GET/v1/ordersYour orders and their statuskey
POST/v1/orders/{id}/cancelCancel a pending orderkey

Admin endpoints exist for the back office and are not part of the public contract.

Schemas

Four surfaces, one naming convention. Timestamps are milliseconds since the epoch, and the venue clock and our receive clock are separate columns.

schema v1

One row per change of the ladder. lp2 (lossless, about 7x smaller than parquet) or parquet.

ts_msint64venue timestamp, milliseconds
local_ts_msint64our receive timestamp, kept apart from the venue clock
token_idstringoutcome token the book belongs to
sideenumbid | ask
pricefloat64level price, 0..1
sizefloat64resting size after the change
actionenumadd | change | remove | snapshot
seqint64monotonic per token; gaps are flagged, not hidden

Delivery and formats

Signed URLs

POST a list of object paths, get back short-lived URLs. The bucket is never exposed and the API never proxies bytes.

lp2

Our lossless columnar format for book events: about 7x smaller than parquet over the same tape. The reader is open source.

parquet

Every surface is also available as parquet, partitioned hour x market, for people who would rather not install anything.

Paths are normalised before signing: absolute paths, backslashes and any component of .. are rejected rather than cleaned up.

Quotas and limits

Four things are kept apart on purpose: what a plan may access, how much it may take, how fast it may ask, and what it actually consumed. Consumption is an idempotent ledger keyed per account, path and minute, so a retried request is never counted twice.

PlanDatasetsSigned URLs / dayRequests / min
freesamples, catalog, coverage5060
research+ full tape20,000600
pro+ full tape200,0003,000
academic+ full tape20,000600

Errors

Errors are a JSON object with a detail field: a string for our own refusals, a list of field errors for schema validation.

StatusdetailWhen
400bad requestA malformed object path: absolute, with .. or a backslash.
401missing or invalid api keyNo Authorization header, or the key was revoked.
402plan does not cover this pathThe path is on the tape and the plan is free.
404not foundUnknown market, series or order.
409conflictYou already hold that plan, or an order is already open.
422validation errorA field is missing or has the wrong type; the body lists them.
429quota exhaustedThe daily signing quota for the plan is used up.

Versioning

Paths carry /v1. Additive changes - new endpoints, new optional fields - ship inside v1. Anything that removes or renames a field gets /v2 and an overlap period. The OpenAPI document is the contract, and the SDK is generated from it.