Skip to the content.

Instructions on how to manage nRFCloud FOTA via REST calls

This document describes how to manage FOTA (Firmware Over The Air) updates using nRF Cloud’s REST API. All examples use curl commands and assume you have set your API key in an environment variable:

export API_KEY="your-nrf-cloud-api-key"

You can find your API_KEY in “User Account” settings in your nRFCloud profile.

For reference, see nRF Cloud REST API

Upload Application Firmware

To upload an application firmware to nRF Cloud, you’ll need your compiled application binary file (typically found in the build/app/zephyr directory after building the project).

# Set path to your application binary
export BIN_FILE="build/app/zephyr/zephyr.signed.bin"  # Or path to your compiled binary

# Create manifest.json with firmware details
cat > manifest.json << EOF
{
    "name": "My Firmware",
    "description": "Firmware description",
    "fwversion": "1.0.0",
    "format-version": 1,
    "files": [
        {
            "file": "$(basename ${BIN_FILE})",
            "type": "application",
            "size": $(stat -f%z ${BIN_FILE})
        }
    ]
}
EOF

# Create zip containing firmware and manifest
zip -j firmware.zip ${BIN_FILE} manifest.json

# Upload to nRF Cloud
curl -X POST "https://api.nrfcloud.com/v1/firmwares" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/zip" \
  --data-binary @firmware.zip

# The response will include URIs like:
# https://firmware.nrfcloud.com/[bundle-id]/APP...
# Extract the bundle ID from the URI path for use in creating FOTA jobs

The bundle ID will be needed when creating FOTA jobs. For application firmware, it can be extracted from the URI path after “firmware.nrfcloud.com/”.

List FOTA Jobs

curl -X GET "https://api.nrfcloud.com/v1/fota-jobs" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

Create FOTA Job

curl -X POST "https://api.nrfcloud.com/v1/fota-jobs" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "deviceIds": ["device-id"],
    "bundleId": "bundle-id"
  }'

The response will include a jobId that can be used to track the job status.

Apply FOTA Job

curl -X POST "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}/apply" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

Check FOTA Status

curl -X GET "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

The status will be one of: “QUEUED”, “IN_PROGRESS”, “FAILED”, “SUCCEEDED”, “TIMED_OUT”, “CANCELLED”, “REJECTED”, “DOWNLOADING”

Update Job Execution State

curl -X PATCH "https://api.nrfcloud.com/v1/fota-job-executions/${DEVICE_ID}/${JOB_ID}" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "CANCELLED"
  }'

Valid status values are: “QUEUED”, “IN_PROGRESS”, “FAILED”, “SUCCEEDED”, “TIMED_OUT”, “CANCELLED”, “REJECTED”, “DOWNLOADING”

Cancel FOTA Job

curl -X PUT "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}/cancel" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

Delete FOTA Job

curl -X DELETE "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}" \
  -H "Authorization: Bearer ${API_KEY}"

Delete Firmware Bundle

curl -X DELETE "https://api.nrfcloud.com/v1/firmwares/${BUNDLE_ID}" \
  -H "Authorization: Bearer ${API_KEY}"

Example Workflow

Here’s a complete example workflow for performing a FOTA update:

# 1. Set up environment variables
export API_KEY="your-nrf-cloud-api-key"
export BIN_FILE="build/zephyr/app_signed.bin"  # Your compiled application binary
export DEVICE_ID="your-device-id"

# 2. Create manifest and upload firmware
cat > manifest.json << EOF
{
    "name": "Application Update",
    "description": "New firmware version",
    "fwversion": "1.0.0",
    "format-version": 1,
    "files": [
        {
            "file": "$(basename ${BIN_FILE})",
            "type": "application",
            "size": $(stat -f%z ${BIN_FILE})
        }
    ]
}
EOF

zip -j firmware.zip ${BIN_FILE} manifest.json

curl -X POST "https://api.nrfcloud.com/v1/firmwares" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/zip" \
  --data-binary @firmware.zip

export BUNDLE_ID=<your_bundle_id>

# 3. Create and apply FOTA job
curl -X POST "https://api.nrfcloud.com/v1/fota-jobs" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{\"deviceIds\": [\"${DEVICE_ID}\"], \"bundleId\": \"${BUNDLE_ID}\"}" \
  | jq -r '.jobId'

export JOB_ID=<your_job_id>

curl -X POST "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}/apply" \
  -H "Authorization: Bearer ${API_KEY}"

# 4. Monitor job status
curl -X GET "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

# 5. Clean up (optional)
# Delete job after completion
curl -X DELETE "https://api.nrfcloud.com/v1/fota-jobs/${JOB_ID}" \
  -H "Authorization: Bearer ${API_KEY}"

# Delete firmware bundle if no longer needed
curl -X DELETE "https://api.nrfcloud.com/v1/firmwares/${BUNDLE_ID}" \
  -H "Authorization: Bearer ${API_KEY}"