#Jamcorder device API
This document describes the network API exposed by Jamcorder firmware. It is written for application and tooling authors who need to discover a Jamcorder, read its state, change settings, transfer files, or stream MIDI.
Purpose: help people access their MIDI data across devices and develop extensions that interact directly with Jamcorder.
The Jamcorder API exposes 167 /api/... paths. Always use the runtime discovery endpoints instead of assuming that every firmware build has every endpoint.
Security: the API is available to anyone on your network. Only connect your Jamcorder device to a trusted network. Endpoints can change persistent settings, delete extensions, reboot the device, and more. For your protection, no API endpoint exists that can delete recordings.
#Related documentation
- JMX MIDI files — the goals, binary structure, custom events, timestamps, bookmarks, stones, and parsing requirements for Jamcorder recordings.
- Local web extensions — static webpages hosted by Jamcorder from its SD card, with access to the complete device API.
#Contents
- Quick start
- Set up Jamcorder Wi-Fi
- Concepts and API domains
- Runtime discovery and compatibility
- HTTP contract
- JSON-plus-binary uploads
- WebSockets
- Endpoint reference
- Getting started and device information
- Music and recordings
- Storage and content
- Device health and feedback
- Updates and maintenance
- Connectivity and setup
- Engineering and manufacturing
- Non-API HTTP routes
- Other transports
- JFU mode
#Quick start
#Set up Jamcorder Wi-Fi
Before using the API, connect your Jamcorder device to Wi-Fi. You can set up Wi-Fi with the Jamcorder app or with Web-based setup.
#App-based setup PREFERRED
In the Jamcorder app, open Settings → [Jamcorder name] → Wi-Fi and follow the setup instructions.
#Web-based setup
Web-based setup lets you configure Wi-Fi from a browser without the app. Hold the device button for about 1.5 seconds, join the jamcorder-xxxxxxxx Wi-Fi network, and open http://192.168.0.1. Select your home network and enter its password.
#Connect to the API
Set JAMCORDER to the device address. A Jamcorder normally advertises jamcorder.local and a secondary mDNS name based on its full UUID; /api/wifi/info reports its current IP address. An IP address is least ambiguous when multiple Jamcorders share a network.
JAMCORDER=http://jamcorder.local
# Learn which API families this firmware supports.
curl --compressed "$JAMCORDER/api/meta/capabilities"
# Get the exact endpoint list for this running build.
curl --compressed "$JAMCORDER/api/meta/endpoints"
# Read device identity.
curl --compressed "$JAMCORDER/api/identities/get"
# Rename the device.
curl --compressed \
-H 'Content-Type: application/json' \
-d '{"jamcorderName":"Studio Jamcorder"}' \
"$JAMCORDER/api/identities/rename/jamcorder"curl --compressed is recommended because JSON responses larger than 1,000 bytes are returned with Content-Encoding: deflate.
#Concepts and API domains
#Identities and names
The identities object separates stable identifiers from user-facing labels:
| Field | Meaning |
|---|---|
jamcorderUuid | Opaque identifier for this physical Jamcorder. It is also used to associate recordings and derive device-facing names. |
jamcorderName | Editable display name for the device, such as Studio Jamcorder. |
performerUuid | Opaque identifier for the performer identity stored on the device. |
performerName | Editable display name for the performer. |
Use UUIDs as database and synchronization keys; use names for UI. Names are not unique and none of these fields is an authentication credential. Treat UUIDs as stable for the life of a provisioned device, but allow them to change after a factory reset or reprovisioning.
#Device state and capabilities
/api/device-state/get is a broad snapshot intended for initial application startup. It combines identities, system information, settings, connectivity, storage, MIDI, recording, lifetime statistics, and current issues. Use the smaller subsystem endpoints for later refreshes so the client transfers and parses only the state it needs.
A capabilities response says which versioned feature families the device understands. /api/meta/endpoints says exactly which calls are present in the currently running firmware. Check both when compatibility matters: capability flags are convenient feature gates, while the endpoint list is definitive for an individual URI.
#Issues, alerts, and logs
These three APIs describe different levels of device health and activity:
| API | What it represents | Typical client use |
|---|---|---|
| Issues | Aggregated operational conditions such as missing storage, invalid time, failed Wi-Fi, transport overruns, update failures, or an unexpected reboot. An issue has occurrence counts and active/resolved state. | Show health status, guide recovery, and collect structured support data. |
| Alerts | Lightweight event notifications such as a change to Wi-Fi, identities, or issues. Recent alerts can be fetched; new alert tokens can be streamed. | Invalidate cached state, then refetch the affected API. |
| Logs | Raw diagnostic text and live log output. | Troubleshooting and support, not application state. |
/api/issues/current contains unresolved issue records. /api/issues/history also includes resolved records. Both include totalRaiseCount, which increases as conditions are raised and can help a client detect change. A record may contain issue, subIssue, occurrences, isResolved, first/latest wall-clock and since-boot timestamps, time since the previous occurrence, didBuzzUser, and an attached error object.
Calling /api/issues/clear/current marks all current records resolved. It does not repair the underlying condition and does not erase history. If the problem continues, firmware can raise the issue again. Applications should display known user-actionable issues prominently and retain unknown issue names for forward compatibility.
#Recordings, assets, and MIDI stones
Jamcorder records MIDI into its native JMX asset format. The library API lists recording assets and can convert the newest recording to a standard MIDI file. An asset is associated with the Jamcorder identity that created it; a single SD card can therefore contain assets from more than one device.
A MIDI stone is an indexed chunk of a JMX recording. Stone downloads and the stone WebSocket support incremental transfer without downloading an entire asset. A negative stoneIdx counts backward from the newest stone, which is useful for tailing a recording.
The MIDI APIs have separate roles: recorder controls what is captured, commands turns configured MIDI input into device actions such as bookmarks, I/O controls live routing between DIN, USB, Bluetooth, and WebSocket, piano state summarizes held and sustained notes, and lifetime statistics tracks cumulative playing activity.
#API domain guide
| Domain | Purpose |
|---|---|
| Getting started and device information | |
| Meta | Discover capability flags and the exact endpoint set. |
| System | Identify the running firmware, check liveness, and reboot the device. |
| Device state | Fetch a consolidated startup snapshot. |
| Identities | Read stable IDs and edit display names. |
| Time | Maintain timestamps, local offset, daylight-saving rules, and SNTP. |
| Music and recordings | |
| Piano | Read derived real-time note, sustain, and activity state. |
| MIDI recorder | Configure capture, silence skipping, and recording fidelity. |
| MIDI commands | Map MIDI gestures to device actions and create bookmarks. |
| MIDI I/O | Configure live routing and stream MIDI over WebSocket. |
| Library | Find recording assets and export the newest recording as MIDI. |
| MIDI stones | Download or stream indexed chunks of a recording. |
| Lifetime statistics | Read or clear cumulative note and playing-time totals. |
| Storage and content | |
| SD card | Inspect storage capacity and format or repair the card. |
| Files | List, download, upload, move, and delete device-side files. |
| Extensions | Install and remove device-hosted extension content. |
| Device health and feedback | |
| Alerts | Read and stream lightweight change notifications. |
| Issues | Read and clear structured, persistent device-health records. |
| Logs | Read recent diagnostic output and stream live logs. |
| Coredump | Inspect and download crash data. |
| Buzzer | Configure or trigger device sounds. |
| Updates and maintenance | |
| OTA | Inspect installed firmware and perform firmware updates. |
| Automatic reboot | Configure scheduled maintenance reboots. |
| Factory reset | Erase device settings and optionally preserve lifetime statistics. |
| Connectivity and setup | |
| Discovery mode | Advertise a Wi-Fi hotspot. Used for Web-based setup. |
| Wi-Fi | Inspect connectivity, scan networks, and configure credentials. |
| Bluetooth | Inspect Bluetooth controller, service, and connection state. |
| USB | Inspect USB state and attached MIDI-device descriptors. |
| Engineering and manufacturing | |
| Fabrication info | Read manufacturing identity and provision its protected values. |
| Verbose logging | Control detailed logging tags used for support and engineering. |
| Asset diagnostics | Inspect recording headers and parsed JMX summaries. |
| Developer settings | Control internal developer-mode switches. |
| Heap diagnostics | Inspect memory use, check integrity, and trace allocations. |
| System debug | Inspect low-level runtime state or deliberately force a crash. |
| NVS debug | Inspect and modify persistent key-value storage. |
| Self-test | List and run hardware tests and the factory test suite. |
| Factory mode | Unlock protected manufacturing operations and provision certificates. |
| STSAFE | Read certificates and perform secure-element challenges. |
| MIDI hardware tests | Inject and emit diagnostic MIDI sequences. |
#Runtime discovery and compatibility
Call these endpoints before using a feature:
| Method | Path | Purpose |
|---|---|---|
GET | /api/meta/capabilities | Merged feature flags such as supportsFilesApiV1 and supportsMidiIOApiV1. |
GET | /api/meta/endpoints | Exact registered URI, MIME type, and internal signature for each endpoint. |
GET | /api/system/software-info | Running application name, version, build information, and hashes. |
GET | /api/ota/overview | Running environment and installed firmware version information. |
An endpoint entry has this shape:
{
"uri": "/api/identities/get",
"mimeType": "application/json",
"sig": "voidToJson"
}The sig determines the HTTP method and body type:
| Registry signature | HTTP method | Request | Response |
|---|---|---|---|
voidToJson | GET | No body | JSON |
uriToJson | GET | URI itself is input | JSON |
jsonToJson | POST | JSON | JSON |
emptyPostToJson | POST | Empty | JSON |
voidToDownload | GET | No body | Binary/text download |
uriToDownload | GET | URI itself is input | Binary/text download |
jsonToDownload | POST | JSON | Binary/text download |
jsbnUploadToJson | POST | JAMCJSBN upload | JSON |
websocketGet | WebSocket upgrade | See WebSockets | Binary frames |
Endpoint availability can vary by firmware build, and MIDI player endpoints are not available in current builds. Treat /api/meta/endpoints as definitive for the connected device.
#HTTP contract
#Requests
- The server listens on plain HTTP port 80.
- Use
GETorPOSTexactly as listed. Some diagnostic endpoints mutate state despite currently being registered asGET; the catalog calls these out. - JSON request bodies use UTF-8 and should be sent as
Content-Type: application/json. - A JSON endpoint given an empty body receives an empty JSON object internally, but required fields still fail validation.
- There is no query-string parameter model. Inputs are JSON, upload metadata, or, for wildcard page routes, part of the URI.
- The server advertises
Access-Control-Allow-Origin: *. Its wildcardOPTIONShandler permitsPOSTand all request headers.
#Success responses
JSON endpoints return 200 OK and a resource-specific JSON value. There is no universal success envelope: some mutation endpoints include apiSuccess, success, or another status field, while read endpoints return their object directly. Treat the HTTP status as authoritative and parse the schema for the specific endpoint.
Large JSON responses are zlib-wrapped and carry Content-Encoding: deflate. Standards-compliant HTTP clients normally decode this automatically when they request compressed content.
Downloads use the MIME type shown by /api/meta/endpoints. File downloads may also set Content-Disposition and Content-Length.
#Error responses
An API failure returns 400 Bad Request with JSON similar to:
{
"error1": "directory does not exist",
"error2": "unable to list directory",
"errorCodeNum": 2,
"errorCodeStr": "generic",
"uri": "/api/files/list/overview",
"apiSuccess": false
}Errors accumulate as error1, error2, and so on. Known errorCodeStr values are generic, nonexistant (spelling preserved by the wire protocol), timedOut, deviceGone, and canceled.
If a streaming download fails after response bytes have begun, the server can only close the stream; it cannot replace the partial body with the JSON error object.
#JSON-plus-binary uploads (JAMCJSBN)
Six upload endpoints accept a custom body consisting of optional JSON metadata followed by raw binary bytes:
offset size value
0 8 ASCII "JAMCJSBN"
8 4 JSON byte length, uint32 little-endian
12 N N bytes of UTF-8 JSON (not NUL-terminated)
12 + N ... binary payloadSet Content-Length to the size of the entire framed body. The binary payload begins immediately after the JSON. If the first eight body bytes are not the magic value, the server treats the entire body as binary and supplies an empty metadata object. Endpoints that require metadata, such as file upload, must use the framed form.
Example Python body construction (the result can be sent with any HTTP client):
import json
import struct
metadata = json.dumps({"filepath": "/upload.bin"}, separators=(",", ":")).encode()
file_bytes = open("upload.bin", "rb").read()
body = b"JAMCJSBN" + struct.pack("<I", len(metadata)) + metadata + file_bytes| Path | Metadata | Binary payload |
|---|---|---|
/api/files/upload/simple | {"filepath": string} | File contents. |
/api/extensions/upload-install-html | {"filename": string} | HTML extension file. |
/api/extensions/upload-install-tar | {"filename": string} | Extension TAR archive. |
/api/ota/sd/upload/simple | None | Encrypted firmware image written to SD card. |
/api/ota/direct/install/simple | None | Encrypted firmware image installed directly. |
/api/ota/resumable/install/upload-chunk | {"otaWritten": integer} matching current progress | One firmware chunk. |
#WebSockets
WebSockets are HTTP-only and use ws://<device>/api/.... The server supports at most a small number of simultaneous sockets, so clients should reconnect with backoff and close unused streams.
The common binary frame convention reserves the first byte:
| Byte | Meaning |
|---|---|
0x00 | Standard application frame; endpoint payload follows. |
0x01 | Server keepalive ping. |
0x02 | Client keepalive pong. |
Reply to a one-byte 0x01 frame with a binary one-byte 0x02 frame. Current handlers update liveness on any received frame, but clients should use the defined pong value for forward compatibility.
| URL | Server-to-client payload | Client-to-server payload |
|---|---|---|
/api/alerts/websocket | 0x00 followed by an ASCII alert token. | Keepalive pong only. |
/api/logs/websocket | Raw log bytes. A one-byte 0x01 is still a ping. | Keepalive pong only. |
/api/midi-io/websocket | 0x00, one reserved byte, then zero or more 12-byte MIDI records. | Same framing; bit 0 of record byte 1 requests recording. |
/api/midi-stones/stream | 0x00, then a stream type byte and its payload. | Keepalive pong only. |
Each MIDI record is:
| Record offset | Size | Meaning |
|---|---|---|
| 0 | 1 | Input source enum. |
| 1 | 1 | Flags/reserved; inbound bit 0 is shouldRecord. |
| 2 | 6 | Event timestamp, unsigned big-endian milliseconds. |
| 8 | 1 | USB-MIDI cable/CIN header. |
| 9 | 3 | MIDI bytes. |
MIDI-stone stream type values are 18 error string, 19 no asset yet, 21 raw file data, and 22 deflate-compressed file data.
#Endpoint reference
The detailed endpoint reference follows the same purpose-based order as the API domain guide. JSON in the request column means a UTF-8 JSON body. Empty means send a zero-length body. Paths containing /debug/ and sections explicitly marked dangerous are not stable application-facing contracts.
#Getting started and device information
#Meta
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/meta/capabilities | None | Merged API capability flags. |
GET | /api/meta/endpoints | None | Registered endpoint array. |
#System
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/system/capabilities | None | System API version flags. |
GET | /api/system/software-info | None | Application, ESP-IDF, partition, hash, and build information. |
GET | /api/system/cpu-info | None | Chip, CPU, MAC, and installed-app information. |
GET | /api/system/is-alive | None | Liveness response. |
POST | /api/system/reboot | Empty | Acknowledges and schedules a reboot. |
#Device state
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/device-state/capabilities | None | Device-state API version flags. |
GET | /api/device-state/get | None | Aggregated identity, settings, system, SD, USB, Bluetooth, piano, and recording state. |
The aggregated response is convenient for initial UI hydration, but individual endpoints are preferable for polling a single subsystem.
#Identities
UUID fields are stable keys; name fields are editable labels. Renaming changes only the corresponding display name and returns the complete identities object.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/identities/capabilities | None | Identities API version flags. |
GET | /api/identities/get | None | jamcorderUuid, jamcorderName, performerUuid, and performerName. |
POST | /api/identities/rename/jamcorder | {"jamcorderName": string} | Updated identities object. |
POST | /api/identities/rename/performer | {"performerName": string} | Updated identities object. |
#Time
unixtime is seconds since the Unix epoch. localOffset is minutes from UTC. timeSource must be factory, manual, or app; app is normally the right choice for an application client. daylightSavings is the firmware's CSV rule string and is optional; omitting it clears the rule.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/time/capabilities | None | Time API version flags. |
GET | /api/time/get | None | Unix time, local offset/string, daylight-saving rule, source, drift estimate, and SNTP state. |
POST | /api/time/set | {"unixtime": number, "localOffset": number, "timeSource": string, "daylightSavings"?: string} | Updated time object. |
POST | /api/time/sntp/disable | Empty | sntpEnabled: false. |
POST | /api/time/sntp/enable | Empty | sntpEnabled: true. |
#Music and recordings
#Piano
Piano state is a derived, real-time view of musical activity rather than a recording file. Use it to render a keyboard or activity UI without decoding the library.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/piano/capabilities | None | Piano API version flags. |
GET | /api/piano/state | None | Per-channel held/sustained notes, RPN state, activity, sound, and timing information. |
#MIDI recorder
maxSilence is milliseconds. recordMode is grand, expressive, technical, or custom. In custom mode, statusMap and exprFidelity are numeric bitfields and ccFidelity is a 128-character hex encoding of 64 bytes. The three custom fields are optional and default to zero/null at the interface layer.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/midi-recorder/capabilities | None | Recorder API version flags. |
GET | /api/midi-recorder/settings/get | None | Current recorder settings. |
POST | /api/midi-recorder/settings/set | silenceSkip, maxSilence, recordMode, optional statusMap, exprFidelity, ccFidelity | Updated recorder settings. |
#MIDI commands
MIDI commands map selected incoming MIDI gestures to Jamcorder actions. The bookmark endpoint triggers that action directly; the settings endpoints control whether command families are accepted and which octave/safety note identifies them.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/midi-cmd/capabilities | None | MIDI-command API version flags. |
POST | /api/midi-cmd/bookmark | Empty | Creates a bookmark and returns its result. |
GET | /api/midi-cmd/settings/get | None | Current command toggles, octave, and safety note. |
POST | /api/midi-cmd/settings/set | disableAllCmds, disablePlayerCmds, disableBookmarkCmds booleans plus integer cmdOctave, cmdSafetyNote | Updated settings. |
#MIDI I/O
All eight booleans are required when setting routes.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/midi-io/capabilities | None | MIDI-I/O API version flags. |
GET | /api/midi-io/settings/get | None | Current filtering and routing matrix. |
POST | /api/midi-io/settings/set | Booleans filtering, dinToDin, dinToBle, dinToUsb, usbToDin, usbToBle, bleToUsb, bleToDin | Updated routing matrix. |
GET | /api/midi-io/msg-counts | None | Per-transport input/output and routed message counters. |
GET | /api/midi-io/active-converters | None | activeInputs and activeOutputs arrays. |
WS | /api/midi-io/websocket | WebSocket upgrade | Bidirectional framed MIDI records. |
#Library
The library is the catalog of recorded JMX assets on storage. Listing can be continued with midiPathContinue; request only the optional metadata a client needs to reduce scanning work. The on-disk recording structure is documented in the JMX MIDI files specification.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/library/capabilities | None | Library API version flags. |
GET | /api/library/download/newest/midi | None | Newest recording as audio/midi. |
POST | /api/library/list/assets | getJmxEof, getFilesize, getAllDevices booleans; optional preferredCount integer and midiPathContinue string | Paginated/recent asset list. |
GET | /api/library/list/years | None | Years represented in the library. |
#MIDI stones
stoneIdx may be an absolute stone index or a negative index counted backward from the newest stone.
| Method | Path | Request | Response |
|---|---|---|---|
POST | /api/midi-stones/download/stone | {"midiPath": string, "stoneIdx": integer} | Deflate-compressed raw stone bytes. |
WS | /api/midi-stones/stream | WebSocket upgrade | Live raw/compressed asset fragments. |
#Lifetime statistics
Clearing lifetime statistics is destructive. The clear operation uses compare-and-clear protection. Both string values must exactly match a preceding get response or the request fails.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/lifestats/capabilities | None | Lifetime-statistics API version flags. |
GET | /api/lifestats/get | None | Numeric lifeNotesPlayed and lifeMillisPlayed. |
POST | /api/lifestats/clear | Matching decimal strings lifeNotesPlayed and lifeMillisPlayed | cleared: true. |
#Storage and content
#SD card — format is destructive
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/sdcard/capabilities | None | SD-card API version flags. |
GET | /api/sdcard/info | None | Detection, mount, capacity, and free-space information. |
GET | /api/sdcard/free-bytes/simple | None | Free bytes. |
POST | /api/sdcard/format-fix/simple | Empty | Formats/repairs the card and returns card information. |
GET | /api/sdcard/debug/details | None | Detailed SD/FAT diagnostics. |
#Files
Filepaths are device-side absolute paths. Use paths returned by the API rather than assuming an SD-card mount name.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/files/capabilities | None | Files API version flags. |
POST | /api/files/list/overview | {"filepath": string} | dir and an array of child names. |
POST | /api/files/list/detailed | {"filepath": string} | dir and entries containing filename, isDirectory, sizeBytes, and modifiedLocalTime. |
POST | /api/files/download/simple | {"filepath": string} | Whole file with attachment filename. |
POST | /api/files/download/offset | {"filepath": string, "offset": integer, "length": integer} | File range. Negative offset is relative to EOF; length <= 0 means through EOF. |
POST | /api/files/upload/simple | JAMCJSBN with {"filepath": string} | Upload result. |
Download example:
curl --fail --output recording.jmx \
-H 'Content-Type: application/json' \
-d '{"filepath":"/recording.jmx"}' \
"$JAMCORDER/api/files/download/simple"#Extensions
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/extensions/capabilities | None | Extensions API version flags. |
GET | /api/extensions/list | None | Installed extensions. |
POST | /api/extensions/upload-install-html | JAMCJSBN with {"filename": string} | Install result. |
POST | /api/extensions/upload-install-tar | JAMCJSBN with {"filename": string} | Install result. |
POST | /api/extensions/uninstall | {"extFolder": string} | Uninstall result. |
Installed extension resources are served by the wildcard /extensions/* route. See Local web extensions for folder structure, packaging, browser API access, development, installation, and security guidance. The device-hosted extension page is /docs/extensions.
#Device health and feedback
#Alerts
Alert tokens mean that something changed; they are not complete state objects. Use the token to decide which read endpoint to refresh.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/alerts/capabilities | None | Alerts API version flags. |
GET | /api/alerts/recent | None | Up to ten recent alert records. |
WS | /api/alerts/websocket | WebSocket upgrade | Live alert tokens. |
#Issues
Issues are structured, persistent health records rather than raw log messages. See Issues, alerts, and logs for record semantics and guidance on clearing them.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/issues/capabilities | None | Issues API version flags. |
GET | /api/issues/current | None | Current unresolved issues. |
GET | /api/issues/history | None | Issue history. |
POST | /api/issues/clear/current | Empty | Clears current issues. |
#Logs
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/logs/capabilities | None | Logs API version flags. |
GET | /api/logs/recent/logs | None | Recent general log bytes. |
GET | /api/logs/recent/errors | None | Warning ring buffer in the current implementation. |
GET | /api/logs/recent/warnings | None | Error ring buffer in the current implementation. |
POST | /api/logs/recent/generic | {"maxLen": integer, "logLevel": string} | Tail of logs, warnings, or errors, limited to maxLen; negative means all. |
WS | /api/logs/websocket | WebSocket upgrade | Live raw log frames. |
#Coredump
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/coredump/capabilities | None | Coredump API version flags. |
GET | /api/coredump/summary | None | Crash metadata and hashes. |
GET | /api/coredump/download | None | Raw coredump (application/octet-stream). |
#Buzzer
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/buzzer/capabilities | None | Buzzer API version flags. |
GET | /api/buzzer/settings/get | None | Current buzzerDisabled setting. |
POST | /api/buzzer/settings/set | {"buzzerDisabled": boolean} | Updated setting. |
#Updates and maintenance
#OTA
Firmware images are encrypted device artifacts. Install operations can reboot the device or leave it running JFU; coordinate them as an exclusive workflow.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/ota/capabilities | None | OTA version and AES-key hash capability. |
GET | /api/ota/overview | None | Running environment and installed normal-firmware/JFU versions and hashes. |
GET | /api/ota/jfu/boot-args/get | None | Pending one-time JFU boot arguments. |
POST | /api/ota/jfu/boot-args/set | Booleans isModeSdCardEnabled, isModeWifiEnabled, isModeBluetoothEnabled, isModeConsoleEnabled | Stored boot-argument object. |
POST | /api/ota/jfu/boot-args/clear | Empty | Empty/current boot-argument object. |
POST | /api/ota/jfu/reboot-into | Empty | Acknowledges and reboots into JFU after about 2.5 seconds. |
POST | /api/ota/sd/upload/simple | JAMCJSBN firmware bytes | Uploaded SD-card filepath. |
GET | /api/ota/sd/firmware/available | None | Firmware files in pending/completed/failed SD folders. |
POST | /api/ota/sd/install/simple | {"filepath": string} | Install result. |
POST | /api/ota/direct/install/simple | JAMCJSBN firmware bytes | Direct-install result. |
GET | /api/ota/resumable/install/progress | None | Current resumable session/progress. |
POST | /api/ota/resumable/install/upload-chunk | JAMCJSBN chunk plus {"otaWritten": integer} | Updated otaWritten progress. |
#Automatic reboot
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/auto-reboot/capabilities | None | Auto-reboot API version flags. |
GET | /api/auto-reboot/settings/get | None | Current autoRebootTime. |
POST | /api/auto-reboot/settings/set | {"autoRebootTime": integer} in minutes | Updated setting. |
#Factory reset — destructive
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/factory-reset/capabilities | None | Factory-reset API version flags. |
POST | /api/factory-reset/all | Empty | Erases all resettable device state. |
POST | /api/factory-reset/choose | {"keepLifeStats": boolean} | Resets state, optionally preserving lifetime statistics. |
#Connectivity and setup
#Discovery mode
Discovery mode advertises a Wi-Fi hotspot used for Web-based setup. Entering discovery mode schedules a restart; the response only confirms that the transition was accepted, so clients must expect the connection to drop. See Web-based setup for setup instructions.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/discovery-mode/capabilities | None | Discovery-mode API version flags. |
POST | /api/discovery-mode/enter | Empty | Acknowledges and transitions/reboots into discovery mode. |
#Wi-Fi
SSID and password values are hex-encoded byte strings, not plain text. For example, Studio is 53747564696f. This preserves arbitrary SSID bytes. Changing credentials stores them but does not immediately move the device to the new network; reboot after receiving a successful response.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/wifi/capabilities | None | Wi-Fi API version flags. |
GET | /api/wifi/info | None | MAC address, mode, connection state, hex SSID, IP, RSSI, and hotspot client count as applicable. |
POST | /api/wifi/credentials/set | {"homeWifiSsid": hex-string, "homeWifiPassword": hex-string} | Stored credentials as hex. |
POST | /api/wifi/credentials/clear | Empty | Empty stored credentials. |
GET | /api/wifi/scan/simple | None | apCount, scan maximum, and apList entries with hex ssid, rssi, auth, and channel. |
#Bluetooth
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/bluetooth/capabilities | None | Bluetooth API version flags. |
GET | /api/bluetooth/state/get | None | High-level Bluetooth state. |
GET | /api/bluetooth/state/detailed | None | Detailed controller, service, connection, and client state. |
#USB
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/usb/capabilities | None | USB API version flags. |
GET | /api/usb/state | None | Current USB state. |
GET | /api/usb/descriptors | None | Attached USB MIDI descriptors. |
#Engineering and manufacturing
#Fabrication info
These endpoints expose manufacturing identity. set is intended for provisioning, not normal client use.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/fab-info/capabilities | None | Fabrication API version flags. |
GET | /api/fab-info/get | None | Fabrication timestamp, physical ID, and product key. |
POST | /api/fab-info/set | {"fabUnixtime": number, "fabProductKey": hex-string} after factory unlock | Stored fabrication record plus physical ID. |
#Verbose logging
firehose, clear, persist, and unpersist mutate state even though the current registry exposes them as GET.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/verbose/capabilities | None | Verbose API version flags. |
GET | /api/verbose/debug/list | None | Tag-number-to-name map. |
GET | /api/verbose/debug/state | None | Known, active, and saved verbose tags. |
POST | /api/verbose/debug/enable | A lone JSON integer tag number | Enabled tag record. |
POST | /api/verbose/debug/disable | A lone JSON integer tag number | Disabled tag record. |
GET | /api/verbose/debug/firehose | None | Enables almost all verbose tags and returns state. |
GET | /api/verbose/debug/clear | None | Disables all verbose tags and returns state. |
GET | /api/verbose/debug/persist | None | Saves enabled tags to NVS. |
GET | /api/verbose/debug/unpersist | None | Clears saved tags. |
#Asset diagnostics
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/asset/debug/next-header | None | Header for the next/current recording asset. |
POST | /api/asset/debug/eof-summary | {"filepath": string} | Parsed JMX EOF summary. |
#Developer settings
Command numbers are firmware-internal. Read the list before changing one. The current implementation of /cmd/unset calls the same setter as /cmd/set; clients that need to clear a command should verify the returned state.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/developer/capabilities | None | Developer API version flags. |
GET | /api/developer/settings | None | Current developer-mode settings. |
POST | /api/developer/mode/enable | Empty | Enables developer mode. |
POST | /api/developer/mode/disable | Empty | Disables developer mode. |
GET | /api/developer/cmd/list | None | Known developer command numbers and state. |
POST | /api/developer/cmd/set | {"cmd": positive number} | Updated developer settings. |
POST | /api/developer/cmd/unset | {"cmd": positive number} | Currently behaves like cmd/set; verify response. |
POST | /api/developer/reset-all | Empty | Resets developer settings. |
#Heap diagnostics
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/heap/debug/free-bytes | None | Heap totals by memory capability. |
GET | /api/heap/debug/alloc-stats | None | Plain-text allocation statistics. |
GET | /api/heap/debug/check-integrity | None | Heap-integrity result. |
POST | /api/heap-trace/debug/start-all | Empty | Starts tracing all allocations. |
POST | /api/heap-trace/debug/start-leaks | Empty | Starts leak tracing. |
POST | /api/heap-trace/debug/pause | Empty | Pauses tracing. |
POST | /api/heap-trace/debug/resume | Empty | Resumes tracing. |
GET | /api/heap-trace/debug/dump/all | None | Plain-text complete trace. |
GET | /api/heap-trace/debug/dump/internal | None | Plain-text internal-memory trace. |
GET | /api/heap-trace/debug/dump/spi | None | Plain-text SPI-RAM trace. |
GET | /api/heap-trace/debug/summary | None | JSON trace summary. |
#System debug
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/debug/freertos-tasks | None | FreeRTOS task/runtime information. |
GET | /api/debug/partition-table | None | Parsed partition table. |
GET | /api/debug/efuses/list | None | Decoded eFuse list. |
GET | /api/debug/efuses/raw | None | Raw eFuse data. |
POST | /api/debug/force-system-crash | Empty | Deliberately crashes the running firmware. A normal response is not guaranteed. |
#NVS debug
Writing NVS values changes persistent device state.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/nvs/debug/list | None | Known NVS keys, types, and readable values. Blob values report length only. |
POST | /api/nvs/debug/set | {"key": string, "value": number or string} | Updated full NVS listing. Blob writes are unsupported. |
#Self-test
Test numbers are runtime-defined; fetch the list first. Factory-suite execution is registered as a GET even though it operates hardware.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/self-test/capabilities | None | Self-test API version flags. |
GET | /api/self-test/list | None | Test numbers and names. |
POST | /api/self-test/run/single-test | A lone JSON integer test number | Test result. |
GET | /api/self-test/run/factory-test-suite | None | Factory-suite result. |
#Factory mode and certificate provisioning
Factory mode must be unlocked before protected manufacturing writes. PEM values for the upload endpoints are hex-encoded bytes.
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/factory-mode/capabilities | None | Factory-mode API version flags. |
POST | /api/factory-mode/unlock | {"password": string} | Unlock state. |
GET | /api/factory-mode/stsafe/preprov-cert-der | None | Pre-provisioned certificate DER bytes. |
POST | /api/factory-mode/stsafe/upload-issued-cert-pem | {"stsafeIssuedCertPem": hex-string} | Provisioning result. |
POST | /api/factory-mode/stsafe/upload-ca-cert-pem | {"stsafeCaCertPem": hex-string} | Provisioning result. |
#STSAFE
| Method | Path | Request | Response |
|---|---|---|---|
GET | /api/stsafe/capabilities | None | STSAFE API version flags. |
GET | /api/stsafe/ca-cert-pem | None | CA certificate as PEM text. |
GET | /api/stsafe/issued-cert-pem | None | Issued certificate as PEM text. |
POST | /api/stsafe/challenge | {"challengeHex": hex-string} | Challenge signature/result. |
POST | /api/stsafe/bulk-challenge/simple | {"challengeHex": hex-string, "bulkCount": integer} | Bulk challenge data download. |
POST | /api/stsafe/print-all-zone-bytes | Empty | Prints secure-element zones and returns status. |
#MIDI hardware tests
| Method | Path | Request | Response |
|---|---|---|---|
POST | /api/midi-tests/debug/triad-out | Empty | Emits an outbound test triad. |
POST | /api/midi-tests/debug/triad-in | Empty | Injects an inbound test triad. |
POST | /api/midi-tests/debug/complex-in | Empty | Injects a complex inbound test sequence. |
POST | /api/midi-tests/debug/complex-out | Empty | Emits a complex outbound test sequence. |
#Non-API HTTP routes
These routes serve built-in UI, diagnostics, and installed extension content. Their HTML is not a machine-readable API contract.
| Method | Route | Purpose |
|---|---|---|
GET | / | Firmware index. |
GET | /favicon.ico | Favicon. |
GET | /logs | Live logs page. |
GET | /webapp | Main web app. |
GET | /webapp/* | Main web-app assets. |
GET | /sdcard/?* | SD-card web-app route. |
GET | /extensions/* | Installed extension resources. |
GET | /docs/extensions | Extension documentation page. |
GET | /internal | Internal diagnostics page. |
GET | /jfu | Firmware-update page. |
GET | /test-pages/websocket-midi | MIDI WebSocket test page. |
GET | /test-pages/websocket-stones | MIDI-stone WebSocket test page. |
GET | /test-pages/websocket-alerts | Alerts WebSocket test page. |
GET | /test-pages/ble-info | BLE information test page. |
GET | /test-pages/ble-http | BtHttp test page. |
GET | /test-pages/ble-stones | BLE MIDI-stone test page. |
GET | /test-pages/ble-alerts | BLE alerts test page. |
GET | /test-pages/ota | OTA test page. |
#Other transports
The same registry-backed API can be invoked over HTTP, Bluetooth BtHttp, or the serial console. WebSockets remain HTTP-only.
#Bluetooth BtHttp
BtHttp is exposed by service 02AA0001-4202-649d-ec11-dfdb58e9372d and characteristic 02AA0002-4202-649d-ec11-dfdb58e9372d. Subscribe to indications before writing a request.
Each BLE packet begins with a socket index and delimiter:
| Offset | Size | Meaning |
|---|---|---|
| 0 | 1 | Client-chosen socket index. A connection supports multiple logical sockets. |
| 1 | 1 | 10 start, 11 continue, 12 end, or 13 single-packet message. |
| 2 | ... | Message fragment. The first fragment begins with a message-type byte. |
Message types are 20 request header, 21 request body, 40 response header, and 41 response body. Header messages are NUL-terminated string pairs. A request header begins with method and URI, then field-name/field-value pairs:
GET\0/api/device-state/get\0Content-Length\00\0A response header begins with Status, its value, then response fields. Every BtHttp request must include a valid Content-Length, including 0 for a GET. Body bytes use the same JSON or JAMCJSBN representation as HTTP. The device can track up to six BLE clients and sixteen logical sockets in the current build.
#Serial console
When the console is enabled, each registered URI is also a command name. JSON input/download commands take a single JSON argument, for example:
/api/identities/get
/api/identities/rename/jamcorder {"jamcorderName":"Bench"}The console also assigns numeric aliases based on registry order. These are diagnostic conveniences and are not stable across firmware versions. Binary downloads are delimited by [transmissionStart] and [transmissionComplete] and encoded as console-safe hex. Upload endpoints and WebSockets are not supported by the console transport.
#JFU mode
JFU is the firmware updater and recovery environment. Most integrations do not need to account for it. Clients that operate while JFU is running should use /api/meta/endpoints as the definitive runtime list.
#API endpoints available in JFU
| Domain | Available endpoints |
|---|---|
| Meta | /api/meta/capabilities/api/meta/endpoints |
| System | /api/system/capabilities/api/system/software-info/api/system/cpu-info/api/system/is-alive/api/system/reboot |
| Issues | /api/issues/capabilities/api/issues/current/api/issues/history/api/issues/clear/current |
| Logs | /api/logs/capabilities/api/logs/recent/logs/api/logs/recent/errors/api/logs/recent/warnings/api/logs/recent/generic/api/logs/websocket |
| Coredump | /api/coredump/capabilities/api/coredump/summary/api/coredump/download |
| OTA | /api/ota/capabilities/api/ota/overview/api/ota/jfu/boot-args/get/api/ota/jfu/boot-args/set/api/ota/jfu/boot-args/clear/api/ota/jfu/reboot-into/api/ota/sd/upload/simple/api/ota/sd/firmware/available/api/ota/sd/install/simple/api/ota/direct/install/simple/api/ota/resumable/install/progress/api/ota/resumable/install/upload-chunk |
| Factory reset | /api/factory-reset/capabilities/api/factory-reset/all/api/factory-reset/choose |
| Fabrication info | /api/fab-info/capabilities/api/fab-info/get/api/fab-info/set |
| Verbose logging | /api/verbose/capabilities/api/verbose/debug/list/api/verbose/debug/state/api/verbose/debug/enable/api/verbose/debug/disable/api/verbose/debug/firehose/api/verbose/debug/clear |
The Verbose logging persistence endpoints, /api/verbose/debug/persist and /api/verbose/debug/unpersist, are not available in JFU.
#Non-API routes available in JFU
| Method | Route | Purpose |
|---|---|---|
GET | / | Firmware index. |
GET | /favicon.ico | Favicon. |
GET | /logs | Live logs page. |