Analyzer Webhooks
The application can be configured to send test data to a webhook URL. This is useful for integrating with other services or for custom data analysis.
The webhook URL can be configured in the settings panel. The application will send a POST request to this URL with a JSON payload. Make sure that appropriate CORS headers are configured.
Triggers
The webhook is sent at the following times:
TEST_STARTED: When a test is started.CONTINUE_TEST: When a test is continued.TEST_FINISHED: When a test is finished.NEW_DATA: Whenever new channel data is received during a test run.DEVICE_READY: When the device has finished heating up and is ready to start a test.ALREADY_TESTING: When the device is already running a test (PM001 only).
PM005 (MiniDock) devices start tests by themselves when a test card is inserted and the lid is closed. For them, TEST_STARTED is sent when the app first sees a new test, and CONTINUE_TEST when the app connects to a test that is already running. The test data always covers the whole test, since the device stores it. NEW_DATA is sent whenever the curves are updated (every 5 to 15 seconds).
Payload
The payload is a JSON object with the following structure:
{
"version": 0,
"event": "string",
"device": {
"family": "string",
"hwVersion": "string",
"swVersion": "string",
"deviceModel": "string",
"sn": "number | string",
"configuration": "string"
},
"test": {
"state": "string",
"recordId": "number",
"result": "object",
"data": {
"temperatureSamples": [
{
"time": "string",
"temp": "number"
}
],
"samples": [
{
"startingChannel": "number",
"firstChannelResult": "number",
"samplingTime": "number",
"samplingTemperature": "number"
}
]
}
}
}
version: The version of the webhook payload format. Currently0.event: A string describing what triggered the webhook. See the "Triggers" section for possible values.
Device
The device object contains information about the device that ran the test.
family: The device family,PM001orPM005.hwVersion: The hardware version of the device.swVersion: The software version of the device.deviceModel: The model of the device.sn: The serial number of the device. A number for PM001, a string for PM005.configuration: The configuration of the device. For PM005, the test programs stored on the device.
Test
The test object contains information about the test itself.
-
state: The current state of the test. This is a string that corresponds to theTestStateenum in the application code. The possible values are:UNINITIALIZEDIDLETESTINGDONEBLOCKED_ALREADY_TESTINGBLOCKED_NOT_READY
For PM005 devices:
UNINITIALIZEDPREHEATINGWAITING_FOR_CARDCARD_ERRORTESTINGDONEDEVICE_ERROR
-
recordId: PM005 only. The ID the device assigned to the test. -
result: The result of the test. This is only present when the test is finished. The structure of this object is:{ "detectionType": "number", "detectionFlowNumber": "number", "detectionResult": "string", "numberOfChannels": "number", "startingChannel": "number", "channelResults": ["string"], "numberOfSubGroups": "number", "subGroupResults": [ { "result": "string", "name": "string" } ] }The
detectionResultfield indicates the overall result of the test. The possible values are:NEGATIVEPOSITIVEINVALID
-
data: The raw data from the test. This includes temperature samples and fluorescence readings. PM005 fluorescence readings are raw sensor values and are not scaled like PM001's.
Examples
Device ready for test
{
"version": 0,
"event": "DEVICE_READY",
"test": {
"state": "IDLE",
"data": { "temperatureSamples": [], "samples": [] }
}
}
Test is already running when test is started
{
"version": 0,
"event": "ALREADY_TESTING",
"test": {
"state": "BLOCKED_ALREADY_TESTING",
"data": { "temperatureSamples": [], "samples": [] }
}
}
Test started
{
"version": 0,
"event": "TEST_STARTED",
"device": {
"hwVersion": "HV3.0.2",
"swVersion": "SV2.2.2.230619_Beta_V2",
"deviceModel": "PM001",
"sn": 0000000000,
"configuration": "CV1.22.7.20"
},
"test": {
"state": "TESTING",
"data": { "temperatureSamples": [], "samples": [] }
}
}
Test continued
{
"version": 0,
"event": "CONTINUE_TEST",
"device": {
"hwVersion": "HV3.0.2",
"swVersion": "SV2.2.2.230619_Beta_V2",
"deviceModel": "PM001",
"sn": 0000000000,
"configuration": "CV1.22.7.20"
},
"test": {
"state": "TESTING",
"data": { "temperatureSamples": [], "samples": [] }
}
}
Incremental updates during test
{
"version": 0,
"event": "NEW_DATA",
"device": {
"hwVersion": "HV3.0.2",
"swVersion": "SV2.2.2.230619_Beta_V2",
"deviceModel": "PM001",
"sn": 0000000000,
"configuration": "CV1.22.7.20"
},
"test": {
"state": "TESTING",
"data": {
"temperatureSamples": [
{ "time": "2025-06-30T16:10:13.802Z", "temp": 63.16767501831055 },
{ "time": "2025-06-30T16:10:15.872Z", "temp": 63.13431167602539 },
{ "time": "2025-06-30T16:10:17.851Z", "temp": 63.13431167602539 },
{ "time": "2025-06-30T16:10:20.057Z", "temp": 63.20106887817383 },
{ "time": "2025-06-30T16:10:21.677Z", "temp": 63.16767501831055 },
{ "time": "2025-06-30T16:10:23.747Z", "temp": 63.16767501831055 }
],
"samples": [
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 1,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 704
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 2,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 896
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 3,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 1088
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 4,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 448
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 5,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 1152
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 6,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 256
}
]
}
}
}
Test completed
{
"version": 0,
"event": "TEST_FINISHED",
"device": {
"hwVersion": "HV3.0.2",
"swVersion": "SV2.2.2.230619_Beta_V2",
"deviceModel": "PM001",
"sn": 0000000000,
"configuration": "CV1.22.7.20"
},
"test": {
"state": "DONE",
"result": {
"detectionType": 1,
"detectionFlowNumber": 166,
"detectionResult": "INVALID",
"numberOfChannels": 7,
"startingChannel": 0,
"channelResults": [
"NEGATIVE",
"NEGATIVE",
"NEGATIVE",
"NEGATIVE",
"NEGATIVE",
"NEGATIVE",
"NEGATIVE"
],
"numberOfSubGroups": 2,
"subGroupResults": [
{ "result": "NEGATIVE", "name": "IC" },
{ "result": "INVALID", "name": "SARS-CoV-2" }
]
},
"data": {
"temperatureSamples": [
{ "time": "2025-06-30T16:10:13.802Z", "temp": 63.16767501831055 },
{ "time": "2025-06-30T16:10:15.872Z", "temp": 63.13431167602539 },
{ "time": "2025-06-30T16:10:17.851Z", "temp": 63.13431167602539 },
...
],
"samples": [
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 1,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 704
},
{
"sampleType": 1,
"sampleStreamNumber": 166,
"currentDataIndex": 7,
"totalNumberOfSamples": 8,
"startingChannel": 2,
"numberOfChannels": 1,
"samplingTime": 4508,
"samplingTemperature": 63.1,
"firstChannelResult": 896
},
...
]
}
}
}