SUQODocs
User GuideAPI ReferenceSDKs

Not yet implemented

Idempotency keys and rate limiting — the intended behaviour, ahead of the feature.

Two behaviours the SDK is built forward-ready for, neither of which the backend supports yet. They are documented here so the shape is settled ahead of the feature rather than bolted on after it, and so nothing on this page reads as if it already works.

Both were previously separate pages, and both said the same thing about their own status; keeping them together makes that status the point of the page.

Idempotency keys

Status: Planned. Idempotency keys are not yet supported by the backend — this page documents the intended header and behaviour now so it drops in cleanly once it is, rather than being bolted on later.

Current behaviour

Write operations (create, cancel, updateBillingCycle) are not retried automatically by the SDK. The API does not yet support idempotency keys, so a retried write could double-act (e.g. create a duplicate subscription). This is a deliberate, single switch in the SDK's retry layer.

Read operations (list, retrieve) are unaffected: they're naturally idempotent and already retried on NetworkError, 429, and 5xx — see Errors.

Intended header

Once supported, write operations will accept an X-Idempotency-Key header. Sending the same key on a repeated write is intended to let the API deduplicate the request instead of performing the action twice.

Intended SDK behaviour

  • The SDK will auto-generate a UUID idempotency key for each write call if the caller doesn't supply one.
  • An override parameter will let callers pass their own key, e.g. to correlate a retry across separate calls.
  • Once the header is honoured by the backend, writes will flip to retryable in the SDK's retry layer.

Why this isn't built yet

Idempotency support is blocked on the backend: the API must dedup requests on the X-Idempotency-Key value before the SDK can safely retry writes. Until the backend honours the header, writes stay non-retryable, and this page stays a description of intended behaviour rather than a reference for a shipped feature.

This page will be updated with real usage examples once idempotency keys are built.

Rate limiting

Status: Planned. The API does not enforce rate limits yet and returns no rate-limit headers today. This page describes the intended model ahead of the feature, not bolted on after the fact.

Current behaviour

No rate limiting is enforced by the API today. Requests are not throttled and no 429 responses are returned for exceeding a rate. Nothing about how you call the SDK needs to change in anticipation of this — the SDK is already built forward-ready (see below).

Intended model

Once enabled, rate limiting is expected to work as a token bucket, per API key:

  • Each API key is allotted a bucket of request tokens that refills over time.
  • Exceeding the bucket returns an HTTP 429, with a Retry-After header indicating how long to wait before the bucket has room again.

Exact bucket size and refill rate are not yet finalized and aren't published here to avoid documenting numbers that could change before launch.

SDK behaviour

The SDK is already built to handle this without a breaking change when it ships:

  • RateLimitError already exists in the SDK's error hierarchy, reserved for 429 responses. It is never thrown today, since the API never returns a 429.
  • The retry path for read operations already honours a Retry-After header when present, with exponential backoff and jitter. No SDK update will be required for read retries to respect rate-limit backoff once it arrives.

Quota metadata — named, not yet built

Beyond Retry-After, names are already reserved for quota metadata, following the IETF RateLimit-* draft that GitHub and Cloudflare have converged on:

Response headerSDK field
RateLimit-LimitrateLimitLimit
RateLimit-RemainingrateLimitRemaining
RateLimit-ResetrateLimitReset

None of these exist in the SDK today — the API doesn't send the headers, and no code reads them. They're listed here only so the names are settled ahead of time. Where exactly they'll surface (on every response, only on RateLimitError, or something else) is still open — this page will be updated with the real shape once that's decided and the headers actually start arriving.

Once rate limiting is live, catch RateLimitError and back off using its retryAfter (milliseconds, derived from the response's Retry-After header when present) before retrying:

import { RateLimitError } from "@suqo/sdk";

try {
  await client.products.list();
} catch (err) {
  if (err instanceof RateLimitError) {
    // err.retryAfter is the suggested backoff in milliseconds, if the
    // response included a Retry-After header.
  }
}

This page will be updated with concrete bucket limits and any additional guidance once rate limiting ships.

On this page