--- id: API-5 family: GR-API level: core profiles: [storage-api] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/gr-api/api-5 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # API-5 — The paginated envelope is a third envelope with four fixed keys *GR-API (Part I) · level: core · profiles: storage-api · added in 1.0* Two envelopes carry a result and a refusal. A paginated result is a third, and its pagination block belongs to the envelope rather than to the rows it sits beside. ## The rule > **Normative.** This is the rule. > > 1. Alongside `{success, data}` and `{success, error}`, a paginated response is `{success, data, pagination}`, where `pagination` carries exactly `total`, `limit`, `offset` and `has_more`, in that order. > > 2. `has_more` is page arithmetic, `(offset + limit) < total`, and not a second query. > > 3. It is spelled `has_more` in every paginated response, whatever the spelling convention of that endpoint's rows: it belongs to the shared envelope, and an implementation must not rename it to match the rows beside it. > > 4. A door must not build a pagination block of its own. ## What it means A result and a refusal are the two envelopes every door already answers in. A paginated result is a third, and it is a shape of its own, not the result envelope with a block appended by whichever door happens to return one: the same four keys, in the same order, on every paginated door. `has_more` is arithmetic the door itself can do — whether the offset and limit it just reported would still leave rows unseen — not a second query run to find out. And it keeps its snake_case spelling regardless of the casing convention the rows beside it use: the block belongs to the shared envelope, not to the endpoint it happens to sit in, so a door must not rename it to match its own rows, and must not build a pagination block of its own. ## Example Two workflows, unfiltered: three keys, and the pagination block reports the whole set (rows elided). ```http title="A list door with two rows" verdict="200 paginated" GET /api/flowdrop/workflows {"success": true, "data": [ … ], "pagination": {"total": 2, "limit": 50, "offset": 0, "has_more": false}} ``` The same four keys, in the same order, sit beside rows spelled the other way. ```http title="A list door whose rows are spelled the other way" verdict="200 paginated" GET /api/flowdrop/workflows/{workflow}/playground/sessions {"success": true, "data": [ … ], "pagination": {"total": 1, "limit": 50, "offset": 0, "has_more": false}} ``` `has_more` is spelled the same both times: once beside rows spelled the same way as the pagination block, once beside rows that are not. ## Related rules - Names: API-6 - Referenced by: API-6 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.