{
  "openapi": "3.1.0",
  "info": {
    "title": "MQcentral API",
    "version": "v2",
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-Proprietary"
    },
    "description": "Provides endpoints to access and manage MachineQ *Resources* and *Devices*. Version 2 delivers performative APIs designed for scale and flexibility.\n"
  },
  "servers": [
    {
      "url": "https://api.machineq.net",
      "description": "Production MachineQ API Server"
    },
    {
      "url": "https://api.preview.machineq.net",
      "description": "Preview MachineQ API Server"
    },
    {
      "url": "https://api.dev.machineq.net",
      "description": "Development MachineQ API Server"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Devices",
      "description": "Select endpoints for the _Devices_ API are available in the V2 release. All other APIs continue to use the v1 designation until updated to v2. The V1 _Devices_ API remains available for backwards compatibility.\n\nResults from these endpoints are streamed. After calculating the `meta` section, the server begins streaming results per _Device_ as the query completes. Streaming enables faster response times for customers with large fleets.\n\nStatistics fields are included at the top-level of each record for easier querying.\n\n_Groups_ are included in each record to support fleet management and filtering.\n"
    },
    {
      "name": "Overview",
      "description": "The MachineQ output system connects MQcentral to client applications by delivering IoT device data and platform operation information. Output is primarily delivered via push mechanisms to configured *Destinations*.\n\n*Destinations* include:\n  - Webhooks\n  - MQTT\n  - Popular cloud solutions including AWS (IoTCore) and Azure (IoTHub)\n\nPlatform operation information is delivered via *Output Alert Events*. When a *Gateway* or *Device* configured with an *Output Alert* meets the alert condition (such as \"gateway online/offline\"), an *Output Alert Event* is delivered to all configured *Destinations*.\n",
      "x-traitTag": true
    },
    {
      "name": "Output Credentials",
      "description": "*Output Credentials* specify the access criteria used when delivering data to *Output Destinations*."
    },
    {
      "name": "Output Destinations",
      "description": "*Output Destinations* define the client-side collector of data emitted from the MQcentral platform.\n\nMost *Output Destinations* require credentials so that the MachineQ output system can establish an authenticated connection.\nAn *Output Credentials* association varies depending on the type of *Output Destination*:\n\n- `webhook` *Output Destinations* typically use `basic_auth` or `client_credentials` credentials. \n- `mqtt` *Output Destinations* typically use `basic_auth` credentials.\n- `aws_iot_core` *Output Destinations* use `x509_certificate` credentials.\n- `azure_iot_hub` *Output Destinations* use `azure_shared_access_policy` credentials.\n"
    },
    {
      "name": "Output Alerts",
      "description": "*Output Alerts* define the relationship between data produced by physical IoT infrastructure and the rules that govern an alert condition."
    },
    {
      "name": "Output Events",
      "description": "*Output Events* are produced by the MachineQ output system when an *Output Alert* rule triggers\nbased on the current state of a specified device or gateway.\n"
    },
    {
      "name": "Device Configuration",
      "description": "API for reading and managing device configurations.\n\n## Codec support\n\nNot all devices support remote configuration — support depends on the device's codec.\nIf the device's codec does not support config encoding, `PUT` will return `400`. Use\n`GET` to check whether a device has ever had a desired config applied.\n\n## Rollout lifecycle\n\nWhen a desired config is submitted via PUT, a **rollout** is created and the first\nfragment is dispatched asynchronously as a LoRaWAN downlink — typically within\nseconds, but callers should not assume immediate delivery. Subsequent fragments are\nsent one at a time after each preceding fragment is confirmed. The rollout moves\nthrough the following statuses:\n\n| Status        | Description |\n|---------------|-------------|\n| `pending`     | Briefly transitional — rollout accepted but first fragment not yet scheduled for transmission. Rarely visible in practice. |\n| `in_progress` | First fragment scheduled for transmission; delivery underway |\n| `applied`     | All fragments confirmed |\n| `failed`      | A fragment failed after exhausting retries |\n| `cancelled`   | Cancelled via DELETE before completion |\n\n## Fragment lifecycle\n\nEach fragment within a rollout transitions independently:\n\n| Status      | Description |\n|-------------|-------------|\n| `pending`             | Not yet scheduled for transmission — either the rollout was just accepted or a prior fragment is still being confirmed |\n| `ready`               | Scheduled for the next transmission attempt |\n| `queued`              | Submitted to the network server |\n| `sent`                | Network server confirmed gateway transmission |\n| `confirmed`           | Device acknowledged (strategy-dependent) |\n| `gateway_unavailable` | No connected gateway can reach the device; fragment is suspended and will resume automatically when device activity is observed |\n| `failed`              | Delivery failed after retry exhaustion |\n| `cancelled`           | Cancelled before confirmation |\n\n## Confirmation strategies\n\nThe codec determines which strategy is used:\n\n- **`downlink-sent`** — fragment confirmed when the network server reports successful\n  gateway transmission.\n- **`uplink-ack`** — fragment confirmed when the device sends a LoRaWAN acknowledged\n  uplink in response to the downlink. Some device types additionally require the device\n  to echo the configuration back in a specific response message before the fragment is\n  considered confirmed.\n- **`reported-config`** — rollout applied when every parameter in the desired\n  configuration is present in the device's reported configuration with the same value.\n  The device may report additional parameters beyond those being set. Used for devices\n  that report their configuration across multiple successive uplinks rather than in a\n  single response. Only single-fragment rollouts are supported."
    }
  ],
  "paths": {
    "/v2/devices": {
      "get": {
        "tags": [
          "Devices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/fieldMaskParam"
          },
          {
            "$ref": "#/components/parameters/limitParam"
          },
          {
            "$ref": "#/components/parameters/pageParam"
          },
          {
            "$ref": "#/components/parameters/orderParam"
          },
          {
            "$ref": "#/components/parameters/qParam"
          }
        ],
        "summary": "Retrieves a list of devices",
        "description": "Returns all *Devices* for the authenticated account. Supports filtering, pagination, field selection, and sorting via query parameters.",
        "operationId": "GetDevices",
        "responses": {
          "200": {
            "description": "Successful response containing the device list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetDevicesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameter supplied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "code": 3,
                  "message": "invalid field mask parameter: id"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/devices/{dev_eui}": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Retrieves a device by DevEUI",
        "description": "Returns the *Device* identified by the given device EUI.",
        "operationId": "GetDevice",
        "parameters": [
          {
            "name": "dev_eui",
            "in": "path",
            "description": "Extended Unique Identifier of the device.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response containing the device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "400": {
            "description": "Invalid DevEUI format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "code": 3,
                  "message": "invalid field DevEui: value 'INVALID' must be a string conforming to regex ^[A-Fa-f0-9]{16}$"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/devices/{dev_eui}/config": {
      "get": {
        "operationId": "getDeviceConfig",
        "summary": "Get device configuration",
        "description": "Returns the reported and desired configuration for a device.\n\n- **`reported`** reflects the last configuration observed from a device uplink.\n  `null` if the device has never sent a config uplink.\n- **`desired`** reflects the most recent config rollout, including terminal\n  rollouts (applied, failed, cancelled). `null` if no rollout has ever been\n  created for the device.\n",
        "tags": [
          "Device Configuration"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DevEUI"
          }
        ],
        "responses": {
          "200": {
            "description": "Device configuration retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfigResponse"
                },
                "examples": {
                  "reported_and_in_progress": {
                    "summary": "Reported config with an in-progress rollout",
                    "value": {
                      "dev_eui": "AABB1122CCDD3344",
                      "reported": {
                        "config": {
                          "report_interval_seconds": 300,
                          "threshold_celsius": 25
                        },
                        "last_uplink_at": "2026-04-18T10:00:00Z"
                      },
                      "desired": {
                        "config": {
                          "report_interval_seconds": 60,
                          "threshold_celsius": 30
                        },
                        "source_type": "manual",
                        "status": "in_progress",
                        "created_by": "Job3ZjzC",
                        "updated_by": "Job3ZjzC",
                        "created_at": "2026-04-20T09:00:00Z",
                        "updated_at": "2026-04-20T09:00:05Z",
                        "started_at": "2026-04-20T09:00:05Z",
                        "progress": {
                          "total_fragments": 2,
                          "fragments_confirmed": 1,
                          "fragments": [
                            {
                              "sequence": 1,
                              "status": "confirmed",
                              "attempt_count": 1,
                              "queued_at": "2026-04-20T09:00:05Z",
                              "sent_at": "2026-04-20T09:00:06Z",
                              "confirmed_at": "2026-04-20T09:00:08Z"
                            },
                            {
                              "sequence": 2,
                              "status": "sent",
                              "attempt_count": 1,
                              "queued_at": "2026-04-20T09:00:09Z",
                              "sent_at": "2026-04-20T09:00:10Z"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "reported_only": {
                    "summary": "Reported config, no rollout ever created",
                    "value": {
                      "dev_eui": "AABB1122CCDD3344",
                      "reported": {
                        "config": {
                          "report_interval_seconds": 300
                        },
                        "last_uplink_at": "2026-04-18T10:00:00Z"
                      },
                      "desired": null
                    }
                  },
                  "applied": {
                    "summary": "Rollout successfully applied",
                    "value": {
                      "dev_eui": "AABB1122CCDD3344",
                      "reported": {
                        "config": {
                          "report_interval_seconds": 60,
                          "threshold_celsius": 30
                        },
                        "last_uplink_at": "2026-04-20T09:01:00Z"
                      },
                      "desired": {
                        "config": {
                          "report_interval_seconds": 60,
                          "threshold_celsius": 30
                        },
                        "source_type": "manual",
                        "status": "applied",
                        "created_by": "Job3ZjzC",
                        "updated_by": "Job3ZjzC",
                        "created_at": "2026-04-20T09:00:00Z",
                        "updated_at": "2026-04-20T09:01:00Z",
                        "started_at": "2026-04-20T09:00:05Z",
                        "completed_at": "2026-04-20T09:01:00Z",
                        "progress": {
                          "total_fragments": 1,
                          "fragments_confirmed": 1,
                          "fragments": [
                            {
                              "sequence": 1,
                              "status": "confirmed",
                              "attempt_count": 1,
                              "queued_at": "2026-04-20T09:00:05Z",
                              "sent_at": "2026-04-20T09:00:06Z",
                              "confirmed_at": "2026-04-20T09:01:00Z"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "failed": {
                    "summary": "Rollout failed after retries",
                    "value": {
                      "dev_eui": "AABB1122CCDD3344",
                      "reported": {
                        "config": {
                          "report_interval_seconds": 300
                        },
                        "last_uplink_at": "2026-04-18T10:00:00Z"
                      },
                      "desired": {
                        "config": {
                          "report_interval_seconds": 60
                        },
                        "source_type": "manual",
                        "status": "failed",
                        "failure_reason": "downlink delivery failed: tx error",
                        "created_by": "Job3ZjzC",
                        "updated_by": "admin",
                        "created_at": "2026-04-20T09:00:00Z",
                        "updated_at": "2026-04-20T09:05:00Z",
                        "started_at": "2026-04-20T09:00:05Z",
                        "completed_at": "2026-04-20T09:05:00Z",
                        "progress": {
                          "total_fragments": 1,
                          "fragments_confirmed": 0,
                          "fragments": [
                            {
                              "sequence": 1,
                              "status": "failed",
                              "attempt_count": 3,
                              "queued_at": "2026-04-20T09:00:05Z",
                              "sent_at": "2026-04-20T09:00:06Z"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "no_config": {
                    "summary": "Device exists but has never reported config or received a desired config",
                    "value": {
                      "dev_eui": "AABB1122CCDD3344",
                      "reported": null,
                      "desired": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/v2/devices/{dev_eui}/config/desired": {
      "put": {
        "operationId": "putDesiredConfig",
        "summary": "Set desired device configuration",
        "description": "Submits a desired configuration for the device. If an active rollout already\nexists it is cancelled and replaced with the new one. The first fragment is\ndispatched asynchronously; subsequent fragments follow as each is confirmed.\n\nThe `config` object must be valid for the device's codec type. The codec\ndetermines how the config is encoded into downlink fragments and which\nconfirmation strategy is used. Returns `400` if the codec does not support\ndevice config encoding or if the config fails validation.\n\nReturns `204 No Content` when the desired config is already fully reflected\nin the device's reported config — no rollout is created in this case.\n\nReturns `202 Accepted` when a rollout is created. Fragment delivery is\nasynchronous; poll `GET /devices/{dev_eui}/config` to track progress.\n",
        "tags": [
          "Device Configuration"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DevEUI"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutDesiredConfigRequest"
              },
              "examples": {
                "single_fragment": {
                  "summary": "Config that encodes into a single downlink",
                  "value": {
                    "config": {
                      "report_interval_seconds": 60,
                      "threshold_celsius": 30
                    }
                  }
                },
                "multi_fragment": {
                  "summary": "Config that encodes into multiple downlinks",
                  "value": {
                    "config": {
                      "report_interval_seconds": 60,
                      "threshold_celsius": 30,
                      "channels": [
                        {
                          "id": 1,
                          "enabled": true,
                          "multiplier": 1.5
                        },
                        {
                          "id": 2,
                          "enabled": false,
                          "multiplier": 1
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Desired config accepted and a rollout created with the first fragment ready for dispatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesiredConfigSection"
                },
                "examples": {
                  "pending": {
                    "summary": "Rollout created (first fragment ready for dispatch, second pending)",
                    "value": {
                      "config": {
                        "report_interval_seconds": 60,
                        "threshold_celsius": 30
                      },
                      "source_type": "manual",
                      "status": "in_progress",
                      "created_by": "Job3ZjzC",
                      "updated_by": "Job3ZjzC",
                      "created_at": "2026-04-20T09:00:00Z",
                      "updated_at": "2026-04-20T09:00:00Z",
                      "started_at": "2026-04-20T09:00:00Z",
                      "progress": {
                        "total_fragments": 2,
                        "fragments_confirmed": 0,
                        "fragments": [
                          {
                            "sequence": 1,
                            "status": "ready",
                            "attempt_count": 1
                          },
                          {
                            "sequence": 2,
                            "status": "pending",
                            "attempt_count": 0
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "204": {
            "description": "Desired config is already reflected in the device's reported config, no rollout created"
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_dev_eui": {
                    "summary": "Invalid dev_eui format",
                    "value": {
                      "message": "Invalid request parameter: 'dev_eui' must be a valid device EUI (16 hexadecimal characters)"
                    }
                  },
                  "codec_unsupported": {
                    "summary": "Codec does not support config encoding",
                    "value": {
                      "message": "codec \"my-sensor-v1\" does not support device config encoding"
                    }
                  },
                  "invalid_config": {
                    "summary": "Config fails codec validation",
                    "value": {
                      "message": "problem encoding device config: report_interval_seconds must be between 10 and 3600"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteDesiredConfig",
        "summary": "Cancel desired device configuration",
        "description": "Cancels the active rollout for the device. Any in-flight fragment is also\ncancelled. If no active rollout exists the response is `204 No Content`.\n\nNote that cancellation only affects the rollout state — any fragments\nalready delivered to the device are not reversed.\n",
        "tags": [
          "Device Configuration"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DevEUI"
          }
        ],
        "responses": {
          "200": {
            "description": "Active rollout found and cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesiredConfigSection"
                },
                "examples": {
                  "cancelled": {
                    "summary": "Rollout cancelled mid-delivery",
                    "value": {
                      "config": {
                        "report_interval_seconds": 60,
                        "threshold_celsius": 30
                      },
                      "source_type": "manual",
                      "status": "cancelled",
                      "created_by": "Job3ZjzC",
                      "updated_by": "Job3ZjzC",
                      "created_at": "2026-04-20T09:00:00Z",
                      "updated_at": "2026-04-20T09:02:00Z",
                      "started_at": "2026-04-20T09:00:05Z",
                      "progress": {
                        "total_fragments": 2,
                        "fragments_confirmed": 1,
                        "fragments": [
                          {
                            "sequence": 1,
                            "status": "confirmed",
                            "attempt_count": 1,
                            "queued_at": "2026-04-20T09:00:05Z",
                            "sent_at": "2026-04-20T09:00:06Z",
                            "confirmed_at": "2026-04-20T09:01:00Z"
                          },
                          {
                            "sequence": 2,
                            "status": "cancelled",
                            "attempt_count": 1,
                            "queued_at": "2026-04-20T09:01:01Z"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "204": {
            "description": "No active rollout for this device, nothing to cancel"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/v2/devices/{dev_eui}/config/history": {
      "get": {
        "operationId": "getDeviceConfigHistory",
        "summary": "Get device reported config history",
        "description": "Returns a paginated log of reported configuration changes for a device, ordered\nmost-recent first. Each record represents a moment when the device's reported\nconfig changed to a new value, as detected from an uplink.\n\nThe log is capped per device. Use `page_token` to paginate through older records.\n`limit` defaults to 20; large values are clamped to a server-side maximum.\nThe `meta.more` field is always present and explicitly indicates whether a\nfurther page exists.\n",
        "tags": [
          "Device Configuration"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DevEUI"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/PageToken"
          }
        ],
        "responses": {
          "200": {
            "description": "Config history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfigHistoryResponse"
                },
                "examples": {
                  "first_page": {
                    "summary": "First page — more results exist",
                    "value": {
                      "records": [
                        {
                          "config": {
                            "report_interval_seconds": 60,
                            "threshold_celsius": 30
                          },
                          "observed_at": "2026-05-20T14:32:00.123456Z"
                        },
                        {
                          "config": {
                            "report_interval_seconds": 300,
                            "threshold_celsius": 25
                          },
                          "observed_at": "2026-05-19T08:00:00.000000Z"
                        }
                      ],
                      "meta": {
                        "next_page_token": "MjAyNi0wNS0yMFQxNDozMjowMC4xMjM0NTZa",
                        "more": true
                      }
                    }
                  },
                  "last_page": {
                    "summary": "Last page — no further results",
                    "value": {
                      "records": [
                        {
                          "config": {
                            "report_interval_seconds": 300,
                            "threshold_celsius": 25
                          },
                          "observed_at": "2026-04-01T12:00:00.000000Z"
                        }
                      ],
                      "meta": {
                        "more": false
                      }
                    }
                  },
                  "empty": {
                    "summary": "No history recorded yet",
                    "value": {
                      "records": [],
                      "meta": {
                        "more": false
                      }
                    }
                  }
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "array",
                  "description": "NDJSON stream represented as an array for documentation purposes. In the actual\nresponse each element is a newline-delimited JSON object. Data records come first;\nthe final element is always a metadata object with a `meta` key. Absence of the\nfinal metadata element indicates a mid-stream error — the client should treat an\nunexpected EOF as a failure.\n",
                  "items": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/HistoricalReportedConfig"
                      },
                      {
                        "type": "object",
                        "description": "Final metadata line. Clients distinguish it from data records by the presence of the `meta` key.",
                        "required": [
                          "meta"
                        ],
                        "properties": {
                          "meta": {
                            "$ref": "#/components/schemas/ConfigHistoryMeta"
                          }
                        }
                      }
                    ]
                  }
                },
                "examples": {
                  "ndjson_first_page": {
                    "summary": "NDJSON — first page with more results",
                    "value": [
                      {
                        "config": {
                          "report_interval_seconds": 60,
                          "threshold_celsius": 30
                        },
                        "observed_at": "2026-05-20T14:32:00.123456Z"
                      },
                      {
                        "config": {
                          "report_interval_seconds": 300,
                          "threshold_celsius": 25
                        },
                        "observed_at": "2026-05-19T08:00:00.000000Z"
                      },
                      {
                        "meta": {
                          "next_page_token": "MjAyNi0wNS0yMFQxNDozMjowMC4xMjM0NTZa",
                          "more": true
                        }
                      }
                    ]
                  }
                }
              },
              "application/jsonl": {
                "schema": {
                  "type": "array",
                  "description": "Identical to application/x-ndjson. Send `Accept: application/jsonl` to receive\n`Content-Type: application/jsonl` in the response — the server echoes the media\ntype the client requested. One JSON object per line; the final line is always a\nmetadata object with a `meta` key.\n",
                  "items": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/HistoricalReportedConfig"
                      },
                      {
                        "type": "object",
                        "description": "Final metadata line. Clients distinguish it from data records by the presence of the `meta` key.",
                        "required": [
                          "meta"
                        ],
                        "properties": {
                          "meta": {
                            "$ref": "#/components/schemas/ConfigHistoryMeta"
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/v2/output/destinations": {
      "get": {
        "tags": [
          "Output Destinations"
        ],
        "summary": "Retrieves a list of output destinations",
        "description": "Returns all *Output Destinations* for the authenticated account.",
        "operationId": "ListOutputDestinations",
        "responses": {
          "200": {
            "description": "Successful response containing the output destination list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListOutputDestinationsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "post": {
        "tags": [
          "Output Destinations"
        ],
        "summary": "Creates a new output destination",
        "description": "Creates a new *Output Destination* with the given configuration.",
        "operationId": "CreateOutputDestination",
        "responses": {
          "201": {
            "description": "Output destination created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifiableOutputDestination"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/OutputDestinationInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/OutputDestinationRequestBody"
        }
      }
    },
    "/v2/output/destinations/{destination_id}": {
      "get": {
        "tags": [
          "Output Destinations"
        ],
        "summary": "Retrieves an output destination by ID",
        "description": "Returns the *Output Destination* identified by the given __destination_id__.",
        "operationId": "GetOutputDestination",
        "parameters": [
          {
            "name": "destination_id",
            "in": "path",
            "description": "Unique identifier of the *Output Destination*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/IdentifiableOutputDestinationSuccessResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputDestinationNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "put": {
        "tags": [
          "Output Destinations"
        ],
        "summary": "Updates an output destination by ID",
        "description": "Replaces the *Output Destination* identified by the given __destination_id__ with the provided configuration.",
        "operationId": "UpdateOutputDestination",
        "parameters": [
          {
            "name": "destination_id",
            "in": "path",
            "description": "Unique identifier of the *Output Destination*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response containing the updated output destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifiableOutputDestination"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/OutputDestinationInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputDestinationNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutputDestination"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Output Destinations"
        ],
        "summary": "Deletes an output destination by ID",
        "description": "Deletes the *Output Destination* identified by the given __destination_id__. This operation is irreversible.\n\n**Important:** Deleting an *Output Destination* also removes it from all associated *Output Alerts* without warning. This may leave one or more *Output Alerts* with zero associated *Output Destinations*.\n\nDeleting an *Output Destination* does not remove the associated *Output Credentials*.\n",
        "operationId": "DeleteOutputDestination",
        "parameters": [
          {
            "name": "destination_id",
            "in": "path",
            "description": "Unique identifier of the *Output Destination*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Output destination deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputDestinationNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/alerts": {
      "get": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Retrieves a list of output alerts",
        "description": "Returns all *Output Alerts* for the authenticated account.",
        "operationId": "ListOutputAlerts",
        "responses": {
          "200": {
            "description": "Successful response containing the output alert list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListOutputAlertsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "post": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Creates a new output alert",
        "description": "Creates a new *Output Alert* with the given configuration.",
        "operationId": "CreateOutputAlert",
        "responses": {
          "201": {
            "description": "Output alert created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifiableOutputAlert"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/OutputAlertInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutputAlert"
              }
            }
          }
        }
      }
    },
    "/v2/output/alerts/{alert_id}": {
      "get": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Retrieves an output alert by ID",
        "description": "Returns the *Output Alert* identified by the given __alert_id__.",
        "operationId": "GetOutputAlert",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/IdentifiableOutputAlertSuccessResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "put": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Updates an output alert by ID",
        "description": "Replaces the *Output Alert* identified by the given __alert_id__ with the provided configuration.",
        "operationId": "UpdateOutputAlert",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/IdentifiableOutputAlertSuccessResponse"
          },
          "400": {
            "$ref": "#/components/responses/OutputAlertInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutputAlert"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Deletes an output alert by ID",
        "description": "Deletes the *Output Alert* identified by the given __alert_id__. This operation is irreversible.\n\nDeleting an *Output Alert* does not remove the associated *Output Destinations*.\n",
        "operationId": "DeleteOutputAlert",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Output alert deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/alerts/{alert_id}/gateways:add": {
      "post": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Adds a gateway to an output alert",
        "description": "Adds the _Gateway_ identified by the given __node_id__ to the *Output Alert* identified by the given __alert_id__ if it does not already exist.\n\nReturns an HTTP `409 Conflict` error if the given __node_id__ is already associated to the *Output Alert*.\n",
        "operationId": "AddOutputAlertGateway",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddOutputAlertGatewayRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Gateway added to the output alert successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "409": {
            "description": "Gateway already associated to the output alert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "message": "Gateway with Node ID 'FFFF00800001069F' already exists for Alert identified by 'TGexoQsP'"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/alerts/{alert_id}/gateways:remove": {
      "post": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Removes a gateway from an output alert",
        "description": "Removes the _Gateway_ identified by the given __node_id__ from the *Output Alert* identified by the given __alert_id__ if it exists.\n\nReturns an HTTP `412 Precondition Failed` error if the given __node_id__ is not currently associated to the *Output Alert*.\n",
        "operationId": "RemoveOutputAlertGateway",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveOutputAlertGatewayRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Gateway removed from the output alert successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "412": {
            "description": "Gateway not associated to the output alert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "message": "Alert Gateway request is not valid: '30DC64A5B1337FAB' not associated to Alert"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/alerts/{alert_id}/gateways:batch_add": {
      "post": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Adds a batch of gateways to an output alert",
        "description": "Adds all _Gateways_ in the given collection of __node_ids__ to the *Output Alert* identified by the given __alert_id__ if they do not already exist.\n\nThe entire batch fails with an HTTP `409 Conflict` error if any of the given __node_ids__ are already associated to the *Output Alert*.\n",
        "operationId": "BatchAddOutputAlertGateways",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchAddOutputAlertGatewayRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Gateways added to the output alert successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "409": {
            "description": "One or more gateways already associated to the output alert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "message": "Gateway with Node ID 'FFFF00800001069F' already exists for Alert identified by 'TGexoQsP'"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/alerts/{alert_id}/gateways:batch_remove": {
      "post": {
        "tags": [
          "Output Alerts"
        ],
        "summary": "Removes a batch of gateways from an output alert",
        "description": "Removes all _Gateways_ in the given collection of __node_ids__ from the *Output Alert* identified by the given __alert_id__ if they exist.\n\nThe entire batch fails with an HTTP `412 Precondition Failed` error if any of the given __node_ids__ are not currently associated to the *Output Alert*.\n",
        "operationId": "BatchRemoveOutputAlertGateways",
        "parameters": [
          {
            "name": "alert_id",
            "in": "path",
            "description": "Unique identifier of the *Output Alert*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRemoveOutputAlertGatewayRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Gateways removed from the output alert successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputAlertNotFoundErrorResponse"
          },
          "412": {
            "description": "One or more gateways not associated to the output alert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Non2XXResponse"
                },
                "example": {
                  "message": "Gateway with Node ID 'FFFF00800001069F' does not exist for Alert identified by 'TGexoQsP'"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    },
    "/v2/output/credentials": {
      "get": {
        "tags": [
          "Output Credentials"
        ],
        "summary": "Retrieves a list of output credentials",
        "description": "Returns all *Output Credentials* for the authenticated account. Sensitive fields are redacted from the response.",
        "operationId": "ListOutputCredentials",
        "responses": {
          "200": {
            "description": "Successful response containing the output credentials list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListOutputCredentialsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "post": {
        "tags": [
          "Output Credentials"
        ],
        "summary": "Creates new output credentials",
        "description": "Creates new *Output Credentials* with the given configuration. Secrets are written to an encrypted store and never persisted in plain text.",
        "operationId": "CreateOutputCredentials",
        "responses": {
          "201": {
            "description": "Output credentials created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SafeIdentifiableOutputCredentials"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/OutputCredentialsInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/OutputCredentialsRequestBody"
        }
      }
    },
    "/v2/output/credentials/{credentials_id}": {
      "get": {
        "tags": [
          "Output Credentials"
        ],
        "summary": "Retrieves output credentials by ID",
        "description": "Returns the *Output Credentials* identified by the given __credentials_id__. Sensitive fields are redacted from the response.",
        "operationId": "GetOutputCredentials",
        "parameters": [
          {
            "name": "credentials_id",
            "in": "path",
            "description": "Unique identifier of the *Output Credentials*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/IdentifiableOutputCredentialsSuccessResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputCredentialsNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      },
      "put": {
        "tags": [
          "Output Credentials"
        ],
        "summary": "Updates output credentials by ID",
        "description": "Replaces the *Output Credentials* identified by the given __credentials_id__ with the provided configuration.",
        "operationId": "UpdateOutputCredentials",
        "parameters": [
          {
            "name": "credentials_id",
            "in": "path",
            "description": "Unique identifier of the *Output Credentials*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/IdentifiableOutputCredentialsSuccessResponse"
          },
          "400": {
            "$ref": "#/components/responses/OutputCredentialsInvalidInputErrorResponse"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputCredentialsNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/OutputCredentialsRequestBody"
        }
      },
      "delete": {
        "tags": [
          "Output Credentials"
        ],
        "summary": "Deletes output credentials by ID",
        "description": "Deletes the *Output Credentials* identified by the given __credentials_id__. This operation is irreversible.\n\n**Important:** Deleting *Output Credentials* also removes the association to *Output Destinations* without warning. This may leave one or more *Output Destinations* requiring association to different *Output Credentials*.\n",
        "operationId": "DeleteOutputCredentials",
        "parameters": [
          {
            "name": "credentials_id",
            "in": "path",
            "description": "Unique identifier of the *Output Credentials*.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Output credentials deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedErrorResponse"
          },
          "404": {
            "$ref": "#/components/responses/OutputCredentialsNotFoundErrorResponse"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorResponse"
          }
        }
      }
    }
  },
  "webhooks": {
    "outputAlertEvent": {
      "post": {
        "summary": "Delivers an output alert event",
        "description": "Delivers an *Output Alert Event* to each *Output Destination* associated with the *Output Alert* when the alert condition is met.",
        "operationId": "PostOutputAlert",
        "tags": [
          "Output Events"
        ],
        "requestBody": {
          "description": "Envelope containing *Output Alert Event* data.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutputAlertEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledgement of receipt of the *Output Alert Event*"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "limitParam": {
        "name": "limit",
        "in": "query",
        "description": "Maximum number of elements to return per page. Optional. When omitted, all results are returned in a single response.",
        "required": false,
        "schema": {
          "type": "integer",
          "format": "int32"
        }
      },
      "pageParam": {
        "name": "page",
        "in": "query",
        "description": "Page number of results to return. Optional. Default: 1.",
        "required": false,
        "schema": {
          "type": "integer",
          "format": "int32"
        }
      },
      "orderParam": {
        "name": "order_by",
        "in": "query",
        "description": "Sorts results by the specified field. Default: ascending alphabetical order. Prefix the value with a \"-\" to sort in descending order.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "fieldMaskParam": {
        "name": "field_mask",
        "in": "query",
        "description": "Selects which fields to include in the results. The specified field is included if present, along with the `dev_eui` field, which is always included. Provide an additional __field_mask__ parameter for each additional field.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "qParam": {
        "name": "q",
        "in": "query",
        "description": "Filters results by specific fields using a set of operators in a JSON-style format:\n\nOperator | Notes\n---|---\n= | Returns all results that are an exact match\n!= | Returns all results excluding those specified\n$like | Returns all results that match a \"~\" wildcard search\n$ilike | Returns all results that match a \"~\" case-insensitive wildcard search\n$in | Returns all results that match the specified list\n$nin | Returns all results excluding those in the specified list\n$and | Returns all results that match all query parameters\n$or | Returns all results that match any of the filter parameters \n$intersects | Returns all results that match a group field value search\n",
        "example": "{\"$or\":{\"name\":{\"$ilike\":\"~temperature~\"},\"health_state\":{\"=\":\"good\"}}}\n",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "DevEUI": {
        "name": "dev_eui",
        "in": "path",
        "required": true,
        "description": "Device EUI — exactly 16 hexadecimal characters (case-insensitive).\nInternally normalized to uppercase.\n",
        "schema": {
          "type": "string",
          "pattern": "^[0-9A-Fa-f]{16}$",
          "example": "AABB1122CCDD3344"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Maximum number of records to return. Defaults to 20 when omitted. Large values are clamped to a server-side maximum.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "example": 20
        }
      },
      "PageToken": {
        "name": "page_token",
        "in": "query",
        "required": false,
        "description": "Opaque pagination cursor from `meta.next_page_token` in the previous response.\nOmit to request the first page.\n",
        "schema": {
          "type": "string",
          "example": "MjAyNi0wNS0yMFQxNDozMjowMC4xMjM0NTZa"
        }
      }
    },
    "schemas": {
      "Identifiable": {
        "description": "A resource with a unique identifier.",
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier of the resource."
          }
        },
        "examples": [
          {
            "id": "Xrzm28a0"
          }
        ]
      },
      "Owned": {
        "description": "A resource with an owner.",
        "type": "object",
        "properties": {
          "owner_id": {
            "type": "string",
            "description": "Unique identifier of the owner of the resource. Resources are isolated to their owner and are not visible across ownership boundaries."
          }
        },
        "examples": [
          {
            "owner_id": "iXeowDYO"
          }
        ]
      },
      "Device": {
        "description": "A LoRaWAN device record with configuration, statistics, and group associations.",
        "type": "object",
        "required": [
          "name",
          "dev_eui",
          "activation_type",
          "service_profile",
          "device_profile"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable name of the _Device_. Required. Must be unique within the account."
          },
          "dev_eui": {
            "type": "string",
            "description": "Extended Unique Identifier (EUI-64) of the device. Required. Must be a 16-character hexadecimal string."
          },
          "owner_id": {
            "type": "string",
            "description": "Identifies the owner of the resource. Resources are isolated to their owner and are not visible across ownership boundaries."
          },
          "activation_type": {
            "type": "string",
            "enum": [
              "ABP",
              "OTAA"
            ],
            "description": "Activation method used by the device. Required.\n- `ABP`: Activation By Personalization — device keys are hardcoded.\n- `OTAA`: Over-The-Air Activation — device keys are negotiated via a join procedure.\n"
          },
          "service_profile": {
            "type": "string",
            "description": "Unique identifier of the _ServiceProfile_ assigned to the device. Required. Retrieve applicable values via GET `/v1/serviceprofiles`."
          },
          "device_profile": {
            "type": "string",
            "description": "Unique identifier of the _DeviceProfile_ assigned to the device. Required. Retrieve applicable values via GET `/v1/deviceprofiles`."
          },
          "decoder_type": {
            "type": "string",
            "description": "Unique identifier of the _Decoder_ used to decode packets from the device. Optional. Retrieve applicable values via GET `/v1/decodertypes`."
          },
          "output_profile": {
            "type": "string",
            "description": "Unique identifier of the _OutputProfile_ used for routing packets to external servers. Optional. Retrieve applicable values via GET `/v1/outputprofiles`."
          },
          "private_data": {
            "type": "boolean",
            "description": "Whether device data is private. True means data is not stored; false means data is stored for future processing."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of _Device_ creation in RFC 3339 format."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the last _Device_ modification in RFC 3339 format."
          },
          "updated_by": {
            "type": "string",
            "description": "Unique identifier of the _User_ or _Subscriber_ that last modified the _Device_."
          },
          "last_uplink": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the last uplink message from the _Device_ in RFC 3339 format. Null if the device has never sent an uplink."
          },
          "health_state": {
            "type": "string",
            "enum": [
              "good",
              "fair",
              "poor",
              "offline"
            ],
            "description": "Calculated health of the _Device_ based on recent activity.\n- `good`: Device is performing well with strong signal quality.\n- `fair`: Device is operational but with degraded signal quality.\n- `poor`: Device is experiencing significant signal degradation.\n- `offline`: Device has not communicated recently.\n"
          },
          "spreading_factor": {
            "type": "integer",
            "format": "int32",
            "description": "Current LoRa Spreading Factor of the device (e.g., 7 = SF7). Range: 7–12."
          },
          "average_rssi": {
            "type": "number",
            "format": "float",
            "description": "Average Received Signal Strength Indicator (RSSI) over the last 24 hours, in dBm."
          },
          "average_esp": {
            "type": "number",
            "format": "float",
            "description": "Average Estimated Signal Power (ESP) over the last 24 hours, in dBm."
          },
          "average_snr": {
            "type": "number",
            "format": "float",
            "description": "Average Signal-to-Noise Ratio (SNR) over the last 24 hours, in dB."
          },
          "packet_error_rate": {
            "type": "number",
            "format": "float",
            "description": "Percentage of dropped packets over the last 24 hours. Range: 0–100."
          },
          "battery_level": {
            "type": "integer",
            "description": "Reported battery level from the _Device_. Null if the device does not report battery status."
          },
          "average_weekly_packets": {
            "type": "integer",
            "format": "int32",
            "description": "Average number of packets per day over the past week."
          },
          "groups": {
            "type": "array",
            "description": "List of _Groups_ to which the _Device_ belongs.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Unique identifier of the _Group_."
                },
                "name": {
                  "type": "string",
                  "description": "Human-readable name of the _Group_."
                }
              }
            }
          }
        }
      },
      "GetDevicesResponse": {
        "description": "A paginated list of device records.",
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          },
          "records": {
            "type": "array",
            "description": "List of _Device_ records returned by the query.",
            "items": {
              "$ref": "#/components/schemas/Device"
            }
          }
        }
      },
      "OutputAlert": {
        "description": "A configuration that defines alert rules and associated output destinations.",
        "type": "object",
        "required": [
          "name",
          "type",
          "destination_ids"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable name of the _Alert_. Required."
          },
          "type": {
            "type": "string",
            "description": "Type of the _Alert_. Required.\n- `gateway_connectivity`: Triggers when a gateway connectivity status changes.\n",
            "enum": [
              "gateway_connectivity"
            ]
          },
          "data": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GatewayConnectivityAlert"
              }
            ]
          },
          "destination_ids": {
            "type": "array",
            "description": "List of unique identifiers of the _Destinations_ to which alert events are delivered. Required. Minimum 1 item.",
            "items": {
              "type": "string"
            }
          }
        },
        "examples": [
          {
            "name": "CorbyCorp Gateway Alert",
            "type": "gateway_connectivity",
            "data": {
              "node_ids": [
                "FFFF00800001069F",
                "FFFFA15A9C20F79F"
              ]
            },
            "destination_ids": [
              "Md14GhHE",
              "wkBWFE4n"
            ]
          }
        ]
      },
      "IdentifiableOutputAlert": {
        "description": "An output alert with a unique identifier.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Identifiable"
          },
          {
            "$ref": "#/components/schemas/Owned"
          },
          {
            "$ref": "#/components/schemas/OutputAlert"
          }
        ]
      },
      "GatewayConnectivityAlert": {
        "description": "Gateway connectivity alert configuration specifying which gateways to monitor.",
        "type": "object",
        "required": [
          "node_ids"
        ],
        "properties": {
          "node_ids": {
            "type": "array",
            "description": "List of gateway `node_id` values to monitor for connectivity changes. Required. Minimum 1 item.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ListOutputAlertsResponse": {
        "description": "A list of output alert records.",
        "type": "object",
        "properties": {
          "meta": {
            "type": "object"
          },
          "records": {
            "type": "array",
            "description": "List of *Output Alert* records.",
            "items": {
              "$ref": "#/components/schemas/IdentifiableOutputAlert"
            }
          }
        }
      },
      "AddOutputAlertGatewayRequest": {
        "description": "A request to add a single gateway to an output alert.",
        "type": "object",
        "required": [
          "node_id"
        ],
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Unique `node_id` of the _Gateway_ to add. Required."
          }
        },
        "examples": [
          {
            "node_id": "FFFF00800001069F"
          }
        ]
      },
      "RemoveOutputAlertGatewayRequest": {
        "description": "A request to remove a single gateway from an output alert.",
        "type": "object",
        "required": [
          "node_id"
        ],
        "properties": {
          "node_id": {
            "type": "string",
            "description": "Unique `node_id` of the _Gateway_ to remove. Required."
          }
        },
        "examples": [
          {
            "node_id": "FFFF00800001069F"
          }
        ]
      },
      "BatchAddOutputAlertGatewayRequest": {
        "description": "A request to add multiple gateways to an output alert.",
        "type": "object",
        "required": [
          "node_ids"
        ],
        "properties": {
          "node_ids": {
            "type": "array",
            "description": "List of gateway `node_id` values to add. Required. Minimum 1 item.",
            "items": {
              "type": "string"
            }
          }
        },
        "examples": [
          {
            "node_ids": [
              "FFFF00800001069F",
              "2CC4070000002E86",
              "FFFFA15A9C20F79F"
            ]
          }
        ]
      },
      "BatchRemoveOutputAlertGatewayRequest": {
        "description": "A request to remove multiple gateways from an output alert.",
        "type": "object",
        "required": [
          "node_ids"
        ],
        "properties": {
          "node_ids": {
            "type": "array",
            "description": "List of gateway `node_id` values to remove. Required. Minimum 1 item.",
            "items": {
              "type": "string"
            }
          }
        },
        "examples": [
          {
            "node_ids": [
              "FFFF00800001069F",
              "2CC4070000002E86",
              "FFFFA15A9C20F79F"
            ]
          }
        ]
      },
      "BasicAuth": {
        "description": "Basic authentication credentials consisting of a username and password.",
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "properties": {
          "username": {
            "type": "string",
            "description": "Username for authentication. Required."
          },
          "password": {
            "type": "string",
            "description": "Password for authentication. Required. Stored in an encrypted store and never persisted in plain text."
          }
        }
      },
      "ClientCredentials": {
        "description": "OAuth 2.0 client credentials used to obtain an access token.",
        "type": "object",
        "required": [
          "client_id",
          "client_secret",
          "auth_url"
        ],
        "properties": {
          "client_id": {
            "type": "string",
            "description": "Client identifier for the OAuth access token request. Required."
          },
          "client_secret": {
            "type": "string",
            "description": "Client secret for the OAuth access token request. Required. Stored in an encrypted store and never persisted in plain text."
          },
          "auth_url": {
            "type": "string",
            "description": "URL to which the OAuth access token request is sent. Required."
          },
          "scopes": {
            "type": "string",
            "description": "Space-separated list of scopes to include in the OAuth access token. Optional."
          },
          "audience": {
            "type": "string",
            "description": "Unique identifier of the target API that the JWT token is intended for. Optional."
          }
        }
      },
      "X509Certificate": {
        "description": "X.509 certificate credentials consisting of a public certificate and private key.",
        "type": "object",
        "required": [
          "private_key",
          "public_key"
        ],
        "properties": {
          "public_key": {
            "type": "string",
            "description": "Client certificate in PEM format with embedded newline characters. Required. Stored in an encrypted store and never persisted in plain text."
          },
          "private_key": {
            "type": "string",
            "description": "Client private key in PEM format with embedded newline characters. Required. Stored in an encrypted store and never persisted in plain text."
          }
        }
      },
      "AzureSharedAccessPolicy": {
        "description": "Azure IoT Hub Shared Access Policy credentials.",
        "type": "object",
        "required": [
          "policy_name",
          "shared_access_key"
        ],
        "properties": {
          "policy_name": {
            "type": "string",
            "description": "Name of the Azure *Shared Access Policy* with \"Device Connect\" permission. Required."
          },
          "shared_access_key": {
            "type": "string",
            "description": "Primary or secondary key of the *Shared Access Policy*. Required. Stored in an encrypted store and never persisted in plain text."
          }
        }
      },
      "OutputCredentials": {
        "description": "A set of credentials used to authenticate when delivering data to output destinations.",
        "type": "object",
        "required": [
          "name",
          "type",
          "data"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/OutputCredentialsName"
          },
          "type": {
            "$ref": "#/components/schemas/OutputCredentialsType"
          },
          "data": {
            "description": "Type-specific credential details. Required.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/BasicAuth"
              },
              {
                "$ref": "#/components/schemas/ClientCredentials"
              },
              {
                "$ref": "#/components/schemas/X509Certificate"
              },
              {
                "$ref": "#/components/schemas/AzureSharedAccessPolicy"
              }
            ]
          }
        }
      },
      "IdentifiableOutputCredentials": {
        "description": "Output credentials with a unique identifier.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Identifiable"
          },
          {
            "$ref": "#/components/schemas/Owned"
          },
          {
            "$ref": "#/components/schemas/OutputCredentials"
          }
        ]
      },
      "SafeOutputCredentials": {
        "description": "Output credentials with sensitive fields redacted.",
        "type": "object",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/OutputCredentialsName"
          },
          "type": {
            "$ref": "#/components/schemas/OutputCredentialsType"
          }
        }
      },
      "SafeIdentifiableOutputCredentials": {
        "description": "Output credentials with a unique identifier and sensitive fields redacted.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Identifiable"
          },
          {
            "$ref": "#/components/schemas/Owned"
          },
          {
            "$ref": "#/components/schemas/SafeOutputCredentials"
          }
        ]
      },
      "OutputCredentialsName": {
        "type": "string",
        "description": "Human-readable name of the _Credentials_. Required.",
        "examples": [
          "CorbyCorp admin user auth"
        ]
      },
      "OutputCredentialsType": {
        "type": "string",
        "description": "Type of the _Credentials_. Required.\n- `basic_auth`: Username and password authentication.\n- `client_credentials`: OAuth 2.0 client credentials grant.\n- `x509_certificate`: X.509 certificate-based authentication.\n- `azure_shared_access_policy`: Azure IoT Hub Shared Access Policy authentication.\n",
        "enum": [
          "basic_auth",
          "client_credentials",
          "x509_certificate",
          "azure_shared_access_policy"
        ]
      },
      "ListOutputCredentialsResponse": {
        "description": "A list of output credentials records with sensitive fields redacted.",
        "type": "object",
        "properties": {
          "meta": {
            "type": "object"
          },
          "records": {
            "type": "array",
            "description": "List of *Output Credentials* records.",
            "items": {
              "$ref": "#/components/schemas/SafeIdentifiableOutputCredentials"
            }
          }
        }
      },
      "OutputDestination": {
        "description": "A destination to which output events are delivered.",
        "type": "object",
        "required": [
          "name",
          "type",
          "data"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable name of the _Destination_. Required."
          },
          "type": {
            "type": "string",
            "description": "Type of the _Destination_. Required.\n- `webhook`: Delivers events via HTTP POST to a URL.\n- `azure_iot_hub`: Delivers events to an Azure IoT Hub.\n- `mqtt`: Delivers events to an MQTT broker.\n- `aws_iot_core`: Delivers events to AWS IoT Core.\n",
            "enum": [
              "webhook",
              "azure_iot_hub",
              "mqtt",
              "aws_iot_core"
            ]
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether *Output Events* are delivered to the _Destination_. True means events are delivered; false means delivery is paused. Optional."
          },
          "credentials_id": {
            "type": "string",
            "description": "Unique identifier of the _Credentials_ used to authenticate delivery. Optional."
          },
          "data": {
            "description": "Type-specific destination configuration details. Required.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/WebhookDestination"
              },
              {
                "$ref": "#/components/schemas/AzureIOTHubDestination"
              },
              {
                "$ref": "#/components/schemas/MQTTDestination"
              },
              {
                "$ref": "#/components/schemas/AWSIOTCoreDestination"
              }
            ]
          }
        }
      },
      "IdentifiableOutputDestination": {
        "description": "An output destination with a unique identifier.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Identifiable"
          },
          {
            "$ref": "#/components/schemas/Owned"
          },
          {
            "$ref": "#/components/schemas/OutputDestination"
          }
        ]
      },
      "ListOutputDestinationsResponse": {
        "description": "A list of output destination records.",
        "type": "object",
        "properties": {
          "meta": {
            "type": "object"
          },
          "records": {
            "type": "array",
            "description": "List of *Output Destination* records.",
            "items": {
              "$ref": "#/components/schemas/IdentifiableOutputDestination"
            }
          }
        }
      },
      "WebhookDestination": {
        "description": "Webhook-specific destination configuration.",
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "URL to which *Output Events* are delivered via HTTP POST. Required."
          },
          "headers": {
            "type": "array",
            "description": "List of custom HTTP headers included when delivering an *Output Event* to the webhook. Optional.",
            "items": {
              "$ref": "#/components/schemas/WebhookHeader"
            }
          }
        }
      },
      "WebhookHeader": {
        "description": "A custom HTTP header included in webhook deliveries.",
        "type": "object",
        "required": [
          "header",
          "value"
        ],
        "properties": {
          "header": {
            "type": "string",
            "description": "Name of the HTTP header. Required."
          },
          "value": {
            "type": "string",
            "description": "Value of the HTTP header. Required."
          }
        }
      },
      "AzureIOTHubDestination": {
        "description": "Azure IoT Hub-specific destination configuration.",
        "type": "object",
        "required": [
          "host"
        ],
        "properties": {
          "host": {
            "type": "string",
            "description": "Fully-qualified hostname of the Azure IoT Hub to which *Output Events* are delivered. Required.\nFormat: `{iothub-name}.azure-devices.net`.\n"
          }
        }
      },
      "MQTTDestination": {
        "description": "MQTT broker-specific destination configuration.",
        "type": "object",
        "required": [
          "host",
          "topic"
        ],
        "properties": {
          "host": {
            "type": "string",
            "description": "Hostname and port of the MQTT broker to which *Output Events* are delivered. Required.\nFormat: `{host}:{port}`. Must not include the scheme.\n"
          },
          "topic": {
            "type": "string",
            "description": "Topic on the MQTT broker to which *Output Events* are published. Required."
          },
          "tls_enabled": {
            "type": "boolean",
            "description": "Whether events are sent over TLS. True means TLS is enabled; false means TLS is disabled. Optional."
          },
          "custom_client_id": {
            "type": "string",
            "description": "Client ID used when connecting to the MQTT broker. Optional. Supports `${DEVEUI}` and `${FPORT}` placeholders,\nwhich are replaced with the actual __dev_eui__ and __fport__ values before delivery. When omitted, the connection\nis established without a client ID.\n"
          }
        }
      },
      "AWSIOTCoreDestination": {
        "description": "AWS IoT Core-specific destination configuration.",
        "type": "object",
        "required": [
          "endpoint"
        ],
        "properties": {
          "endpoint": {
            "type": "string",
            "description": "Endpoint URL of the AWS IoT Core instance to which *Output Events* are delivered. Required.\nFormat: `{account-specific-prefix}.iot.{aws-region}.amazonaws.com`.\n"
          }
        }
      },
      "ListMeta": {
        "description": "Pagination metadata for list responses.",
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total number of results matching the query parameters."
          },
          "count": {
            "type": "integer",
            "description": "Number of results returned in the current page. Equal to `total` when no limit is set."
          },
          "page": {
            "type": "integer",
            "description": "Current page number. Default: 1."
          },
          "more": {
            "type": "boolean",
            "description": "Whether additional pages of results exist. True means more results are available; false means the current page is the last."
          }
        }
      },
      "Non2XXResponse": {
        "description": "An error response returned for non-2xx status codes.",
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "format": "int32",
            "description": "Error code specific to the type of error that occurred. Optional."
          },
          "message": {
            "type": "string",
            "description": "Developer-facing error message describing the failure."
          },
          "details": {
            "type": "array",
            "description": "List of additional error detail messages. Optional.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "OutputAlertEvent": {
        "description": "An event produced when an output alert condition is met.",
        "type": "object",
        "required": [
          "type",
          "timestamp",
          "data"
        ],
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the event was processed, in RFC 3339 format."
          },
          "type": {
            "type": "string",
            "enum": [
              "gateway_connectivity"
            ],
            "description": "Type of the alert event.\n- `gateway_connectivity`: Indicates a change in gateway connectivity status.\n"
          },
          "data": {
            "type": "object",
            "description": "Type-specific event payload.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/GatewayConnectivityEvent"
              }
            ]
          }
        },
        "examples": [
          {
            "timestamp": "2023-01-10T14:58:35.455152Z",
            "type": "gateway_connectivity",
            "data": {
              "timestamp": "2023-01-10T14:58:29.076699Z",
              "node_id": "FFFFA15A9C20F79F",
              "status": "offline"
            }
          }
        ]
      },
      "GatewayConnectivityEvent": {
        "description": "Event payload describing a gateway connectivity status change.",
        "type": "object",
        "required": [
          "node_id",
          "timestamp",
          "status"
        ],
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the connectivity status changed, in RFC 3339 format."
          },
          "node_id": {
            "type": "string",
            "description": "Unique `node_id` of the _Gateway_ whose connectivity status changed."
          },
          "status": {
            "type": "string",
            "enum": [
              "online",
              "offline"
            ],
            "description": "Current connectivity status of the _Gateway_.\n- `online`: Gateway is connected and communicating.\n- `offline`: Gateway is not communicating.\n"
          }
        }
      },
      "ConfigResponse": {
        "type": "object",
        "required": [
          "dev_eui",
          "reported",
          "desired"
        ],
        "properties": {
          "dev_eui": {
            "type": "string",
            "description": "Device EUI (uppercase).",
            "example": "AABB1122CCDD3344"
          },
          "reported": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ReportedConfigSection"
              },
              {
                "type": "null"
              }
            ],
            "description": "Last configuration observed from a device uplink. `null` if the device\nhas never sent a config uplink.\n"
          },
          "desired": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DesiredConfigSection"
              },
              {
                "type": "null"
              }
            ],
            "description": "Most recent config rollout regardless of status. `null` if no rollout has\never been created for the device.\n"
          }
        }
      },
      "ReportedConfigSection": {
        "type": "object",
        "required": [
          "config",
          "last_uplink_at"
        ],
        "properties": {
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Decoded device configuration as reported by the device.",
            "example": {
              "report_interval_seconds": 300,
              "threshold_celsius": 25
            }
          },
          "last_uplink_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the uplink from which this config was last observed.",
            "example": "2026-04-18T10:00:00Z"
          }
        }
      },
      "DesiredConfigSection": {
        "type": "object",
        "required": [
          "config",
          "source_type",
          "status",
          "created_by",
          "updated_by",
          "created_at",
          "updated_at",
          "progress"
        ],
        "properties": {
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "The desired configuration that was submitted.",
            "example": {
              "report_interval_seconds": 60,
              "threshold_celsius": 30
            }
          },
          "source_type": {
            "type": "string",
            "description": "How this desired config was created.\n- `manual`: Submitted by a user via the API.\n",
            "enum": [
              "manual"
            ],
            "example": "manual"
          },
          "status": {
            "type": "string",
            "description": "Current lifecycle status of the rollout.\n- `pending`: Briefly transitional — rollout accepted but first fragment not yet scheduled for transmission.\n- `in_progress`: First fragment scheduled for transmission; delivery underway.\n- `applied`: All fragments confirmed.\n- `failed`: A fragment failed after exhausting retries.\n- `cancelled`: Cancelled via DELETE before completion.\n",
            "enum": [
              "pending",
              "in_progress",
              "applied",
              "failed",
              "cancelled"
            ],
            "example": "in_progress"
          },
          "failure_reason": {
            "type": ["string", "null"],
            "description": "Human-readable failure description. Present only when `status` is `failed`.",
            "example": "downlink delivery failed: tx error"
          },
          "created_by": {
            "type": "string",
            "description": "Identity that created the rollout.",
            "example": "Job3ZjzC"
          },
          "updated_by": {
            "type": "string",
            "description": "Identity that last updated the rollout.",
            "example": "Job3ZjzC"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-04-20T09:00:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-04-20T09:00:05Z"
          },
          "started_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the first fragment entered `ready` state (i.e. when the rollout\ntransitioned to `in_progress`). `null` only while `status` is `pending`.\n",
            "example": "2026-04-20T09:00:05Z"
          },
          "completed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the rollout reached a terminal state (`applied`, `failed`, or `cancelled`).\n`null` while the rollout is still active.\n",
            "example": "2026-04-20T09:01:00Z"
          },
          "progress": {
            "$ref": "#/components/schemas/DesiredConfigProgress",
            "description": "Fragment delivery progress. Always present."
          }
        }
      },
      "DesiredConfigProgress": {
        "type": "object",
        "required": [
          "total_fragments",
          "fragments_confirmed",
          "fragments"
        ],
        "properties": {
          "total_fragments": {
            "type": "integer",
            "description": "Total number of downlink fragments in this rollout.",
            "example": 2
          },
          "fragments_confirmed": {
            "type": "integer",
            "description": "Number of fragments that have been confirmed.",
            "example": 1
          },
          "fragments": {
            "type": "array",
            "description": "Per-fragment delivery state, ordered by sequence number.",
            "items": {
              "$ref": "#/components/schemas/DesiredConfigFragment"
            }
          }
        }
      },
      "DesiredConfigFragment": {
        "type": "object",
        "required": [
          "sequence",
          "status",
          "attempt_count"
        ],
        "properties": {
          "sequence": {
            "type": "integer",
            "description": "1-based position of this fragment within the rollout.",
            "example": 1
          },
          "status": {
            "type": "string",
            "description": "Current delivery status of this fragment.\n- `pending`: Not yet scheduled for transmission — either the rollout was just accepted or a prior fragment is still being confirmed.\n- `ready`: Scheduled for the next transmission attempt.\n- `queued`: Submitted to the network server.\n- `sent`: Network server confirmed gateway transmission.\n- `confirmed`: Device acknowledged (strategy-dependent).\n- `failed`: Delivery failed after retry exhaustion.\n- `cancelled`: Cancelled before confirmation.\n- `gateway_unavailable`: No connected gateway can reach the device; fragment is suspended and will resume automatically when device activity is observed.\n",
            "enum": [
              "pending",
              "ready",
              "queued",
              "sent",
              "confirmed",
              "failed",
              "cancelled",
              "gateway_unavailable"
            ],
            "example": "confirmed"
          },
          "attempt_count": {
            "type": "integer",
            "description": "Number of delivery attempts initiated for this fragment. Set to `1` when the\nfragment enters `ready` state (marking the start of the first ready→queued→sent\ncycle). Incremented on each retry. `0` only while the fragment is `pending`.\n",
            "example": 1
          },
          "ready_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When this fragment most recently entered `ready` state. Reset on each retry, so it\nalways reflects the start of the current `ready→queued` delivery cycle. `null` for\n`pending` fragments and for fragments created before this field was introduced.\n",
            "example": "2026-04-20T09:00:04Z"
          },
          "queued_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When the fragment was submitted to the network server. `null` until `queued`.",
            "example": "2026-04-20T09:00:05Z"
          },
          "sent_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Gateway transmission timestamp reported by the network server. `null` until `sent`.\nThis is the network server's clock, not the API server's.\n",
            "example": "2026-04-20T09:00:06Z"
          },
          "confirmed_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When this fragment was confirmed (strategy-dependent). `null` until `confirmed`.",
            "example": "2026-04-20T09:00:08Z"
          },
          "gateway_unavailable_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "When this fragment entered `gateway_unavailable` state. Non-null only while the\nfragment is suspended waiting for device activity to resume. Cleared when the\nfragment returns to `ready`.\n",
            "example": "2026-04-20T09:00:09Z"
          }
        }
      },
      "ConfigHistoryResponse": {
        "type": "object",
        "required": [
          "records",
          "meta"
        ],
        "properties": {
          "records": {
            "type": "array",
            "description": "History entries ordered most-recent first.",
            "items": {
              "$ref": "#/components/schemas/HistoricalReportedConfig"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ConfigHistoryMeta"
          }
        }
      },
      "ConfigHistoryMeta": {
        "type": "object",
        "required": [
          "more"
        ],
        "properties": {
          "next_page_token": {
            "type": "string",
            "description": "Opaque cursor for the next page. Pass as `page_token` on the next request.\nPresent only when `more` is `true`.\n",
            "example": "MjAyNi0wNS0yMFQxNDozMjowMC4xMjM0NTZa"
          },
          "more": {
            "type": "boolean",
            "description": "Whether a subsequent page of results exists. Always present.",
            "example": true
          }
        }
      },
      "HistoricalReportedConfig": {
        "type": "object",
        "required": [
          "config",
          "observed_at"
        ],
        "properties": {
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Decoded device configuration as reported at this point in time.",
            "example": {
              "report_interval_seconds": 60,
              "threshold_celsius": 30
            }
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this configuration was first observed — the moment the reported-config\nchange was detected from an uplink. Microsecond precision.\n",
            "example": "2026-05-20T14:32:00.123456Z"
          }
        }
      },
      "PutDesiredConfigRequest": {
        "type": "object",
        "required": [
          "config"
        ],
        "properties": {
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Desired device configuration. The structure is codec-specific — the device's\ncodec type determines how this object is validated and encoded into downlink\nfragments.\n",
            "example": {
              "report_interval_seconds": 60,
              "threshold_celsius": 30
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable description of the error.",
            "example": "device not found"
          }
        }
      }
    },
    "requestBodies": {
      "OutputDestinationRequestBody": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OutputDestination"
            },
            "examples": {
              "Webhook": {
                "value": {
                  "name": "CorbyCorp Webhook Event Monitor",
                  "type": "webhook",
                  "enabled": true,
                  "credentials_id": "xLu4B38N",
                  "data": {
                    "url": "https://monitor.corbycorp.com/gateways/alerts",
                    "headers": [
                      {
                        "header": "api_key",
                        "value": "YWxramRhc2RnYXNkZ2FzZGdsYXNkZ2FzZAo="
                      },
                      {
                        "header": "accept",
                        "value": "application/json"
                      }
                    ]
                  }
                }
              },
              "Azure IoT Hub": {
                "value": {
                  "name": "CorbyCorp IoTHub Event Monitor",
                  "type": "azure_iot_hub",
                  "enabled": true,
                  "credentials_id": "GRVVcAC-",
                  "data": {
                    "host": "corbycorp-hub.azure-devices.net"
                  }
                }
              },
              "MQTT": {
                "value": {
                  "name": "CorbyCorp MQTT Event Monitor",
                  "type": "mqtt",
                  "enabled": true,
                  "credentials_id": "5DFk8vzO",
                  "data": {
                    "host": "corbycorp-mqtt:8883",
                    "topic": "machineq/output/events",
                    "tls_enabled": true,
                    "custom_client_id": "/devices/${DEVEUI}/${FPORT}"
                  }
                }
              },
              "AWS IoT Core": {
                "value": {
                  "name": "CorbyCorp Iot Core Event Monitor",
                  "type": "aws_iot_core",
                  "enabled": true,
                  "credentials_id": "Tz07qwZq",
                  "data": {
                    "endpoint": "corbycorp-thing.iot.us-east-1.amazonaws.com"
                  }
                }
              }
            }
          }
        }
      },
      "OutputCredentialsRequestBody": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OutputCredentials"
            },
            "examples": {
              "BasicAuth": {
                "value": {
                  "name": "CorbyCorp user auth",
                  "type": "basic_auth",
                  "data": {
                    "username": "gateway_monitor",
                    "password": "$ecret!"
                  }
                }
              },
              "ClientCredentials": {
                "value": {
                  "name": "CorbyCorp websec client",
                  "type": "client_credentials",
                  "data": {
                    "client_id": "gateway_monitor",
                    "client_secret": "dnwnvwtqylskrlvzushd",
                    "auth_url": "https://oauth.corbycorp.com/oauth2/token",
                    "scopes": "alert:reader gateway:admin",
                    "audience": "https://api.corbycorp.net"
                  }
                }
              },
              "X509Certificate": {
                "value": {
                  "name": "CorbyCorp X509 cert",
                  "type": "x509_certificate",
                  "data": {
                    "public_key": "-----BEGIN CERTIFICATE-----\nMIICuTCCAl6gAwIBAgIUPBcCp/humG2kg2I7dKdblhsndzcwCgYIKoZIzj0EAwIw...n9uSb6PE0Q1XejUiVCtY8gAgJnzoc4dzsTQNNsg=\n-----END CERTIFICATE-----",
                    "private_key": "-----BEGIN PRIVATE KEY-----\nMHcCAQEEIKtpBmtz3AmjzovVIoslZ2bu12zKiWHxiAArmQWAoHU8oAoGCCqGSM49...xveOJ4==\n-----END PRIVATE KEY-----"
                  }
                }
              },
              "AzureSharedAccessPolicy": {
                "value": {
                  "name": "CorbyCorp Iot Hub Owner",
                  "type": "azure_shared_access_policy",
                  "data": {
                    "policy_name": "iothubowner",
                    "shared_access_key": "TMjz20pTp19zBeH6yt7Ugb7sJ04Qk4JdTlkach99pNHU="
                  }
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "IdentifiableOutputCredentialsSuccessResponse": {
        "description": "Successful response containing the output credentials",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/SafeIdentifiableOutputCredentials"
            }
          }
        }
      },
      "OutputCredentialsNotFoundErrorResponse": {
        "description": "Output credentials not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Could not find Credentials identified by 'iN0pLTEv'"
            }
          }
        }
      },
      "OutputCredentialsInvalidInputErrorResponse": {
        "description": "Invalid output credentials input",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Credentials are not valid: 'name' is required."
            }
          }
        }
      },
      "IdentifiableOutputDestinationSuccessResponse": {
        "description": "Successful response containing the output destination",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/IdentifiableOutputDestination"
            }
          }
        }
      },
      "OutputDestinationNotFoundErrorResponse": {
        "description": "Output destination not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Could not find Destination identified by '2Daub56g'"
            }
          }
        }
      },
      "OutputDestinationInvalidInputErrorResponse": {
        "description": "Invalid output destination input",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Destination is not valid: 'name' is required."
            }
          }
        }
      },
      "IdentifiableOutputAlertSuccessResponse": {
        "description": "Successful response containing the output alert",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/IdentifiableOutputAlert"
            }
          }
        }
      },
      "OutputAlertNotFoundErrorResponse": {
        "description": "Output alert not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Could not find Alert identified by 'TGexoQsP'"
            }
          }
        }
      },
      "OutputAlertInvalidInputErrorResponse": {
        "description": "Invalid output alert input",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "Alert is not valid: 'name' is required."
            }
          }
        }
      },
      "UnauthorizedErrorResponse": {
        "description": "Missing or invalid authorization token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "code": 16,
              "message": "invalid token or token is expired."
            }
          }
        }
      },
      "InternalServerErrorResponse": {
        "description": "Unexpected internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Non2XXResponse"
            },
            "example": {
              "message": "unexpected error occurred, please try the request again."
            }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid request — the message field describes the specific problem",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Invalid request parameter: 'dev_eui' must be a valid device EUI (16 hexadecimal characters)"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid authentication credentials",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "unauthorized"
            }
          }
        }
      },
      "NotFound": {
        "description": "Device not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "device not found for dev_eui: AABB1122CCDD3344"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Unexpected internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "internal server error"
            }
          }
        }
      }
    }
  },
  "x-tagGroups": [
    {
      "name": "Device",
      "tags": [
        "Devices",
        "Device Configuration"
      ]
    },
    {
      "name": "Output System",
      "tags": [
        "Overview",
        "Output Credentials",
        "Output Destinations",
        "Output Alerts",
        "Output Events"
      ]
    }
  ],
  "x-resourceObjects": {
    "Devices": "Device",
    "Device Configuration": "ConfigResponse",
    "Output Credentials": "IdentifiableOutputCredentials",
    "Output Destinations": "IdentifiableOutputDestination",
    "Output Alerts": "IdentifiableOutputAlert",
    "Output Events": "GatewayConnectivityEvent"
  }
}
