Pagination, fields & caching
Paginate Havoptic API lists with opaque cursors, trim responses with fields= and expand=, and save quota with ETag / If-None-Match conditional requests.
Cursor pagination
List endpoints (/v1/releases, /v1/tools/{id}/releases, /v1/changes) return an envelope with has_more and next_cursor. Pass the cursor back unchanged to get the next page. Cursors are opaque: do not build or parse them.
curl "https://api.havoptic.com/v1/releases?tool=cursor&limit=2"
{
"object": "list",
"data": [ { "id": "cursor-2026.10.17", "version": "2026.10.17", "...": "..." }, { "...": "..." } ],
"has_more": true,
"next_cursor": "eyJwIjoiMjAyNi0xMC0xNSIsImlkIjoiY3Vyc29yLTIwMjYuMTAuMTUifQ",
"meta": { "dataset_updated_at": "2026-10-19T10:12:00.000Z", "api_version": "2026-11-01" }
}
curl "https://api.havoptic.com/v1/releases?tool=cursor&limit=2&cursor=eyJwIjoiMjAyNi0xMC0xNSIsImlkIjoiY3Vyc29yLTIwMjYuMTAuMTUifQ"
limitdefaults to 20, maximum 100.- Stop when
has_moreis false (next_cursoris then null). - The SDK does this for you:
for await (const r of havoptic.releases.iterate({ tool: "cursor" })).
Field selection and expansion
Trim list items to the fields you need with fields=, and pull in related data with expand=:
# Just the basics
curl "https://api.havoptic.com/v1/releases?tool=claude-code&fields=id,version,published_at,abstract"
# One release with its typed changes and full notes
curl "https://api.havoptic.com/v1/releases/claude-code-2.1.302?expand=changes,notes"
expand accepts changes, notes and product. sort accepts -published_at (default), published_at and product.
Formats
JSON is the default. /v1/digest, /v1/tools/{id}/upgrade and /v1/changelog also answer Accept: text/markdown with an agent-ready brief.
ETags and 304 Not Modified
Every 200 response carries a weak ETag and Last-Modified. Send the ETag back in If-None-Match; if nothing changed you get an empty 304 and keep your cached body. The ETag changes whenever the dataset is refreshed.
curl -i "https://api.havoptic.com/v1/tools/claude-code/latest"
# ETag: W/"5f1c…"
curl -i -H 'If-None-Match: W/"5f1c…"' "https://api.havoptic.com/v1/tools/claude-code/latest"
# HTTP/2 304
With the SDK: new Havoptic({ etagCache: true }) sends If-None-Match and replays the cached body on 304.