Why we throttle
The Guest Talk platform enforces rate limits for two reasons — fair sharing across tenants on the multi-tenant backend, and protection of the write path from runaway integrations that would otherwise overwhelm the queueing layer during peak season. The limits below are chosen to be generous enough that a well-behaved integration never sees a 429 in normal operation, tight enough that a runaway loop trips the ceiling within seconds rather than filling a queue that then takes an hour to drain.
Every limit is enforced per tenant, not per API token. If an integration issues multiple tokens for scoping or rotation, all of them draw against the same tenant budget. This means a rotation strategy that keeps two overlapping tokens active does not double your capacity; only the ceiling raise procedure at the bottom of this page does.
Per-tenant global limit
Every tenant on the platform gets a global budget of 600 requests per minute aggregated across every endpoint. The budget is a sliding-window count, not a fixed calendar-minute reset — the window is the trailing sixty seconds from the moment the current request lands. A tenant that pushes 600 requests in the first ten seconds of a minute cannot issue another request until the earliest of those 600 falls out of the window, roughly fifty seconds later.
The global budget is the outer envelope. Even if a specific endpoint has room in its own sub-budget, a request that would push a tenant over the global 600/min still returns 429. Conversely, a tenant well under the global budget can still trip a per-endpoint cap on a hot write path — see the next section.
Per-endpoint limits
On top of the global budget, individual endpoints carry their own sub-caps that reflect the cost of the operation on our backend. Read endpoints get the most headroom; write endpoints that touch the reservation write-ahead log get less; endpoints that trigger channel sync out to OTAs get least. The table below summarises the caps that apply to the endpoints an integrator typically hits.
| Endpoint | Method | Cap (per minute) |
|---|---|---|
| /reservations | GET | 300 |
| /reservations | POST | 120 |
| /reservations/{id} | PATCH | 120 |
| /availability | GET | 300 |
| /availability | POST | 60 |
| /folios/{id}/charges | POST | 240 |
| /messages | POST | 90 |
| /reports/{name} | GET | 60 |
| /webhook-endpoints | POST/PATCH | 10 |
A per-endpoint cap counts only against itself; a POST /reservations at the ceiling does not affect the budget available on PATCH /reservations/{id}. The per-endpoint cap is the reason a well-behaved integration rarely trips the global 600/min — the sub-caps distribute the pressure across endpoints before it becomes a whole-tenant problem.
Bulk endpoints
A handful of endpoints accept batched payloads — POST /availability takes up to 1,000 date-room tuples per request; POST /rate-plans/bulk-update takes up to 500 rate updates. These count as one request against your budget but are subject to a separate row budget of 30,000 rows per minute per tenant to prevent a single caller from monopolising the write path.
The row budget is the right lever for a channel manager or a revenue-management integration that needs to sync large windows. A caller that stays inside 30,000 rows per minute can move a full year of availability in about two minutes without ever tripping the endpoint cap. A caller that tries to do it in thirty seconds trips the row budget and receives a 429 with a suggested pacing in Retry-After.
Response headers
Every response — success or throttle — carries the rate-limit header family so that a well-behaved client can pace itself without ever waiting for a 429. The headers describe the state of the endpoint bucket the request was accounted against.
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 34
X-RateLimit-Scope: endpoint:POST /reservations
Content-Type: application/json - X-RateLimit-Limit — the cap for the bucket the request was accounted against.
- X-RateLimit-Remaining — how many requests remain in the bucket before the next request would trip the ceiling.
- X-RateLimit-Reset — the number of seconds until the bucket refills to the full cap. On a sliding window this is the time for the oldest request in the window to age out.
- X-RateLimit-Scope — which bucket applied. Values are
global,endpoint:METHOD path, orrow-budget. - Retry-After — only on
429responses; the number of seconds until the caller can retry safely. Always honour this value in preference to your own guess.
Handling 429
A 429 Too Many Requests response carries a JSON body with error code TG-5001 or TG-5002, a human message, and the Retry-After header in seconds. The recommended handling is: on receipt, sleep for the number of seconds in Retry-After plus a small jitter, then retry the exact same request. Do not walk your own exponential backoff on top of Retry-After; the platform already knows the right wait, and stacking a client-side backoff produces the thundering-herd problem the header exists to prevent.
If your workload is a long-running batch — nightly rate sync, weekly analytics extract — the correct pattern is to read X-RateLimit-Remaining on every response and pace yourself preemptively. A batch that pauses for one second when Remaining drops below 20 will effectively never see a 429. This is cheaper than the alternative because retries after 429 consume the token twice — once for the failed call, once for the retry.
Client-side example
import time, requests
def call_with_pacing(session, method, url, **kwargs):
while True:
r = session.request(method, url, **kwargs)
remaining = int(r.headers.get("X-RateLimit-Remaining", "999"))
if r.status_code == 429:
wait = int(r.headers.get("Retry-After", "1"))
time.sleep(wait + 0.25)
continue
if remaining < 20:
time.sleep(1.0) # preemptive slowdown
return r The pattern above generalises to any HTTP client — read Remaining, slow down before you hit zero, obey Retry-After if you did anyway. A single-threaded caller that follows this pattern will stay under the endpoint cap without any additional coordination. A multi-threaded caller needs a shared token bucket in front of the HTTP layer, and the token bucket should be seeded with X-RateLimit-Limit from the first successful response so it self-calibrates to whichever cap actually applies to your tenant.
Raising the limit for Enterprise
The default caps are enough for the operational profile of a single property or a small portfolio. Larger operations — a chain moving availability for 40 properties every hour, a channel manager pushing 200 tenants through a single integration, a data warehouse extracting a rolling year of folio movements every night — routinely need a higher ceiling. Talkguest raises the per-tenant global and the per-endpoint caps on request for Enterprise contracts.
To arrange a raise, contact the integrations team through the contact page or request Enterprise access. The information we ask for is the expected peak requests per minute, the endpoints involved, the timing of the peak (nightly window, check-in surge, month-end reporting) and whether the traffic is coming from a single caller or fanning out from many. The raise is applied per tenant, effective within one business day, and does not affect the sandbox environment — sandbox stays at the default caps so that a load test in sandbox reflects the default customer profile.
Next steps
Cross-check the shape of the responses you will be pacing against on the API reference. Read the webhooks page if you can replace polling with events — the cheapest request is the one you never make. Read the error codes page for the TG-5001 and TG-5002 details. For architecture help or a ceiling raise, reach us through the contact page.