Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.amps.ai/llms.txt

Use this file to discover all available pages before exploring further.

Every Amps response uses the same envelope. Successes carry a data field, failures carry an error field, and both carry meta for tracing and pagination. The shape is predictable across every endpoint, every device type, every status code.

The envelope

A successful response:
{
  "success": true,
  "data": { "id": "device_abc123", "state": "..." },
  "meta": { "requestId": "req_..." }
}
A failed response:
{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_UNIT",
    "message": "Parameter `power` does not accept unit `percent` on this device.",
    "details": {
      "parameter": "power",
      "providedUnit": "percent",
      "supportedUnits": ["kw"],
      "deviceCapabilities": "..."
    }
  },
  "meta": { "requestId": "req_..." }
}
code is a stable, machine-readable identifier. message is a human-readable explanation. details is an optional object with structured data you can act on. Errors always carry a code. Generic 500-class failures use INTERNAL_ERROR. Recurring details fields: unsupportedModes[], unsupportedParameters[], conflictingActionIds[], conflictingScheduleIds[], deviceCapabilities, requestedExecution, supportedExecution. These let you fix the request in a single round trip. deviceCapabilities returns the same shape as the GET response, so you can re-derive a valid request without re-fetching the device.

Authentication

CodeHTTPTrigger
UNAUTHORIZED401No API key in the request.
INVALID_API_KEY401Key is unrecognised, malformed, revoked, or soft-deleted.
EXPIRED_TOKEN401Key has passed its expiry.
RATE_LIMIT_EXCEEDED401Key has exceeded its rate ceiling.
INSUFFICIENT_PERMISSIONS403Key lacks the required permission.
LIVE_ACCESS_DISABLED403Live key against a customer not enabled for live.
See auth and environments for context.

Resource access

CodeHTTPTrigger
DEVICE_NOT_FOUND404Device does not exist or is not linked to your account in this environment.
404 rather than 403 to avoid leaking the existence of devices owned by other customers.

Action validation

CodeHTTPTrigger
UNSUPPORTED_MODE422The command (mode) is not in the device’s commands map.
UNSUPPORTED_PARAMETER422A parameter is not declared for the resolved command. Body carries unsupportedParameters[] and deviceCapabilities.
UNSUPPORTED_UNIT422A parameter unit is not declared as valid for this device.
PARAMETER_OUT_OF_RANGE422A parameter value is outside the declared min/max bounds.
EXECUTION_NOT_SUPPORTED422The request shape (immediate, scheduled, or windowed) is not in the mode’s execution array. Body carries details: { requestedExecution, supportedExecution }.
START_IN_PAST422The start value is in the past.
START_OUT_OF_RANGE422The start value is beyond the 30-day scheduling horizon.
INVALID_TIME_WINDOW422start or end violates the time-window contract. Body carries details.reason naming the specific issue.
UNSUPPORTED_SETTING422Setting key is not declared for this device.
READ_ONLY_SETTING422Setting key is declared but read-only.
SETTING_OUT_OF_RANGE422Setting value is outside the declared bounds.
INVALID_TIME_WINDOW reasons: invalid_end_format, end_not_after_start, malformed_iso, sub_minute_window_not_supported, window_must_not_span_midnight, utc_offset_not_supported_until_plant_timezone_resolved, relative_duration_not_supported_for_windowed_modes.

Conflicts

CodeHTTPTrigger
CONFLICT409Non-terminal action exists on the device and onConflict was not supplied. Body carries conflictingActionIds[] and strategies[].
SCHEDULER_ACTIVE409Device-side scheduler conflicts with the requested action. Body carries details.reason and details.recoveryStrategies.
SCHEDULER_FULL409Merged schedule would exceed the OEM’s group limit. Body carries details.existingGroupCount and details.maxGroupCount.
ACTION_NOT_CANCELLABLE409Cancel request for an action already in acknowledged, completed, failed, or cancelled.
See conflict resolution for the full model.

Runtime and platform

CodeHTTPTrigger
INTERNAL_ERROR500Unexpected fault. Includes requestId for support correlation.
SERVICE_UNAVAILABLE503Transient unavailability. Safe to retry with exponential backoff.
503 also covers transient internal unavailability. Standard retry behaviour suffices.

When to retry

ClassRetry?
5xx (INTERNAL_ERROR, SERVICE_UNAVAILABLE)Yes, with exponential backoff and jitter.
429-class rate limit (RATE_LIMIT_EXCEEDED)Yes, after a backoff.
401 / 403No. Fix auth or live-access enablement first.
404 (DEVICE_NOT_FOUND)No. The link is missing.
409 (CONFLICT, SCHEDULER_ACTIVE)Resolve via onConflict or wait for the conflict to terminate, then re-submit.
422No. Fix the request body using details.
Push actions are not retried server-side on OEM rejection. Commands are time-sensitive, and running minutes later is usually worse than failing. You decide whether to re-submit, and with what.

Recovery patterns

A 422 is solvable from the response alone. The details payload carries the device’s current capability snapshot, so the agent or developer can re-derive a valid request without a second GET. UNSUPPORTED_MODE and UNSUPPORTED_PARAMETER carry a deviceCapabilities snapshot, so you can rebuild the request without a second GET. EXECUTION_NOT_SUPPORTED carries both what you sent and what the mode supports, in the same vocabulary, so you pick a valid shape directly. The error response is enough on its own to fix the call. Fields are never silently discarded. An unknown field returns 422. A known-but-unsupported field returns the corresponding 422. There is no path where a field is accepted, ignored, and you believe it took effect. meta.requestId ties a request to platform logs. Surface it in your error handler when escalating to support.

Frequently asked questions

What does a typical error response look like?

A JSON body with success: false, an error object with code and message (plus optional details), and a meta object with requestId. The shape is identical across every endpoint, device type, and status code. Successes use the same envelope with success: true and data. The code is stable and machine-readable; the message is human-readable; details is structured data the caller can act on (e.g., unsupportedParameters[], conflictingActionIds[], a deviceCapabilities snapshot).

Which error codes are retryable?

5xx (INTERNAL_ERROR, SERVICE_UNAVAILABLE) and 429-class rate limit (RATE_LIMIT_EXCEEDED) are retryable with exponential backoff and jitter. 401 and 403 are not retryable: fix auth or live-access enablement first. 404 (DEVICE_NOT_FOUND) is not retryable: the link is missing. 409s are resolvable via onConflict. 422s are not retryable as-is: fix the request body using details. Push actions are never retried server-side on OEM rejection because commands are time-sensitive.

How do I distinguish a client error from a server error?

By status code class. 4xx codes name client errors: 401 (auth), 403 (permissions), 404 (resource access), 409 (conflict), 422 (validation). 5xx codes name server-side faults: 500 (INTERNAL_ERROR), 503 (SERVICE_UNAVAILABLE). The body in either class follows the same envelope. When escalating to support, surface meta.requestId in your error handler; it ties the request to platform logs.

Why does the API never silently discard fields?

Because silent discarding hides bugs and breaks the contract. Every field a client supplies is either honoured, validated, or rejected. Sending an unknown field returns 422. Sending a known-but-unsupported parameter returns 422 UNSUPPORTED_PARAMETER. Sending a value outside its bounds returns 422 PARAMETER_OUT_OF_RANGE. There is no path where the field is accepted, ignored, and the client believes the field took effect. Honest rejections are part of the API design contract.

Canonical Actions

The shape that produces validation errors.

Conflict Resolution

CONFLICT, SCHEDULER_ACTIVE deep dive.

Capabilities

The deviceCapabilities snapshot returned in rejections.

Auth and Environments

Authentication errors in detail.