Errors
Every Hostex OpenAPI v3 response uses the same envelope:
{
"request_id": "RT2026052115252141408b3",
"error_code": 200,
"error_msg": "Done.",
"data": {}
}
- The HTTP status is
200even for application-level errors. Always
branch onerror_code, not on the HTTP status. error_code: 200means success. Any other value is a failure.datacarries the endpoint's result and is omitted when the endpoint has
nothing to return.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 |
|---|---|---|---|
200 | 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-account, per-endpoint, per-thread, or per-token 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 Layer 1 per-account 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.
404 on DELETE /reservations/{code}
404 on DELETE /reservations/{code}This endpoint cancels manually created reservations only. A booking
that came from a channel (Booking.com, Agoda, Ctrip, …) is not
addressable here and returns 404 with
Only manually created reservations can be cancelled through this endpoint. — cancel it on the channel side instead. A code prefix other
than 5- tells you up front that this call cannot succeed.
This resource is no longer available. on the same route means the code
really is unknown under your account.
Both are 404: verify and stop. Do not retry — before 2026-09-08
this case was reported as 500, which our own guidance says to retry.
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.
