openapi: 3.1.0 info: title: Afero Cloud Devices API version: v1 description: 'The Afero Cloud API is the RESTful control plane for the Afero IoT platform: it lists the devices and users on an Afero account, reports real-time device state, executes attribute read/write actions against connected devices, and manages the over-the-air (OTA) firmware pipeline — firmware types, firmware pool images, binary upload, device-type associations, firmware tags, and firmware pushes. All requests are made over TLS to https://api.afero.io and are authenticated with an OAuth 2.0 bearer access token obtained from the /oauth/token endpoint using the partner OAuth Client ID and Client Secret issued in the Afero Profile Editor. This OpenAPI was DERIVED by API Evangelist from Afero''s public developer documentation (resource URLs, HTTP methods, request headers, request payload model schemas, response model schemas and examples transcribed verbatim from the docs); it is NOT a provider-published specification. Afero publishes no machine-readable spec: https://api.afero.io/api-docs and https://api.afero.io/v1/openapi.json both answer HTTP 401 (authenticated access required), probed 2026-08-02.' contact: name: Afero Developer Documentation url: https://afero-docs.readthedocs.io/en/latest/CloudAPIs/ email: sales@afero.io license: name: Afero Developer Terms of Service url: https://cdn.afero.io/tos/developer/v1/developer.html x-apievangelist-derived-from: https://afero-docs.readthedocs.io/en/latest/CloudAPIs/ x-apievangelist-derived-on: '2026-08-02' x-apievangelist-provider-published: false x-apievangelist-split-from: openapi/_original/afero-cloud-api-openapi.yml externalDocs: description: Afero Developer Docs url: https://afero-docs.readthedocs.io/en/latest/ servers: - url: https://api.afero.io description: Afero Cloud API production base URL tags: - name: Devices description: 'Afero devices on an account: listing, real-time state, attribute actions and naming.' externalDocs: url: https://afero-docs.readthedocs.io/en/latest/API-DeviceEndpoints/ paths: /v1/accounts/{accountId}/devices: get: operationId: listDevices tags: - Devices summary: List current devices and state information description: Lists the devices associated with the specified account. The response can be enriched with the `expansions` query parameter to include device state, device tags, or device attributes. externalDocs: url: https://afero-docs.readthedocs.io/en/latest/API-DeviceEndpoints/ parameters: - name: accountId in: path description: The Afero account ID. schema: type: string required: true - name: expansions in: query description: Selects the additional information returned for each device. One of `state`, `tags` or `attributes`. schema: type: string enum: - state - tags - attributes required: false responses: '200': description: The devices on the account. content: application/json: schema: type: array items: $ref: '#/components/schemas/Device' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' security: - bearerAuth: [] /v1/accounts/{accountId}/devices/{deviceId}: get: operationId: getDevice tags: - Devices summary: Get a single device and its state information description: Returns a single device on the specified account. The response can be enriched with the `expansions` query parameter to include device state, device tags, or device attributes. externalDocs: url: https://afero-docs.readthedocs.io/en/latest/API-DeviceEndpoints/ parameters: - name: accountId in: path description: The Afero account ID. schema: type: string required: true - name: deviceId in: path description: The Afero device ID. schema: type: string required: true - name: expansions in: query description: Selects the additional information returned for each device. One of `state`, `tags` or `attributes`. schema: type: string enum: - state - tags - attributes required: false responses: '200': description: The device. content: application/json: schema: $ref: '#/components/schemas/Device' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' security: - bearerAuth: [] /v1/accounts/{accountId}/devices/{deviceId}/actions: post: operationId: executeDeviceAction tags: - Devices summary: Execute an action on a device description: 'Submits an attribute read or write against a device by attribute ID. `data` must be hexadecimal encoded, little endian. Read and write commands are ASYNCHRONOUS: the call may return before the read/write takes place, and if the device is offline the request may never complete.' externalDocs: url: https://afero-docs.readthedocs.io/en/latest/API-DeviceEndpoints/ parameters: - name: accountId in: path description: The Afero account ID. schema: type: string required: true - name: deviceId in: path description: The Afero device ID. schema: type: string required: true requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DeviceAction' responses: '200': description: The accepted action request. content: application/json: schema: $ref: '#/components/schemas/DeviceActionResult' example: type: attribute_write requestId: 14 timestampMs: 1449267297894 sender: ClientApi source: type: user userId: 123acdfa-asd2-4b26-2cd2-68cfe2acdd8b8 firstName: Mike lastName: Smith '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' security: - bearerAuth: [] /v1/accounts/{accountId}/devices/{deviceId}/friendlyName: put: operationId: updateDeviceFriendlyName tags: - Devices summary: Update the friendly name of a device description: Changes the friendly name of the specified device. This name is visible in the Afero Profile Editor. externalDocs: url: https://afero-docs.readthedocs.io/en/latest/API-DeviceEndpoints/ parameters: - name: accountId in: path description: The Afero account ID. schema: type: string required: true - name: deviceId in: path description: The Afero device ID. schema: type: string required: true requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FriendlyName' responses: '200': description: The updated friendly name. content: application/json: schema: $ref: '#/components/schemas/FriendlyName' example: friendlyName: cool_new_name '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' security: - bearerAuth: [] components: securitySchemes: bearerAuth: type: http scheme: bearer description: 'The OAuth 2.0 access token returned by POST /oauth/token, sent as `Authorization: Bearer `. Tokens expire (approximately four hours per the Afero docs).' schemas: DeviceTag: type: object description: Returned when the `tags` expansion is requested. properties: deviceTagId: type: string deviceTagType: type: string description: e.g. `SYSTEM`. value: type: string localizationKey: type: string FriendlyName: type: object required: - friendlyName properties: friendlyName: type: string Error: type: object description: The Afero Cloud API error envelope, observed live on api.afero.io (2026-08-02). properties: timestamp: type: integer description: Epoch milliseconds the error was produced. status: type: integer description: The HTTP status code. error: type: string description: The short error code, e.g. `unauthorized`. error_description: type: string description: Human readable description of the error. service_name: type: string description: The Afero service that produced the error, e.g. `ClientApi`. region: type: string description: The Afero cloud region, e.g. `us-west-2`. DeviceState: type: object description: Returned when the `state` expansion is requested. properties: available: type: boolean visible: type: boolean dirty: type: boolean rebooted: type: boolean connectable: type: boolean connected: type: boolean linked: type: boolean rssi: type: integer updatedTimestamp: type: integer location: $ref: '#/components/schemas/DeviceLocation' DeviceLocation: type: object properties: latitude: type: string longitude: type: string lastUpdatedTimestamp: type: integer ActionSource: type: object properties: type: type: string description: e.g. `user`. userId: type: string firstName: type: string lastName: type: string Device: type: object properties: deviceId: type: string profileId: type: string description: The device Profile ID. deviceTypeId: type: string partnerId: type: string friendlyName: type: string updating: type: boolean virtual: type: boolean developerDevice: type: boolean disconnectNotificationLevel: type: string description: e.g. `LOW`, `MEDIUM`. createdTimestamp: type: integer deviceState: $ref: '#/components/schemas/DeviceState' deviceTags: type: array items: $ref: '#/components/schemas/DeviceTag' attributes: type: array items: $ref: '#/components/schemas/DeviceAttribute' DeviceAttribute: type: object description: Returned when the `attributes` expansion is requested. properties: id: type: integer description: The device attribute ID. data: type: string description: Hexadecimal encoded, little endian attribute value. updatedTimestamp: type: integer DeviceAction: type: object required: - type - attrId properties: type: type: string enum: - attribute_read - attribute_write description: The action to perform. The attribute must support the operation. attrId: type: integer description: The device attribute ID to read or write. data: type: string description: Hexadecimal encoded, little endian value to write. DeviceActionResult: type: object properties: type: type: string requestId: type: integer timestampMs: type: integer sender: type: string description: The Afero service that accepted the request, e.g. `ClientApi`. source: $ref: '#/components/schemas/ActionSource' responses: Unauthorized: description: Full authentication is required to access this resource. content: application/json: schema: $ref: '#/components/schemas/Error' example: timestamp: 1785679681261 status: 401 error: unauthorized error_description: Full authentication is required to access this resource service_name: ClientApi region: us-west-2 Forbidden: description: The authenticated principal does not hold the required account or partner privilege. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: The requested resource does not exist. content: application/json: schema: $ref: '#/components/schemas/Error' security: - bearerAuth: []