Icom CI-V Explorer

Searchable reference for the Icom CI-V protocol across multiple radios.

Top-level radio info: default CI-V transceiver address and command count. Click a row for capabilities.

IDModelCI-V AddressCommandsCapabilities

Browse a radio's commands by code. Pick a radio to see its command codes, then click a code to drill into its sub-commands.

RadioCmdSub cmdDataDescription

Spotted a wrong or missing command or capability? Submit a correction for review. The API is read-only; this is the only write path and submissions never modify the reference data directly.

Download all submitted feedback (JSONL)

API Documentation

Interactive Swagger UI is available at /docs (OpenAPI spec at /openapi.json). The sections below show how to call the API from code or an AI agent.

Endpoints

MethodPathDescription
GET/radiosList all supported radios with CI-V addresses and command counts.
GET/radios/{radio_id}Single radio info (id is a lowercase short code like 7300).
GET/radios/{radio_id}/capabilitiesCapability matrix for one radio.
GET/commands?radio_id=7300&q=frequency&limit=100&offset=0Search/filter commands. q matches cmd, sub_cmd, data, and description (case-insensitive).
GET/radios/{radio_id}/commands?q=vfoCommands for one radio, with optional search.
POST/feedbackSubmit a correction (JSON body). Only write path; appends to a review queue.
GET/feedbackDownload all submitted feedback as a JSONL file (one JSON object per line).
GET/healthHealth check.

Quick facts

Calling the API from code

curl

List radios, then search the IC-7300 command table for frequency commands:

curl -k https://localhost:8443/radios
curl -k "https://localhost:8443/commands?radio_id=7300&q=frequency&limit=10"

-k skips cert verification for the self-signed dev cert. Drop it when using a real CA-signed certificate.

Python (requests)

import requests

BASE = "https://localhost:8443"
SESSION = requests.Session()
SESSION.verify = False  # dev cert only; use a real CA bundle in production

# Which radios are supported?
radios = SESSION.get(f"{BASE}/radios").json()
for r in radios:
    print(r["id"], r["name"], r["address"], r["command_count"])

# Search IC-9700 commands for "satellite"
hits = SESSION.get(f"{BASE}/radios/9700/commands", params={"q": "sat"}).json()
for c in hits["items"]:
    print(c["cmd"], c["sub_cmd"], c["description"])

# Capabilities of the IC-7300
caps = SESSION.get(f"{BASE}/radios/7300/capabilities").json()
for cap in caps:
    print(cap["name"], cap["radios"]["7300"])

Python (httpx, async)

import httpx

async with httpx.AsyncClient(base_url="https://localhost:8443", verify=False) as client:
    radios = (await client.get("/radios")).json()
    cmds  = (await client.get("/commands", params={"radio_id": "7300", "q": "vfo"})).json()

JavaScript (fetch)

const BASE = "https://localhost:8443";

// List radios
const radios = await (await fetch(`${BASE}/radios`)).json();

// Search commands for the IC-7300
const url = new URL(`${BASE}/commands`);
url.searchParams.set("radio_id", "7300");
url.searchParams.set("q", "frequency");
url.searchParams.set("limit", "50");
const result = await (await fetch(url)).json();
console.log(result.total, result.items);

Submitting feedback

curl -k -X POST https://localhost:8443/feedback \
  -H "Content-Type: application/json" \
  -d '{"radio_id":"7300","cmd":"05","sub_cmd":"","field":"description",\
        "suggested_value":"Set operating frequency (corrected)",\
        "notes":"Manual p.19-9","submitter":"tester"}'

Using the API from an AI agent

The API is read-only (except POST /feedback) and returns structured JSON, which makes it straightforward for an LLM/agent to call via HTTP tool use. Recommended workflow:

  1. Discover supported radios with GET /radios to get valid radio ids and addresses.
  2. Search with GET /commands?q=... (and optionally radio_id=...) to find commands by functionality or code. q is plain substring matching — keep queries short.
  3. Drill down with GET /radios/{id}/capabilities to check whether a feature is supported on a specific radio.
  4. Submit corrections with POST /feedback when the agent finds a wrong or missing entry. Validate radio_id against /radios first.

Agent tool schema (example)

When exposing the API to an agent, describe each endpoint as an HTTP tool. Example tool definitions (OpenAI function-calling style, trimmed):

{
  "name": "civ_search_commands",
  "description": "Search Icom CI-V commands across cmd/sub_cmd/data/description. Returns JSON.",
  "parameters": {
    "type": "object",
    "properties": {
      "q":        {"type": "string", "description": "Free-text search, e.g. 'frequency'"},
      "radio_id": {"type": "string", "description": "Optional radio id: 705,7100,7300,7300mk2,7610,7760,9700"},
      "limit":    {"type": "integer", "minimum": 1, "maximum": 500, "default": 100},
      "offset":   {"type": "integer", "minimum": 0, "default": 0}
    }
  }
}
{
  "name": "civ_list_radios",
  "description": "List supported Icom radios with default CI-V addresses and command counts.",
  "parameters": {"type": "object", "properties": {}}
}
{
  "name": "civ_radio_capabilities",
  "description": "Get the capability matrix for one radio.",
  "parameters": {
    "type": "object",
    "properties": {"radio_id": {"type": "string"}},
    "required": ["radio_id"]
  }
}

Agent prompt guidance

Pointing an agent at this server

If your agent framework reads an OpenAPI spec, point it at /openapi.json. The spec is self-describing and includes parameter constraints (hex patterns, length caps, enums) that help the agent construct valid requests.