API v1: one response envelope, real JSON types and standard errors
2026-09-29
Every /api/v1 endpoint now uses the response format below. The URLs stay the same, the JSON changed, so please check your integration. The MCP server was updated at the same time.
- Every JSON response is { "data": ..., "meta": { ... } }. meta.generated_at replaces generatedAt and timestamp; meta.as_of replaces dataDate, date and dates.
- All fields are snake_case, for example computedAt becomes computed_at and sourceTopic becomes source_topic.
- Numbers are JSON numbers ("189.4500" becomes 189.45 and "+1.25%" becomes 1.25), trading dates are YYYY-MM-DD, timestamps are RFC 3339 UTC, and missing values are null instead of empty strings.
- Candles and chart pattern points use a date field (YYYY-MM-DD) instead of time in Unix seconds.
- Errors are RFC 9457 application/problem+json documents with a stable code and a request_id; the error field is replaced by title and detail.
- Validation is strict: malformed or out-of-range parameters, impossible dates, unknown screener slugs and unknown pattern ids return 400 instead of being adjusted or ignored. Out-of-range values are rejected, not clamped to the nearest valid value.
- List endpoints page with limit and cursor (meta.pagination.next_cursor and a Link header), which on /screeners/{slug} replaces the old page parameter (now removed) and pins the snapshot date across pages instead of repeating date on every request.
- New RateLimit and RateLimit-Policy headers, Retry-After on every 429, and requests that end in 400, 401, 403, 404 or 304 no longer count against your quota.
- Responses carry ETag and Cache-Control: private, max-age=60. Send If-None-Match to get a 304 that costs no quota.
- The OpenAPI spec at /openapi.yaml and /openapi.json is now version 3.1, using JSON Schema 2020-12 nullability instead of the old nullable keyword.
- Public endpoints (/screeners, /stocks/{symbol}, /search/*) allow 30 requests per minute per IP without a key, and an invalid key now returns 401 instead of anonymous data.
- /stocks/{symbol} now only sources data from the screeners included in your plan, so anonymous and free-tier requests no longer see paid-only screener data through this endpoint.
- /search/screeners now omits screeners above your plan from the results; the 3 free-tier screeners are always included.
- POST /patterns now returns 403 SCREENER_NOT_ACCESSIBLE when a requested screener is above your plan, instead of silently dropping it from the results.
- MCP tools are updated in lockstep with this release: the same envelope, fields and error codes, and cursor-based paging in place of page.
- Fixed: /screeners/market-momentum returns data again, /stocks/{symbol} returns percent_change reliably, and impossible dates return 400 instead of 500.