Rate limits

Budget you can see, not a wall you hit. Every response carries X-RateLimit-Remaining and X-RateLimit-Reset. Four independent buckets (reads, writes, bookings-feed, analytics) mean a batch inventory push does not steal budget from your booking-feed consumer. A higher budget is a free config change, not a re-integration — see the SLA for the default numbers and Why Quendoo Connect for how this compares against the hidden fixed limits every other vendor ships.

Every call to /v1/qc/* (and to the outbound webhook fanout) is budgeted. Budgets are per (client_id, endpoint bucket, minute) — shared across your workers, not per host, not per token. The default numbers live on the SLA page; this page covers behaviour: what the headers mean, what a 429 means, what does and does not count.

The headers on every response

X-RateLimit-Limit:     600
X-RateLimit-Remaining: 597
X-RateLimit-Reset:     1735689600
X-RateLimit-Bucket:    reads
Header Meaning
X-RateLimit-Limit The per-minute budget for THIS bucket at your tier. Never changes mid-window.
X-RateLimit-Remaining Budget left this minute. Decrements with every call the bucket accepted.
X-RateLimit-Reset Unix seconds at which X-RateLimit-Remaining resets to Limit. Fires on wall-clock minute boundaries, not on your first call.
X-RateLimit-Bucket Which bucket THIS call landed in — reads / config-writes / inventory-writes / webhook-fanout.

Read every response for these — the safe pacing rule is "if Remaining hits a low watermark, defer non-urgent calls until Reset".

429 — you spent the budget

HTTP/1.1 429 Too Many Requests
Retry-After: 27
X-RateLimit-Limit:     600
X-RateLimit-Remaining: 0
X-RateLimit-Reset:     1735689600

{"status":"error","message":"errors.qc.rate_limit_exceeded"}

Wait Retry-After seconds — never a naked retry-now loop that just eats latency. Retry-After and X-RateLimit-Reset agree; the former is a convenience, the latter is the authoritative wall-clock.

429 is a bucket miss, NOT an availability miss

A 429 does not count as downtime under the SLA. It's expected behaviour under a valid tier. If you keep hitting it, the answer is either back off or upgrade — never open an incident on us.

What counts

What does NOT count

The four buckets

Bucket Endpoints
reads GET /properties, /room_types, /rate_plans, /availability, /rates, /bookings?revisions=…, and every configuration surface GET (extras, promos, policies, gallery, reviews, content pages).
config-writes Every POST / PATCH / DELETE on the configuration surfaces — extras, promotions, policies, content, gallery, booking buttons, room types, rate plans, guest feedback.
inventory-writes POST /v1/qc/properties/{ext}/inventory/* — availability, rates, restrictions. High-frequency; separate bucket by design so a burst on inventory doesn't starve config writes.
webhook-fanout Outbound only — how many webhook deliveries we'll attempt on your behalf per day.

Why "per minute" and not "per second"

A per-minute window smooths bursts a per-second window couldn't tolerate — you can flush a 60-row inventory push in ten seconds and sit idle for the other fifty. The trade-off is that a bad minute looks worse in a per-minute view; expect the Remaining counter to slide fast when a batch runs, then flatline until reset.

Pacing patterns that work

Steady state — mind the low watermark

Read X-RateLimit-Remaining off the last response; if it's below say 10% of Limit, defer non-urgent calls (write-behind updates, speculative reads) until Reset fires. Cost: a shorter tail on your median latency, and no 429s in the log.

Burst — align on the reset

If you're pushing a big batch (multi-hundred-property nightly sync), start the batch at a wall-clock second aligned with our reset — X-RateLimit-Reset from any prior call gives you the boundary. You get a full 60 s to burn the whole minute's budget without throttling.

Retry — exponential + jitter

On 429 (or 5xx) use Retry-After if present, else exponential backoff starting at 500 ms with ±20% jitter. Do NOT sleep exactly Retry-After in a fleet — every worker unblocks at the same instant, hammering the reset boundary. Add jitter.

What happens on a workflow bucket miss

The webhook-fanout bucket applies to outbound deliveries. When you exceed it we do NOT drop events. We queue them; the retry ladder from the SLA still runs. Sustained bucket saturation degrades your webhook latency SLA — which you own — not your delivery guarantee, which we own.

The daily fanout budget resets at 00:00 UTC.

Cross-cutting reads

What we don't do