Runnable. The shapes below were captured live from
https://phosra-api-sandbox-production.up.railway.app on 2026-07-06. The
catalog reads (/api/v1/platforms, /api/v1/ratings/systems) need no API key.The two shapes at a glance
| Surface | Shape | Page with | next signal | Example |
|---|---|---|---|---|
| Product data plane (families, devices, enforce history, webhook deliveries, viewing history) | a bare JSON array | ?limit= and ?offset= | array shorter than limit ⇒ last page | GET /api/v1/enforce/history?limit=20&offset=40 |
| OCSS census rails (advisor audit log, CSM bulk ratings) | an envelope { "<items>": [...], "next_cursor": … } | cursor in the body/query | next_cursor is null ⇒ last page | POST /api/v1/csm/reviews/bulk |
| Static catalogs (platforms, ratings systems, standards) | a bare JSON array, complete | (not paginated) | full set every time | GET /api/v1/platforms |
Offset lists (product data plane)
Most product list endpoints return a plain array and acceptlimit and, where
supported, offset. An empty result is [], never null.
curl
Response · 200
Limits and defaults
Each endpoint sets its own default and ceiling. Ask for more than the ceiling and you get the ceiling.| Endpoint | limit default | limit max | offset |
|---|---|---|---|
GET /api/v1/enforce/history | 20 | 100 | ✅ |
GET /api/v1/webhooks/{id}/deliveries | 50 | — | — |
GET /api/v1/viewing-history/{childId} | repo default | — | ✅ |
Walk every page
Keep advancingoffset by limit until you get back fewer rows than you
asked for — that short page is the last one.
Offset lists are newest-first and mutable. New rows land at
offset 0, so a
row can shift while you page. For an audit-stable walk, filter by a fixed
created_at/since window rather than relying on offsets across a long crawl.Cursor lists (OCSS census rails)
The OCSS census rails return an envelope with the collection plus anext_cursor. The cursor is opaque — treat it as a token, never parse it — and
null means you have reached the end. Pass it back verbatim to get the next page.
Response · 200 (advisor audit log)
Request body
TypeScript
Choosing a page size
Bigger pages, fewer calls
Each request counts against your rate limit. Pull
100 at a
time on offset lists rather than 10 at a time.Detect the end correctly
Offset lists: a short page ends the walk. Cursor lists: a null
next_cursor ends the walk. Never guess with a count you were not given.Next steps
Limits & quotas
The enforced
limit ceilings per endpoint, plus body-size and ID-length caps.Rate limits
Fewer, larger pages keep you inside your window.
Idempotency
Cursor rails are signed writes — see how replay-safety works.