- Implement pagination on every list endpoint — never return unbounded result sets. Default to 20-50 items per page with a configurable limit.
- Use cursor-based pagination for large or frequently changing datasets. Use offset-based only for small, stable collections.
- Return pagination metadata in every response: total count (when feasible), next/previous cursors or links, and current page size.
- Support filtering via query parameters with a consistent naming convention: ?status=active&created_after=2024-01-01.
- Cap the maximum page size (e.g., 100 items). Reject requests exceeding the cap with a 400 error explaining the limit.
- Implement sorting with a sort parameter: ?sort=created_at for ascending, ?sort=-created_at for descending. Support multiple sort fields.
- Use cursor-based pagination keyed on a stable, unique, indexed column (like id or created_at + id). Never cursor on a non-unique column alone.
- Return RFC 8288 Link headers or a links object with next, prev, first, last URLs. Clients should follow links rather than constructing URLs.
- Support field selection to reduce payload size: ?fields=id,name,email. Return only requested fields plus the id.
- Encode cursors as opaque base64 strings. Clients should not parse or construct cursors — they are API-internal implementation details.