GuidesResources
Best practices
Each rule below follows from something documented elsewhere. The reasoning is included so you can decide when it does not apply to you.
Response compression
Section titled “Response compression”Response compression is rolling out on data.predictefy.com from 2026-10-05: JSON and NDJSON responses of 1,024 bytes or more are compressed (gzip or deflate) when the client sends Accept-Encoding (the SDKs do this automatically); exec.predictefy.com does not compress responses. Make a proxy safe before it reaches you.
Any HTTP client that decompresses transparently (Node.js fetch, undici, node-fetch, Python requests, httpx, aiohttp) returns decoded bodies but retains upstream Content-Encoding and Content-Length.
Before re-emitting a response, drop both headers, re-serialize parsed JSON without upstream headers, or request Accept-Encoding: identity.
Correctness
Section titled “Correctness”Check capability before assuming support
Section titled “Check capability before assuming support”Read the venue’s has map or the capabilities field rather than discovering a gap through
a caught exception. Seventeen venues genuinely differ, and NOT_SUPPORTED is an answer
rather than a fault. See Capability-honest data.
Never render a synthetic book as depth
Section titled “Never render a synthetic book as depth”Venues without a real order book return a book-shaped response labelled synthetic. It is a faithful representation of price and is not orders anyone can fill against. Feeding it into a sizing calculation produces a number with no meaning.
Do not equate similar markets across venues
Section titled “Do not equate similar markets across venues”Matched clusters carry a similarity score, not an identity claim, and two venues can settle what looks like the same question differently. A price gap is an indicative price discrepancy until every executable gate passes.
Use asOf, not your own clock
Section titled “Use asOf, not your own clock”A timestamp you generate on receipt describes your request. asOf describes the data.
Persist marketId, not slug
Section titled “Persist marketId, not slug”Slugs derive from titles and change when a venue renames a market. See Identifiers.
Follow cursors instead of parallelising offsets
Section titled “Follow cursors instead of parallelising offsets”nextCursor freezes the catalog snapshot from page one, so a long walk never skips or
double-counts rows that move while you page. Parallel offset pages give up that guarantee
and spend the rate allowance faster.
Offsets above 10,000 are rejected. Snapshot/offset cursors are signed; if a cursor fails validation, restart the walk from page one.
Cursors do not live forever: each one carries a TTL, and on live-published surfaces such as
arbitrage it is also pinned to the publish it started on. Either way a stale cursor returns
400 VALIDATION_ERROR with Cursor has expired — treat that as the signal to restart the
walk from page one, not as an error to retry.
Batch where a batch verb exists
Section titled “Batch where a batch verb exists”fetchOrderBooks takes many outcomes in one request. It is priced by items, so it saves
rate allowance rather than credits.
Stream rather than poll
Section titled “Stream rather than poll”A WebSocket subscription delivers book and trade updates without consuming the request window. Streaming is metered at 2 credits per connection-minute (800 while a Polymarket pending-fills subscription is held); polling also consumes the request allowance and the endpoint’s credits.
Cache what does not move
Section titled “Cache what does not move”Capability maps and taxonomy change rarely. Re-fetching them per
query is pure overhead. Authenticated API responses carry Cache-Control: no-store, so browsers
and shared HTTP caches do not store them; keep those values in your own application cache instead.
Request only the window you need
Section titled “Request only the window you need”History is priced per query regardless of range, but a narrower window returns faster and is less likely to hit a lane bound.
Resilience
Section titled “Resilience”Branch on code and retryable, not on HTTP status
Section titled “Branch on code and retryable, not on HTTP status”Several codes share a status, and retryable is the field that answers the question you are
actually asking. See Errors.
Retry only when retryable is true, with exponential backoff and jitter
Section titled “Retry only when retryable is true, with exponential backoff and jitter”That includes retryable 502 upstream and relay failures as well as 429 and 503. Errors marked
non-retryable fail identically on the second attempt. INSUFFICIENT_CREDITS in particular will not
resolve by retrying.
Never auto-retry a write
Section titled “Never auto-retry a write”Expect empty results to be legitimate
Section titled “Expect empty results to be legitimate”A market with no trades today returns an empty tape. fetchSeries on a venue without the
concept returns an empty list. Neither is an error.
Handle 503 on billing-session writes while other routes keep flowing
Section titled “Handle 503 on billing-session writes while other routes keep flowing”When rate limiting is degraded, only the zero-credit checkout, subscribe, and portal routes fail closed. Reads and other writes are not in that special fail-closed set. The narrow guard prevents unlimited billing-session creation while the limiter is unavailable.
Keys and secrets
Section titled “Keys and secrets”Send keys in the Authorization header, never in a query string
Section titled “Send keys in the Authorization header, never in a query string”Query strings end up in request logs, browser history, and referrer headers.
Keep keys server-side
Section titled “Keep keys server-side”Only a hash of the key authenticates requests; the console keeps an encrypted copy solely so the API keys page can show it to its owner again. A key that reaches a browser bundle is disclosed permanently and must be revoked or regenerated.
Predictefy REST sends no CORS headers by design, so
proxy browser history calls through your server.
WebSocket first-frame authentication is the one
sanctioned browser use. Give that page a dedicated read-only key with no trade or sql
scope, treat it as disclosed, and be prepared to revoke it.
Use separate keys per environment
Section titled “Use separate keys per environment”Rate limits and credit spend are tracked per key, so one key across staging and production makes both untraceable and lets a test loop exhaust a production allowance.