Support/Developer Platform/Pagination, filtering, rate limits, and versioning

Developer Platform

Pagination, filtering, rate limits, and versioning

Implement list traversal, server-side filters, 429 recovery, and contract pinning from the exact OpenAPI operation.

Module lists
pageNumber + hasMore
Organization lists
afterAppAccountId cursor
Rate limits
429 + required Retry-After

BuildWithHQ uses one public v1 API with operation-specific list contracts. The OpenAPI operation defines its parameters, defaults, bounds, response shape, credential class, and scopes. A client should not impose one pagination or filter shape on routes that publish different contracts.

Use the declared pagination family

List familyRequestContinue withStop when
Most first-class modulespageNumber, pageSize, and declared filtersIncrement pageNumberhasMore is false
Organization discoveryafterAppAccountId, pageSize, optional searchReturn nextAfterAppAccountId as the next cursorThe next cursor is absent
Bounded history/projection routesThe operation's documented limit or other boundOnly as that response declaresThe operation-specific condition is reached

Module list envelopes can report pageNumber, pageSize, totalRecords, totalPages, totalIsExact, hasMore, and items. Drive traversal with hasMore. Treat a total as exact only when totalIsExact is true.

Filter before data reaches the browser

Send only filters declared for the operation, such as search, status, locationId, or a module-specific state. Omit an unused filter. The server applies verified app, account, user, DataRole, Location, and permission scope before the requested filter. IDs and cursors select targets inside that boundary; they do not grant access.

Honor the rate-limit contract

Every published 429 Too Many Requests response declares a required Retry-After header containing whole seconds with a minimum of one. Wait that long, then retry within a bounded attempt count. Use capped exponential backoff with jitter for transient 502, 503, and 504 responses.

const waitSeconds = Number(response.headers.get("Retry-After"));
if (response.status === 429 && Number.isInteger(waitSeconds) && waitSeconds >= 1) {
  await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000));
}

GET and HEAD requests can be retried safely. Retry a write only when its operation supports an idempotency key or explicitly defines repeat-safe behavior. Reuse the same key and payload. Preserve the API error correlationId when the bounded attempts end.

Pin and update the contract

Generate against the OpenAPI file in the immutable Developer Kit. For an app with marketplace services, call GET /v1/apps/{saasAppId}/openapi.json and pin X-BuildWithHQ-Contract-SHA256 or the matching document fingerprint. Regenerate when it changes. Clients must ignore additive response properties they do not recognize; breaking changes require an explicit API version and migration guidance.

Run the offline example

The Developer Kit includes examples/api-client-policy.mjs with a bounded request loop, numbered-page iterator, and organization cursor iterator. Its test uses mocked HTTP responses and needs no credential:

node --test examples/api-client-policy.test.mjs
Note

Page-size bounds and allowed filters belong to each OpenAPI operation. Never copy one route's maximum, default, status values, or cursor semantics into another client method.

Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.