Interview concept

Stripe API Pagination, Expansion, And Rate Limits

Asked of: Software Engineer

Last updated

What's being tested

Candidates must show practical mastery of designing and using paginated REST APIs, the expansion pattern for reducing round-trips, and robust handling of rate limits in client and server designs. Interviewers probe system correctness (consistency and ordering), performance (latency and throughput), operational safety (retry/backoff, idempotency), and tradeoffs between simplicity and scale. At Stripe, this maps to reliable developer UX for high-volume clients and safe multi-tenant service operation.

Core knowledge

  • Pagination: know difference between cursor-based and offset-based pagination; cursor is stable and O(1) per page while offset degrades with large offsets (O(offset) in many DBs). Use cursor when N >> page_size.

  • Cursor semantics: a cursor should be an opaque, compact token (e.g., base64 of last-seen key + shard id + timestamp); it must encode sorting key and tie-breaker to guarantee deterministic paging.

  • Offset pitfalls: OFFSET in Postgres/MySQL scans/skips rows; for deep pages prefer WHERE (key, id) > (k, id) LIMIT M indexed scans or keyset pagination.

  • Consistent pagination: decide between snapshot isolation (stable view, heavier — e.g., timestamped snapshot or transaction id) and eventual view (reflects concurrent writes). Be explicit in API docs about staleness guarantees.

  • Expansion pattern: expansion (e.g., expand=customer in Stripe API) inlines related resources to avoid N+1 client fetches; server must fetch efficiently (batch queries, IN (...)), enforce size limits, and document extra cost.

  • Rate limiting models: know token bucket (smooth bursts) vs leaky bucket (steady rate). Implement counters in Redis for distributed enforcement and use sliding-window or fixed-window with jitter to reduce thundering herd.

  • Client behavior on 429s: honor Retry-After header; use exponential backoff with jitter (e.g., base * 2^n + random) and respect idempotency for retries. Surface backoff info to users or observability.

  • Idempotency: design write APIs to accept an idempotency key (e.g., UUID) and persist the result for at least the time window clients may retry; consider storage TTL and eviction semantics.

  • Operational headers & telemetry: expose X-RateLimit-Limit/Remaining/Reset or similar; log p99 latency, error rates, and 429 counts per client and per route to tune quotas.

  • Performance tradeoffs: precomputing denormalized lists (cache) speeds page responses for heavy reads but complicates consistency; measure reads per second and eviction cost before denormalizing.

  • Security & quotas: apply per-API-key, per-account, and per-IP quotas. Differentiate authentication tiers (e.g., test vs live) and implement graceful degradation (soft limits, informative 429 payloads).

  • Backwards compatibility: expanding fields changes response size; version responses and cap total payload size to avoid breaking mobile clients.

Worked example — "Design a paginated API for listing transactions"

Start by clarifying semantics: ask whether ordering must be strictly stable (e.g., by created_at, id) and whether the client expects a consistent snapshot across pages. Declare assumptions: sort by created_at DESC, id DESC, eventual consistency acceptable, and page size default 50.

Organize the solution into pillars: API contract (query parameters limit, cursor; return fields data, has_more, next_cursor); storage access (use keyset pagination: WHERE (created_at,id) < (:cursor_created_at, :cursor_id) ORDER BY created_at DESC, id DESC LIMIT :limit with an index on (created_at, id)); and operational concerns (rate limiting, caching). Explain scaling: for low-latency, read-through Redis cache per-account for most recent pages; for deep scans use index-only scans or a streaming background process to materialize per-account lists.

Flag tradeoffs: cursor tokens are safe and efficient but require clients to hold state; snapshot guarantees require storing a snapshot id or using MVCC and increase complexity. For heavy multi-tenant load, per-account cursor state persisted in Redis reduces recomputation but needs eviction rules.

Close: note follow-ups — if more time, discuss prefetching next page, partial responses with expand controls, and monitoring metrics like page p99 and 429 rates to tune per-account quotas.

A second angle — "Implement a client library that handles rate limits and expansions"

Here the constraint is client-side: limited memory (mobile) and intermittent connectivity. The same concepts apply but framing shifts: the client should expose a high-level retry policy using exponential backoff with jitter, queue user-initiated requests and persist idempotency keys to local storage, and support lazy expansion (only expand when caller requests). For bandwidth constraints use If-None-Match/ETag or request small pages first and allow server-side expand hints. The client must surface Retry-After to the caller and offer cancellation hooks; on unstable networks, prefer idempotent operations and exponential backoff with capped retries.

Common pitfalls

Pitfall: Choosing OFFSET pagination for large datasets.
Using OFFSET for deep pages leads to high DB CPU and unpredictable latency; interviewers will prefer keyset (cursor) pagination and ask how you handle ties.

Pitfall: Ignoring expansion cost and payload size.
Blindly allowing unlimited expansions can produce large responses and backend N+1 queries; always cap expansions server-side and batch related-fetches (SELECT ... WHERE id IN (...)).

Pitfall: Retrying non-idempotent writes without idempotency keys.
A tempting quick fix is naive retries on 5xx/429; a stronger answer explicitly requires idempotency keys and explains TTL/cleanup and semantic guarantees.

Connections

This area commonly pivots to API versioning (how changes to expanded fields affect clients), distributed caching (cache invalidation strategies for paginated lists), and observability/alerting (instrumenting 429 spikes and per-client throttling metrics). Interviewers may also ask about database indexing and query plans when you justify keyset vs offset.

Further reading

Related concepts