> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nerves-hub.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload a Firmware for a Product

> Accepts an fwup archive (`.fw`) or an ESP-IDF application image (`.bin`).
The format is determined from the file itself, not its name or extension.

A product accepts only the formats listed in its `allowed_update_tools`,
which is `["fwup"]` by default. ESP-IDF additionally requires the platform
to have `ESP_IDF_FIRMWARE_ENABLED` set.

**Firmware must be signed** against a key registered to the organization: an
Ed25519 key for fwup and AtomVM, or an RSA-3072 Secure Boot v2 key for
ESP-IDF.

Two per-product settings excuse a *missing* signature, and nothing else.
`allow_unsigned_esp_idf_firmware` accepts an ESP-IDF image with no signature
block, and `allow_unsigned_atomvm_firmware` accepts a packbeam with no
signature entry. Firmware that does carry a signature is always verified,
and fwup archives are always verified.

The firmware's own metadata declares which product it belongs to, and that
must match the product in the path.




## OpenAPI

````yaml https://manage.nervescloud.com/api/openapi post /api/orgs/{org_name}/products/{product_name}/firmwares
openapi: 3.0.0
info:
  description: >
    The NervesCloud API gives users full access to their

    Orgs, Products, and corresponding Device fleets.


    The API can be used to integrate with your own systems, providing full
    access to your Product and Device data.


    The API is documented using the OpenAPI 3.0 specification.
  title: NervesCloud API
  version: 2.0.0
servers:
  - url: https://manage.nervescloud.com
    variables: {}
security:
  - bearer_auth: []
tags:
  - description: User authentication and API token creation
    name: Auth
  - description: Organization Certificate Authority management
    name: CA Certificates
  - description: >-
      Device management, including action requests eg. upgrade, reboot,
      reconnect
    name: Devices
  - description: Log lines Devices have sent over the logging extension
    name: Device Logs
  - description: >-
      Device management, including action requests eg. upgrade, reboot,
      reconnect
    name: Devices (short URL)
  - description: Device Certificate management
    name: Device Certificates
  - description: Identities a Device holds on networks NervesHub does not run
    name: Network Identities
  - description: Deployment Group and release management
    name: Deployment Groups
  - description: Firmware uploading and management
    name: Firmwares
  - description: Organization iroh endpoint id registration
    name: Iroh Endpoints
  - description: Organization management
    name: Organizations
  - description: Organization User membership management
    name: Organization Members
  - description: Product management
    name: Products
  - description: Organization Signing Key management
    name: Signing Keys
  - description: Product Support Script management
    name: Support Scripts
  - description: Platform healthcheck
    name: Platform Status
paths:
  /api/orgs/{org_name}/products/{product_name}/firmwares:
    post:
      tags:
        - Firmwares
      summary: Upload a Firmware for a Product
      description: >
        Accepts an fwup archive (`.fw`) or an ESP-IDF application image
        (`.bin`).

        The format is determined from the file itself, not its name or
        extension.


        A product accepts only the formats listed in its `allowed_update_tools`,

        which is `["fwup"]` by default. ESP-IDF additionally requires the
        platform

        to have `ESP_IDF_FIRMWARE_ENABLED` set.


        **Firmware must be signed** against a key registered to the
        organization: an

        Ed25519 key for fwup and AtomVM, or an RSA-3072 Secure Boot v2 key for

        ESP-IDF.


        Two per-product settings excuse a *missing* signature, and nothing else.

        `allow_unsigned_esp_idf_firmware` accepts an ESP-IDF image with no
        signature

        block, and `allow_unsigned_atomvm_firmware` accepts a packbeam with no

        signature entry. Firmware that does carry a signature is always
        verified,

        and fwup archives are always verified.


        The firmware's own metadata declares which product it belongs to, and
        that

        must match the product in the path.
      operationId: NervesHubWeb.API.FirmwareController.create
      parameters:
        - description: Organization Name
          example: example_org
          in: path
          name: org_name
          required: true
          schema:
            type: string
        - description: Product Name
          example: example_product
          in: path
          name: product_name
          required: true
          schema:
            type: string
      requestBody:
        content:
          multipart/form-data: {}
        description: Firmware file upload
        required: false
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FirmwareResponse'
          description: Firmware response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Forbidden
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FirmwareUploadErrorResponse'
          description: Upload rejected
      callbacks: {}
      security:
        - bearer_auth: []
components:
  schemas:
    FirmwareResponse:
      description: Response schema for a single Firmware
      example:
        data:
          architecture: arm
          author: NervesHub
          platform: rpi0
          product: MyProduct
          tool: fwup
          uuid: d9f8c63a-1234-5678-abcd-ef0123456789
          version: 1.0.0
      properties:
        data:
          $ref: '#/components/schemas/Firmware'
      title: FirmwareResponse
      type: object
    ErrorResponse:
      description: Error response
      example:
        errors:
          detail: Resource Not Found or Authorization Insufficient
      properties:
        errors:
          properties:
            detail:
              type: string
          type: object
      title: ErrorResponse
      type: object
    FirmwareUploadErrorResponse:
      description: >
        Upload failure.


        Changeset failures (a duplicate UUID, say) are keyed by field. Failures

        raised before the changeset — an unrecognised format, a format this

        product does not accept, an unsigned image, a version that is not SemVer
        —

        carry a single `detail` message instead.
      example:
        errors:
          detail: >-
            This ESP-IDF image is not signed. Sign it with `espsecure.py
            sign_data --version 2` and register the matching public key against
            your organization, or allow unsigned images in this product's
            settings.
      oneOf:
        - $ref: '#/components/schemas/ChangesetErrorResponse'
        - $ref: '#/components/schemas/ErrorResponse'
      title: FirmwareUploadErrorResponse
      type: object
    Firmware:
      example:
        architecture: arm
        author: NervesHub
        platform: rpi0
        product: MyProduct
        tool: fwup
        uuid: d9f8c63a-1234-5678-abcd-ef0123456789
        version: 1.0.0
      properties:
        architecture:
          type: string
        author:
          type: string
        platform:
          type: string
        product:
          description: Product name
          type: string
        tool:
          description: >-
            The update tool that handles this firmware, determined from the
            uploaded file
          enum:
            - fwup
            - esp-idf
          type: string
        uuid:
          format: uuid
          type: string
        version:
          type: string
      title: Firmware
      type: object
    ChangesetErrorResponse:
      description: Validation error response
      example:
        errors:
          identifier:
            - can't be blank
      properties:
        errors:
          additionalProperties:
            items:
              type: string
            type: array
          type: object
      title: ChangesetErrorResponse
      type: object
  securitySchemes:
    bearer_auth:
      scheme: bearer
      type: http

````