Documentation
Partner API

Rate limits

Two requests a second with small bursts on the default plan, Retry-After on 429, monthly caps, and the non-JSON 403 edge throttle with a 90-second back-off.

Updated 2026-10-24MarkdownOpenAPI

Two limits apply to your keys: a pace per key, and monthly caps per plan. Both answer 429 with a JSON envelope. The network edge in front of the API adds a third, coarser one that answers without JSON.

Pace

The default plan allows 2 requests a second per key with bursts up to 10; your plan may allow more, and GET /v1/ping reports your rate_limit. Over the limit you get 429 RATE_LIMITED with Retry-After in seconds, X-RateLimit-Limit and X-RateLimit-Remaining. Throttled calls are logged like any other and counted in your usage.

Monthly caps

Your plan may cap requests, live orders and test orders per calendar month (UTC). GET /v1/account shows the caps under limits — monthly_request_cap, monthly_order_cap, monthly_test_order_cap, where 0 means no cap — and this month's usage. At 80 percent of a cap you get usage.warning once; at the cap, 429 QUOTA_EXCEEDED until the first of next month. The request cap is checked against a count refreshed every 30 seconds, so a handful of calls may pass over it. A quote cap per day (quote_daily_cap) works the same way.

The edge throttle

In front of the API sits a network edge that protects every LayerCrew service. Above roughly 5 requests a second from one address it answers 403 with an HTML or empty body — no JSON envelope, no X-Request-ID.

  • Treat a 403 without JSON as the edge: back off 90 seconds, then resume at two requests a second.
  • Keep to two requests a second per source address, with small bursts, even when your plan's key limit is higher.
  • Never retry a create blindly. For an order, send the same Idempotency-Key again or look it up by reference; for a file, list your files; for a webhook endpoint, list your endpoints.

Designing for the limits

  • Use webhooks for state changes and the events feed to reconcile; polling each order is the pattern that hits the limits first.
  • Batch your reads: lists take per_page up to 100, the feed limit up to 200.
  • One client, one queue: a shared token bucket in your integration keeps bursts in bounds.
  • Back off on 429 and on 5xx with jitter; quote X-Request-ID if a pattern repeats.
Node
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function layercrew(path, init = {}, attempt = 0) {
  const res = await fetch(`https://engine.layercrew.com/v1${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.LAYERCREW_API_KEY}`, ...(init.headers ?? {}) },
  });
  const isJson = (res.headers.get("content-type") ?? "").includes("application/json");
  if (res.status === 403 && !isJson) {
    await sleep(90_000);                       // the edge: back off 90 seconds
    return layercrew(path, init, attempt + 1); // same init, same Idempotency-Key
  }
  if ((res.status === 429 || res.status >= 500) && attempt < 5) {
    const retryAfter = Number(res.headers.get("retry-after")) || 2 ** attempt;
    await sleep(retryAfter * 1000 + Math.random() * 500);
    return layercrew(path, init, attempt + 1);
  }
  return res;
}

A fetch wrapper that honours Retry-After, backs off the edge and never retries a create without its key

Body size

Request bodies are limited to 256 KiB — 413 PAYLOAD_TOO_LARGE beyond it. File bytes never travel in JSON; they go to the signed upload URL described under Files.

We value your privacy

We use cookies for analytics and advertising to improve your experience and measure our marketing. See our Privacy Policy.