Skip to content
Getting Started

Connect in 5 Minutes

Send your first API request to AudioMap and start building.

Prerequisites

  • AudioMap installed and running on your machine with a Pro license
  • Any language with WebSocket support (Python, JavaScript, C++, etc.)

The API server starts automatically when AudioMap launches. The API is gated behind the Pro license tier.

1

Connect via WebSocket

Open a WebSocket connection to ws://127.0.0.1:9010. The API uses JSON-RPC 2.0 — every message is a JSON object with jsonrpc, method, and id fields.

Python
import asyncio, websockets, json
from pathlib import Path

async def main():
    async with websockets.connect("ws://127.0.0.1:9010") as ws:
        # Step 1: Read the session token
        token_path = Path.home() / "Library/Application Support/AudioMap/api_session_token"
        token = token_path.read_text().strip()

        # Step 2: Authenticate (must be the first message)
        await ws.send(json.dumps({
            "jsonrpc": "2.0",
            "method": "authenticate",
            "params": {"token": token},
            "id": 1
        }))
        auth = json.loads(await ws.recv())
        assert auth["result"]["authenticated"]

        # Step 3: Now you can call any API method
        await ws.send(json.dumps({
            "jsonrpc": "2.0",
            "method": "ping",
            "id": 2
        }))
        response = json.loads(await ws.recv())
        print(response)

asyncio.run(main())

Install: pip install websockets

JavaScript (Node.js)
import { readFileSync } from "fs";
import { homedir } from "os";
import { join } from "path";

// Read the session token
const tokenPath = join(homedir(), "Library/Application Support/AudioMap/api_session_token");
const token = readFileSync(tokenPath, "utf-8").trim();

const ws = new WebSocket("ws://127.0.0.1:9010");

ws.onopen = () => {
    // Authenticate first (must be the first message)
    ws.send(JSON.stringify({
        jsonrpc: "2.0",
        method: "authenticate",
        params: { token },
        id: 1
    }));
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.id === 1 && msg.result?.authenticated) {
        // Authenticated — now send API requests
        ws.send(JSON.stringify({
            jsonrpc: "2.0",
            method: "ping",
            id: 2
        }));
    } else {
        console.log(msg);
    }
};
2

Authenticate

The first message on every new connection must be an authenticate call. All other API methods are rejected until authentication succeeds.

How it works

  1. 1AudioMap generates a random session token on launch and writes it to a local file.
  2. 2Your client reads the token and sends it with the authenticate method.
  3. 3The token changes every time AudioMap restarts. It is deleted on shutdown.

Token file location

macOS~/Library/Application Support/AudioMap/api_session_token
Windows%APPDATA%\AudioMap\api_session_token
Request
{
  "jsonrpc": "2.0",
  "method": "authenticate",
  "params": {
    "token": "a1b2c3d4e5f6..."
  },
  "id": 1
}
Response
{
  "jsonrpc": "2.0",
  "result": {
    "authenticated": true
  },
  "id": 1
}

Why token-based auth? The token file is only readable by the local user account, preventing other devices on the network from accessing the API without physical access to the machine.

3

Query App State

Use getState to see the current configuration:

Request
{
  "jsonrpc": "2.0",
  "method": "getState",
  "id": 2
}
Response
{
  "jsonrpc": "2.0",
  "result": {
    "audioDevice": "Built-in Output",
    "sampleRate": 48000,
    "fftSize": 4096,
    "numSources": 2,
    "numReceivers": 1,
    "measurementCount": 5
  },
  "id": 2
}
4

Trigger a Capture

The capture method is asynchronous — it returns immediately and sends a completion event when done. Subscribe to events first to receive the result.

# 1. Subscribe to capture events
await ws.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "subscribe",
    "params": {"events": ["captureComplete"]},
    "id": 3
}))
await ws.recv()  # subscription confirmation

# 2. Trigger capture
await ws.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "capture",
    "id": 4
}))
await ws.recv()  # {"result": {"captureId": "...", "status": "started"}}

# 3. Wait for completion event
event = json.loads(await ws.recv())
# {"method": "event.captureComplete", "params": {"success": true, ...}}
5

Read Measurement Data

List measurements, then fetch frequency response data for any measurement:

# List all measurements
await ws.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getMeasurements",
    "id": 5
}))
measurements = json.loads(await ws.recv())

# Get transfer function data for first measurement
measurement_id = measurements["result"]["measurements"][0]["id"]
await ws.send(json.dumps({
    "jsonrpc": "2.0",
    "method": "getMeasurementData",
    "params": {"id": measurement_id},
    "id": 6
}))
data = json.loads(await ws.recv())
# data["result"]["frequencies"], data["result"]["magnitude"], etc.

Error Handling

Errors follow JSON-RPC 2.0 conventions. Check for an error field in the response:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": 1
}
CodeMeaning
-32700Parse error (invalid JSON)
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error
-32000App not ready (audio engine not initialized)
-32001Capture in progress
-32002Operation timeout
-32003Invalid measurement ID
-32004Not authenticated (send authenticate first)