Skip to main content

REST API

All REST endpoints are served by the FastAPI server on port 8000.

Health

GET /health

Returns server health status.

Response:

{
"status": "healthy",
"service": "contop-server",
"version": "0.1.0"
}

Pairing

POST /api/pair

Generate a new pairing token and return QR code as PNG image.

Query Parameters:

ParameterTypeDefaultDescription
device_idstringnullDevice identifier (auto-generated if omitted)
connection_typestring"permanent""permanent" (30-day) or "temp" (4-hour)

Response: PNG image bytes with headers:

  • x-pairing-token — The generated token string
  • x-pairing-expires-at — ISO 8601 expiration timestamp

Notes: For permanent connections, reuses an existing valid token if one exists. The QR code is always regenerated to reflect current network configuration.

GET /api/qr-image

Return the current QR code as a PNG image.

Response: PNG image bytes, or 404 if no active QR exists.

GET /api/pair/status

Return current pairing token status without exposing the token value.

Query Parameters:

ParameterTypeDefaultDescription
device_idstringnullFilter by device ID

Response:

{
"status": "active",
"expires_at": "2026-04-26T12:00:00Z",
"connection_type": "permanent"
}

DELETE /api/pair

Revoke the active pairing token and force-disconnect any active WebRTC session.

Query Parameters:

ParameterTypeDefaultDescription
device_idstringnullRevoke specific device's token

Response:

{ "revoked": true }

Devices

GET /api/devices

Return all paired devices with connection status and recent events.

Query Parameters:

ParameterTypeDefaultDescription
sincestringnullISO timestamp — return events since this time

Response:

{
"devices": [
{
"device_id": "abc123",
"device_name": "iPhone 15 Pro",
"connection_type": "permanent",
"connected": true,
"connection_path": "LAN",
"last_location": { "lat": 37.7749, "lon": -122.4194 },
"last_seen": "2026-03-27T10:30:00Z",
"paired_at": "2026-03-01T08:00:00Z",
"expires_at": "2026-03-31T08:00:00Z"
}
],
"events": []
}

Connection

GET /api/connection-info

Return current network connection information.

Response:

{
"lan_ip": "192.168.1.100",
"tailscale_ip": "100.64.0.1",
"tailscale_available": true,
"tunnel_url": "https://abc.trycloudflare.com",
"tunnel_active": true,
"connected_clients": 1,
"has_active_token": true,
"token_expires_at": "2026-04-26T12:00:00Z",
"token_connection_type": "permanent"
}

POST /api/tunnel/start

Start the Cloudflare tunnel on demand. Returns existing URL if already running.

Response:

{
"tunnel_url": "https://abc.trycloudflare.com",
"already_running": false
}

Settings

GET /api/settings

Return current settings JSON.

PUT /api/settings

Update settings. Requires version, restricted_paths, forbidden_commands keys.

Request Body: Full settings JSON object.

Response: Updated settings JSON.

POST /api/settings/reset

Reset all settings to defaults.

GET /api/decrypted-keys

Return API keys from the Tauri desktop app. Keys are stored in plaintext in settings.json.

Response:

{
"gemini_api_key": "...",
"openai_api_key": "...",
"anthropic_api_key": "...",
"openrouter_api_key": "..."
}

GET /api/default-prompts

Return the built-in default system prompts.

Response:

{
"conversation": "...",
"execution": "..."
}

Skills

GET /api/skills

List all discovered skills (metadata only).

Response:

[
{
"name": "web-research",
"description": "Search the web and extract information",
"version": "1.0.0",
"skill_type": "mixed",
"enabled": true,
"has_scripts": true
}
]

POST /api/skills

Create a new skill.

Request Body:

{
"name": "my-skill",
"description": "What this skill does"
}

GET /api/skills/{name}

Return full SKILL.md content for a skill.

PUT /api/skills/{name}

Update a skill's SKILL.md content. Validates YAML frontmatter.

GET /api/skills/{name}/workflows

Return list of script files (YAML workflows and Python tools) with content for a skill.

Response:

{
"skill_name": "web-research",
"workflows": [
{ "name": "search", "filename": "search.yaml", "content": "..." }
]
}

POST /api/skills/{name}/enable

Enable a skill. Checks for tool name conflicts before saving.

POST /api/skills/{name}/disable

Disable a skill.

WebSocket Signaling

WS /ws/signaling

WebSocket endpoint for WebRTC SDP/ICE exchange. Used only during initial connection setup — the WebSocket is closed once the P2P connection is established.

CLI Proxy

POST /api/provider-health

Check connectivity to the CLI proxy for a given provider.

Request Body:

{ "provider": "anthropic" }

Response:

{
"status": "ok",
"models": [{ "id": "claude-sonnet-4-6", "object": "model" }],
"auth_type": "subscription"
}

POST /api/notify-proxy-change

Notify connected mobile clients of proxy status changes. Called by the desktop app after starting/stopping CLI proxies.

Response:

{
"pushed": 1,
"provider_auth": {
"anthropic": { "mode": "cli_proxy", "available": true },
"gemini": { "mode": "api_key", "available": false },
"openai": { "mode": "api_key", "available": false }
}
}

Away Mode

GET /api/away-mode/status

Return Away Mode status by querying the Tauri health server.

Response:

{
"away_mode": false,
"overlay_active": false
}

Related: Contop Server · Data Channel Protocol · Configuration