Errors
Every Hostex OpenAPI v3 response uses the same envelope:
{
"request_id": "RT2026052115252141408b3",
"error_code": 0,
"error_msg": "",
"data": {}
}
- The HTTP status is
200even for application-level errors. Always
branch onerror_code, not on the HTTP status. error_code: 0means success. Any non-zero value is a failure.error_msgis a short human-readable English string. Do not parse it
programmatically — match onerror_codeinstead.request_idshould be quoted in any support ticket about a specific
failing call. Every server-side log line is keyed by it.
Error code reference
The codes mirror standard HTTP status semantics so you can map them
straight into your own client.
error_code | Class | When | What to do |
|---|---|---|---|
0 | success | The call succeeded. | — |
400 | bad request | Input is malformed — missing required body, wrong JSON, parameter conflict (e.g. entire scope + non-empty property_ids). | Fix the request; do not retry. |
401 | auth | Token is missing, invalid, deleted, or has the wrong scope. Also returned by OAuth endpoints on bad client_id / client_secret / code_verifier. | Re-issue / re-authorize. See Authentication. |
403 | forbidden | You are authenticated, but the resource is not yours — e.g. accessing a conversation thread belonging to another operator. | Stop attempting; the user does not own this resource. |
404 | not found | The resource id does not exist (or the path is misspelled). | Verify the id; do not retry. |
409 | conflict | The action would create a duplicate (e.g. creating a tag whose name already exists). | Reconcile state and retry without the duplicate. |
422 | validation | Body parsed but failed validation rules (e.g. note too long, start_date after end_date, id_required value not in enum). error_msg includes the failing field. | Fix the request; do not retry. |
420 | account / subscription | Underlying Hostex account problem: subscription expired, Basic edition trying to use Pro-only feature, account suspended. | Do not retry. Surface the message to the host — only they can fix it in the portal. |
429 | rate-limit | Per-token, per-endpoint, or per-thread throttle hit. May also come from OAuth brute-force guard. | Back off according to Retry-After header. See Rate Limits. |
500 | server | Hostex-side bug, partial outage, or upstream channel timeout. | Retry with exponential backoff; if it persists, file a support ticket with request_id. |
501 | not implemented | Endpoint exists but the feature is disabled for your account (e.g. dynamic OAuth client registration when no public client is configured). | Surface to the user; do not retry. |
502 / 503 / 504 | upstream | Hostex is reachable but a downstream channel (Airbnb, Booking.com, etc.) failed. | Retry. If repeated, file a ticket. |
Common error scenarios — recipes
"Invalid access token" on the very first call
- Header typo:
Hostex-Access-Token(note the dash), not
Hostex_Access_TokenorHostex-Access_Token. - Whitespace: trim the token before sending.
- Token revoked or rotated in the Host Portal.
"Not authorized for this action"
Your access token is read-only. Token scope is fixed at creation
time — create a new writable token in the OpenAPI Settings page and
revoke the old one.
429 on POST /conversations/{id} even though you are well under 1200/min
429 on POST /conversations/{id} even though you are well under 1200/minYou hit the per-thread message throttle (Layer 3 in
Rate Limits), not the per-token quota. Spread sends
across threads, or drop the cadence on automated replies in the same
thread.
409 when creating a reservation tag or property tag
409 when creating a reservation tag or property tagA tag with the same name already exists (or was soft-deleted and will
be transparently restored — try a GET /reservation_tags?keyword=…
first). Names are unique within the operator's account.
420 on every call
420 on every callThe host's subscription expired or downgraded to Basic. The token is
fine; the host must renew / upgrade in the Host Portal. There is
nothing your integration can do server-side.
404 on DELETE /reservation_tags/{id}
404 on DELETE /reservation_tags/{id}The tag is a system default tag (is_default: true), which cannot
be deleted via the API. Only custom tags belonging to the operator can
be removed. Filter on is_default in the GET /reservation_tags
response before offering "delete" in your UI.
429 from OAuth /oauth/authorizations
429 from OAuth /oauth/authorizationsBrute-force guard. After 10 failed client_secret / code_verifier
attempts in 10 minutes for a single client_id, exchange calls are
rejected for the rest of the window. Make sure your refresh-token
flow has a deduplication mutex (one in-flight refresh per token).
When to file a support ticket
Include all of the following so the on-call team can reproduce the
issue in under a minute:
- The
request_idfrom the failing response body. - Approximate timestamp (UTC) of the failure.
- The HTTP method and path called (no need to redact the path — only
the body / headers contain secrets). - Whether you authenticated with an access token or OAuth bearer
token (do not include the token itself). - Expected behaviour vs observed behaviour.
