A boundary that keeps cursor channels apart

Within the documented v1 surface, list pagination and search pagination use separate continuation mechanisms. List cursors are object identifiers supplied through one of two mutually exclusive fields; search continuation instead uses a token returned in a search response.

Search begins with no page field, then a later request supplies the earlier response token in page. For both endpoint families, treat has_more as the documented availability signal for another result page, rather than as an application promise about a stable dataset or recoverable stored state.

Use an application-owned tagged record that keeps endpoint family, resource or query identity, direction or phase, and cursor origin together. This is a proposed boundary design, not a provider-prescribed implementation. Its purpose is to make an invalid cursor route unrepresentable, or at least rejectable, before an HTTP request is assembled.

Four request decisions

Application boundary decisions for documented Stripe v1 pagination
CaseEndpoint familyTraversal direction or phaseCursor provenancePermitted request parameterDocumented ordering or stopping evidenceInvalid combination to rejectBounded application-owned action
Advance a list from its final returned itemListForwardAn object ID taken from the final item in the received list pagestarting_afterNewest-created records come first; when has_more becomes false, end traversal.Adding ending_before to the same requestBuild a forward-list request only after the record is tagged as a list object-ID cursor.
Move a list toward the prior pageListBackwardAn object ID taken from the first item in the received list pageending_beforeThe request selects records before the supplied object; list ordering is reverse by creation time.Adding starting_after to the same requestRequire an explicit backward-list action and retain its direction in state.
Start a searchSearchInitial phaseNo cursor exists yetOmit pageNo page parameter belongs on the initial search; stop when has_more is false.Supplying any saved continuation token as page on the initial phaseCreate an initial-search state without a cursor and wait for the response.
Continue a search after a result pageSearchContinuation phaseThe next_page value returned by the preceding search responsepageUse the returned token as page when has_more indicates another page.Using a list object ID in page, or routing a search token into a list fieldAccept only a search-tagged continuation record that matches the active search operation.

The table deliberately separates the source-defined request shapes from local policy. In particular, preserving direction and checking resource or query identity are application safeguards; they are not claims that a cursor provides durable checkpoint or consistency semantics.

Hypothetical mismatch walkthrough

Hypothetical example: a client has retained a continuation token from a search response. A caller accidentally sends that record to the list-navigation route. The proposed boundary sees the search tag where a list object-ID cursor is required, rejects the mismatch before constructing a request, leaves the caller's existing traversal state unchanged, and asks the caller to choose the corresponding search-continuation operation.

This is a local failure-handling rule, not a reported execution or a recovery guarantee. It avoids converting a search token into starting_after or ending_before; the caller can instead resume only through the matching search path after applying whatever application validation policy is appropriate.

Alternatives and scope limits

A single untyped cursor string is possible, but it shifts family, phase, and provenance checks to every request-construction site. A tagged boundary centralizes those checks and makes the supported request field a consequence of the record type. If a simpler design is necessary, retain an explicit endpoint-family discriminator alongside the string and validate it before selecting a parameter.

This article is limited to the documented Stripe v1 list and search behavior. The API reference identifies pagination under /v2 as a different interface, so it needs a separate boundary review. SDK auto-pagination, performance tuning, durable import checkpoints, and guarantees about concurrent dataset changes are intentionally outside this design.