Rate Limits

Rate Limits

Hostex applies rate limiting at three layers to keep the service stable
for everyone. Exceeding a limit returns HTTP 200 with error_code: 429
in the body and a Retry-After header (in seconds).


Layer 1 — Per-token (user) limit

Applies to all v3 endpoints combined, keyed on your access token.

WindowMax requests
1 minute1,200
5 minutes12,000
1 hour20,000
24 hours100,000

These four are checked in parallel — you hit 429 as soon as any one
is breached.

Layer 2 — Per-token + per-endpoint limit

Applies to one endpoint at a time, keyed on (access token, request path).

Endpoint pattern1 min5 min1 h24 h
POST /v3/availabilities120
POST /v3/listings/* (prices / inventories / restrictions / calendar)120
POST /v3/reservations60
All other endpoints6006,00010,00050,000

A dash means that window is not enforced for that pattern (the user-level
limit still applies).

Layer 3 — Per-thread throttle on POST /conversations/{id}

Sending a message to a guest is throttled per thread (independent of your
access token), because OTAs aggressively rate-limit channel-side message
APIs and Hostex must shield the channel account from suspensions:

WindowMax messages per thread
5 seconds5
60 seconds10
30 minutes30
2 hours60
24 hours120

All five are checked in parallel. Plan templates and HostGPT auto-replies
accordingly.


Response on rate-limit hit

HTTP/1.1 200 OK
Retry-After: 60
X-RateLimit-Scope: user            # or "endpoint"
X-RateLimit-Window: 1m
X-RateLimit-Reason: user rate limit exceeded: 1200 requests per 1m

{"error_code":429,"error_msg":"Too Many Attempts.","request_id":"RT..."}

For Layer 3 (message throttle) the body explicitly tells you when to retry:

{"error_code":429,"error_msg":"Too many requests. Try again in 60 seconds.","request_id":"RT..."}

How to stay under the limit

  1. Always send a meaningful User-Agent — e.g. MyCleaningApp/1.2.3 ([email protected]). It helps Hostex bypass IP-level bot defences
    and lets the on-call team contact you about behaviour issues.
  2. Cache dictionary endpoints aggressively. GET /custom_channels,
    GET /income_items, GET /expense_items, GET /income_methods,
    GET /expense_methods, GET /tags, GET /groups change rarely —
    refresh once an hour at most, not on every reservation create.
  3. Batch where possible. POST /listings/prices accepts a list — one
    call per listing-day-range, not per day.
  4. Add jitter on retry. When you get 429, exponential backoff
    starting at the Retry-After value, plus ±25% random jitter, prevents
    thundering-herd against the next window.
  5. Don't tail webhooks with polling. Subscribe to
    Webhooks instead of polling
    GET /reservations every minute — the events arrive in < 5 s.
  6. Use id filters when querying after a write. Re-querying a single
    record via GET /reservations?id=… is far lighter than re-pulling the
    whole list to find the one you just changed.

What is not a rate-limit

ErrorLooks like 429 but isn't
420 Subscription expired / Basic editionAccount-level issue. Do not retry — the host must take action in the portal.
429 Too many attempts. from /oauth/authorizationsOAuth brute-force guard, not the user-level rate limit. Stop attempting for 10 minutes after >10 failed exchanges.