Skip to content

Errors and responses

Every endpoint except the OAuth endpoints wraps its result:

{ "status": "SUCCESS", "data": { … } }
{ "status": "FAILED", "message": "Device does not belong to current user" }

There is no numeric error code. Branch on the HTTP status and, where you need more detail, on the message text.

The OAuth authorize and token endpoints use RFC 6749 bodies, {"error", "error_description"}, and the user info endpoint returns a plain object. The two request-rate limiters return {"status": "ERROR", "message": …}.

Status When
200 Success. chemistryCard may also set partial: true
201 OAuth client created
302 Authorization page redirecting back to your application with a code
400 Malformed JSON, missing field or out-of-range value; OAuth request errors
401 Missing or invalid bearer token; OAuth client authentication failed
403 The user does not own the controller
404 Unknown path, with a plain-text body. v2 only: GET …/state before any state exists, with a JSON body
409 v2 only: the controller is not on v2 firmware or has not been heard from recently
429 Request-rate limit, or the controller is busy or cooling down
500 Controller did not answer in time, or an unexpected failure
503 v1 writes and scheduleInfo when the API’s link to the controller network is down; v2 only: v2 not enabled on the server. A cold v1 read with the link down returns 500 MQTT client not connected
504 v2 only: the controller did not answer a query or action in time

Retry-After is sent only on the request-rate limiter 429s, not on controller-busy 429s.

Two different things produce 429:

  • Request-rate limits on sign-in and site refresh. The body has "status": "ERROR" and the response carries Retry-After. Wait that long.
  • Controller throttling on device endpoints. The body has "status": "FAILED" and a message containing device busy:, sometimes prefixed with the operation, such as failed to create schedule: device busy: …. When the message contains retry after <duration>, the duration is written like 5s, 30s or 1m0s; wait at least that long. Otherwise wait 5 seconds. See Rate limits and throttling.

A message ending in timeout waiting for response means the controller did not reply within the endpoint’s timeout. The controller may be offline, busy or on a poor connection. Check online in the site list, wait, and retry with back-off. A single timeout already starts a 5-second cool-down, and repeated timeouts lengthen it; see Rate limits and throttling.