The Management API is an independent HTTPS server that enables remote configuration, lifecycle management, and monitoring of Teleton agents via typed HTTP endpoints — replacing SSH-based management.
It runs on port 7778 by default, uses self-signed TLS, and authenticates requests with tltn_-prefixed API keys.
- Quick Start
- Bootstrap Mode
- Authentication
- TLS Certificates
- Endpoints
- Rate Limiting
- Security
- Configuration
- CLI Commands
- Error Format
- Examples
api:
enabled: true
port: 7778 # default
# allowed_ips: [] # empty = allow all authenticated requeststeleton startOn first start, a tltn_-prefixed API key is generated and printed to the log. Copy it — it won't be shown again.
To get the key as JSON (useful for automation):
teleton start --json-credentials
# Output: {"apiKey":"tltn_...","fingerprint":"a1b2c3...","port":7778}curl -k https://localhost:7778/v1/agent/status \
-H "Authorization: Bearer tltn_your_key_here"Note:
-kskips TLS verification for self-signed certs. For production, pin the certificate fingerprint instead (see TLS Certificates).
Start the API without an existing config.yaml — useful for provisioning a fresh VPS entirely over HTTP.
teleton start --apiThis starts only the Management API with null dependencies. All /v1/setup/* endpoints are available for remote configuration. Once setup is complete:
# Complete setup via /v1/setup endpoints, then start the agent:
curl -k https://localhost:7778/v1/agent/start \
-X POST \
-H "Authorization: Bearer tltn_..."The agent boots, and all other endpoints become available. Routes that require the agent return 503 Service Unavailable until it starts.
teleton start --api
│
▼
API server starts (null deps)
│
▼
POST /v1/setup/* ── configure provider, Telegram, wallet...
│
▼
POST /v1/agent/start ── creates TeletonApp, hot-swaps deps
│
▼
All /v1/* endpoints operational
All /v1/* routes require a Bearer token in the Authorization header:
Authorization: Bearer tltn_<base64url-encoded key>
- Prefix:
tltn_ - Payload: 32 random bytes, base64url-encoded
- Example:
tltn_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345678901234
- The raw API key is shown once at first start (or via
--json-credentials) - Only the SHA-256 hash is persisted in
config.yaml(api.key_hash) - On each request, the provided key is hashed and compared using
timingSafeEqual(constant-time, timing-attack resistant)
teleton api-rotate-keyGenerates a new key, prints it, and persists the new hash to config.yaml. The old key is immediately invalidated.
The API generates a self-signed certificate on first start, stored at:
~/.teleton/api-cert.pem(certificate)~/.teleton/api-key.pem(private key)
Both files have 0o600 permissions (owner read/write only).
| Property | Value |
|---|---|
| Algorithm | RSA 2048-bit, SHA-256 |
| Validity | 2 years |
| SANs | localhost (DNS), 127.0.0.1 (IPv4), ::1 (IPv6) |
| Auto-renewal | Regenerated automatically if expired |
Get the TLS fingerprint for certificate pinning:
teleton api-fingerprint
# Output: a1b2c3d4e5f6... (SHA-256, 64 hex chars)Or via --json-credentials at startup.
# Instead of -k, pin the certificate:
curl --cacert ~/.teleton/api-cert.pem \
https://localhost:7778/healthzNo authentication required.
| Method | Path | Description |
|---|---|---|
| GET | /healthz |
Liveness probe — always returns { "status": "ok" } |
| GET | /readyz |
Readiness probe — 200 if agent running, 503 with setup status otherwise |
/readyz response when agent is not running:
{
"status": "not_ready",
"state": "stopped",
"setup": {
"workspace": true,
"config": true,
"wallet": true,
"telegram_session": true,
"embeddings_cached": false
}
}| Method | Path | Description |
|---|---|---|
| POST | /v1/agent/start |
Start the agent (fire-and-forget). Returns 409 if already running or stopping. |
| POST | /v1/agent/stop |
Stop the agent. Returns 409 if already stopped or starting. |
| POST | /v1/agent/restart |
Stop then start (fire-and-forget). Returns 409 during transitions. |
| GET | /v1/agent/status |
Returns { state, uptime, error } |
| GET | /v1/agent/events |
SSE stream of lifecycle state changes |
Agent states: stopped → starting → running → stopping → stopped
SSE event format (/v1/agent/events):
event: status
id: 1710312345678
data: {"state":"running","error":null,"timestamp":1710312345678}
A ping event is sent every 30 seconds to keep the connection alive.
| Method | Path | Description |
|---|---|---|
| GET | /v1/system/version |
Teleton version, Node.js version, OS, arch, API version |
| GET | /v1/system/info |
CPU model/cores/load, memory usage, process/system uptime |
Example response (/v1/system/version):
{
"teleton": "0.8.3",
"node": "v22.0.0",
"os": "linux",
"arch": "x64",
"apiVersion": "1.0.0"
}| Method | Path | Description |
|---|---|---|
| POST | /v1/auth/validate |
Validates the API key. Returns { "valid": true, "keyPrefix": "tltn_aBcD..." } |
Useful for testing connectivity and key validity without side effects.
| Method | Path | Description |
|---|---|---|
| GET | /v1/api-logs/recent?lines=100 |
Returns recent log lines (max 1000) |
| GET | /v1/api-logs/stream |
SSE stream of live log entries |
| Method | Path | Description |
|---|---|---|
| DELETE | /v1/api-memory/sessions/:chatId |
Delete a specific chat session. Returns 404 if not found. |
| POST | /v1/api-memory/sessions/prune |
Prune sessions older than N days. Body: { "maxAgeDays": 30 } (default: 30). |
| Method | Path | Description |
|---|---|---|
| GET | /v1/openapi.json |
OpenAPI 3.1 specification |
The API mounts all existing WebUI route factories under /v1/, giving you full access to every dashboard feature via HTTP:
| Prefix | Description |
|---|---|
/v1/status |
Agent status and metrics |
/v1/tools |
Tool inventory and configuration |
/v1/logs |
Conversation logs |
/v1/memory |
Memory search and management |
/v1/soul |
System prompt (read-only) |
/v1/plugins |
Plugin management |
/v1/mcp |
MCP server configuration |
/v1/workspace |
Workspace file management |
/v1/tasks |
Scheduled tasks |
/v1/config |
Configuration read/write |
/v1/marketplace |
Plugin marketplace |
/v1/hooks |
Hook management |
/v1/ton-proxy |
TON Proxy control |
/v1/setup |
Setup wizard (works without agent) |
Routes that require agent subsystems (memory, bridge, etc.) return
503with an RFC 9457 error if the agent is not running.
Three tiers of rate limiting apply to all /v1/* routes:
| Tier | Limit | Applies to |
|---|---|---|
| Global | 60 requests/min | All methods |
| Mutations | 10 requests/min | POST, PUT, DELETE |
| Reads | 300 requests/min | GET |
Rate limits are keyed per API key prefix. When exceeded, the server returns 429 Too Many Requests with a Retry-After header.
Restrict access to specific IPs via api.allowed_ips in config. When the list is empty (default), any authenticated request is accepted.
api:
allowed_ips:
- "203.0.113.10"
- "198.51.100.0/24"Non-whitelisted IPs receive 403 Forbidden. IPv4-mapped IPv6 addresses (::ffff:X.X.X.X) are normalized automatically.
- 10 failed attempts per IP within a 5-minute window triggers a 15-minute block
- Blocked IPs receive
429 Too Many RequestswithRetry-After: 900 - Failed attempt counters are cleaned up every 5 minutes
All mutating operations (POST, PUT, DELETE) are logged at warn level with:
{
"audit": true,
"event": "api_mutation",
"method": "POST",
"path": "/v1/agent/restart",
"statusCode": 200,
"durationMs": 12,
"sourceIp": "203.0.113.10",
"keyPrefix": "tltn_aBcD",
"requestId": "550e8400-e29b-41d4-a716-446655440000"
}Request bodies, headers, and secrets are never logged.
Every response includes:
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
X-Request-Id |
UUID (auto-generated or forwarded from client) |
api:
enabled: true # Enable the Management API (default: false)
port: 7778 # HTTPS port (default: 7778)
key_hash: "" # SHA-256 hash of the API key (auto-generated on first start)
allowed_ips: [] # IP whitelist (empty = allow all)| Variable | Purpose | Default |
|---|---|---|
TELETON_API_ENABLED |
Enable Management API | false |
TELETON_API_PORT |
HTTPS port | 7778 |
TELETON_JSON_CREDENTIALS |
Output credentials as JSON on startup | false |
Environment variables take precedence over config.yaml.
| Command | Description |
|---|---|
teleton start |
Start agent (API starts if api.enabled: true) |
teleton start --api |
Bootstrap mode — API only, no config needed |
teleton start --json-credentials |
Print {"apiKey","fingerprint","port"} to stdout |
teleton api-rotate-key |
Generate new API key and persist hash |
teleton api-fingerprint |
Print TLS certificate SHA-256 fingerprint |
All errors follow RFC 9457 Problem Detail with Content-Type: application/problem+json:
{
"type": "about:blank",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid API key"
}| Status | When |
|---|---|
401 |
Missing, malformed, or invalid API key |
403 |
IP not in whitelist |
409 |
Agent state conflict (e.g., start when already running) |
413 |
Request body exceeds 2MB |
429 |
Rate limit or brute-force block exceeded |
503 |
Agent subsystem not available (not started yet) |
curl -k https://localhost:7778/v1/agent/status \
-H "Authorization: Bearer $TELETON_API_KEY"curl -k https://localhost:7778/v1/agent/restart \
-X POST \
-H "Authorization: Bearer $TELETON_API_KEY"curl -k -N https://localhost:7778/v1/agent/events \
-H "Authorization: Bearer $TELETON_API_KEY"curl -k https://localhost:7778/v1/system/info \
-H "Authorization: Bearer $TELETON_API_KEY"curl -k https://localhost:7778/v1/api-memory/sessions/prune \
-X POST \
-H "Authorization: Bearer $TELETON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"maxAgeDays": 7}'curl -k https://localhost:7778/v1/auth/validate \
-X POST \
-H "Authorization: Bearer $TELETON_API_KEY"# 1. Start API-only mode
teleton start --api --json-credentials > /tmp/creds.json
# 2. Extract key
KEY=$(jq -r .apiKey /tmp/creds.json)
# 3. Check readiness (see what's missing)
curl -k https://localhost:7778/readyz
# 4. Configure via setup endpoints
curl -k https://localhost:7778/v1/setup/provider \
-X POST \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"provider":"anthropic","api_key":"sk-ant-..."}'
# 5. Start the agent
curl -k https://localhost:7778/v1/agent/start \
-X POST \
-H "Authorization: Bearer $KEY"docker run -d \
--name teleton \
--restart unless-stopped \
-e TELETON_API_ENABLED=true \
-e TELETON_JSON_CREDENTIALS=true \
-v teleton-data:/data \
-p 7777:7777 \
-p 7778:7778 \
ghcr.io/tonresistor/teleton-agentservices:
teleton:
image: ghcr.io/tonresistor/teleton-agent:latest
restart: unless-stopped
ports:
- "7777:7777" # WebUI
- "7778:7778" # Management API
volumes:
- teleton-data:/data
environment:
- TELETON_API_ENABLED=true
healthcheck:
test: ["CMD", "curl", "-kf", "https://localhost:7778/healthz"]
interval: 30s
timeout: 10s
retries: 3