Rate limits
Limits are per application and per account, not per IP. Your whole fleet shares one budget for one host, and each host you are connected to has its own.
Headers
Every response carries your current position, not just a 429.
X-RateLimit-Limit-Read: 600
X-RateLimit-Remaining-Read: 573
X-RateLimit-Reset-Read: 1756654920
The suffix is Read or Write, matching what the call you just made spends. A write carries the Write trio and never the Read one, so look for the suffix rather than a fixed header name.
Two budgets are charged on every call — the per-account one and the client-wide one — but only one trio comes back: whichever of the two is closer to running out. Reporting the roomier number would be worse than reporting nothing, because the one you can see is then not the one that will stop you.
Read Remaining and slow down before you hit zero. A client that only reacts to 429s is a client that generates them.
When you exceed one
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Scope: account
X-RateLimit-Reason: per-account write limit exceeded: 120 requests per 1m
{
"success": false,
"value": null,
"error": {
"detail": "rate_limited",
"message": "Rate limit exceeded.",
"requestId": "0f7e4c1a-2b8d-…",
"data": { "retryAfterSeconds": 12, "scope": "account", "window": "1m" }
}
}
X-RateLimit-Scope names which budget you exhausted, so you know whether to slow down against one host or across your whole integration.
Honoring Retry-After
Wait at least the number of seconds given, then add jitter of 25 percent or more.
Jitter is not politeness. A fleet that all received the same Retry-After and all retry at exactly that moment reconstructs the burst that caused the limit, and the second wave is worse than the first because it arrives synchronized.
delay = retry_after * (1 + random.uniform(0, 0.25))
Reads and writes are budgeted separately
Writes are more expensive: each one fans out to a channel manager, an email, sometimes an SMS. Read budgets are correspondingly larger.
Your tier is set at approval from your volume estimate and can be raised. If you are hitting limits during normal operation, that is a conversation rather than something to engineer around; write to info@bookwithhaven.com with your client id and the correlation id of a limited request.
Staying under
Prefer webhooks to polling. Once webhooks ship, an event tells you something changed and one read confirms it. Polling every listing every five minutes is the traffic shape limits exist to bound.
Use updated_since. Re-walking a portfolio to find the one thing that changed is the expensive way to ask a cheap question.
Cache what does not move. A listing's timezone, currency and capacity change rarely. The listing list is not a hot resource.
Batch where an endpoint offers it, and do not fan out one request per row when a filtered list would do.
Back off on 5xx as well as 429. A retry storm against an origin that is already struggling is how a degraded service becomes an outage.
What is not limited here
The two discovery documents are CDN-cached constants and are not rate limited. The token endpoint has its own limits, described in The token endpoint; notably it limits by attempts rather than by successful mints, so a refresh bug slows you down rather than locking you out for a day.