REST API and WebSocket interface for programmatic access to PigStick devices.
http://10.0.0.1 or http://pigstick-XXXX.local. All responses are application/json unless otherwise noted.
The PigStick exposes a REST API over HTTP and three WebSocket endpoints for real-time streaming and shared-state control. The API requires no authentication—access is controlled by WiFi connectivity to the device's network.
Content-Type: application/json unless noted (binary waveform data, ZIP exports)POST and PUT use JSON| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/device | Device identity and capabilities |
| GET | /api/v1/status | Full device state snapshot |
| GET | /api/v1/power | Battery status |
| GET | /api/v1/accel | Accelerometer and orientation |
| GET | /api/v1/temperature | MCU temperature |
| GET | /api/v1/time | System time and sync status |
| GET | /api/v1/recorder/status | Recorder state and active job |
| GET | /api/v1/recorder/config | Trigger and audio configuration |
| POST | /api/v1/recorder/config | Update recorder configuration |
| POST | /api/v1/recorder/arm | Arm or disarm recorder |
| POST | /api/v1/recorder/grab | Capture a manual passage on the device |
| GET | /api/v1/sensitivity | Magnetic sensitivity state |
| POST | /api/v1/sensitivity | Apply magnetic sensitivity |
| GET | /api/v1/calibration/mfl-offsets | MFL offset calibration status |
| POST | /api/v1/calibration/mfl-offsets/start | Start MFL offset calibration |
| GET | /api/v1/events | List all event metadata |
| GET | /api/v1/events/{id} | Single event metadata |
| GET | /api/v1/events/{id}/magnetic | Binary magnetic waveform |
| GET | /api/v1/events/{id}/audio | Binary ADPCM audio |
| POST | /api/v1/events/{id}/cursor | Set cursor position on event |
| POST | /api/v1/events/refresh | Rebuild event manifest |
| DELETE | /api/v1/events/{id} | Delete single event |
| DELETE | /api/v1/events | Delete all events |
| GET | /api/v1/jobs | List all jobs |
| POST | /api/v1/jobs | Create new job |
| PUT | /api/v1/jobs/{client}/{job} | Update job metadata |
| POST | /api/v1/jobs/{client}/{job}/activate | Set active job |
| DELETE | /api/v1/jobs/{client}/{job} | Delete job |
| GET | /api/v1/jobs/{client}/{job}/export | Export job as ZIP |
| GET | /api/v1/gps | GPS position and satellites |
| GET | /api/v1/wifi | WiFi mode and connection status |
| GET | /api/v1/wifi/scan | Scan for available networks |
| GET | /api/v1/wifi/networks | List saved networks |
| POST | /api/v1/wifi/networks | Save a WiFi network |
| DELETE | /api/v1/wifi/networks | Delete a saved network |
| POST | /api/v1/wifi/coexist | Enable/disable Starlink / Local Network Mode |
| POST | /api/v1/service/check-updates | Check for software updates |
| GET | /api/v1/service/status | Update-check result and hint |
| GET | /api/v1/ota/status | OTA install progress |
| POST | /api/v1/ota/accept | Accept an advertised update |
| POST | /api/v1/provision | Run fleet provisioning |
| POST | /api/v1/setserial | Set device serial number |
| POST | /api/v1/app-version | Report browser app version |
| GET | /api/v1/system/info | System information |
| GET | /api/v1/system/ws-diagnostics | WebSocket ownership diagnostics |
| POST | /api/v1/system/restart | Restart device |
| WS | /api/v1/ws/audio | Real-time geophone audio stream |
| WS | /api/v1/ws/magnetic | Real-time magnetic stream + events |
| WS | /api/v1/ws/control | Shared state and acknowledged commands |
Returns device identity, firmware version, and hardware capabilities.
{
"device": {
"serial": "PS2609A0110",
"name": "pigstick-0110",
"firmware": "2.2.72",
"uptime": 3621,
"bootCount": 47,
"capabilities": {
"audio": true,
"magnetic": true,
"gps": true,
"battery": true
},
"limits": {
"maxWsClients": 2,
"maxEvents": 103
}
}
}
| Field | Type | Description |
|---|---|---|
| serial | string | Device serial number (PS format) |
| name | string | Device name (matches WiFi AP SSID) |
| firmware | string | Firmware version |
| uptime | number | Seconds since boot |
| bootCount | number | Total boot cycles |
| capabilities | object | Available hardware features |
| limits.maxWsClients | number | Maximum concurrent WebSocket clients |
| limits.maxEvents | number | Maximum stored events before FIFO eviction |
Comprehensive device state snapshot including recorder, GPS, power, and connectivity.
{
"status": {
"timestamp": 1773868800000,
"device": "pigstick-0110",
"serial": "PS2609A0110",
"firmware": "2.2.72",
"app": "2.2.95",
"uptime": 3621,
"storage": {
"eventCount": 12,
"total": 10379264,
"used": 1245184,
"free": 9134080,
"evictionCount": 0
},
"job": {
"client": "Acme Pipeline",
"jobName": "Run-042",
"operator": "J. Smith"
},
"recorder": {
"state": "armed",
"eventCount": 12,
"freeSpace": 9134080,
"captureProgress": null,
"holdoffRemainingMs": null,
"lastTriggerTime": 1773868500000,
"capturesSinceBoot": 3,
"autoArm": false,
"audioEnabled": true
},
"gps": {
"timeSynced": true,
"fix": true,
"fixQuality": 1,
"satellites": 7,
"lat": 30.267153,
"lon": -97.743057,
"altitude": 149.20,
"speedKnots": 0.04,
"speedMps": 0.0206,
"utcEpochMs": 1773868800000
},
"power": {
"voltage": 4.05,
"percent": 82,
"charging": false,
"source": "usb"
},
"temperature": 42.5,
"wifiConnected": false,
"mqttConnected": false,
"iotJobsBusy": false,
"startupBehavior": {
"armOnBoot": false
}
}
}
| Field | Type | Description |
|---|---|---|
| timestamp | number | Current UTC epoch milliseconds |
| job | object|null | Active job info, or null if none |
| recorder.state | string | One of: idle, armed, capturing, writing, holdoff |
| recorder.captureProgress | number|null | 0–100 during capture, null otherwise |
| recorder.holdoffRemainingMs | number|null | Milliseconds remaining in hold-off, null otherwise |
| gps.lat, gps.lon | number | Conditional: only present when fix is true |
| gps.utcEpochMs | number | Conditional: only present when GPS time is valid |
| temperature | number | MCU temperature in °C (omitted if sensor error) |
| ota | object | Conditional: only present during OTA update |
Battery voltage, charge percentage, and power source.
{
"power": {
"voltage": 4.05,
"percent": 82,
"charging": false,
"source": "usb"
}
}
Cached accelerometer axes, activity, and device-owned orientation state. Reading this endpoint does not poll the sensor hardware.
Internal MCU temperature reading.
{
"temperatureC": 42.50,
"temperatureF": 108.50
}
{
"error": "sensorReadFailed"
}
System clock status. Time is synced from GPS satellites.
{
"synced": true,
"time": "2026-03-17T14:30:00"
}
{
"synced": false
}
The event recorder follows a state machine: IDLE → ARMED → CAPTURING → WRITING → HOLDOFF → ARMED. Configuration changes are rejected while a capture is in progress.
Current recorder state, capture statistics, and active job context.
{
"recorder": {
"state": "armed",
"eventCount": 12,
"freeSpace": 9134080,
"captureProgress": null,
"holdoffRemainingMs": null,
"lastTriggerTime": 1773868500000,
"capturesSinceBoot": 3,
"autoArm": false,
"audioEnabled": true,
"activeJob": {
"client": "Acme Pipeline",
"jobName": "Run-042",
"clientDir": "Acme_Pipeline",
"jobDir": "Run-042",
"createdAt": 1773782400,
"notes": ""
}
}
}
Current trigger, audio, and speed estimation configuration.
{
"config": {
"trigger": {
"mode": "zeroCrossing",
"thresholdPercent": 50,
"holdoffMs": 5000,
"preDurationMs": 10000,
"postDurationMs": 10000
},
"audio": {
"enabled": true,
"sampleRate": 8000
},
"speed": {
"intervalWindow": 5,
"segmentLengthFt": 40,
"pigThreshold": 30
},
"autoArm": false,
"activeJob": { ... }
}
}
| Field | Type | Description |
|---|---|---|
| trigger.mode | string | zeroCrossing, threshold, or combined |
| trigger.thresholdPercent | number | 0–100, trigger level for threshold mode |
| trigger.holdoffMs | number | Minimum time between captures (ms) |
| trigger.preDurationMs | number | Pre-trigger buffer duration (ms) |
| trigger.postDurationMs | number | Post-trigger capture duration (ms) |
| audio.enabled | boolean | Whether audio is captured with events |
| speed.segmentLengthFt | number | Pipeline segment length in feet |
Update recorder configuration. All fields are optional—only provided fields are changed.
{
"triggerMode": "threshold",
"threshold": 40,
"holdoffMs": 3000,
"audioEnabled": true,
"autoArm": false
}
| Field | Type | Description |
|---|---|---|
| triggerMode | string | zeroCrossing, threshold, or combined |
| threshold | number | 0–100 percent of full scale |
| holdoffMs | number | Hold-off time in milliseconds |
| preDurationMs | number | Pre-trigger buffer (ms) |
| postDurationMs | number | Post-trigger capture (ms) |
| audioEnabled | boolean | Enable/disable audio capture |
| autoArm | boolean | Arm on boot |
| intervalWindow | number | Speed estimation window |
| segmentLengthFt | number | Segment length in feet |
| pigThreshold | number | Speed detection threshold |
| browserTime | number | Epoch seconds—sets device clock if GPS not synced |
{"status": "ok"}
400 — Invalid JSON or invalid triggerMode value409 — Config rejected (capture in progress){"event":"configChanged"} to all WebSocket clients.
Arm or disarm the event recorder.
{"armed": true}
{
"recorder": {
"state": "armed",
"armed": true
}
}
{"event":"armState","armed":true} to all WebSocket clients.
Start a device-side manual passage capture using the PigStick's magnetic and audio pre-trigger ring buffers. The normal post-trigger capture, LittleFS storage, job export, and multi-viewer notification pipeline is used.
{"accepted":true,"captureOrigin":"manual","audioPartial":false}
409 Conflict while the recorder is capturing, writing, or in holdoff.
Returns the active field magnetic sensitivity level, profile name, dirty state, and preset availability.
Apply a field sensitivity preset. Rejected while the recorder or update service is busy.
{"level":"medium"}
Returns value-blind MFL offset calibration state, running flag, and operator message.
Starts local MFL offset calibration. Rejected while the recorder or update service is busy.
Events are recorded pig passages containing magnetic waveform data and optional geophone audio. Each event has a numeric ID and is stored on the device's flash filesystem. The device can store up to 103 events; older events are automatically evicted when storage is full.
List all event metadata for the active job.
{
"events": [
{
"id": 1,
"timestamp": 1773868500000,
"triggerSample": 2000,
"magSamples": 4000,
"magRate": 200,
"audioSamples": 160000,
"audioRate": 8000,
"peakMagnetic": 1842,
"triggerMode": 0,
"threshold": 50,
"latitude": 30.267153,
"longitude": -97.743057,
"hasAudio": true,
"magDataSize": 8000,
"audioDataSize": 40000
}
],
"total": 1,
"freeSpace": 9134080
}
| Field | Type | Description |
|---|---|---|
| id | number | Event ID |
| timestamp | number | UTC epoch milliseconds at trigger |
| triggerSample | number | Sample index of trigger point |
| magSamples | number | Total magnetic samples |
| magRate | number | Magnetic sample rate (Hz) |
| audioSamples | number | Total audio samples (0 if no audio) |
| audioRate | number | Audio sample rate (Hz) |
| peakMagnetic | number | Peak magnetic reading (raw ADC) |
| triggerMode | number | 0 = zero crossing, 1 = threshold, 2 = combined |
| hasAudio | boolean | Whether audio data is available |
| magDataSize | number | Magnetic data size in bytes |
| audioDataSize | number | ADPCM audio data size in bytes |
Single event metadata with additional fields.
{
"id": 1,
"timestamp": 1773868500000,
"triggerSample": 2000,
"magSamples": 4000,
"magRate": 200,
"audioSamples": 160000,
"audioRate": 8000,
"peakMagnetic": 1842,
"triggerMode": 0,
"threshold": 50,
"latitude": 30.267153,
"longitude": -97.743057,
"hasAudio": true,
"magDataSize": 8000,
"audioDataSize": 40000,
"deviceSerial": "PS2609A0110",
"agmSiteNumber": "AGM-001",
"cursorSample": 2150
}
| Field | Type | Description |
|---|---|---|
| deviceSerial | string | Serial of device that recorded the event |
| agmSiteNumber | string | User-assigned site identifier |
| cursorSample | number|null | Saved cursor position (sample index), or null |
404 — Event not foundRaw magnetic waveform data as a binary array.
Content-Type: application/octet-stream
int16[] (little-endian, 2 bytes per sample)magSamples from metadata404 — Event not found or file missingGeophone audio data encoded as IMA ADPCM.
Content-Type: application/octet-stream
404 — Event not found or no audio dataSet or clear the cursor position on a recorded event.
{"sample": 2150}
Set to null to clear: {"sample": null}
{"ok": true}
{"event":"cursorUpdated","id":1,"sample":2150} to all WebSocket clients.
Force rebuild of the event manifest from disk. Use after manual file operations.
Same format as GET /api/v1/events.
Delete a single event.
{"status": "ok"}
{"event":"eventDeleted","id":1} to all WebSocket clients.
Delete all events in the active job.
{"status": "ok"}
{"event":"eventsCleared"} to all WebSocket clients.
Events are organized under jobs, grouped by client. One job is active at a time—new events are recorded into the active job. Jobs are stored on-device and persist across reboots.
List all jobs grouped by client, with the active job indicated.
{
"active": "Acme_Pipeline/Run-042",
"clients": [
{
"client": "Acme_Pipeline",
"jobs": [
{
"jobName": "Run-042",
"operator": "J. Smith",
"pipelineSegment": "Segment-A",
"siteNameTemplate": "AGM-{n:3}",
"notes": "",
"createdAt": 1773782400,
"siteNameCounter": 4
}
]
}
]
}
| Field | Type | Description |
|---|---|---|
| active | string|null | Path of active job (Client/Job), or null |
| clients[].client | string | Client directory name |
| jobs[].jobName | string | Job directory name |
| jobs[].operator | string | Operator/technician name |
| jobs[].siteNameTemplate | string | Auto-numbering template (e.g. AGM-{n:3}) |
| jobs[].createdAt | number | Epoch seconds when job was created |
| jobs[].siteNameCounter | number | Next site number for auto-generation |
Create a new job. Becomes the active job by default.
{
"client": "Acme Pipeline",
"jobName": "Run-043",
"operator": "J. Smith",
"pipelineSegment": "Segment-B",
"siteNameTemplate": "AGM-{n:3}",
"notes": "",
"setActive": true
}
| Field | Type | Required | Description |
|---|---|---|---|
| client | string | Yes | Client or company name |
| jobName | string | Yes | Job identifier |
| operator | string | No | Operator name |
| pipelineSegment | string | No | Pipeline segment |
| siteNameTemplate | string | No | Site number template |
| notes | string | No | Job notes |
| siteNameCounter | number | No | Starting site number |
| setActive | boolean | No | Activate immediately (default: true) |
{
"status": "ok",
"clientDir": "Acme_Pipeline",
"jobDir": "Run-043"
}
Update job metadata. All fields are optional—only provided fields are changed.
{
"operator": "A. Jones",
"notes": "Updated notes"
}
{"status": "ok"}
404 — Job not foundSwitch the active job. New events will be recorded into this job.
{"status": "ok"}
404 — Job not foundDelete a job and all its events. Cannot delete the currently active job.
{"status": "ok"}
404 — Job not foundStream the entire job as a ZIP archive.
Content-Type: application/zip
The archive contains:
job.json — Job metadatamanifest.json — Full event manifest{id}.json — Per-event metadata{id}.mag — Binary magnetic waveform (int16[]){id}.audio — Binary ADPCM audio (if available)404 — Job not foundGPS receiver status, movement-aware duty cycling, EASY ephemeris, fix quality, and position (when a fix is available).
{
"gps": {
"timeSynced": true,
"fix": true,
"fixQuality": 1,
"satellites": 7,
"hdop": 1.2,
"duty": "rest",
"dutyEnabled": true,
"fixAgeS": 91,
"dutyStatus": {
"state": "rest",
"enabled": true,
"movementAware": true,
"relocating": false,
"orientationKnown": true,
"upright": true,
"quietForS": 184,
"nextWakeS": 209,
"qualityQualified": true,
"qualityFallback": false,
"qualityStreak": 3,
"qualityRequired": 3,
"minSatellites": 5,
"maxHdop": 3.0,
"quietRequiredS": 15,
"navSeen": true,
"lastNavAgeS": 1,
"recoveryPhase": "idle",
"wakeReason": "scheduled",
"wakeAttempts": 3,
"hotRestarts": 0,
"faultCount": 0,
"fallbackContinuous": false
},
"easy": {
"state": "enabled",
"known": true,
"enabled": true,
"predictionDays": 3
},
"lat": 30.267153,
"lon": -97.743057,
"altitude": 149.20,
"speedKnots": 0.04,
"speedMps": 0.0206,
"utcEpochMs": 1773868800000
}
}
{
"gps": {
"timeSynced": false,
"fix": false,
"fixQuality": 0,
"satellites": 0,
"hdop": 0.0,
"duty": "acquire",
"dutyEnabled": true
}
}
| Field | Type | Description |
|---|---|---|
| timeSynced | boolean | Whether system clock is GPS-synced |
| fix | boolean | Whether GPS has a position fix |
| fixQuality | number | 0 = no fix, 1 = GPS, 2 = DGPS |
| satellites | number | Satellites in use |
| hdop | number | Receiver-reported horizontal dilution of precision |
| duty | string | off, acquire, settle, rest, refix, relocate, or fault |
| dutyEnabled | boolean | Whether standby duty cycling is enabled |
| dutyStatus | object | Movement/orientation, next wake, quality gate, and receiver recovery state. Normal gate: 15 s without movement, 3 fresh RMC/GGA pairs, 5+ satellites, HDOP ≤3.0. Recovery reports navigation age, wake reason/attempts, hot restarts, faults, and fail-open continuous mode. Orientation is informational and does not block standby. |
| easy | object | L96 EASY enable/check state and 0-3 day prediction extension |
| fixAgeS | number | Seconds since the last valid RMC position |
| lat | number | Latitude (conditional: fix = true) |
| lon | number | Longitude (conditional: fix = true) |
| altitude | number | Altitude in meters (conditional) |
| speedKnots | number | Speed in knots (conditional) |
| speedMps | number | Speed in m/s (conditional) |
| utcEpochMs | number | GPS UTC time in ms (conditional: time valid) |
WiFi mode, coexist state, access point info, and station connection status. internet is true when the device has proven connectivity (cloud session or completed time sync); cloud is true while the AWS IoT MQTT session is live. mdnsUrl is the address where this interface is reachable from either network.
{
"wifi": {
"mode": "AP+STA",
"coexist": true,
"internet": true,
"cloud": true,
"hostname": "pigstick-2001",
"mdnsUrl": "http://pigstick-2001.local",
"ap": {
"ssid": "PigStick-2001",
"channel": 1,
"clients": 1
},
"sta": {
"connected": true,
"enabled": true,
"pausedForAp": false,
"reconnectHeld": false,
"subnetConflict": false,
"ssid": "FieldOffice",
"rssi": -52,
"channel": 1,
"ip": "192.168.1.105"
}
}
}
When the station is disconnected, sta instead carries lastDisconnectReason (e.g. "NO_AP_FOUND", "AUTH_FAIL") when one is known. subnetConflict is true when the uplink lease collides with the access point's own 10.0.0.0/24 subnet. reconnectHeld means the station link is being kept alive while reconnect/scan activity is held for an access-point client.
Enable or disable Starlink / Local Network Mode (simultaneous AP + station operation with the interface and cloud served over the uplink network). Persisted in NVS; takes effect on the next restart. Requires at least one user-saved network to become active.
{"enabled": true}
{"success": true, "coexist": true, "rebootRequired": true}
Scan for available WiFi networks. This is a blocking operation that takes a few seconds.
{
"networks": [
{
"ssid": "FieldOffice",
"rssi": -52,
"secure": true,
"channel": 1,
"bssid": "c0:6f:98:9b:58:c6"
},
{
"ssid": "OpenNetwork",
"rssi": -78,
"secure": false,
"channel": 11,
"bssid": "aa:bb:cc:dd:ee:ff"
}
]
}
List saved WiFi networks. Passwords are not returned. factory:true marks the built-in factory/bench network, which the interface hides outside admin mode. channel/bssid are the cached identity from the last successful connection (used for fast reconnects and access-point channel pinning), 0/null when unknown.
{
"networks": [
{
"ssid": "FieldOffice",
"priority": 0,
"channel": 1,
"factory": false,
"bssid": "c0:6f:98:9b:58:c6"
}
]
}
Save a WiFi network. The device stores up to 5 networks.
{
"ssid": "FieldOffice-5G",
"password": "secretpass"
}
{"success": true}
400 — Missing or empty SSID400 — Maximum networks reached (5)Delete a saved WiFi network.
{"ssid": "FieldOffice-5G"}
{"success": true}
400 — Missing or empty SSID404 — Network not foundFirmware version and storage statistics.
{
"system": {
"firmware": "2.2.72",
"storage": {
"total": 10379264,
"used": 1245184,
"free": 9134080
},
"uptime": 3621
}
}
Returns bounded, in-memory connection ownership evidence: HTTP and stream registry counts, active viewer UUIDs and fd generations, close-cause counters, and the 16 most recent lifecycle events. The history resets when the device restarts.
Add the same page-scoped ?viewer=<uuid> value to the audio, magnetic, and control WebSocket URLs so one viewer's sockets can be correlated.
Restart the device. The restart occurs after a 1-second delay to allow the response to be sent.
{
"restart": {
"scheduled": true,
"delayMs": 1000
}
}
Check for software updates. Behavior depends on connectivity:
"rebooting": false. The manifest is fetched, the update hint refreshed, and any queued update job is requested immediately (a manual check also overrides the wait-for-idle rule for the next 10 minutes). Poll /api/v1/service/status for the result."rebooting": true and the device goes offline shortly after.{"service": {"scheduled": true, "mode": "checkUpdates", "rebooting": false, "online": true}}
{"service": {"scheduled": true, "mode": "checkUpdates", "rebooting": true, "delayMs": 1500}}
409 — No saved WiFi networkService-mode state and the most recent update-check result. updateHint.status is checking, available, none, skipped, or error; the interface polls this after an in-place check.
{
"service": {
"active": false,
"request": 0,
"lastStatus": "complete",
"lastDetail": "Checking for updates over WiFi network",
"updateHint": {
"status": "none",
"detail": "No update indicated by fleet manifest",
"available": false,
"firmware": false,
"app": false,
"firmwareVersion": "2.2.72",
"appVersion": "2.2.95",
"checkedBootMs": 108721
}
}
}
Lightweight OTA phase and byte progress for polling while install activity temporarily stops live streams. The active flag remains true during post-reboot validation.
{"ota":{"phase":"downloading","component":"firmware","downloaded":512000,"total":1024000,"percent":50,"active":true}}
Accept an update job currently advertised by updateHint. Stale or arbitrary job IDs are rejected.
{"jobId":"pigstick-update-2-2-72-20260726"}
Run AWS IoT fleet provisioning with a valid PigStick serial number. Intended for manufacturing and authorized service workflows.
Set the device serial without cloud provisioning. A restart is required before the new identity and WiFi name are fully applied.
Report the connected browser app version for device status and cloud shadow reporting.
{"version":"2.2.95"}
The PigStick provides audio and magnetic sensor streams plus a shared-state control channel. Audio and magnetic allow two clients each; control allows four, subject to the global HTTP socket budget.
Real-time geophone audio stream.
| Field | Type | Description |
|---|---|---|
| freq | number | Test tone frequency (Hz) |
| amp | number | Test tone amplitude (0–100%) |
| preamp | number | Hardware pre-amp gain multiplier |
| armed | number | 1.0 = arm, 0.0 = disarm |
| threshold | number | Trigger threshold (0–100%) |
Send as JSON text frame, e.g.: {"preamp": 4.0}
Real-time magnetic sensor stream with JSON event notifications.
Format 8 frames contain a 12-byte v2 shared-stream header, aligned MFL and ELF-envelope int16 arrays, and a final format byte.
Text frames carry real-time event notifications:
| Event | Description |
|---|---|
trigger | Trigger detected: {"event":"trigger","peak":1842,"time":1773868500000} |
eventWritten | Passage saved: {"event":"eventWritten","id":5} |
armState | Arm state changed: {"event":"armState","armed":true} |
configChanged | Recorder config updated |
cursorUpdated | Cursor set on event: {"event":"cursorUpdated","id":1,"sample":2150} |
eventDeleted | Event removed: {"event":"eventDeleted","id":1} |
eventsCleared | All events deleted |
jobCreated | New job: {"event":"jobCreated","client":"...","job":"..."} |
jobActivated | Active job switched |
jobUpdated | Job metadata changed |
jobDeleted | Job removed |
Device-authoritative shared settings with state broadcasts and acknowledged get/set commands.
{"type":"set","id":102,"set":{"preamp":64,"threshold":55}}
{"type":"ack","id":102,"ok":true,"rev":43,"state":{"preamp":64,"filterHp":0,"filterLp":500,"armed":true,"threshold":55,"magMode":"both"}}
| Code | Meaning |
|---|---|
200 | Success |
400 | Bad request (invalid input, missing fields) |
404 | Resource not found (event, job, file) |
409 | Conflict (e.g., config change during capture) |
413 | Payload too large |
500 | Internal server error |
All errors return a JSON object with an error field:
{
"error": "Description of what went wrong"
}
| Error | Endpoint | Cause |
|---|---|---|
Event not found | Events | Invalid event ID |
Job not found | Jobs | Invalid client/job path |
Config rejected (capturing in progress) | Recorder config | Cannot change config while capturing |
Invalid triggerMode | Recorder config | Must be zeroCrossing, threshold, or combined |
Maximum networks reached | WiFi | Already 5 saved networks |
No audio data | Event audio | Event was captured without audio |