Skip to main content
The Cloud Chat API lets you read and manage your Cloud Chat data from your own systems. It is a curated surface: a set of endpoints we commit to and version, not a window onto everything the Cloud Chat app does internally. The endpoints available today are listed in the sidebar, and the set grows over time. Everything on this page applies to all of them. Each endpoint’s own page covers what is specific to it.

Two headers, every call

Authorization carries the id_token from POST /auth/v1/signin — not the access_token, which does not carry the identity we authorize on. One token works across every Cloud Humans API, and expires after the expires_in seconds the sign-in response reports. cloudchat-instance says which Cloud Chat instance holds your data. Cloud Chat runs on several instances with independent databases, and your company lives on exactly one of them, so the value is fixed for you: set it once in your client’s configuration and forget it. You are told it at onboarding, and it is also written into your own token — the Find your credentials page reads it out for you.
Omit cloudchat-instance and the call is rejected before authentication, with a 400 that does not use the normal error envelope:
Send the wrong instance and you get a 401 or a 404 instead: either that instance does not accept your token, or the account you asked for simply isn’t in its database. You never reach someone else’s data by guessing.

Signing in is a loop, not a call

POST /auth/v1/signin does not always answer with a token. Some accounts have a temporary password, and some have two-step verification turned on — for those, a 200 carries a challenge instead: no token, and a session to answer it with. So the shape to write is a loop, not a single request. Post credentials, then keep answering whatever comes back at POST /auth/v1/signin/challenge until a token appears. To just get a token now — challenge and all — the Find your credentials page runs the whole flow for you and asks only for the code from the text message. Branch on the body, not on the status. Both outcomes are 200, and both endpoints return the same two shapes — which is also why answering a challenge can hand you another one. A first-access user who also has two-step verification genuinely goes NEW_PASSWORD_REQUIREDSMS_MFA → token, and each step returns a new session that replaces the one you just used.

If you are putting this on a screen

Three things are worth knowing before the first user hits it. Send the code as a string. Codes can start with a zero, and "012345" parsed into a JSON number is a different code. A number is rejected with a 400 rather than coerced, precisely so this shows up on your first test instead of as one user in ten who “can’t log in”. A wrong code and a dead session look identical. Both come back 400 CodeMismatchException, so the screen cannot honestly say which happened. Offer a retry, and next to it a way back to the beginning — retrying against an expired session never recovers, and a user with no way out is stuck on a screen that only ever says the code is wrong. The session is not yours to keep. It belongs to one sign-in attempt, so there is nothing to persist and nothing to resume — and it stops being accepted well before the token it leads to would have expired. When that happens the only move is /auth/v1/signin again, which sends a fresh code.
Accounts configured for a challenge type other than these two — an authenticator app, for instance — cannot finish signing in through this API, and have to use the Cloud Chat interface to get a token.

Accounts are explicit

The account id travels in the path: /v1/accounts/{accountId}/.... It has to be an account your token grants membership on, and it has to live on the instance you named — the two are checked together. That is deliberately unlike the Claudia API, where the account is derived from the token alone. Cloud Chat users routinely hold several accounts, so making the caller name one is clearer than picking for them.

Errors

Every response the API itself produces uses one envelope:
Branch on code. It is stable. message is not: it is localized to your account’s language — English, Spanish or Brazilian Portuguese, falling back to English — and the wording changes between releases. details, when present, stays in English regardless, because it describes fields rather than speaking to an end user.

404 covers “not yours”, not just “not there”

One distinction is worth internalizing before you write error handling, because it is the opposite of what most APIs do. Asking for an account you are not a member of returns 404, not 403 — identical to asking for an account that does not exist, same body, and the message stays in English in both so it cannot even leak the account’s configured language. That is on purpose: nobody can walk the accountId space to learn which accounts exist. The cost is that a 404 doesn’t tell you which of the two happened, so there is nothing to retry — check the accountId, the cloudchat-instance value, and that your user is actually a member. 403 is left with exactly one meaning: you are a member, and the account is suspended. Nothing on it can be read or written until that is resolved.

400 is about shape, 422 is about values

A 400 always means the request itself was unreadable — invalid JSON, a missing or non-object payload wrapper, or a query parameter sent as an array or nested object (?page[]=1). A 422 means the request was understood and a value was refused. Retrying a 400 unchanged never helps; the fix is always in how the request is built.

Rate limits

Requests are rate limited per source IP. The limit is not something to hardcode — read it from the response, because every response carries the current state: Over the limit you get 429 with a bare message, since the request never reached the API:
Handle it by waiting, not by retrying immediately: sleep for Retry-After seconds and try again. If you are running a batch, watch ratelimit-remaining as you go and pause when it approaches zero — that keeps you from ever seeing a 429, and it adapts on its own if the limit changes.