Rate limits & request IDs

How the Fungies API rate limits requests, how to back off from a 429, and how to correlate a call with x-request-id.

Rate limits

The API is rate limited at the edge, per client IP, to keep one caller from crowding out others. Exceeding the limit returns 429 Too Many Requests, and further requests from that IP are rejected for a short cooldown before traffic is accepted again.

Build against the behaviour below rather than against a specific number — the edge limit can change without an API version bump.

The limit is generous enough that normal integration traffic doesn't reach it. Bursts of parallel requests are the usual cause, so spacing calls out is more effective than retrying harder.

A few endpoints carry a second limit of their own, counted per workspace rather than per IP, because of what they hand out. Where one applies, the endpoint's own reference page says so and names the number. Handle that 429 the same way as the one above.

Handling a 429

Treat 429 as retryable: back off and retry rather than failing the operation.

Choose your own retry schedule — exponential backoff with jitter, starting around half a second.

async function withBackoff(request, { attempts = 5 } = {}) {
  for (let attempt = 0; attempt < attempts; attempt++) {
    const response = await request();
    if (response.status !== 429) return response;

    await sleep(2 ** attempt * 500 + Math.random() * 250);
  }
  throw new Error("Rate limited after 5 attempts");
}

Practical guidance:

  • Serialize bulk work. The API handles one object per request, so a large import is a lot of calls. Run them in a small, bounded queue instead of firing them all at once.
  • Page with larger pages. Fewer, bigger pages beat many small ones — see Pagination.
  • Cache what doesn't change. Product and offer data rarely changes between checkouts.

Retrying a write after a 429 is only safe under the rules on Idempotency & retries — the request may have been rejected before it was applied, but don't assume it.

Request IDs

Every response carries an x-request-id header:

$ curl -i "https://api.fungies.io/v0/products/list" \
    -H "x-fngs-public-key: pub_your_public_key"

HTTP/1.1 200 OK
content-type: application/json
x-request-id: 3f8c1e02-9b4a-4f27-8d31-6a5e0c7b12d4

If your request already carries an x-request-id, that value is reused and echoed back, so you can correlate a call end-to-end with your own tracing id. Otherwise one is generated for you.

Log the x-request-id on every non-2xx response. Quoting it in a support request is by far the fastest way for us to find your exact call — much faster than a timestamp and an endpoint name.

Sending and reading x-request-id is a server-side facility. Cross-origin browser calls are limited to the request headers the API advertises (content-type, x-fngs-public-key, x-fngs-secret-key) and can't read the response header back, which is one more reason to call the API from your backend.

Last updated