{
  "openapi": "3.1.0",
  "info": {
    "title": "MQ FUOTA API",
    "description": "\n# Introduction\n\nUser the MachineQ **F**irmware **U**pdate **O**ver **T**he **A**ir (<abbr title=\"Firmware Update Over The Air\">FUOTA</abbr>) <abbr title=\"Application Programming Interface or API is a connection between programs or computers.\nIt allows to access the target application or service through a defined standard software interface. For example, a TV remote is an equivalent to physical API to your TV.\">API</abbr> to easily update LoRaWAN devices.\nWhether you want to update 1, 5, or a 1000 of LoRaWAN devices - it is possible with **MachineQ FUOTA**.\n\nFor documentation please go to the [official FUOTA documentation](/docs).\n\nMore details about different API versions can be found at [Change log](/docs/changelog) and [Versions](/docs/changelog/versions) page.\n",
    "version": "v3.2"
  },
  "servers": [
    {
      "url": "/api/latest"
    }
  ],
  "paths": {
    "/campaigns": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Retrieves all campaigns",
        "description": "Retrieves all campaigns for the authenticated subscriber. Returns a list of campaign summary objects including stage, device counts, and scheduling information.",
        "operationId": "get_campaigns",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of campaign summary objects for the authenticated subscriber.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignListV3_2"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Creates a new campaign",
        "description": "Creates a new firmware update campaign or schedules one for later execution. Returns 202 with a partial campaign status while initialization is in progress.\n\n* `name` \u2014 a human-readable label for the campaign.\n* `image_name` \u2014 name of the firmware image previously uploaded via\n    [/images](#/FirmwareImages/upload_image).\n* `device_group_id` \u2014 identifier of the target device group, created via\n    [/device_groups/keygen](#/DeviceGroups/CreateDevicesGroupKeygen)\n    or [/device_groups](#/DeviceGroups/CreateDevicesGroup).\n* `expected_version` \u2014 expected firmware version after the update. Accepts a semantic version\n    string (e.g., `0.1.2.3` or `1.2.3`) or a 16-character hex pattern.\n    [(See hex pattern documentation)](/docs/features/firmware_version_parsing).\n    Inferred from `image_name` when omitted.\n* `multicast_setup_time` \u2014 (optional) multicast setup window in seconds. Automatically determined in most cases. Consult the\n    [documentation](/docs/getting_started/multicast_setup_time).",
        "operationId": "create_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignInV3_2"
              },
              "examples": {
                "Simple": {
                  "summary": "Simple campaign creation",
                  "value": {
                    "name": "Update to 1.2.3",
                    "image_name": "my_firmware_v1.2.3.bin",
                    "device_group_id": "YqcZo3"
                  }
                },
                "With multicast_setup_time": {
                  "summary": "Campaign creation with multicast_setup_time specified",
                  "description": "This is an example with multicast_setup_time manually set. The `multicast_setup_time` parameter in this case is 2 hours in seconds.",
                  "value": {
                    "name": "Update to 1.2.5",
                    "image_name": "my_firmware_v1.2.5.bin",
                    "device_group_id": "12345q",
                    "multicast_setup_time": 7200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Partial campaign status returned while initialization is in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignOutStatus"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/bulk-status": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Retrieves statuses for multiple campaigns",
        "description": "Retrieves status information for multiple campaigns in a single request. Returns a dictionary keyed by campaign ID, where each value is an array of [`stage`, `successful_device_count`, `total_device_count`].",
        "operationId": "get_bulk_status",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "array",
              "items": {},
              "description": "List of campaign IDs to retrieve. Supports comma-separated values in a single query parameter.",
              "title": "Campaign Ids"
            },
            "description": "List of campaign IDs to retrieve. Supports comma-separated values in a single query parameter."
          }
        ],
        "responses": {
          "200": {
            "description": "Dictionary of campaign IDs mapped to their stage, success count, and total device count.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkCampaignResponse"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/{campaign_id}": {
      "delete": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Deletes a campaign asynchronously",
        "description": "Deletes the specified campaign asynchronously and stops the update process if it is running. Returns 202 once the deletion is accepted. This operation is irreversible and does not preserve device update history. Use the [/halt](#/Campaigns/halt_campaign) endpoint first to preserve history before deleting.",
        "operationId": "delete",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the campaign.",
              "title": "Campaign Id"
            },
            "description": "Unique identifier of the campaign."
          }
        ],
        "responses": {
          "202": {
            "description": "Campaign deletion accepted and processing asynchronously.",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Retrieves a specific campaign",
        "description": "Retrieves the full campaign state for the given campaign ID. Returns 202 while the campaign is still initializing. Debug and troubleshooting information is included only when the respective flags are enabled.",
        "operationId": "get_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the campaign.",
              "title": "Campaign Id"
            },
            "description": "Unique identifier of the campaign."
          }
        ],
        "responses": {
          "200": {
            "description": "Full campaign state including all device statuses and progress information.",
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Campaign",
                  "$ref": "#/components/schemas/CampaignOutV3_2"
                }
              }
            }
          },
          "202": {
            "description": "Campaign is still initializing; returns partial status with campaign ID and current stage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignOutStatus"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/{campaign_id}/halt": {
      "post": {
        "tags": [
          "CampaignTools"
        ],
        "summary": "Halt Campaign",
        "description": "Stops the running campaign without deleting its state.",
        "operationId": "halt_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the campaign.",
              "title": "Campaign Id"
            },
            "description": "Unique identifier of the campaign."
          }
        ],
        "responses": {
          "204": {
            "description": "Campaign halted successfully with no content returned."
          }
        }
      }
    },
    "/campaigns/{campaign_id}/restart": {
      "post": {
        "tags": [
          "CampaignTools"
        ],
        "summary": "Restarts a campaign for failed devices",
        "description": "Restarts the campaign for devices that failed in a previous attempt. Devices that successfully updated retain their state.",
        "operationId": "restart_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the campaign.",
              "title": "Campaign Id"
            },
            "description": "Unique identifier of the campaign."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestartCampaignInV3"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Partial campaign status confirming the restart is in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignOutStatus"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns/{campaign_id}/short-status": {
      "get": {
        "tags": [
          "CampaignTools"
        ],
        "summary": "Retrieves an abbreviated campaign status",
        "description": "Retrieves an abbreviated campaign status showing only the most vital state parameters for each device. Returns 202 if the campaign state is not yet ready.",
        "operationId": "get_short_status",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the campaign.",
              "title": "Campaign Id"
            },
            "description": "Unique identifier of the campaign."
          }
        ],
        "responses": {
          "200": {
            "description": "Abbreviated campaign status with per-device stage, attempt count, and failure reason.",
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Short Status",
                  "$ref": "#/components/schemas/ShortCampaignStatus"
                }
              }
            }
          },
          "202": {
            "description": "Campaign is still initializing; returns partial status with campaign ID and current stage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignOutStatus"
                }
              }
            }
          }
        }
      }
    },
    "/device_groups": {
      "get": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Retrieves all device groups",
        "description": "Retrieves a list of all device groups with basic information including ID, name, class, and devices.",
        "operationId": "get_device_groups",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of device group objects with ID, name, class, and device details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupListV3_2"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Creates a device group",
        "description": "Creates a device group. The `devices` field is a list of DevEUIs. Keys for the DevEUIs can be uploaded separately via `/key_management`.\n\nGateways may optionally be provided; otherwise the FUOTA server automatically assigns gateways based on the best gateway for the provided devices. A maximum of ten gateway NodeIDs per group is allowed.\n\n`lora_class` accepts \"A\" or \"C\". When omitted or set to `null`, the FUOTA server automatically determines the LoRaWAN class from the devices in the group. Device groups with mixed device classes are disallowed.",
        "operationId": "create_device_group",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceGroupInV3_2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Newly created device group with server-assigned group ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_groups/keygen/{device_group_id}/add_devices": {
      "patch": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Adds devices to a device group with keygen",
        "description": "Adds devices to an existing device group using automatic key generation. The `devices` field is a list of DevEUIs. Only the \"machineq\" `keygen_type` is currently supported.",
        "operationId": "add_devices_keygen",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DevicesWithKeygen"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device group reflecting the newly added devices with auto-generated keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_groups/{device_group_id}": {
      "delete": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Deletes a device group",
        "description": "Deletes the device group identified by `device_group_id`. Fails if any campaign is still associated with the group; delete the campaign first.",
        "operationId": "delete_device_group",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "responses": {
          "204": {
            "description": "Device group deleted successfully with no content returned."
          }
        }
      },
      "get": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Retrieves a device group",
        "description": "Retrieves a single device group by `device_group_id`.",
        "operationId": "get_device_group",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "responses": {
          "200": {
            "description": "Device group details including name, class, devices, and gateways.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Updates a device group partially",
        "description": "Updates the device group identified by `device_group_id` with partial data. Only provided fields are modified.",
        "operationId": "patch_device_group",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceUpdatePatchV3_2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device group with the modified fields applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Replaces a device group",
        "description": "Replaces the device group identified by `device_group_id` with the provided data.",
        "operationId": "put_device_group",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceGroupInV3_2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replaced device group with the updated configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_groups/{device_group_id}/add_devices": {
      "patch": {
        "tags": [
          "DeviceGroups"
        ],
        "summary": "Adds devices to a device group",
        "description": "Adds devices to an existing device group. The `devices` field is a list of DevEUIs.",
        "operationId": "add_devices",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "device_group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the device group. 6-character alphanumeric string.",
              "title": "Device Group Id"
            },
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DevicesNoKeys"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated device group reflecting the newly added devices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceGroupOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_version": {
      "get": {
        "tags": [
          "DeviceVersion"
        ],
        "summary": "Retrieves firmware versions for specified devices",
        "description": "Retrieves the reported firmware version for one or more devices identified by `deveuis`.",
        "operationId": "get_deveui_versions",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "deveuis",
            "in": "query",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "List of DevEUIs to retrieve firmware versions for. Required. Supports repeated query parameters or a single comma-separated value.",
              "title": "Deveuis"
            },
            "description": "List of DevEUIs to retrieve firmware versions for. Required. Supports repeated query parameters or a single comma-separated value."
          }
        ],
        "responses": {
          "200": {
            "description": "The firmware version for each requested device.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipleDeviceVersionOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_version/all": {
      "get": {
        "tags": [
          "DeviceVersion"
        ],
        "summary": "Retrieves firmware versions for all subscriber devices",
        "description": "Retrieves the firmware version of all devices belonging to the authenticated subscriber. Devices that have never reported a version are excluded from the response.\n\nIf `delegated_subscriber_id` is provided, returns only firmware versions for devices delegated by that subscriber. Returns 404 if the subscriber has no delegated devices.",
        "operationId": "get_all_deveui_versions",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "delegated_subscriber_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Subscriber ID of a delegating subscriber. When provided, returns firmware versions only for devices delegated by this subscriber. Returns 404 if no devices are delegated.",
              "title": "Delegated Subscriber Id"
            },
            "description": "Subscriber ID of a delegating subscriber. When provided, returns firmware versions only for devices delegated by this subscriber. Returns 404 if no devices are delegated."
          }
        ],
        "responses": {
          "200": {
            "description": "The firmware version for each device that has reported one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MultipleDeviceVersionOut"
                }
              }
            }
          }
        }
      }
    },
    "/device_version/{deveui}": {
      "get": {
        "tags": [
          "DeviceVersion"
        ],
        "summary": "Retrieves firmware version for a single device",
        "description": "Retrieves the reported firmware version for a single device identified by `deveui`. Returns 404 if the device has never reported a version.",
        "operationId": "get_deveui_version",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "deveui",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "DevEUI of the device to retrieve the firmware version for. 16-character hexadecimal string.",
              "title": "Deveui"
            },
            "description": "DevEUI of the device to retrieve the firmware version for. 16-character hexadecimal string."
          }
        ],
        "responses": {
          "200": {
            "description": "The firmware version of the requested device.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceVersionOut"
                }
              }
            }
          }
        }
      }
    },
    "/history": {
      "get": {
        "tags": [
          "UpdateHistory"
        ],
        "summary": "Retrieves update history for all devices",
        "description": "Retrieves the firmware update history for every device belonging to the authenticated subscriber.",
        "operationId": "get_history",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the update history for all devices belonging to the subscriber, keyed by DevEUI.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriberHistory"
                }
              }
            }
          }
        }
      }
    },
    "/history/{deveui}": {
      "get": {
        "tags": [
          "UpdateHistory"
        ],
        "summary": "Retrieves update history for a single device",
        "description": "Retrieves the firmware update history for a single device identified by `deveui`.",
        "operationId": "get_deveui_history",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "deveui",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "16-character hexadecimal DevEUI identifying the device.",
              "title": "Deveui"
            },
            "description": "16-character hexadecimal DevEUI identifying the device."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the update history entries for the specified device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceHistory"
                }
              }
            }
          }
        }
      }
    },
    "/images": {
      "get": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Lists all firmware images with metadata",
        "description": "Retrieves all available firmware images with their metadata, including name, hash, and tags, for the subscriber.",
        "operationId": "get_images",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a list of firmware images with name, hash, and tags.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ImageInfo"
                  },
                  "title": "Response Get Images"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Uploads a firmware image with tags",
        "description": "Creates a new firmware image by uploading a binary file with optional tags. Allowed extensions: .bin, .hex, .sfb.",
        "operationId": "upload_image",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ImageUploadWithTags"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns metadata of the uploaded image, including name, hash, and tags.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageInfo"
                }
              }
            }
          }
        }
      }
    },
    "/images/tags": {
      "get": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Lists all tags",
        "description": "Retrieves a sorted list of all unique tags across all firmware images for the subscriber.",
        "operationId": "get_all_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a sorted list of all unique tags across all firmware images.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "title": "Response Get All Tags"
                }
              }
            }
          }
        }
      }
    },
    "/images/tags/{image_name}": {
      "delete": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Deletes all tags from an image",
        "description": "Deletes all tags associated with the specified firmware image.",
        "operationId": "delete_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image.",
              "title": "Image Name"
            },
            "description": "Filename of the firmware image."
          }
        ],
        "responses": {
          "204": {
            "description": "All tags removed from the image successfully with no content returned."
          }
        }
      },
      "get": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Lists tags for an image",
        "description": "Retrieves a sorted list of tags associated with the specified firmware image.",
        "operationId": "get_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image.",
              "title": "Image Name"
            },
            "description": "Filename of the firmware image."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a sorted list of tags for the specified firmware image.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "title": "Response Get Tags"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Replaces tags for an image",
        "description": "Replaces the entire tag list for the specified firmware image with the provided tags. Returns the updated sorted tag list.",
        "operationId": "overwrite_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image.",
              "title": "Image Name"
            },
            "description": "Filename of the firmware image."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15,
                    "pattern": "^[A-Za-z0-9_.\\/-]*$",
                    "description": "Alphanumeric label used to categorize a firmware image."
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 15,
                      "pattern": "^[A-Za-z0-9_.\\/-]*$",
                      "description": "Alphanumeric label used to categorize a firmware image."
                    }
                  },
                  {
                    "type": "array",
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 15,
                      "pattern": "^[A-Za-z0-9_.\\/-]*$",
                      "description": "Alphanumeric label used to categorize a firmware image."
                    }
                  }
                ],
                "title": "Tags"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the updated sorted list of tags after replacement.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "title": "Response Overwrite Tags"
                }
              }
            }
          }
        }
      }
    },
    "/images/tags/{image_name}/add": {
      "patch": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Adds tags to an image",
        "description": "Creates one or more new tag associations on the specified firmware image. Returns the updated sorted tag list.",
        "operationId": "append_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image.",
              "title": "Image Name"
            },
            "description": "Filename of the firmware image."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15,
                    "pattern": "^[A-Za-z0-9_.\\/-]*$",
                    "description": "Alphanumeric label used to categorize a firmware image."
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 15,
                      "pattern": "^[A-Za-z0-9_.\\/-]*$",
                      "description": "Alphanumeric label used to categorize a firmware image."
                    }
                  },
                  {
                    "type": "array",
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 15,
                      "pattern": "^[A-Za-z0-9_.\\/-]*$",
                      "description": "Alphanumeric label used to categorize a firmware image."
                    }
                  }
                ],
                "title": "Tag Names"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the updated sorted list of tags after addition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "title": "Response Append Tags"
                }
              }
            }
          }
        }
      }
    },
    "/images/tags/{image_name}/remove": {
      "patch": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Removes tags from an image",
        "description": "Removes one or more tags from the specified firmware image. Tags are not validated, allowing removal of previously valid tags that may no longer pass validation. Returns the updated sorted tag list.",
        "operationId": "remove_tags",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image.",
              "title": "Image Name"
            },
            "description": "Filename of the firmware image."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  {
                    "type": "array",
                    "uniqueItems": true,
                    "items": {
                      "type": "string"
                    }
                  }
                ],
                "title": "Tags"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the updated sorted list of tags after removal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "title": "Response Remove Tags"
                }
              }
            }
          }
        }
      }
    },
    "/images/{image_id}": {
      "delete": {
        "tags": [
          "FirmwareImages"
        ],
        "summary": "Deletes a firmware image",
        "description": "Deletes the specified firmware image. Fails with 409 if the image is currently used by any campaign.",
        "operationId": "delete_image",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "image_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Filename of the firmware image to delete.",
              "title": "Image Id"
            },
            "description": "Filename of the firmware image to delete."
          }
        ],
        "responses": {
          "204": {
            "description": "Firmware image deleted successfully with no content returned."
          }
        }
      }
    },
    "/key_management": {
      "delete": {
        "tags": [
          "KeyManagement"
        ],
        "summary": "Deletes multicast keys for devices",
        "description": "Deletes multicast keys from the FUOTA server for the provided devices.",
        "operationId": "delete_keys",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "List of 16-character hexadecimal DevEUI strings identifying the devices whose multicast keys should be removed.",
                "title": "Devices"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Multicast keys deleted successfully for the specified devices."
          }
        }
      },
      "post": {
        "tags": [
          "KeyManagement"
        ],
        "summary": "Uploads multicast keys for devices",
        "description": "Stores multicast keys to make them available to the FUOTA server when campaigns are created and/or managed by the server. If using MachineQ MQmonitor, MQflex, or MQio devices, there is no need to upload keys.",
        "operationId": "upload_keys",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadMulticastKeys",
                "description": "Mapping of DevEUIs to their 32-character hexadecimal multicast key values."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Multicast keys stored successfully.",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/managed_campaigns": {
      "get": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Retrieves all managed campaigns",
        "description": "Retrieves all managed campaigns for the authenticated subscriber.",
        "operationId": "get_managed_campaigns",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a list of all managed campaigns belonging to the subscriber.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedCampaigns"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Creates a new managed campaign",
        "description": "Creates a managed campaign that automatically updates devices matching the specified firmware version patterns.\n\nMost parameters have sensible defaults; only `include_versions`, `image_name`, and `gateways` are typically required.\nThe server infers `expected_version` from the semantic version in `image_name` when it is not provided.\nCurrently only a single gateway is supported.\n\n* `include_versions` - A list of 16-character hex patterns, where '.' indicates any value. The\n    managed campaign will attempt to load the image onto any device seen by the gateway whose\n    hexadecimal firmware version matches **any** of the `include_versions` patterns.\n* `exclude_versions` - A list in the same format as `include_versions`, but with the opposite\n    effect: any device whose firmware version matches **any** of the `exclude_versions`\n    patterns.\n\n    This takes priority over `include_versions`, so a device that matched a pattern in both\n    would be excluded from the managed campaign.",
        "operationId": "create_managed_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagedCampaignIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the created managed campaign with its assigned identifier and initial state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedCampaignOut"
                }
              }
            }
          }
        }
      }
    },
    "/managed_campaigns/upload_multicast_keys": {
      "post": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Uploads multicast keys for managed campaigns",
        "description": "Stores multicast keys to make them available to managed campaigns. Devices without known keys cannot be included in a managed campaign. Deprecated in favor of /api/latest/key_management.",
        "operationId": "upload_managed_campaign_keys",
        "deprecated": true,
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadMulticastKeys"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the uploaded DevEUI-to-multicast-key mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadMulticastKeys"
                }
              }
            }
          }
        }
      }
    },
    "/managed_campaigns/{managed_campaign_id}": {
      "delete": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Deletes a managed campaign",
        "description": "Deletes a managed campaign identified by `managed_campaign_id`. The managed campaign must be in the FINISHED, CLEANED, or ERROR_SETTING_UP stage before it can be deleted.",
        "operationId": "delete_managed_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "managed_campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the managed campaign.",
              "title": "Managed Campaign Id"
            },
            "description": "Unique identifier of the managed campaign."
          }
        ],
        "responses": {
          "204": {
            "description": "Managed campaign deleted successfully."
          }
        }
      },
      "get": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Retrieves a single managed campaign",
        "description": "Retrieves a managed campaign by `managed_campaign_id`, including devices that have been updated and devices scheduled for the next child campaign.",
        "operationId": "get_managed_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "managed_campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the managed campaign.",
              "title": "Managed Campaign Id"
            },
            "description": "Unique identifier of the managed campaign."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the managed campaign details including scheduled and updated devices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedCampaignOut"
                }
              }
            }
          }
        }
      }
    },
    "/managed_campaigns/{managed_campaign_id}/halt": {
      "post": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Halts a managed campaign",
        "description": "Halts a managed campaign by `managed_campaign_id`, stopping any currently-running child campaign. Once halted, the managed campaign transitions into a completed state.",
        "operationId": "halt_managed_campaign",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "managed_campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the managed campaign.",
              "title": "Managed Campaign Id"
            },
            "description": "Unique identifier of the managed campaign."
          }
        ],
        "responses": {
          "202": {
            "description": "Halting is in progress; the managed campaign and any active child campaign are being stopped.",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "204": {
            "description": "Managed campaign is already halted or finished."
          }
        }
      }
    },
    "/managed_campaigns/{managed_campaign_id}/problematic_devices": {
      "delete": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Clears the problematic devices list",
        "description": "Clears the problematic devices list for the managed campaign identified by `managed_campaign_id`. Future child campaigns will no longer exclude previously problematic devices.",
        "operationId": "clear_managed_campaign_problematic_devices",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "managed_campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the managed campaign.",
              "title": "Managed Campaign Id"
            },
            "description": "Unique identifier of the managed campaign."
          }
        ],
        "responses": {
          "204": {
            "description": "Problematic devices list cleared successfully."
          }
        }
      },
      "get": {
        "tags": [
          "ManagedCampaigns"
        ],
        "summary": "Retrieves problematic devices for a managed campaign",
        "description": "Retrieves problematic devices for the managed campaign identified by `managed_campaign_id`. Problematic devices are those that have failed in two or more child campaigns.",
        "operationId": "get_managed_campaign_problematic_devices",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "managed_campaign_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the managed campaign.",
              "title": "Managed Campaign Id"
            },
            "description": "Unique identifier of the managed campaign."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a list of devices that have failed in two or more child campaigns, with failure reasons.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ManagedCampaignFailedDevice"
                  },
                  "title": "Response Get Managed Campaign Problematic Devices"
                }
              }
            }
          }
        }
      }
    },
    "/reliable_downlinks": {
      "get": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Lists all reliable downlink jobs with status",
        "description": "Retrieves all reliable downlink jobs for the authenticated subscriber, including device completion statuses.",
        "operationId": "get_jobs",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of all jobs with device completion statuses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReliableDownlinkListFull"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Creates a reliable downlink job",
        "description": "Creates a reliable downlink job that sends the specified payload and waits for an expected device response. Retries automatically at the configured interval until the maximum retry count is reached. Accepts either a list of devices, a `device_group_id`, or both.",
        "operationId": "create_job",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReliableDownlinkIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Newly created reliable downlink job with server-assigned job ID and timestamp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReliableDownlinkOut"
                }
              }
            }
          }
        }
      }
    },
    "/reliable_downlinks/{job_id}": {
      "delete": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Deletes a reliable downlink job",
        "description": "Deletes the reliable downlink job identified by `job_id`. Stops all pending device downlink attempts, clears queued downlinks, and removes the job and its associated device states.",
        "operationId": "delete_job",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Job deleted successfully with no content returned."
          }
        }
      },
      "get": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Retrieves a reliable downlink job status",
        "description": "Retrieves the current status of a reliable downlink job identified by `job_id`, including device success and failure counts.",
        "operationId": "get_job",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job details with device success and failure counts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReliableDownlinkStatus"
                }
              }
            }
          }
        }
      }
    },
    "/reliable_downlinks/{job_id}/restart": {
      "put": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Restarts a reliable downlink job",
        "description": "Restarts the reliable downlink job identified by `job_id` by re-sending the downlink to all previously failed devices. Fails if any devices are still actively being processed or if all devices already succeeded.",
        "operationId": "restart_job",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Restarted job with updated device list targeting previously failed devices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReliableDownlinkOut"
                }
              }
            }
          }
        }
      }
    },
    "/reliable_downlinks/{job_id}/stop": {
      "put": {
        "tags": [
          "ReliableDownlink"
        ],
        "summary": "Stops a reliable downlink job",
        "description": "Stops the reliable downlink job identified by `job_id`. Halts all pending device downlink attempts and transitions pending devices to the failed state. Devices that already succeeded remain successful. Even if a downlink was already queued and delivered, the device response is ignored after stopping.",
        "operationId": "stop_job",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status after stopping, with pending devices transitioned to failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReliableDownlinkStatus"
                }
              }
            }
          }
        }
      }
    },
    "/upgrade_delegation": {
      "get": {
        "tags": [
          "UpgradeDelegation"
        ],
        "summary": "Retrieves all upgrade delegation records",
        "description": "Retrieves all upgrade delegation records for the current subscriber. Includes records where the subscriber is delegating upgrades to another party and records where the subscriber is receiving delegated upgrades.",
        "operationId": "get_delegations",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Returns a list of all delegation records where the current subscriber is either the delegator or the delegatee.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UpgradeDelegationOut"
                  },
                  "title": "Response Get Delegations"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "UpgradeDelegation"
        ],
        "summary": "Creates an upgrade delegation record",
        "description": "Creates a new upgrade delegation record that grants another subscriber permission to manage device upgrades.\n\nCheck out [the documentation about upgrade delegation](/docs/features/upgrade_delegation).\n\nNote: currently the API does not support gateway delegation, only device delegation. The fields `include_gateways` and `exclude_gateways` are ignored for now. Later patches will add support for gateway delegation.",
        "operationId": "add_delegation",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpgradeDelegationIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the newly created delegation record with server-assigned `delegation_id`, `delegate_from`, and `created_at` fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpgradeDelegationOut"
                }
              }
            }
          }
        }
      }
    },
    "/upgrade_delegation/{delegation_id}": {
      "delete": {
        "tags": [
          "UpgradeDelegation"
        ],
        "summary": "Deletes an upgrade delegation record",
        "description": "Deletes an upgrade delegation record. Only the subscriber that created the record can delete it.",
        "operationId": "remove_delegation",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "delegation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the delegation record to delete.",
              "title": "Delegation Id"
            },
            "description": "Unique identifier of the delegation record to delete."
          }
        ],
        "responses": {
          "204": {
            "description": "Delegation record deleted successfully with no content returned."
          }
        }
      },
      "get": {
        "tags": [
          "UpgradeDelegation"
        ],
        "summary": "Retrieves a single upgrade delegation record",
        "description": "Retrieves a single upgrade delegation record by `delegation_id`. Returns the record regardless of whether the current subscriber is the delegator or the delegatee.",
        "operationId": "get_delegation",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "delegation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the delegation record to retrieve.",
              "title": "Delegation Id"
            },
            "description": "Unique identifier of the delegation record to retrieve."
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the delegation record matching the specified `delegation_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpgradeDelegationOut"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "UpgradeDelegation"
        ],
        "summary": "Updates an upgrade delegation record",
        "description": "Updates an existing upgrade delegation record with a partial patch. Only the subscriber that created the record can update it. Only supplied fields are modified; omitted fields remain unchanged.",
        "operationId": "update_delegation",
        "security": [
          {
            "OAuth2AuthorizationCodeBearer": []
          },
          {
            "HTTPBearer": []
          }
        ],
        "parameters": [
          {
            "name": "delegation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Unique identifier of the delegation record to update.",
              "title": "Delegation Id"
            },
            "description": "Unique identifier of the delegation record to update."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpgradeDelegationPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returns the updated delegation record with the patched fields applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpgradeDelegationOut"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BulkCampaignResponse": {
        "additionalProperties": {
          "items": {},
          "type": "array"
        },
        "type": "object",
        "title": "BulkCampaignResponse",
        "description": "Mapping of campaign IDs to [stage, successful_device_count, total_device_count] arrays.",
        "examples": [
          {
            "campaignid1": [
              "7",
              3,
              5
            ],
            "campaignid2": [
              "3",
              0,
              25
            ]
          }
        ]
      },
      "CampaignInV3_2": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the campaign."
          },
          "image_name": {
            "type": "string",
            "title": "Image Name",
            "description": "Name of the firmware image previously uploaded via /images."
          },
          "device_group_id": {
            "type": "string",
            "title": "Device Group Id",
            "description": "Identifier of the target device group."
          },
          "mcast_deveui": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Deveui",
            "description": "Multicast DevEUI. Auto-generated when omitted. If provided, mcast_devaddr and mcast_mc_key must also be set."
          },
          "mcast_dr": {
            "type": "integer",
            "exclusiveMaximum": 15.0,
            "exclusiveMinimum": 0.0,
            "title": "Mcast Dr",
            "description": "Multicast data rate. Allowed values: 1-14.",
            "default": 11
          },
          "mcast_freq": {
            "type": "number",
            "exclusiveMaximum": 1000.0,
            "exclusiveMinimum": 0.0,
            "title": "Mcast Freq",
            "description": "Multicast frequency in MHz. Must be between 0 and 1000 exclusive.",
            "default": 923.9
          },
          "mcast_session_timeout": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Session Timeout",
            "description": "Multicast session timeout in seconds. Must be a power of 2. Null lets the server choose automatically."
          },
          "redundancy": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Redundancy",
            "description": "Fraction of redundancy fragments to send, from 0.0 (none) to 1.0 (100%).",
            "default": 0.3
          },
          "expected_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Version",
            "description": "Expected firmware version after the update (e.g., '0.1.2.3'). Inferred from image_name when omitted."
          },
          "frag_send_delay": {
            "type": "number",
            "minimum": 0.0,
            "title": "Frag Send Delay",
            "description": "Delay between sending each fragment, in seconds.",
            "default": 2
          },
          "acceptable_time_drift": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Acceptable Time Drift",
            "description": "Maximum acceptable clock drift between server and device, in seconds.",
            "default": 20
          },
          "sleep_after_frag_sent": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Sleep After Frag Sent",
            "description": "Wait time after all fragments are sent before proceeding, in seconds.",
            "default": 600
          },
          "descriptor": {
            "type": "string",
            "title": "Descriptor",
            "description": "8-character hex descriptor for the firmware image.",
            "default": "00000000"
          },
          "min_downlink_delay": {
            "type": "number",
            "minimum": 0.0,
            "title": "Min Downlink Delay",
            "description": "Minimum delay between consecutive downlinks to a device, in seconds.",
            "default": 5
          },
          "min_timeout_delay": {
            "type": "number",
            "minimum": 0.0,
            "title": "Min Timeout Delay",
            "description": "Minimum timeout before retrying a downlink, in seconds. Must be greater than min_downlink_delay.",
            "default": 900
          },
          "force_initial_version_check": {
            "type": "boolean",
            "title": "Force Initial Version Check",
            "description": "Whether to verify the device firmware version before starting the update. True means the version check is enforced.",
            "default": true
          },
          "completed_email_alert": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Completed Email Alert",
            "description": "Reserved. Currently unused.",
            "default": []
          },
          "max_final_version_check_retry": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Max Final Version Check Retry",
            "description": "Maximum number of retries for the final firmware version check.",
            "default": 15
          },
          "automatic_retry_count": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Automatic Retry Count",
            "description": "Number of automatic retries for failed devices. 0 disables automatic retries.",
            "default": 0
          },
          "automatic_retry_interval": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Automatic Retry Interval",
            "description": "Interval between automatic retries, in seconds.",
            "default": 120
          },
          "downlink_delay_rand_s": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Downlink Delay Rand S",
            "description": "Maximum random jitter added to downlink delays, in seconds. 0 disables jitter.",
            "default": 0
          },
          "individual_fragment_retransmit": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Individual Fragment Retransmit",
            "description": "Number of individual fragment retransmissions per device. 0 disables individual retransmission. Experimental.",
            "default": 0
          },
          "multicast_setup_time": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Multicast Setup Time",
            "description": "Multicast setup window in seconds. Auto-determined when omitted."
          },
          "scheduled_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Start At",
            "description": "Scheduled start time in RFC 3339 format. Must be in the future. Null starts the campaign immediately."
          },
          "mcast_devaddr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Devaddr",
            "description": "Multicast device address. Required when mcast_deveui is provided."
          },
          "mcast_mc_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Mc Key",
            "description": "Multicast session key (32-character hex). Required when mcast_deveui is provided."
          },
          "is_debug": {
            "type": "boolean",
            "title": "Is Debug",
            "description": "Whether to collect debug information for each device. True enables debug logging in the campaign response.",
            "default": false
          },
          "is_troubleshooting": {
            "type": "boolean",
            "title": "Is Troubleshooting",
            "description": "Whether to run automated troubleshooting checks on each device. True enables troubleshooting output in the campaign response.",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "name",
          "image_name",
          "device_group_id"
        ],
        "title": "CampaignInV3_2",
        "description": "A request to create a new v3.2 campaign."
      },
      "CampaignListV3_2": {
        "items": {
          "$ref": "#/components/schemas/CampaignSummary"
        },
        "type": "array",
        "title": "CampaignListV3_2",
        "description": "List of campaign summary objects.",
        "examples": [
          [
            {
              "campaign_id": "XgAEtg",
              "created_at": "2023-01-21T18:51:28.469107Z",
              "device_group_id": "poiuyt",
              "name": "Fuota v3.0.0",
              "num_devices_fail": 0,
              "num_devices_in_progress": 10,
              "num_devices_success": 0,
              "scheduled_start_at": "2024-01-23T19:57:55.628Z",
              "stage": 0,
              "stage_str": "INITIALIZING",
              "status": ""
            },
            {
              "campaign_id": "abcdef",
              "created_at": "2026-01-21T00:00:00.000000Z",
              "device_group_id": "tgbyhn",
              "name": "Some campaign",
              "num_devices_fail": 5,
              "num_devices_in_progress": 0,
              "num_devices_success": 5,
              "scheduled_start_at": "2026-01-21T01:00:00.000Z",
              "stage": 7,
              "stage_str": "FINISHED",
              "status": ""
            }
          ]
        ]
      },
      "CampaignOutStatus": {
        "properties": {
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Unique identifier of the campaign."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the campaign."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Free-text status message. Empty when no notable status exists."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "Timestamp when the campaign was created, in RFC 3339 format."
          },
          "scheduled_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Start At",
            "description": "Scheduled start time in RFC 3339 format. Null if the campaign starts immediately."
          },
          "stage": {
            "$ref": "#/components/schemas/CampaignStage",
            "description": "Current numeric stage of the campaign."
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "String representation of the stage. For complete list see `stage` of the campaign schema"
          }
        },
        "type": "object",
        "required": [
          "campaign_id",
          "name",
          "status",
          "created_at",
          "scheduled_start_at",
          "stage",
          "stage_str"
        ],
        "title": "CampaignOutStatus",
        "description": "Partial campaign status returned while the campaign is still initializing (HTTP 202).",
        "examples": [
          {
            "campaign_id": "XgAEtg",
            "created_at": "2023-01-21T18:51:28.469107Z",
            "name": "Fuota v3.0.0",
            "scheduled_start_at": "2024-01-23T19:57:55.628Z",
            "stage": 0,
            "stage_str": "INITIALIZING",
            "status": ""
          }
        ]
      },
      "CampaignOutV3_2": {
        "properties": {
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Unique identifier of the campaign."
          },
          "stage": {
            "$ref": "#/components/schemas/CampaignStage",
            "description": "Current stage of the campaign."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "Timestamp when the campaign was created, in RFC 3339 format."
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started At",
            "description": "Timestamp when the campaign started, in RFC 3339 format. Null if not yet started."
          },
          "finished_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Finished At",
            "description": "Timestamp when the campaign finished, in RFC 3339 format. Null if not yet finished."
          },
          "class_c_start_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Class C Start At",
            "description": "Timestamp when Class C fragment transmission begins, in RFC 3339 format. Null for Class A campaigns."
          },
          "estimated_frags_complete": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Estimated Frags Complete",
            "description": "Estimated time when all fragments will be sent, in RFC 3339 format. Null if not yet calculated."
          },
          "data_fragments": {
            "type": "integer",
            "title": "Data Fragments",
            "description": "Total number of data fragments to transmit."
          },
          "redundancy_fragments": {
            "type": "integer",
            "title": "Redundancy Fragments",
            "description": "Total number of redundancy fragments to transmit."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway identifiers used by this campaign. Maximum 10 items."
          },
          "total_devices": {
            "type": "integer",
            "title": "Total Devices",
            "description": "Total number of devices in the campaign."
          },
          "retry_success_rates": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Retry Success Rates",
            "description": "List of cumulative successful device counts after each attempt."
          },
          "attempts": {
            "type": "integer",
            "title": "Attempts",
            "description": "Number of update attempts executed so far."
          },
          "current_fragment_cnt": {
            "type": "integer",
            "title": "Current Fragment Cnt",
            "description": "Number of fragments sent so far in the current attempt."
          },
          "devices": {
            "items": {
              "$ref": "#/components/schemas/DeviceStateOutV3_2"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of per-device states including troubleshooting results."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Free-text status message. Empty when no notable status exists."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the campaign."
          },
          "image_name": {
            "type": "string",
            "title": "Image Name",
            "description": "Name of the firmware image previously uploaded via /images."
          },
          "device_group_id": {
            "type": "string",
            "title": "Device Group Id",
            "description": "Identifier of the target device group."
          },
          "mcast_deveui": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Deveui",
            "description": "Multicast DevEUI. Auto-generated when omitted. If provided, mcast_devaddr and mcast_mc_key must also be set."
          },
          "mcast_dr": {
            "type": "integer",
            "title": "Mcast Dr",
            "description": "Multicast data rate. Allowed values: 1-14."
          },
          "mcast_freq": {
            "type": "number",
            "title": "Mcast Freq",
            "description": "Multicast frequency in MHz. Must be between 0 and 1000 exclusive."
          },
          "mcast_session_timeout": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mcast Session Timeout",
            "description": "Multicast session timeout in seconds. Must be a power of 2. Null lets the server choose automatically."
          },
          "redundancy": {
            "type": "number",
            "title": "Redundancy",
            "description": "Fraction of redundancy fragments to send, from 0.0 (none) to 1.0 (100%)."
          },
          "expected_version": {
            "type": "string",
            "title": "Expected Version",
            "description": "Expected firmware version after the update as a 16-character hex mask, where '.' matches any hex digit."
          },
          "frag_send_delay": {
            "type": "number",
            "title": "Frag Send Delay",
            "description": "Delay between sending each fragment, in seconds."
          },
          "acceptable_time_drift": {
            "type": "integer",
            "title": "Acceptable Time Drift",
            "description": "Maximum acceptable clock drift between server and device, in seconds."
          },
          "sleep_after_frag_sent": {
            "type": "integer",
            "title": "Sleep After Frag Sent",
            "description": "Wait time after all fragments are sent before proceeding, in seconds."
          },
          "descriptor": {
            "type": "string",
            "title": "Descriptor",
            "description": "8-character hex descriptor for the firmware image."
          },
          "min_downlink_delay": {
            "type": "number",
            "title": "Min Downlink Delay",
            "description": "Minimum delay between consecutive downlinks to a device, in seconds."
          },
          "min_timeout_delay": {
            "type": "number",
            "title": "Min Timeout Delay",
            "description": "Minimum timeout before retrying a downlink, in seconds. Must be greater than min_downlink_delay."
          },
          "force_initial_version_check": {
            "type": "boolean",
            "title": "Force Initial Version Check",
            "description": "Whether to verify the device firmware version before starting the update. True means the version check is enforced."
          },
          "max_final_version_check_retry": {
            "type": "integer",
            "title": "Max Final Version Check Retry",
            "description": "Maximum number of retries for the final firmware version check."
          },
          "automatic_retry_count": {
            "type": "integer",
            "title": "Automatic Retry Count",
            "description": "Number of automatic retries for failed devices. 0 disables automatic retries."
          },
          "automatic_retry_interval": {
            "type": "integer",
            "title": "Automatic Retry Interval",
            "description": "Interval between automatic retries, in seconds."
          },
          "downlink_delay_rand_s": {
            "type": "integer",
            "title": "Downlink Delay Rand S",
            "description": "Maximum random jitter added to downlink delays, in seconds. 0 disables jitter."
          },
          "individual_fragment_retransmit": {
            "type": "integer",
            "title": "Individual Fragment Retransmit",
            "description": "Number of individual fragment retransmissions per device. 0 disables individual retransmission. Experimental."
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "Human-readable name of the campaign stage."
          },
          "multicast_setup_time": {
            "type": "integer",
            "title": "Multicast Setup Time",
            "description": "Multicast setup window in seconds. 0 indicates the server determined the value automatically."
          },
          "scheduled_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Start At",
            "description": "Scheduled start time in RFC 3339 format. Null if the campaign was started immediately."
          },
          "is_debug": {
            "type": "boolean",
            "title": "Is Debug",
            "description": "Whether debug information is collected for each device. True enables per-device debug_info in the response.",
            "default": false
          },
          "is_troubleshooting": {
            "type": "boolean",
            "title": "Is Troubleshooting",
            "description": "Whether automated troubleshooting checks run on each device. True enables per-device troubleshooting output in the response.",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "campaign_id",
          "stage",
          "created_at",
          "started_at",
          "finished_at",
          "class_c_start_at",
          "estimated_frags_complete",
          "data_fragments",
          "redundancy_fragments",
          "gateways",
          "total_devices",
          "retry_success_rates",
          "attempts",
          "current_fragment_cnt",
          "devices",
          "status",
          "name",
          "image_name",
          "device_group_id",
          "mcast_deveui",
          "mcast_dr",
          "mcast_freq",
          "mcast_session_timeout",
          "redundancy",
          "expected_version",
          "frag_send_delay",
          "acceptable_time_drift",
          "sleep_after_frag_sent",
          "descriptor",
          "min_downlink_delay",
          "min_timeout_delay",
          "force_initial_version_check",
          "max_final_version_check_retry",
          "automatic_retry_count",
          "automatic_retry_interval",
          "downlink_delay_rand_s",
          "individual_fragment_retransmit",
          "stage_str",
          "multicast_setup_time",
          "scheduled_start_at"
        ],
        "title": "CampaignOutV3_2",
        "description": "Full campaign state returned by v3.2 endpoints. Includes per-device troubleshooting information.",
        "examples": [
          {
            "acceptable_time_drift": 40,
            "attempts": 1,
            "automatic_retry_count": 0,
            "automatic_retry_interval": 120,
            "campaign_id": "XgAEtg",
            "class_c_start_at": "2023-10-17T20:53:46.893534Z",
            "completed_email_alert": [],
            "created_at": "2023-10-13T14:56:48.464374Z",
            "current_fragment_cnt": 0,
            "data_fragments": 67,
            "delayed_start": 0,
            "descriptor": "00000000",
            "device_group_id": "tEgdxH",
            "devices": [
              {
                "attempts": 0,
                "deveui": "2CC407FFFE5171AA",
                "lora_class": "A",
                "ready_for_fragments_at": "2023-10-17T20:44:48.580644Z",
                "reason": "",
                "session_start_at": 1697576027,
                "stage": 5,
                "stage_str": "FAIL",
                "troubleshooting": {
                  "checks": [
                    {
                      "details": "Device appears offline. Last uplink was at 2025-01-01 12:00:00",
                      "id": 1,
                      "name": "Device online",
                      "result": "FAIL"
                    }
                  ],
                  "summary": "Device was offline during the entire campaign."
                }
              }
            ],
            "downlink_delay_rand_s": 10,
            "estimated_frags_complete": "2023-10-17T20:58:02.893534Z",
            "expected_version": "0.2.0.0",
            "force_initial_version_check": true,
            "frag_send_delay": 2,
            "gateways": [
              "1122334455667788"
            ],
            "image_name": "fuota_v3.0.0.bin",
            "individual_fragment_retransmit": 0,
            "max_final_version_check_retry": 15,
            "mcast_deveui": "EDC1ECE9EDC1ECE9",
            "mcast_dr": 11,
            "mcast_freq": 923.9,
            "mcast_session_timeout": 256,
            "min_downlink_delay": 5,
            "min_timeout_delay": 30,
            "name": "Fuota v3.0.0",
            "redundancy": 0.3,
            "redundancy_fragments": 21,
            "retry_success_rates": [],
            "sleep_after_frag_sent": 600,
            "stage": 2,
            "stage_str": "SETTING_UP_DEVICES",
            "start_in": 600,
            "started_at": "2023-10-17T20:43:46.893618Z",
            "total_devices": 1
          }
        ]
      },
      "CampaignStage": {
        "type": "integer",
        "enum": [
          0,
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10
        ],
        "title": "CampaignStage",
        "description": "Campaign stages:\n\n* INITIALIZING (0): campaign was created by the state was not initialized yet\n* DELAYED_START (1): campaign was created with a delayed start time\n* SETTING_UP_DEVICES (2): the server is setting up the devices\n* SENDING_FRAGMENTS (3): the server is sending fragments\n* FRAG_SEND_DELAY (4): the server is waiting for the fragment send delay to pass.\nGives devices time to process the fragments and restart.\n* FINAL_VERSION_CHECK (5): the server is checking that all devices have the expected version\n* RETRY_SCHEDULED (6): either campaign is scheduled to retry.\nTriggered manually or automatically on failure.\n* FINISHED (7): campaign finished. Either success or failure.\n* ERROR_SETTING_UP (8): campaign failed to set up. Mostly related to error while\ncreating the multicast group or gateway tagging.\n* DELETING (9): campaign is being deleted.\n* DELETE_ERROR (10): campaign deletion failed."
      },
      "CampaignSummary": {
        "properties": {
          "campaign_id": {
            "type": "string",
            "title": "Campaign Id",
            "description": "Unique identifier of the campaign."
          },
          "image_name": {
            "type": "string",
            "title": "Image Name",
            "description": "Name of the firmware image used by this campaign."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the campaign."
          },
          "device_group_id": {
            "type": "string",
            "title": "Device Group Id",
            "description": "Identifier of the device group targeted by this campaign."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Free-text status message. Empty when no notable status exists."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "Timestamp when the campaign was created, in RFC 3339 format."
          },
          "scheduled_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Start At",
            "description": "Scheduled start time in RFC 3339 format. Null if the campaign starts immediately."
          },
          "stage": {
            "type": "integer",
            "title": "Stage",
            "description": "Integer representation of the stage. For complete list see `stage` of the campaign schema"
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "String representation of the stage. For complete list see `stage` of the campaign schema"
          },
          "num_devices_success": {
            "type": "integer",
            "title": "Num Devices Success",
            "description": "Number of devices that have successfully updated."
          },
          "num_devices_fail": {
            "type": "integer",
            "title": "Num Devices Fail",
            "description": "Number of devices that failed to update."
          },
          "num_devices_in_progress": {
            "type": "integer",
            "title": "Num Devices In Progress",
            "description": "Number of devices still in progress or setting up."
          }
        },
        "type": "object",
        "required": [
          "campaign_id",
          "image_name",
          "name",
          "device_group_id",
          "status",
          "created_at",
          "scheduled_start_at",
          "stage",
          "stage_str",
          "num_devices_success",
          "num_devices_fail",
          "num_devices_in_progress"
        ],
        "title": "CampaignSummary",
        "description": "Summary of a single campaign, including progress counts."
      },
      "CheckOutput": {
        "properties": {
          "id": {
            "type": "integer",
            "title": "Id",
            "description": "Sequential identifier of the check within the troubleshooting run."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable name of the check."
          },
          "result": {
            "$ref": "#/components/schemas/CheckResult",
            "description": "Outcome of the check. Allowed values: `PASS`, `FAIL`, `WARNING`, `SKIP`."
          },
          "details": {
            "type": "string",
            "title": "Details",
            "description": "Human-readable explanation of the check outcome. Empty when no additional detail exists."
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "result",
          "details"
        ],
        "title": "CheckOutput",
        "description": "Result of a single troubleshooting check performed on a device."
      },
      "CheckResult": {
        "type": "string",
        "enum": [
          "PASS",
          "FAIL",
          "WARNING",
          "SKIP"
        ],
        "title": "CheckResult"
      },
      "DeviceClass": {
        "type": "string",
        "enum": [
          "A",
          "B",
          "C"
        ],
        "title": "DeviceClass",
        "description": "LoRaWAN device class that determines how the FUOTA server sends downlinks.\nClass A sends all downlinks immediately, queuing them on the network server.\nClass C sends downlinks one by one, waiting for a response from the device before proceeding to the next step."
      },
      "DeviceGroupInV3_2": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the device group."
          },
          "lora_class": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DeviceClass"
              },
              {
                "type": "null"
              }
            ],
            "description": "LoRaWAN device class that determines downlink behavior. `A`: sends all downlinks immediately, queuing them on the network server. `C`: sends downlinks one by one, waiting for a device response before proceeding. When omitted or null, automatically determined from the devices in the group."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway NodeIDs assigned to this group. Maximum 10. When empty, gateways are automatically selected."
          },
          "devices": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of 16-character hexadecimal DevEUIs to include in the group."
          }
        },
        "type": "object",
        "required": [
          "name",
          "devices"
        ],
        "title": "DeviceGroupInV3_2",
        "description": "Request to create or replace a device group using a list of DevEUIs. Keys are managed separately via `/key_management`.",
        "examples": [
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "name": "My Device Group"
          },
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "lora_class": "A",
            "name": "My Device Group"
          }
        ]
      },
      "DeviceGroupListV3_2": {
        "items": {
          "$ref": "#/components/schemas/DeviceGroupOut"
        },
        "type": "array",
        "title": "DeviceGroupListV3_2",
        "description": "List of device group summary objects.",
        "examples": [
          [
            {
              "device_group_id": "123456q",
              "devices": [
                "0102030405060708",
                "0102030405060709"
              ],
              "lora_class": "A",
              "name": "My Device Group"
            },
            {
              "device_group_id": "abcabca",
              "devices": [
                "010203040506070a",
                "010203040506070b"
              ],
              "lora_class": "C",
              "name": "My Other Device Group"
            }
          ]
        ]
      },
      "DeviceGroupOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the device group."
          },
          "lora_class": {
            "$ref": "#/components/schemas/DeviceClass",
            "description": "LoRaWAN device class that determines downlink behavior. `A`: sends all downlinks immediately, queuing them on the network server. `C`: sends downlinks one by one, waiting for a device response before proceeding."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway NodeIDs assigned to this group. Maximum 10. When empty, gateways are automatically selected."
          },
          "device_group_id": {
            "type": "string",
            "title": "Device Group Id",
            "description": "Unique identifier of the device group. 6-character alphanumeric string."
          },
          "devices": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of DevEUIs belonging to this device group."
          }
        },
        "type": "object",
        "required": [
          "name",
          "lora_class",
          "device_group_id",
          "devices"
        ],
        "title": "DeviceGroupOut",
        "description": "Device group returned by the API, including its unique identifier and member devices.",
        "examples": [
          {
            "device_group_id": "123456q",
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "lora_class": "A",
            "name": "My Device Group"
          }
        ]
      },
      "DeviceHistory": {
        "items": {
          "$ref": "#/components/schemas/DeviceHistoryStatus"
        },
        "type": "array",
        "title": "DeviceHistory",
        "description": "Chronological list of firmware update history entries for a single device.",
        "examples": [
          [
            {
              "campaign_id": "0b8kLb",
              "entry_date": "2022-02-18 22:34:46",
              "expected_version": "0.0.83.0",
              "initial_version": "0.0.84.0",
              "post_update_version": "0.0.83.0",
              "reason": "",
              "status": "SUCCESS"
            }
          ]
        ]
      },
      "DeviceHistoryStatus": {
        "properties": {
          "entry_date": {
            "type": "string",
            "format": "date-time",
            "title": "Entry Date",
            "description": "Timestamp when the history entry was recorded, in RFC 3339 format."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Outcome status of the update attempt (e.g., `success`, `failure`, `timeout`)."
          },
          "reason": {
            "type": "string",
            "title": "Reason",
            "description": "Human-readable explanation of the status."
          },
          "initial_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Initial Version",
            "description": "Firmware version of the device before the update. Null if unknown."
          },
          "post_update_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Post Update Version",
            "description": "Firmware version of the device after the update. Null if the device did not report a new version."
          },
          "expected_version": {
            "type": "string",
            "title": "Expected Version",
            "description": "Target firmware version the update was intended to install."
          },
          "campaign_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Campaign Id",
            "description": "Identifier of the campaign that triggered the update. Null if not associated with a campaign."
          }
        },
        "type": "object",
        "required": [
          "status",
          "reason",
          "initial_version",
          "post_update_version",
          "expected_version"
        ],
        "title": "DeviceHistoryStatus",
        "description": "Single firmware update history entry for a device."
      },
      "DeviceStage": {
        "type": "integer",
        "enum": [
          0,
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          9
        ],
        "title": "DeviceStage",
        "description": "Device stages for the FUOTA process:\n\n* INIT (0): device state was created but not initialized yet\n* INITIAL_VERSION_CHECK (1): the server is checking device's initial version\n* MCAST_GROUP_SETUP (2): the server is setting up the multicast group\n* FRAG_SETUP (3): the server is setting up the fragmentation session\n* MCAST_SESSION_SETUP (4): the server is setting up the multicast session\n* FRAGMENTS (5): the device is set up to receive fragments\nThe fragmentation will be sent at `class_c_start_at`.\n* FINAL_VERSION_CHECK (6): the server is checking that the device has the expected version.\n* SUCCESS (7): the device has the expected version.\n* FAIL (9): the device failed to update to the expected version."
      },
      "DeviceStateOutV3_2": {
        "properties": {
          "deveui": {
            "type": "string",
            "title": "Deveui",
            "description": "Extended Unique Identifier of the device (16-character hex)."
          },
          "stage": {
            "$ref": "#/components/schemas/DeviceStage",
            "description": "Numeric stage of the device in the update process."
          },
          "initial_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Initial Version",
            "description": "Firmware version reported by the device before the update (16-character hex). Null if not yet reported."
          },
          "latest_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest Version",
            "description": "Most recently reported firmware version (16-character hex). Null if not yet reported."
          },
          "lora_class": {
            "$ref": "#/components/schemas/DeviceClass",
            "description": "LoRaWAN device class. Allowed values: A, C."
          },
          "session_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Session Start At",
            "description": "Timestamp when the device joined the multicast session, in RFC 3339 format. Null if the device has not yet joined."
          },
          "reason": {
            "type": "string",
            "title": "Reason",
            "description": "Human-readable reason for the current device stage. Empty when no notable reason exists."
          },
          "attempts": {
            "type": "integer",
            "title": "Attempts",
            "description": "Number of update attempts made for this device."
          },
          "ready_for_fragments_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ready For Fragments At",
            "description": "Timestamp when the device became ready to receive fragments, in RFC 3339 format. Null if not yet ready."
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "Human-readable name of the device stage."
          },
          "debug_info": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Debug Info",
            "description": "Chronological list of debug log entries collected during the update. Empty when debug mode is disabled.",
            "default": []
          },
          "troubleshooting": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DeviceTroubleshooting"
              },
              {
                "type": "null"
              }
            ],
            "description": "Troubleshooting results for the device. Null when troubleshooting is disabled for the campaign."
          }
        },
        "type": "object",
        "required": [
          "deveui",
          "stage",
          "initial_version",
          "latest_version",
          "lora_class",
          "session_start_at",
          "reason",
          "attempts",
          "ready_for_fragments_at",
          "stage_str"
        ],
        "title": "DeviceStateOutV3_2",
        "examples": [
          {
            "attempts": 0,
            "deveui": "2CC407FFFE5171AA",
            "initial_version": "005500000000000B",
            "latest_version": "005600000000000B",
            "lora_class": "A",
            "ready_for_fragments_at": "2023-10-17T20:44:48.580644Z",
            "reason": "",
            "session_start_at": 1697576027,
            "stage": 5,
            "stage_str": "FRAGMENTS",
            "troubleshooting": {
              "checks": [
                {
                  "details": "Device appears offline. Last uplink was at 2025-01-01 12:00:00",
                  "id": 1,
                  "name": "Device online",
                  "result": "FAIL"
                }
              ],
              "summary": "Device was offline during the entire campaign."
            }
          }
        ]
      },
      "DeviceTroubleshooting": {
        "properties": {
          "summary": {
            "type": "string",
            "title": "Summary",
            "description": "One-line summary of the troubleshooting outcome. Empty when no checks have run.",
            "default": ""
          },
          "checks": {
            "items": {
              "$ref": "#/components/schemas/CheckOutput"
            },
            "type": "array",
            "title": "Checks",
            "description": "Ordered list of individual check results.",
            "default": []
          }
        },
        "type": "object",
        "title": "DeviceTroubleshooting",
        "description": "Aggregated troubleshooting information for a single device."
      },
      "DeviceUpdatePatchV3_2": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the device group."
          },
          "lora_class": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DeviceClass"
              },
              {
                "type": "null"
              }
            ],
            "description": "LoRaWAN device class that determines downlink behavior. `A`: sends all downlinks immediately, queuing them on the network server. `C`: sends downlinks one by one, waiting for a device response before proceeding. When omitted or null, automatically determined from the devices in the group."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway NodeIDs assigned to this group. Maximum 10. When empty, gateways are automatically selected."
          },
          "devices": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of 16-character hexadecimal DevEUIs to include in the group."
          }
        },
        "type": "object",
        "title": "DeviceUpdatePatchV3_2",
        "examples": [
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "name": "My Device Group"
          },
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "lora_class": "A",
            "name": "My Device Group"
          }
        ]
      },
      "DeviceVersionItem": {
        "properties": {
          "version_hex": {
            "type": "string",
            "title": "Version Hex",
            "description": "Raw firmware version as a hexadecimal string."
          },
          "reported_at": {
            "type": "string",
            "format": "date-time",
            "title": "Reported At",
            "description": "Timestamp when the device reported this firmware version, in RFC 3339 format."
          }
        },
        "type": "object",
        "required": [
          "version_hex",
          "reported_at"
        ],
        "title": "DeviceVersionItem",
        "description": "Firmware version report for a single device."
      },
      "DeviceVersionOut": {
        "properties": {
          "version_hex": {
            "type": "string",
            "title": "Version Hex",
            "description": "Raw firmware version as a hexadecimal string."
          },
          "reported_at": {
            "type": "string",
            "format": "date-time",
            "title": "Reported At",
            "description": "Timestamp when the device reported this firmware version, in RFC 3339 format."
          },
          "firmware_version": {
            "type": "string",
            "title": "Firmware Version",
            "description": "Parsed semantic version derived from `version_hex` (e.g., \"1.2.3\").",
            "readOnly": true
          }
        },
        "type": "object",
        "required": [
          "version_hex",
          "reported_at",
          "firmware_version"
        ],
        "title": "DeviceVersionOut",
        "description": "Firmware version report for a single device, including the parsed semantic version.",
        "examples": [
          {
            "firmware_version": "0.0.73.1",
            "reported_at": "2022-07-21T18:51:28.469107Z",
            "version_hex": "0149000000007E0B"
          }
        ]
      },
      "DevicesNoKeys": {
        "properties": {
          "devices": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of 16-character hexadecimal DevEUIs to add to the group."
          }
        },
        "type": "object",
        "required": [
          "devices"
        ],
        "title": "DevicesNoKeys",
        "description": "Request body for adding devices without keys.",
        "examples": [
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ]
          }
        ]
      },
      "DevicesWithKeygen": {
        "properties": {
          "keygen_type": {
            "$ref": "#/components/schemas/Keygen",
            "description": "Key generation algorithm to use. Currently only `machineq` is supported."
          },
          "devices": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of 16-character hexadecimal DevEUIs to add to the group."
          }
        },
        "type": "object",
        "required": [
          "keygen_type",
          "devices"
        ],
        "title": "DevicesWithKeygen",
        "description": "Request body for adding devices to a device group using automatic key generation.",
        "examples": [
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "keygen_type": "machineq"
          }
        ]
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "ImageInfo": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Filename of the firmware image."
          },
          "hash": {
            "type": "string",
            "title": "Hash",
            "description": "Hex-encoded hash of the firmware image contents."
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "description": "List of tags associated with the firmware image."
          }
        },
        "type": "object",
        "required": [
          "name",
          "hash",
          "tags"
        ],
        "title": "ImageInfo",
        "description": "Metadata for a single firmware image, including its hash and tags.",
        "examples": [
          {
            "hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            "name": "image_v1.bin",
            "tags": [
              "tag1",
              "tag2",
              "tag3"
            ]
          },
          {
            "hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
            "name": "image_v2.bin",
            "tags": []
          }
        ]
      },
      "ImageUploadWithTags": {
        "properties": {
          "image": {
            "type": "string",
            "format": "binary",
            "title": "Image",
            "description": "Binary firmware image file to upload. Allowed extensions: .bin, .hex, .sfb."
          },
          "tags": {
            "items": {
              "type": "string",
              "maxLength": 15,
              "minLength": 1,
              "pattern": "^[A-Za-z0-9_.\\/-]*$",
              "description": "Alphanumeric label used to categorize a firmware image."
            },
            "type": "array",
            "title": "Tags",
            "description": "One or more tags to associate with the uploaded image. Defaults to an empty list if omitted.",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "image"
        ],
        "title": "ImageUploadWithTags",
        "description": "Multipart form payload containing a firmware image file and optional tags."
      },
      "Keygen": {
        "type": "string",
        "enum": [
          "machineq"
        ],
        "title": "Keygen",
        "description": "Supported key generation algorithms for deriving device GenAppKeys during FUOTA."
      },
      "ManagedCampaignFailedDevice": {
        "properties": {
          "deveui": {
            "type": "string",
            "title": "Deveui",
            "description": "DevEUI of the problematic device, as a 16-character hexadecimal string."
          },
          "failed_campaigns": {
            "items": {
              "prefixItems": [
                {
                  "type": "string"
                },
                {
                  "type": "string"
                }
              ],
              "type": "array",
              "maxItems": 2,
              "minItems": 2
            },
            "type": "array",
            "title": "Failed Campaigns",
            "description": "List of [campaign_id, reason] pairs. The campaign ID may be empty if the failure occurred before a child campaign was created."
          }
        },
        "type": "object",
        "required": [
          "deveui",
          "failed_campaigns"
        ],
        "title": "ManagedCampaignFailedDevice",
        "description": "Device that has failed in two or more child campaigns within a managed campaign.",
        "examples": [
          {
            "deveui": "0102030405060700",
            "failed_campaigns": [
              [
                "zHOf3o",
                "Something failed"
              ],
              [
                "7kht3I",
                "Something else failed"
              ]
            ]
          }
        ]
      },
      "ManagedCampaignIn": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the managed campaign.",
            "default": ""
          },
          "include_versions": {
            "items": {
              "type": "string",
              "description": "String representation of one or multiple firmware versions, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Versions",
            "description": "List of 16-character hexadecimal version-mask patterns where '.' matches any hex digit. Devices whose firmware version matches any pattern are eligible for update."
          },
          "exclude_versions": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "description": "String representation of one or multiple firmware versions, where a dot '.' represents ANY hex value"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exclude Versions",
            "description": "List of 16-character hexadecimal version-mask patterns. Devices whose firmware version matches any pattern are excluded from the campaign. Takes priority over `include_versions`."
          },
          "image_name": {
            "type": "string",
            "title": "Image Name",
            "description": "Name of a firmware image previously uploaded via the /images endpoint."
          },
          "expected_version": {
            "type": "string",
            "title": "Expected Version",
            "description": "16-character hexadecimal version-mask pattern that devices are expected to report after a successful update. If omitted, the server attempts to infer it from semantic versioning in `image_name`."
          },
          "preferred_start_time_utc": {
            "type": "string",
            "format": "time",
            "title": "Preferred Start Time Utc",
            "description": "UTC time of day (HH:MM) when new child campaigns should be created. Only hours and minutes are used; seconds and below are ignored",
            "default": "12:00:00"
          },
          "stop_when_no_match": {
            "type": "boolean",
            "title": "Stop When No Match",
            "description": "When true, the managed campaign transitions to its finished state once no new matching devices are discovered. When false, the campaign continues running until `run_until`.",
            "default": false
          },
          "run_until": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Run Until",
            "description": "RFC 3339 datetime after which no new child campaigns are created. Defaults to seven days from creation when omitted."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway identifiers used to monitor for devices. Currently only a single gateway is supported.",
            "default": []
          },
          "whole_subscriber": {
            "type": "boolean",
            "title": "Whole Subscriber",
            "description": "Reserved for future use. Must be false; setting to true returns a 400 error.",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "include_versions",
          "image_name",
          "expected_version"
        ],
        "title": "ManagedCampaignIn",
        "description": "Configuration for creating a managed campaign that automatically updates devices as they are discovered.",
        "examples": [
          {
            "expected_version": "04030200........",
            "gateways": [
              "1122334455667788"
            ],
            "image_name": "fuota_v2.3.4.bin",
            "include_versions": [
              "03020100........"
            ],
            "name": "Some managed campaign",
            "preferred_start_time_utc": "11:00",
            "run_until": "2025-01-01T12:00:00.000000Z",
            "stop_when_no_match": true,
            "whole_subscriber": false
          }
        ]
      },
      "ManagedCampaignOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the managed campaign.",
            "default": ""
          },
          "include_versions": {
            "items": {
              "type": "string",
              "description": "String representation of one or multiple firmware versions, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Versions",
            "description": "List of 16-character hexadecimal version-mask patterns where '.' matches any hex digit. Devices whose firmware version matches any pattern are eligible for update."
          },
          "exclude_versions": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "description": "String representation of one or multiple firmware versions, where a dot '.' represents ANY hex value"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exclude Versions",
            "description": "List of 16-character hexadecimal version-mask patterns. Devices whose firmware version matches any pattern are excluded from the campaign. Takes priority over `include_versions`."
          },
          "image_name": {
            "type": "string",
            "title": "Image Name",
            "description": "Name of a firmware image previously uploaded via the /images endpoint."
          },
          "expected_version": {
            "type": "string",
            "title": "Expected Version",
            "description": "16-character hexadecimal version-mask pattern that devices are expected to report after a successful update. If omitted, the server attempts to infer it from semantic versioning in `image_name`."
          },
          "preferred_start_time_utc": {
            "type": "string",
            "format": "time",
            "title": "Preferred Start Time Utc",
            "description": "UTC time of day (HH:MM) when new child campaigns should be created. Only hours and minutes are used; seconds and below are ignored",
            "default": "12:00:00"
          },
          "stop_when_no_match": {
            "type": "boolean",
            "title": "Stop When No Match",
            "description": "When true, the managed campaign transitions to its finished state once no new matching devices are discovered. When false, the campaign continues running until `run_until`.",
            "default": false
          },
          "run_until": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Run Until",
            "description": "RFC 3339 datetime after which no new child campaigns are created. Defaults to seven days from creation when omitted."
          },
          "gateways": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gateways",
            "description": "List of gateway identifiers used to monitor for devices. Currently only a single gateway is supported.",
            "default": []
          },
          "whole_subscriber": {
            "type": "boolean",
            "title": "Whole Subscriber",
            "description": "Reserved for future use. Must be false; setting to true returns a 400 error.",
            "default": false
          },
          "managed_campaign_id": {
            "type": "string",
            "title": "Managed Campaign Id",
            "description": "Unique identifier assigned to the managed campaign at creation.",
            "default": ""
          },
          "next_update_session_time": {
            "type": "string",
            "format": "date-time",
            "title": "Next Update Session Time",
            "description": "RFC 3339 datetime of the next scheduled child-campaign creation.",
            "default": "9999-12-31T23:59:59.999999"
          },
          "scheduled_devices": {
            "additionalProperties": {
              "$ref": "#/components/schemas/DeviceVersionItem"
            },
            "type": "object",
            "title": "Scheduled Devices",
            "description": "Map of DevEUI to firmware-version information for devices scheduled in the next child campaign.",
            "default": {}
          },
          "stage": {
            "$ref": "#/components/schemas/ManagedCampaignStage",
            "description": "Numeric stage of the managed campaign lifecycle.",
            "default": 0
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "title": "Started At",
            "description": "RFC 3339 datetime when the managed campaign was created."
          },
          "updated_devices": {
            "additionalProperties": {
              "$ref": "#/components/schemas/DeviceVersionItem"
            },
            "type": "object",
            "title": "Updated Devices",
            "description": "Map of DevEUI to firmware-version information for devices that have been successfully updated.",
            "default": {}
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "Human-readable name of the current managed campaign stage.",
            "readOnly": true
          }
        },
        "type": "object",
        "required": [
          "include_versions",
          "image_name",
          "expected_version",
          "stage_str"
        ],
        "title": "ManagedCampaignOut",
        "description": "Full representation of a managed campaign returned by the API, including runtime state and device tracking.",
        "examples": [
          {
            "expected_version": "04030200........",
            "gateways": [
              "1122334455667788"
            ],
            "image_name": "fuota_v2.3.4.bin",
            "include_versions": [
              "03020100........"
            ],
            "managed_campaign_id": "mWa77N",
            "name": "Some managed campaign",
            "next_update_session_time": "2024-08-01T11:12:13.141516Z",
            "preferred_start_time_utc": "11:00",
            "run_until": "2025-01-01T12:00:00.000000Z",
            "scheduled_devices": {
              "1111222233334444": {
                "reported_at": "2024-07-01T01:01:01.010101Z",
                "version_hex": "03020100abcdef00"
              }
            },
            "stage": 1,
            "stage_str": "GATHERING_DEVICES",
            "started_at": "2024-06-06T06:06:06.654321Z",
            "stop_when_no_match": true,
            "updated_devices": {
              "1212232334344545": {
                "reported_at": "2024-06-20T00:00:00.000000Z",
                "version_hex": "04030200abcdef00"
              }
            },
            "whole_subscriber": false
          }
        ]
      },
      "ManagedCampaignStage": {
        "type": "integer",
        "enum": [
          0,
          1,
          3,
          7,
          8,
          9
        ],
        "title": "ManagedCampaignStage",
        "description": "Managed campaign stages:\n\n* INITIALIZING (0): managed campaign was created but the state was not initialized yet\n* GATHERING_DEVICES (1): the server is gathering a list of devices while waiting for the next start time, and a campaign may or may not be running with previously-discovered devices\n* RUNNING_LAST_CAMPAIGN (3): no more devices will be gathered, waiting for the last campaign to be launched to finish\n* FINISHED (7): The last campaign has finished running\n* CLEANED (8): Finished and all campaigns (7+ days old at this point) have been deleted, this is the final state for a managed campaign\n* ERROR_SETTING_UP (9): managed campaign failed to set up\n\nThe managed campaign is complete when the stage is CLEANED or ERROR_SETTING_UP."
      },
      "ManagedCampaigns": {
        "items": {
          "$ref": "#/components/schemas/ManagedCampaignOut"
        },
        "type": "array",
        "title": "ManagedCampaigns",
        "description": "List of all managed campaigns belonging to the subscriber.",
        "examples": [
          {
            "expected_version": "04030200........",
            "gateways": [
              "1122334455667788"
            ],
            "image_name": "fuota_v2.3.4.bin",
            "include_versions": [
              "03020100........"
            ],
            "managed_campaign_id": "40TIGg",
            "name": "First managed campaign",
            "next_update_session_time": "2024-08-01T11:12:13.141516Z",
            "preferred_start_time_utc": "11:00",
            "run_until": "2025-01-01T12:00:00.000000Z",
            "scheduled_devices": {
              "1111222233334444": {
                "reported_at": "2024-07-01T01:01:01.010101Z",
                "version_hex": "03020100abcdef00"
              }
            },
            "stage": 1,
            "stage_str": "GATHERING_DEVICES",
            "started_at": "2024-06-06T06:06:06.654321Z",
            "stop_when_no_match": true,
            "updated_devices": {
              "1212232334344545": {
                "reported_at": "2024-06-20T00:00:00.000000Z",
                "version_hex": "04030200abcdef00"
              }
            },
            "whole_subscriber": false
          },
          {
            "expected_version": "03020100........",
            "gateways": [
              "1122334455667788"
            ],
            "image_name": "fuota_v1.2.3.bin",
            "include_versions": [
              "04030200........"
            ],
            "managed_campaign_id": "RxB15o",
            "name": "Anti-first managed campaign",
            "next_update_session_time": "2024-08-01T11:12:13.141516Z",
            "preferred_start_time_utc": "12:00",
            "run_until": "2025-01-01T12:00:00.000000Z",
            "scheduled_devices": {
              "1111222233334444": {
                "reported_at": "2024-07-02T01:01:01.010101Z",
                "version_hex": "04030200abcdef00"
              }
            },
            "stage": 1,
            "stage_str": "GATHERING_DEVICES",
            "started_at": "2024-06-06T06:06:06.654321Z",
            "stop_when_no_match": true,
            "updated_devices": {
              "1212232334344545": {
                "reported_at": "2024-06-21T00:00:00.000000Z",
                "version_hex": "03020100abcdef00"
              }
            },
            "whole_subscriber": false
          }
        ]
      },
      "MultipleDeviceVersionOut": {
        "additionalProperties": {
          "anyOf": [
            {
              "$ref": "#/components/schemas/DeviceVersionOut"
            },
            {
              "type": "null"
            }
          ]
        },
        "type": "object",
        "title": "MultipleDeviceVersionOut",
        "description": "Map of DevEUIs to their firmware version reports. Null value indicates the device has never reported a version.",
        "examples": [
          {
            "0102030405060708": {
              "firmware_version": "0.0.73.1",
              "reported_at": "2022-07-21T18:51:28.469107Z",
              "version_hex": "0149000000007E0B"
            },
            "0102030405060709": {
              "firmware_version": "0.0.73.3",
              "reported_at": "2022-07-21T18:51:28.469107Z",
              "version_hex": "0349000000007E0B"
            }
          }
        ]
      },
      "ReliableDownlinkIn": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the reliable downlink job."
          },
          "downlink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Downlink Hex",
            "description": "Hexadecimal-encoded payload to send to the devices."
          },
          "downlink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Downlink Fport",
            "description": "LoRaWAN FPort number for the downlink message."
          },
          "expected_uplink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Expected Uplink Hex",
            "description": "Hexadecimal-encoded payload expected as the device response to the downlink."
          },
          "expected_uplink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Expected Uplink Fport",
            "description": "LoRaWAN FPort number on which the expected uplink response arrives"
          },
          "devices": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Devices",
            "description": "Optional list of unique DevEUIs to target. At least one of `devices` or `device_group_id` must be provided."
          },
          "device_group_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Device Group Id",
            "description": "Optional identifier of a device group whose members are targeted. At least one of `devices` or `device_group_id` must be provided."
          },
          "max_retries": {
            "type": "integer",
            "title": "Max Retries",
            "description": "Maximum number of retry attempts per device before marking it as failed.",
            "default": 24
          },
          "retry_interval": {
            "type": "integer",
            "title": "Retry Interval",
            "description": "Delay in seconds between downlink retry attempts per device.",
            "default": 900
          }
        },
        "type": "object",
        "required": [
          "name",
          "downlink_hex",
          "downlink_fport",
          "expected_uplink_hex",
          "expected_uplink_fport"
        ],
        "title": "ReliableDownlinkIn",
        "description": "Input parameters for creating a reliable downlink job.",
        "examples": [
          {
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "downlink_fport": 73,
            "downlink_hex": "01020304",
            "expected_uplink_fport": 73,
            "expected_uplink_hex": "0101",
            "name": "Update devices config"
          }
        ]
      },
      "ReliableDownlinkListFull": {
        "items": {
          "$ref": "#/components/schemas/ReliableDownlinkStatus"
        },
        "type": "array",
        "title": "ReliableDownlinkListFull",
        "description": "List of all reliable downlink jobs with their device completion statuses.",
        "examples": [
          [
            {
              "created_at": "2023-10-17T20:29:12.925738Z",
              "devices": [
                "0102030405060708",
                "0102030405060709"
              ],
              "downlink_fport": 73,
              "downlink_hex": "01020304",
              "expected_uplink_fport": 73,
              "expected_uplink_hex": "0101",
              "job_id": "bk64vg",
              "max_retries": 10,
              "name": "Update devices config",
              "retry_interval": 30
            }
          ]
        ]
      },
      "ReliableDownlinkOut": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the reliable downlink job."
          },
          "downlink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Downlink Hex",
            "description": "Hexadecimal-encoded payload to send to the devices."
          },
          "downlink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Downlink Fport",
            "description": "LoRaWAN FPort number for the downlink message."
          },
          "expected_uplink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Expected Uplink Hex",
            "description": "Hexadecimal-encoded payload expected as the device response to the downlink."
          },
          "expected_uplink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Expected Uplink Fport",
            "description": "LoRaWAN FPort number on which the expected uplink response arrives"
          },
          "devices": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Devices",
            "description": "Optional list of unique DevEUIs to target. At least one of `devices` or `device_group_id` must be provided."
          },
          "device_group_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Device Group Id",
            "description": "Optional identifier of a device group whose members are targeted. At least one of `devices` or `device_group_id` must be provided."
          },
          "max_retries": {
            "type": "integer",
            "title": "Max Retries",
            "description": "Maximum number of retry attempts per device before marking it as failed.",
            "default": 24
          },
          "retry_interval": {
            "type": "integer",
            "title": "Retry Interval",
            "description": "Delay in seconds between downlink retry attempts per device.",
            "default": 900
          },
          "job_id": {
            "type": "string",
            "title": "Job Id",
            "description": "Server-assigned unique identifier for the reliable downlink job.",
            "default": ""
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "Timestamp when the job was created, in RFC 3339 format."
          }
        },
        "type": "object",
        "required": [
          "name",
          "downlink_hex",
          "downlink_fport",
          "expected_uplink_hex",
          "expected_uplink_fport"
        ],
        "title": "ReliableDownlinkOut",
        "description": "Reliable downlink job as returned after creation, including server-assigned identifiers.",
        "examples": [
          {
            "created_at": "2023-10-17T20:29:12.925738Z",
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "downlink_fport": 73,
            "downlink_hex": "01020304",
            "expected_uplink_fport": 73,
            "expected_uplink_hex": "0101",
            "job_id": "bk64vg",
            "max_retries": 10,
            "name": "Update devices config",
            "retry_interval": 30
          }
        ]
      },
      "ReliableDownlinkStatus": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Human-readable label for the reliable downlink job."
          },
          "downlink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Downlink Hex",
            "description": "Hexadecimal-encoded payload to send to the devices."
          },
          "downlink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Downlink Fport",
            "description": "LoRaWAN FPort number for the downlink message."
          },
          "expected_uplink_hex": {
            "type": "string",
            "maxLength": 484,
            "title": "Expected Uplink Hex",
            "description": "Hexadecimal-encoded payload expected as the device response to the downlink."
          },
          "expected_uplink_fport": {
            "type": "integer",
            "exclusiveMaximum": 224.0,
            "exclusiveMinimum": 0.0,
            "title": "Expected Uplink Fport",
            "description": "LoRaWAN FPort number on which the expected uplink response arrives"
          },
          "devices": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Devices",
            "description": "Optional list of unique DevEUIs to target. At least one of `devices` or `device_group_id` must be provided."
          },
          "device_group_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Device Group Id",
            "description": "Optional identifier of a device group whose members are targeted. At least one of `devices` or `device_group_id` must be provided."
          },
          "max_retries": {
            "type": "integer",
            "title": "Max Retries",
            "description": "Maximum number of retry attempts per device before marking it as failed.",
            "default": 24
          },
          "retry_interval": {
            "type": "integer",
            "title": "Retry Interval",
            "description": "Delay in seconds between downlink retry attempts per device.",
            "default": 900
          },
          "job_id": {
            "type": "string",
            "title": "Job Id",
            "description": "Server-assigned unique identifier for the reliable downlink job.",
            "default": ""
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "Timestamp when the job was created, in RFC 3339 format."
          },
          "successful_devices": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Successful Devices",
            "description": "List of DevEUIs that responded with the expected uplink. Null when no devices have succeeded yet."
          },
          "failed_devices": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Failed Devices",
            "description": "List of DevEUIs that exhausted all retry attempts without the expected response. Null when no devices have failed yet."
          },
          "device_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Device Count",
            "description": "Total number of devices targeted by the job. Null if the count is unavailable."
          },
          "successful_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Successful Count",
            "description": "Number of devices that responded successfully. Null if the count is unavailable."
          },
          "failed_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Failed Count",
            "description": "Number of devices that failed after all retry attempts. Null if the count is unavailable."
          }
        },
        "type": "object",
        "required": [
          "name",
          "downlink_hex",
          "downlink_fport",
          "expected_uplink_hex",
          "expected_uplink_fport"
        ],
        "title": "ReliableDownlinkStatus",
        "description": "Reliable downlink job with aggregated device completion status.",
        "examples": [
          {
            "created_at": "2023-10-17T20:29:12.925738Z",
            "device_count": 2,
            "devices": [
              "0102030405060708",
              "0102030405060709"
            ],
            "downlink_fport": 73,
            "downlink_hex": "01020304",
            "expected_uplink_fport": 73,
            "expected_uplink_hex": "0101",
            "failed_count": 1,
            "failed_devices": [
              "0102030405060709"
            ],
            "job_id": "ila81a",
            "max_retries": 10,
            "name": "Update devices config",
            "retry_interval": 30,
            "successful_count": 1,
            "successful_devices": [
              "0102030405060708"
            ]
          }
        ]
      },
      "RestartCampaignInV3": {
        "properties": {
          "gateways": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gateways",
            "description": "Optional list of gateway IDs to use for the restarted campaign. If omitted or empty, gateways are selected automatically."
          },
          "multicast_setup_time": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Multicast Setup Time",
            "description": "Optional multicast setup time in seconds. If not set, original value preserved. Set to 0 or null to use the automatic value."
          },
          "scheduled_start_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scheduled Start At",
            "description": "Optional RFC 3339 timestamp to schedule the campaign restart. Must be in the future."
          },
          "automatic_retry_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Automatic Retry Count",
            "description": "Optional number of automatic retry attempts for failed devices. If omitted, the previous value is preserved."
          },
          "redundancy": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Redundancy",
            "description": "Optional fragment redundancy ratio between 0 and 1. If omitted, the previous value is preserved."
          }
        },
        "type": "object",
        "title": "RestartCampaignInV3",
        "examples": [
          {
            "automatic_retry_count": 3,
            "gateways": [
              "A3C758BC411751C2",
              "25DC71D3B04CDC55"
            ],
            "multicast_setup_time": 300,
            "redundancy": 0.2,
            "scheduled_start_at": "2026-05-21T14:00:00Z"
          }
        ]
      },
      "ShortCampaignStatus": {
        "properties": {
          "devices": {
            "items": {
              "$ref": "#/components/schemas/ShortDeviceStatus"
            },
            "type": "array",
            "title": "Devices",
            "description": "List of abbreviated per-device statuses."
          },
          "current_fragment_cnt": {
            "type": "integer",
            "title": "Current Fragment Cnt",
            "description": "Number of fragments sent so far in the current attempt."
          }
        },
        "type": "object",
        "required": [
          "devices",
          "current_fragment_cnt"
        ],
        "title": "ShortCampaignStatus",
        "description": "Abbreviated campaign status containing only per-device stages and fragment progress.",
        "examples": [
          {
            "current_fragment_cnt": 551,
            "devices": [
              {
                "attempts": 1,
                "deveui": "0102030405060708",
                "reason": "",
                "stage": 4,
                "stage_str": "FRAGMENTS"
              },
              {
                "attempts": 1,
                "deveui": "0102030405060708",
                "reason": "Final version check fail",
                "stage": 4,
                "stage_str": "FRAGMENTS"
              }
            ]
          }
        ]
      },
      "ShortDeviceStatus": {
        "properties": {
          "deveui": {
            "type": "string",
            "title": "Deveui",
            "description": "Extended Unique Identifier of the device (16-character hex)."
          },
          "stage": {
            "$ref": "#/components/schemas/DeviceStage",
            "description": "Numeric stage of the device in the update process."
          },
          "stage_str": {
            "type": "string",
            "title": "Stage Str",
            "description": "Human-readable name of the device stage."
          },
          "attempts": {
            "type": "integer",
            "title": "Attempts",
            "description": "Number of update attempts made for this device."
          },
          "reason": {
            "type": "string",
            "title": "Reason",
            "description": "Human-readable failure reason. Empty when the device has not failed.",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "deveui",
          "stage",
          "stage_str",
          "attempts"
        ],
        "title": "ShortDeviceStatus",
        "description": "Abbreviated status of a single device within a campaign."
      },
      "SubscriberHistory": {
        "additionalProperties": {
          "items": {
            "$ref": "#/components/schemas/DeviceHistoryStatus"
          },
          "type": "array"
        },
        "type": "object",
        "title": "SubscriberHistory",
        "description": "Firmware update history for all devices belonging to a subscriber, keyed by DevEUI.",
        "examples": [
          {
            "0102030405060708": [
              {
                "campaign_id": "0b8kLa",
                "entry_date": "2022-02-18 22:34:46",
                "expected_version": "0.0.83.0",
                "initial_version": "0.0.84.0",
                "post_update_version": "0.0.83.0",
                "reason": "",
                "status": "SUCCESS"
              },
              {
                "campaign_id": "0b8kLa",
                "entry_date": "2022-02-19 11:51:46",
                "expected_version": "0.0.83.0",
                "initial_version": "0.0.84.0",
                "post_update_version": "0.0.84.0",
                "reason": "",
                "status": "FAIL"
              }
            ],
            "0102030405060709": [
              {
                "campaign_id": "lq159A",
                "entry_date": "2022-02-18 22:29:13",
                "expected_version": "0.0.83.0",
                "initial_version": "0.0.84.0",
                "post_update_version": "0.0.83.0",
                "reason": "",
                "status": "SUCCESS"
              }
            ]
          }
        ]
      },
      "UpgradeDelegationIn": {
        "properties": {
          "delegate_to": {
            "type": "string",
            "title": "Delegate To",
            "description": "Subscriber ID of the party receiving upgrade management permissions."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "title": "Expires At",
            "description": "RFC 3339 timestamp indicating when the delegation expires. Requests after this time are rejected."
          },
          "include_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Devices",
            "description": "List of DevEUI patterns identifying devices included in the delegation."
          },
          "exclude_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Devices",
            "description": "List of DevEUI patterns identifying devices excluded from the delegation.",
            "default": []
          },
          "include_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Gateways",
            "description": "List of DevEUI patterns identifying gateways included in the delegation. Currently ignored; reserved for future use.",
            "default": []
          },
          "exclude_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Gateways",
            "description": "List of DevEUI patterns identifying gateways excluded from the delegation. Currently ignored; reserved for future use.",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "delegate_to",
          "expires_at",
          "include_devices"
        ],
        "title": "UpgradeDelegationIn",
        "description": "Request body for creating an upgrade delegation record.",
        "examples": [
          {
            "delegate_to": "mq61lp",
            "exclude_devices": [
              "2CC407..00000FF1"
            ],
            "expires_at": "2100-12-31T23:59:59Z",
            "include_devices": [
              "2CC407..00000FF."
            ]
          }
        ]
      },
      "UpgradeDelegationOut": {
        "properties": {
          "delegate_to": {
            "type": "string",
            "title": "Delegate To",
            "description": "Subscriber ID of the party receiving upgrade management permissions."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "title": "Expires At",
            "description": "RFC 3339 timestamp indicating when the delegation expires. Requests after this time are rejected."
          },
          "include_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Devices",
            "description": "List of DevEUI patterns identifying devices included in the delegation."
          },
          "exclude_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Devices",
            "description": "List of DevEUI patterns identifying devices excluded from the delegation.",
            "default": []
          },
          "include_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Gateways",
            "description": "List of DevEUI patterns identifying gateways included in the delegation. Currently ignored; reserved for future use.",
            "default": []
          },
          "exclude_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Gateways",
            "description": "List of DevEUI patterns identifying gateways excluded from the delegation. Currently ignored; reserved for future use.",
            "default": []
          },
          "delegation_id": {
            "type": "string",
            "title": "Delegation Id",
            "description": "Server-assigned unique identifier for the delegation record."
          },
          "delegate_from": {
            "type": "string",
            "title": "Delegate From",
            "description": "Subscriber ID of the party that created the delegation."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At",
            "description": "RFC 3339 timestamp indicating when the delegation record was created."
          }
        },
        "type": "object",
        "required": [
          "delegate_to",
          "expires_at",
          "include_devices",
          "delegation_id",
          "delegate_from"
        ],
        "title": "UpgradeDelegationOut",
        "description": "Upgrade delegation record with server-assigned metadata.",
        "examples": [
          {
            "created_at": "2023-10-17T20:29:12.925738Z",
            "delegate_from": "ujei86",
            "delegate_to": "mq61lp",
            "delegation_id": "qz112p",
            "exclude_devices": [
              "2CC407..00000FF1"
            ],
            "expires_at": "2100-12-31T23:59:59Z",
            "include_devices": [
              "2CC407..00000FF."
            ]
          }
        ]
      },
      "UpgradeDelegationPatch": {
        "properties": {
          "include_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Devices",
            "description": "Replacement list of DevEUI patterns identifying devices included in the delegation.",
            "default": []
          },
          "exclude_devices": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Devices",
            "description": "Replacement list of DevEUI patterns identifying devices excluded from the delegation.",
            "default": []
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expires At",
            "description": "RFC 3339 timestamp indicating the new expiration time. Null leaves the current value unchanged."
          },
          "include_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Include Gateways",
            "description": "Replacement list of DevEUI patterns identifying gateways included in the delegation. Currently ignored; reserved for future use.",
            "default": []
          },
          "exclude_gateways": {
            "items": {
              "type": "string",
              "description": "16-byte string representing one or multiple DevEUIs, where a dot '.' represents ANY hex value"
            },
            "type": "array",
            "title": "Exclude Gateways",
            "description": "Replacement list of DevEUI patterns identifying gateways excluded from the delegation. Currently ignored; reserved for future use.",
            "default": []
          }
        },
        "type": "object",
        "title": "UpgradeDelegationPatch",
        "description": "Partial update payload for an upgrade delegation record. Only supplied fields are modified.",
        "examples": [
          {
            "exclude_devices": [
              "2CC407..00000FF1"
            ],
            "expires_at": "2100-12-31T23:59:59Z",
            "include_devices": [
              "2CC407..00000FF."
            ]
          }
        ]
      },
      "UploadMulticastKeys": {
        "additionalProperties": {
          "type": "string"
        },
        "type": "object",
        "title": "UploadMulticastKeys",
        "description": "Mapping of DevEUIs to multicast key values used for firmware update encryption.",
        "examples": [
          {
            "0011223344556677": "aabbccddeeffaabbccddeeffaabbccdd",
            "0102030405060708": "01020304050607080102030405060708"
          }
        ]
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "OAuth2AuthorizationCodeBearer": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "scopes": {
              "openid": ""
            },
            "authorizationUrl": "https://identity.dev.machineq.net/oauth/authorize",
            "tokenUrl": "https://identity.dev.machineq.net/oauth/token"
          }
        }
      },
      "HTTPBearer": {
        "type": "http",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "Campaigns",
      "description": "Manages firmware update campaigns, including creation, monitoring, and deletion."
    },
    {
      "name": "CampaignTools",
      "description": "Provides campaign lifecycle operations such as restart, halt, and short status retrieval."
    },
    {
      "name": "DeviceGroups",
      "description": "Manages device groups used as targets for firmware update campaigns."
    },
    {
      "name": "FirmwareImages",
      "description": "Handles firmware image uploads, listings, and metadata."
    },
    {
      "name": "DeviceVersion",
      "description": "Retrieves the latest reported firmware version for one or more devices."
    },
    {
      "name": "UpdateHistory",
      "description": "Retrieves device firmware update history records."
    },
    {
      "name": "ManagedCampaigns",
      "description": "Manages long-running managed campaigns that automatically discover and update devices."
    },
    {
      "name": "ReliableDownlink",
      "description": "Sends reliable downlinks to devices with confirmation and retry logic."
    },
    {
      "name": "UpgradeDelegation",
      "description": "Manages upgrade delegations that allow one subscriber to update another subscriber's devices."
    },
    {
      "name": "KeyManagement",
      "description": "Manages device encryption keys used during firmware updates."
    },
    {
      "name": "Admin",
      "description": "Administrative endpoints for internal server management."
    }
  ],
  "x-resourceObjects": {
    "Campaigns": "CampaignSummary",
    "DeviceGroups": "DeviceGroupOut",
    "DeviceVersion": "DeviceVersionOut",
    "UpdateHistory": "DeviceHistoryStatus",
    "FirmwareImages": "ImageInfo",
    "ManagedCampaigns": "ManagedCampaignOut",
    "ReliableDownlink": "ReliableDownlinkStatus",
    "UpgradeDelegation": "UpgradeDelegationOut"
  }
}