Rate Limits and Retries
OpenAPI limits excessive request frequency to protect service and device communication stability. Clients should not depend on fixed quotas and must handle rate-limit responses correctly.
When a Request Is Limited
A rate-limited request returns:
- HTTP status
429 - Error code
RATE_LIMITED - A
Retry-Afterresponse header in seconds data.retryAfterSeconds, with the same meaning asRetry-Afterdata.rateLimitScope, identifying the rate-limit bucket rather than an API Client permission
Real-time refresh and device control are protected more strictly than ordinary queries. When changing multiple relays, send them in one relays array instead of splitting them into consecutive requests.
409 DEVICE_BUSY is different from rate limiting: it means that another operation is currently communicating with the device. Wait for that operation to finish and do not retry concurrently. 429 RATE_LIMITED means that requests are too close together or the accumulated quota was exceeded; retry after the delay in the response.
Requests rejected with 429 do not consume additional quota or extend the current window. Service instances using the same API Client share endpoint quotas; continuous concurrent retries can consume the newly available quota immediately after the window resets.
Idempotency-Key
Idempotency-Key is a unique request key generated by the caller for one command request.
Use it when the HTTP connection closes or the client times out before receiving a valid OpenAPI response. If the client cannot determine whether the request was accepted, it can retry the identical request with the same key without creating a duplicate command.
A command object's TIMEOUT status is a terminal result for the original command; it is not an HTTP request timeout. Reusing the same key returns the same commandId and result without sending another device command. Generate a new key only after deciding to perform a new physical operation. For operations with side effects, confirm device state and assess duplicate-execution risk first.
Rules:
- Generate a new
Idempotency-Keyfor each new command request - Reuse the original key when retrying because no definitive OpenAPI response was received
- Do not reuse a key for another device, command, or request body
Idempotency-Keyis not an access token and is not used for authentication
Client Handling
- After
429, retry after the delay inRetry-Afterordata.retryAfterSeconds - After
409 DEVICE_BUSY, wait for the current device operation to finish and retry with backoff - For
500 INTERNAL_ERROR, use bounded exponential backoff - Retries of commands with side effects must reuse the original
Idempotency-Key - Coordinate backoff across service instances to avoid another simultaneous burst
- Except for
DEVICE_BUSY, do not retry400,401,403,404,409, or422without changing the request or credentials
Response Example
HTTP/1.1 429 Too Many Requests
Retry-After: 1{
"code": "RATE_LIMITED",
"message": "Too many requests",
"requestId": "req_001",
"data": {
"retryAfterSeconds": 1,
"rateLimitScope": "endpoint",
"limit": 30,
"windowSeconds": 60
}
}The legacy data.scope field remains temporarily for compatibility. New clients should use data.rateLimitScope. Missing permissions return 403 AUTH_SCOPE_DENIED with data.requiredScope and are unrelated to rate-limit scopes.
