openJII MQTT API (AWS IoT Core)

v1.0.0MQTT
API Information: This AsyncAPI specification defines the MQTT topics and message schemas for AWS IoT Core. It details channels for device status updates and sensor data, allowing devices to publish their state and sensor readings securely.

Servers

production

URLa123456789.iot.us-east-1.amazonaws.com
ProtocolMQTT
DescriptionAWS IoT Core production endpoint

Security

sigv4

Type: apiKey

Location: user

AWS Signature Version 4 is used to sign the MQTT connection requests to AWS IoT Core.

Operations

SUBSCRIBEexperiment/data_ingest/v1/{experimentId}/{sensorType}/{sensorVersion}/{sensorId}
Channel for ingesting experiment sensor data. This shape carries no protocol attribution in the topic; publishers carry it in the payload instead (`protocol_id`, see the message schema), alongside the workbook attribution fields. The path parameters represent:
  • experimentId: Unique identifier of the experiment (e.g., exp123).
  • sensorType: The type or family of sensor (e.g., MutlispeQ, Ambit...).
  • sensorVersion: Sensor firmware/hardware revision (without the 'v' prefix, e.g., 1, 2.1).
  • sensorId: Unique sensor identifier (UUID format recommended).

Parameters

NameTypeDescription
experimentIdstringUnique identifier of the experiment (e.g., exp123).
sensorTypestringThe type or family of sensor (e.g., MutlispeQ, Ambit...).
sensorVersionstringSensor firmware/hardware revision (without the 'v' prefix, e.g., 1, 2.1).
sensorIdstringUnique sensor identifier (UUID format recommended).

Subscribe Operation

Operation ID: ingestExperimentData

Summary: Ingest experiment sensor data.

SUBSCRIBEexperiment/data_ingest/v1/{experimentId}/{sensorType}/{sensorVersion}/{sensorId}/{protocolId}
TRANSITIONAL: the legacy ingest shape with a trailing protocolId segment, published by fielded mobile builds. New publishers must use the shape without protocolId.

Parameters

NameTypeDescription
experimentIdstringUnique identifier of the experiment (e.g., exp123).
sensorTypestringThe type or family of sensor (e.g., MutlispeQ, Ambit...).
sensorVersionstringSensor firmware/hardware revision (without the 'v' prefix, e.g., 1, 2.1).
sensorIdstringUnique sensor identifier (UUID format recommended).
protocolIdstringLegacy protocol identifier carried in the trailing topic segment; the lean topic shape omits it.

Subscribe Operation

Operation ID: ingestExperimentDataLegacy

Summary: Ingest experiment sensor data (legacy topic shape).

PUBLISHdevice/scripts/v1/{sensorType}/{sensorVersion}/{thingName}
Channel for delivering behaviour scripts to a device. The cloud publishes and the device subscribes, then applies the script to its attached sensor. Messages are published retained at QoS 1 so a device that reconnects immediately receives the current script for its topic. The path parameters represent:
  • sensorType: The target sensor family (e.g., MultispeQ, Ambit...).
  • sensorVersion: Target firmware/hardware revision (without the 'v' prefix, e.g., 1, 2.1).
  • thingName: AWS IoT Thing name of the target device. The IoT policy binds this segment to ${iot:Connection.Thing.ThingName}, so a device (authenticated by its X.509 certificate) can only subscribe to and receive its own scripts.

Parameters

NameTypeDescription
sensorTypestringThe target sensor family (e.g., MultispeQ, Ambit...).
sensorVersionstringTarget firmware/hardware revision (without the 'v' prefix, e.g., 1, 2.1).
thingNamestringAWS IoT Thing name of the target device (e.g., dom_ludo_prototype_ambyte_thing_v2).

Publish Operation

Operation ID: deliverDeviceScript

Summary: Deliver a behaviour script to a device.

Messages

Experiment Data Ingestion Message

A message containing sensor data for an experiment.

NameExperimentDataMessage
Content Typeapplication/json

Payload Schema

{
  "type": "object",
  "additionalProperties": true,
  "properties": {
    "sample": {
      "type": "string",
      "description": "Sensor sample data: a JSON object of readings or an array of them (a burst). Raw JSON string, or gzip+base64 encoded when _sample_encoding is set.\n"
    },
    "_sample_encoding": {
      "type": "string",
      "enum": [
        "gzip+base64"
      ],
      "description": "When present, the `sample` field is compressed (gzip) and base64-encoded. Absent on raw (uncompressed) payloads.\n"
    },
    "timestamp": {
      "type": "string",
      "description": "ISO 8601 timestamp with UTC offset captured at measurement time using the synced clock (e.g. \"2026-03-09T10:30:00.000-05:00\").\n"
    },
    "timezone": {
      "type": "string",
      "description": "IANA timezone identifier at measurement time (e.g. \"America/Chicago\"). Preserved across retries so the original measurement-time timezone is never lost.\n"
    },
    "protocol_id": {
      "type": "string",
      "description": "Platform id of the protocol that produced this measurement, resolved by the publisher per result (a workbook run can span several protocols). Required on the lean topic shape for the row to be attributed; the sentinel value \"questions\" marks question-only uploads. On the legacy topic shape the topic's trailing segment takes precedence.\n"
    },
    "workbook_version_id": {
      "type": "string",
      "description": "Platform id of the workbook version this measurement was produced under. Absent outside workbook runs.\n"
    },
    "workbook_id": {
      "type": "string",
      "description": "Platform id of the workbook the producing version belongs to. Mobile-local replay aid (re-running the stored macro resolves the producing workbook even if the experiment is re-linked); the pipeline keys on workbook_version_id.\n"
    },
    "workbook_run_id": {
      "type": "string",
      "description": "Publisher-minted id shared by every measurement of one workbook run, correlating results across devices and protocols.\n"
    },
    "macro_context": {
      "type": "string",
      "description": "JSON-encoded macro execution context; stays a string because its keys are dynamic.\n"
    },
    "macros": {
      "type": "array",
      "description": "Macros applied to this measurement. Publishers that embed a macros array (of macro ids) inside each sample object instead may omit this field; the pipeline reads either.\n",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platform macro id."
          },
          "name": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          }
        }
      }
    },
    "questions": {
      "type": "array",
      "description": "Question/answer entries attached to the measurement.",
      "items": {
        "type": "object",
        "properties": {
          "question_label": {
            "type": "string"
          },
          "question_text": {
            "type": "string"
          },
          "question_answer": {
            "type": "string"
          }
        }
      }
    },
    "annotations": {
      "type": "array",
      "description": "Annotations attached at capture time.",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "rowId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "comment",
              "flag"
            ]
          },
          "content": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string"
              },
              "flagType": {
                "type": "string"
              }
            }
          },
          "createdBy": {
            "type": "string"
          },
          "createdByName": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        }
      }
    },
    "user_id": {
      "type": "string",
      "description": "Platform id of the contributing user's session."
    },
    "device_id": {
      "type": "string",
      "description": "Device identifier as reported by the instrument."
    },
    "device_name": {
      "type": "string",
      "description": "Device name as reported by the instrument."
    },
    "device_version": {
      "type": "string",
      "description": "Firmware version as reported by the device."
    },
    "device_firmware": {
      "type": "string",
      "description": "Firmware identifier as reported by the device."
    },
    "device_battery": {
      "type": "number",
      "description": "Battery reading as the device reports it; the unit is device-defined (volts on some families, percent on others).\n"
    },
    "output": {
      "type": "string",
      "description": "Device-native output block, passed through as text."
    },
    "latitude": {
      "type": "number",
      "description": "GPS latitude at measurement time, if available."
    },
    "longitude": {
      "type": "number",
      "description": "GPS longitude at measurement time, if available."
    }
  },
  "required": [
    "timestamp"
  ]
}

Example

Example 1
{
  "timestamp": "2026-03-09T10:30:00.000-05:00",
  "timezone": "America/Chicago",
  "protocol_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "sample": "{\"moisture\": 30.5, \"temperature\": 22.1}",
  "device_version": "1.1.0",
  "device_battery": 4.1
}

Device Script Update Message

A protocol measurement script delivered from the cloud to a device.

NameDeviceScriptMessage
Content Typeapplication/json

Payload Schema

{
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "script_update"
      ],
      "description": "Command discriminator, so the same topic can carry future command types."
    },
    "id": {
      "type": "string",
      "description": "Unique update identifier (e.g. upd-2026-06-08-001). Lets a device skip an update it has already applied."
    },
    "payload": {
      "type": "string",
      "description": "The protocol measurement script body (Lua source), sent inline. May be a raw string or a gzip+base64 encoded string when _payload_encoding is set.\n"
    },
    "_payload_encoding": {
      "type": "string",
      "enum": [
        "gzip+base64"
      ],
      "description": "When present, indicates that the `payload` field has been compressed (gzip) and base64-encoded. Absent on raw (uncompressed) payloads.\n"
    },
    "checksum": {
      "type": "string",
      "description": "SHA-256 hex digest of the decoded script body, for integrity verification before applying."
    }
  },
  "required": [
    "type",
    "id",
    "payload"
  ]
}

Example

Example 1
{
  "type": "script_update",
  "id": "upd-2026-06-08-001",
  "payload": "-- Lua protocol script\nreturn { pulses = 100, interval_ms = 500 }",
  "checksum": "adaeff5386f5e9dcaef58c0cc39f69f2d62a98bedae07195d02bdc82595a90ad"
}

Contact & License

Organization: openJII

Contact: ji-institute@info.nl

License: GNU General Public License