Errors
Every status code the partner API and the OAuth endpoints answer with, what it means, and what to do about it.
The API uses ordinary HTTP status codes. A 2xx means it worked; anything else carries a JSON body that says why.
The error body
Most errors carry a sentence in detail, written so you can log it or show it to the hotel:
{
"detail": "The price has changed: the total is now USD 180.00."
}A 422 carries a list instead, one entry per field problem. loc is where the problem is:
{
"detail": [
{ "loc": ["body", "departure"], "msg": "Field required", "type": "missing" },
{ "loc": ["body", "guest"], "msg": "Field required", "type": "missing" }
]
}Check the type of detail before you read it: string or array.
Status codes
| Status | Meaning | What to do |
|---|---|---|
200, 201 | Worked. 201 when a reservation was made | |
400 | The request is well formed but can't be done as asked: a past arrival, too much paid, card payments not set up | Read detail. Retrying the same request gives the same answer |
401 | No credential, or one that is wrong, revoked or expired | Refresh the access token, or ask for a new key. Don't retry as is |
402 | The hotel's plan doesn't include this (card payment links) | Hide the feature for this hotel |
403 | The app's connection doesn't have the scope, or the hotel's account isn't active | Ask the hotel to connect again with the scope; see Scopes |
404 | Not found, or not this credential's property | Check the ID and which property the credential is for |
409 | Conflicts with the current state: price changed, duplicate external_ref, booking cancelled, an Idempotency-Key still in progress | Read detail; usually show the guest something new |
422 | A field is missing or the wrong shape, or an Idempotency-Key was reused for a different request | Fix the request |
429 | Too many calls | Wait Retry-After seconds; see Rate limits |
502 | Stripe refused or didn't answer (payment links only) | Nothing was made. Retry later |
503 | The partner API is paused for this hotel or for everyone | Wait Retry-After seconds (600) |
500 | Something broke on our side | Retry with the same Idempotency-Key; tell us if it lasts |
Errors you will meet
| Status | detail | When |
|---|---|---|
401 | A valid API key or access token is needed: Authorization: Bearer cbk_... or cbat_... | No Authorization header, or a wrong, revoked or expired credential |
403 | This connection was not allowed 'reservations:write'. Ask the hotel to connect the app again with that scope. | The app token lacks the scope |
403 | This hotel's ChatBeds account is not active. | The hotel's account is suspended or closed |
404 | Reservation not found | Unknown ID, or another property's booking |
404 | Property not found | The path's property_id is not the credential's property |
409 | The price has changed: the total is now USD 180.00. | expected_total no longer matches. Nothing was booked |
409 | A booking with external_ref BK-104233 already exists (a589df05-30ad-4ee5-9832-16ff6c2c1d0e). | You already booked this external_ref. Fetch it rather than booking again |
409 | A request with this Idempotency-Key is already being processed. | Two requests with one key at the same moment. Wait and retry |
422 | This Idempotency-Key was used for a different request. | Same key, different body or path |
400 | Idempotency-Key must be 1 to 255 characters. | |
400 | Card payments are not set up for this hotel. An owner connects Stripe on the Finance page. | No Stripe; don't offer card payment |
429 | Too many calls for this key (at most 120 a minute). Wait 12 seconds and try again. | Over the rate limit |
Each operation in the API reference lists its own errors.
OAuth errors
The /oauth/* endpoints answer as RFC 6749 says: error is a fixed code, error_description says why.
{
"error": "invalid_client",
"error_description": "Unknown client, or wrong client secret."
}| Status | error | error_description |
|---|---|---|
401 | invalid_client | Unknown client, or wrong client secret. or This app is suspended. |
400 | invalid_grant | The code is unknown, used or expired. Start the connection again. |
400 | invalid_grant | redirect_uri must be the one sent to /oauth/authorize. |
400 | invalid_grant | code_verifier does not match the code_challenge. |
400 | invalid_grant | The hotel disconnected the app. |
400 | invalid_grant | This refresh token was already used. All tokens for this connection were stopped. |
400 | invalid_grant | The connection was ended or the refresh token expired. Connect again. |
400 | unsupported_grant_type | grant_type is authorization_code or refresh_token. |
429 | slow_down | Too many requests. Wait N seconds. |
invalid_grant on a refresh means the connection is over: mark it disconnected in your app and ask the hotel to connect again. See OAuth.
Retrying safely
| Status | Retry? |
|---|---|
429, 503 | Yes, after Retry-After |
500, 502, a timeout, a dropped connection | Yes, with backoff and the same Idempotency-Key |
409 (key in progress) | Yes, after a second or two |
Any other 4xx | No: change the request first |
With an Idempotency-Key, a retry of a write that did go through returns the first answer instead of doing it twice. See Idempotency.
Building something?