API Reference
The Centter API is served at /api/v1. All endpoints return JSON.
Authenticated endpoints require a Bearer JWT token in the Authorization header.
Health
GET /api/v1/health
Health check. No authentication required.
// Response 200
{
"status": "ok",
"version": "0.2.0",
"uptime": 3600
} Auth
POST /api/v1/auth/register
Create a new user account.
| Auth | None |
|---|---|
| Status | 201 Created, 400 Missing fields, 409 Email exists |
// Request
{ "email": "user@example.com", "name": "Alice", "password": "secret123" }
// Response 201
{
"token": "eyJ...",
"user": { "id": "uuid", "email": "user@example.com", "name": "Alice" }
} POST /api/v1/auth/login
Authenticate and receive a JWT token (7-day expiry).
| Auth | None |
|---|---|
| Status | 200 OK, 401 Invalid credentials |
// Request
{ "email": "user@example.com", "password": "secret123" }
// Response 200
{
"token": "eyJ...",
"user": { "id": "uuid", "email": "user@example.com", "name": "Alice" }
} POST /api/v1/auth/api-key
Generate an API key for programmatic access.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK |
// Response 200
{ "api_key": "amk_...", "user_id": "uuid" } Networks
POST /api/v1/networks
Create a new network. A slug is generated from the name.
| Auth | Bearer JWT |
|---|---|
| Status | 201 Created, 400 Missing name, 409 Slug exists |
// Request
{ "name": "My Network" }
// Response 201
{ "id": "uuid", "owner_id": "uuid", "name": "My Network", "slug": "my-network", "created_at": "..." } GET /api/v1/networks
List all networks owned by the authenticated user.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK |
// Response 200
[
{ "id": "uuid", "name": "My Network", "slug": "my-network", "agent_count": "3", "team_count": "1", ... }
] GET /api/v1/networks/:id
Get network details including agent count, team count, and unassigned agent count.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200
{
"id": "uuid", "name": "My Network", "slug": "my-network",
"agent_count": "7", "team_count": "1", "unassigned_count": "0",
"transport_mode": "both", "smart_routing": true,
"previous_transport_config": null, ...
} PUT /api/v1/networks/:id
Update network settings. When transport_mode changes, saves previous config and recalculates all routes.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 400 Invalid transport_mode, 404 Not found |
// Request
{ "transport_mode": "http_jwt" }
// Response 200 (when transport changes)
{
"id": "uuid", "transport_mode": "http_jwt",
"routing_summary": { "vpc_internal": 4, "tailscale": 0, "public_https": 6 }
} GET /api/v1/networks/:id/transport
Get transport configuration and agent counts by transport mode.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200
{
"transport_mode": "both",
"require_jwt": false,
"jwks_url": "/api/v1/networks/uuid/.well-known/jwks.json",
"agent_count_by_transport": { "tailscale": 4, "http_jwt": 2 }
} GET /api/v1/networks/:id/routing-table
Get the full routing table with summary counts by route type.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200
{
"network": { "id": "uuid", "name": "Coinsenda Agents", "smart_routing": true },
"summary": { "vpc_internal": 12, "tailscale": 42, "public_https": 0 },
"routes": [
{ "source": "Linda", "target": "Sol", "type": "vpc_internal", "endpoint": "http://10.10.1.20:8080/a2a", "jwt_required": false }
]
} GET /api/v1/networks/:id/dns
List all DNS records for agents in a network.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200
{
"network": "Coinsenda Agents",
"domain": "coinsenda.mesh.coinsenda.ai",
"records": [
{ "agent_id": "uuid", "agent": "Linda", "fqdn": "linda.coinsenda.mesh.coinsenda.ai", "ip": "54.1.2.3", "status": "active" }
]
} GET /api/v1/networks/:id/discover
Discover agents in a network. Filter by capability, status, transport, role, or skill name. Returns agents from the NATS registry (falls back to DB).
| Auth | Bearer JWT |
|---|---|
| Query | capability, status (online|offline|any), transport (nats|http|any), role, skill |
| Status | 200 OK, 404 Not found |
// GET /api/v1/networks/:id/discover?capability=deploy&status=online
// Response 200
{
"agents": [
{ "id": "uuid", "name": "Sol", "status": "online", "skills": ["coinsenda-devops"], "transport": "nats", "model": "claude-sonnet-4-6" }
],
"query": { "capability": "deploy", "status": "online", "transport": null, "role": null, "skill": null },
"total": 1
} GET /api/v1/networks/:id/presence
Real-time agent presence from NATS (not DB). Shows which agents are online, their transport, and last heartbeat.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200
{
"agents": [
{ "id": "uuid", "name": "Linda", "status": "online", "transport": "nats", "last_heartbeat": "2026-03-06T19:25:00Z" }
],
"online_count": 7,
"total_count": 7
} Agents
POST /api/v1/networks/:networkId/agents
Register a new agent in a network.
| Auth | Bearer JWT |
|---|---|
| Status | 201 Created, 400 Missing name, 404 Network not found |
// Request
{ "name": "translator", "description": "Translates text", "endpoint_url": "https://agent.example.com" }
// Response 201
{
"id": "uuid", "network_id": "uuid", "name": "translator", "status": "active",
"api_key": "amk_a1b2c3...64hex", // returned ONCE — save immediately
...
} Note: The api_key is returned only at creation time. Store it securely — it cannot be retrieved later. Only the SHA-256 hash is persisted.
POST /api/v1/agents/:id/regenerate-key
Generate a new API key for an agent, invalidating the previous key.
| Auth | Bearer JWT |
|---|---|
| Status | 201 Created, 404 Agent not found |
// Response 201
{ "api_key": "amk_...", "agent_id": "uuid" } The new key is returned once. The old key is immediately invalidated.
GET /api/v1/networks/:networkId/agents
List all agents in a network.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK |
GET /api/v1/agents/:id
Get agent details.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
PUT /api/v1/agents/:id
Update agent fields. All fields are optional (uses COALESCE).
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Not found |
// Request (all optional)
{ "name": "...", "description": "...", "endpoint_url": "...", "tailscale_ip": "...", "status": "...", "agent_card": {...} } DELETE /api/v1/agents/:id
Delete an agent permanently.
| Auth | Bearer JWT |
|---|---|
| Status | 204 No Content, 404 Not found |
POST /api/v1/agents/:id/heartbeat
Agent heartbeat — updates last_seen_at.
| Auth | X-Agent-Key header |
|---|---|
| Status | 200 OK, 401 Missing key, 404 Agent not found |
// Response 200
{ "ok": true } GET /api/v1/agents/:id/peers
Get routes to all peer agents in the same network. Uses cached routes if available, otherwise calculates on-the-fly.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Agent not found |
// Response 200
{
"agent": { "id": "uuid", "name": "Linda" },
"peers": [
{
"agent_id": "uuid",
"name": "Sol",
"routes": [
{ "route_type": "vpc_internal", "endpoint": "http://10.10.1.20:8080/a2a", "jwt_required": false, "priority": 0 },
{ "route_type": "tailscale", "endpoint": "http://100.101.45.76:8080/a2a", "jwt_required": false, "priority": 1 }
],
"best_route": { "route_type": "vpc_internal", "endpoint": "http://10.10.1.20:8080/a2a", "jwt_required": false }
}
]
} POST /api/v1/agents/:id/token
Issue a long-lived agent-to-agent token for direct communication.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Agent not found |
// Request
{ "target_agent_id": "uuid", "scopes": ["skill:execute:translate"] }
// Response 200
{ "token": "eyJ...", "expires_in": 86400 } GET /api/v1/agents/:id/connections
Get ego-centric connection graph showing peer cards with routes, scopes, and skills.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Agent not found |
// Response 200
{
"agent": { "id": "uuid", "name": "Linda", "skills": ["weather", "search"] },
"peers": [
{
"id": "uuid", "name": "Sol",
"route": { "type": "vpc_internal", "endpoint": "http://10.10.1.20:8080/a2a" },
"scopes": ["skill:execute:*"],
"skills": ["coding-agent"]
}
]
} GET /api/v1/agents/:id/card
Get agent's A2A Agent Card (public, no auth).
| Auth | None |
|---|---|
| Status | 200 OK, 404 Not found |
// Response 200 (custom card or fallback)
{ "name": "translator", "description": "...", "url": "https://agent.example.com", "version": "1.0" } POST /api/v1/agents/:id/dns
Create or update DNS record for an agent. Sets the agent's subdomain to the specified IP.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 400 Invalid IP, 404 Agent not found |
// Request
{ "ip": "52.14.50.118" }
// Response 200
{ "fqdn": "sol.coinsenda-agents.mesh.coinsenda.ai", "ip": "52.14.50.118", "status": "ok" } DELETE /api/v1/agents/:id/dns
Remove DNS record for an agent.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Agent not found |
// Response 200
{ "status": "removed" } POST /api/v1/agents/:id/message
Send a message to another agent. Server relays via NATS if target is connected, otherwise queues for HTTP delivery.
| Auth | Bearer JWT |
|---|---|
| Status | 201 Created, 400 Validation, 403 No permission, 404 Agent not found |
// Request
{ "to": "target-agent-uuid", "text": "Hello from Sol" }
// Response 201
{ "ok": true, "message_id": "uuid", "transport": "nats", "delivered": true } Routing
Routing endpoints are under the Networks section: GET /networks/:id/routing-table, GET /networks/:id/presence, PUT /networks/:id (transport mode), and GET /networks/:id/transport.
Route types: nats (priority -1, no JWT), vpc_internal (priority 0, no JWT), tailscale (priority 1, no JWT), public_https (priority 2, JWT required).
Permissions
GET /api/v1/scope-templates
Get available scope templates for quick permission assignment.
| Auth | None |
|---|---|
| Status | 200 OK |
// Response 200
[
{ "pattern": "skill:execute:*", "description": "Execute any skill" },
{ "pattern": "skill:read:*", "description": "Read any skill data" },
{ "pattern": "infra:*", "description": "Full infrastructure access" },
{ "pattern": "newsletter:send", "description": "Send newsletters" },
{ "pattern": "*", "description": "Full access (admin)" }
] POST /api/v1/networks/:networkId/permissions
Grant a permission between two agents.
| Auth | Bearer JWT |
|---|---|
| Status | 201 Created, 400 Missing fields, 409 Duplicate |
// Request
{ "requester_agent_id": "uuid", "target_agent_id": "uuid", "scope": "skill:execute:translate" }
// Response 201
{ "id": "uuid", "network_id": "uuid", "requester_agent_id": "...", "target_agent_id": "...", "scope": "..." } GET /api/v1/networks/:networkId/permissions
List permissions in matrix format (grouped by requester → target).
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK |
// Response 200
{
"permissions": [
{
"requester": { "id": "uuid", "name": "Agent A" },
"target": { "id": "uuid", "name": "Agent B" },
"scopes": ["skill:execute:*", "skill:read:*"],
"permission_ids": ["uuid1", "uuid2"]
}
],
"raw": [...]
} GET /api/v1/role-scopes
Get all role templates and their default scopes. Used for role-based auto-grant.
| Auth | None |
|---|---|
| Status | 200 OK |
// Response 200
[
{ "role": "assistant", "scopes": ["skill:execute:*", "skill:read:*"] },
{ "role": "developer", "scopes": ["skill:execute:*", "skill:read:*", "skill:write:*", "infra:*"] },
{ "role": "analyst", "scopes": ["skill:read:*"] }
] GET /api/v1/networks/:networkId/agents/:agentId/effective-permissions
Get an agent's effective permissions — all granted scopes from roles and manual grants.
| Auth | Bearer JWT |
|---|---|
| Status | 200 OK, 404 Agent/Network not found |
// Response 200
{
"agent_id": "uuid",
"permissions": [
{ "scope": "skill:execute:*", "source": "role:developer", "auto_granted": true },
{ "scope": "newsletter:send", "source": "manual", "auto_granted": false }
]
} DELETE /api/v1/permissions/:id
Revoke a permission.
| Auth | Bearer JWT |
|---|---|
| Status | 204 No Content, 404 Not found |
Authority
GET /api/v1/networks/:networkId/.well-known/jwks.json
Public JWKS endpoint for token verification.
| Auth | None |
|---|---|
| Status | 200 OK |
// Response 200
{
"keys": [
{ "kty": "EC", "crv": "P-256", "x": "...", "y": "...", "kid": "uuid", "use": "sig" }
]
} POST /api/v1/networks/:networkId/auth/token
Issue an ES256-signed JWT token for an agent. Scopes are filtered against granted permissions. The token is signed with the network's EC P-256 authority key; verify it via the JWKS endpoint above.
| Auth | None (agent API key) |
|---|---|
| Algorithm | ES256 (EC P-256) |
| Status | 200 OK, 400 Missing fields, 403 Agent not found/inactive/invalid key |
// Request
{ "agent_id": "uuid", "api_key": "amk_...", "scopes": ["skill:execute:translate"] }
// Response 200
{ "token": "eyJ...", "expires_in": 3600 }
// Token header: { "alg": "ES256", "kid": "uuid" }
// Verify via: GET /networks/:networkId/.well-known/jwks.json NATS JWT + Accounts
Multi-tenant NATS authentication. Each Network maps to a NATS Account, each Agent to a NATS User with role-based permissions.
POST /api/v1/networks/:networkId/nats/account
Create a NATS account for a network. One account per network — enables JWT auth for agents.
| Auth | Bearer JWT (network owner) |
|---|---|
| Status | 201 Created, 404 Network not found, 409 Already exists |
// Response 201
{ "account_name": "net-a1b2c3d4-My_Network", "account_key": "AABC..." } POST /api/v1/agents/:id/nats/credentials
Generate NATS credentials (.creds file) for an agent. Returned once — save immediately. Role-based permissions embedded.
| Auth | Bearer JWT (network owner) |
|---|---|
| Status | 201 Created, 400 No NATS account, 403 Not authorized, 404 Not found |
// Response 201
{ "user_name": "agent-a1b2c3d4-Linda", "public_key": "UABC...",
"role": "coordinator", "permissions": { "pub": [...], "sub": [...] },
"creds": "-----BEGIN NATS USER JWT-----\n..." } PUT /api/v1/agents/:id/nats/permissions
Update agent NATS permissions by role. Returns new creds — agent must reconnect.
| Auth | Bearer JWT (network owner) |
|---|---|
| Body | {"role": "developer"} — coordinator, developer, analyst, support, assistant |
| Status | 200 OK, 400 Invalid role / no creds, 403 Not authorized |
DELETE /api/v1/agents/:id/nats/credentials
Revoke agent NATS access immediately.
Auth Bearer JWT (network owner) Status 200 OK, 400 No creds, 403 Not authorized
GET /api/v1/networks/:networkId/nats/status
NATS account status — shows JWT vs token auth per agent, migration progress.
Auth Bearer JWT (network owner) Status 200 OK
// Response 200
{ "status": "configured", "auth_mode": "mixed",
"summary": { "total": 7, "jwt_auth": 5, "token_auth": 2, "migration_complete": false } }
POST /api/v1/networks/:networkId/authority/rotate
Rotate the network's authority signing keys (EC P-256).
Auth Bearer JWT Status 201 Created, 404 Network not found
// Response 201
{ "kid": "uuid", "message": "Key rotated successfully" }
Audit
GET /api/v1/networks/:networkId/audit
Query audit log entries with pagination and filters.
Auth Bearer JWT Query action, requester, from, to, limit (max 200), offset Status 200 OK, 404 Network not found
// Response 200
{
"entries": [
{ "id": "uuid", "action": "permission.grant", "requester": "uuid", "target": "uuid", "scopes": [...], "result": "granted", "ip": "...", "created_at": "..." }
],
"total": 42,
"limit": 50,
"offset": 0
}
GET /api/v1/networks/:networkId/audit/export
Export audit log as CSV.
Auth Bearer JWT Query action, requester, from, to Status 200 OK (text/csv)
Content-Type: text/csv
Content-Disposition: attachment; filename=audit-log.csv
timestamp,action,requester,target,scopes,result,ip
"2025-01-01T00:00:00.000Z","permission.grant","uuid","uuid","skill:execute:*","granted","127.0.0.1"
Teams
POST /api/v1/teams
Create a team. Auto-creates a network if network_id is not provided.
Auth Bearer JWT Status 201 Created, 400 Missing name / BYOK needs key, 404 Network not found
// Request
{
"name": "My Team",
"plan": "starter",
"api_key_mode": "byok",
"anthropic_api_key": "sk-ant-...",
"network_id": "uuid" // optional
}
// Response 201
{ "id": "uuid", "name": "My Team", "slug": "my-team-abc123", "plan": "starter", "api_key_mode": "byok", "anthropic_api_key_encrypted": "***", "network_name": "...", ... }
GET /api/v1/teams
List teams. Optionally filter by ?network_id=uuid.
Auth Bearer JWT Status 200 OK
// Response 200
[
{ "id": "uuid", "name": "My Team", "plan": "starter", "agent_count": "3", "network_name": "...", ... }
]
GET /api/v1/teams/:id
Team detail with list of agents.
Auth Bearer JWT Status 200 OK, 404 Not found
// Response 200
{
"id": "uuid", "name": "My Team", ...,
"agents": [
{ "id": "uuid", "agent_name": "Bot A", "role": "assistant", "deploy_status": "ready", ... }
]
}
PUT /api/v1/teams/:id
Update team settings (name, API key mode).
Auth Bearer JWT Status 200 OK, 404 Not found
// Request (all optional)
{ "name": "New Name", "api_key_mode": "byok", "anthropic_api_key": "sk-ant-..." }
DELETE /api/v1/teams/:id
Soft-delete a team. All agents are marked as terminated.
Auth Bearer JWT Status 204 No Content, 404 Not found
Team Agents
GET /api/v1/templates/roles
Get available agent role templates (assistant, sales, support, developer, analyst, coordinator).
Auth None Status 200 OK
GET /api/v1/plan-limits
Get agent limits per plan tier.
Auth None Status 200 OK
// Response 200
{
"starter": { "maxAgents": 2 },
"team": { "maxAgents": 5 },
"business": { "maxAgents": 15 },
"enterprise": { "maxAgents": 999 }
}
POST /api/v1/teams/:teamId/agents
Add a new agent to a team. Validates role, plan limits, and optional Telegram bot token.
Auth Bearer JWT Status 201 Created, 400 Invalid, 403 Plan limit, 404 Team not found
// Request
{ "name": "Sales Bot", "role": "sales", "telegram_bot_token": "123:ABC...", "personality": "Custom soul text", "model": "claude-sonnet-4-20250514" }
// Response 201
{ "id": "uuid", "team_id": "uuid", "agent_id": "uuid", "role": "sales", "deploy_status": "pending", "agent_name": "Sales Bot", ... }
POST /api/v1/teams/:teamId/agents/assign
Assign an existing agent (from the same network) to a team.
Auth Bearer JWT Status 201 Created, 404 Agent not found, 409 Already assigned, 403 Plan limit
// Request
{ "agent_id": "uuid" }
// Response 201
{ "id": "uuid", "deploy_status": "ready", "agent_name": "...", ... }
DELETE /api/v1/teams/:teamId/agents/:id/unassign
Remove agent from team without terminating it. Agent stays in the network.
Auth Bearer JWT Status 204 No Content, 404 Not found
POST /api/v1/teams/:teamId/agents/:id/deploy
Trigger agent deployment (EC2 provisioning). Agent must be in pending or failed state.
Auth Bearer JWT Status 200 OK, 400 Already deployed, 404 Not found
// Response 200
{ "id": "uuid", "deploy_status": "provisioning" }
GET /api/v1/teams/:teamId/agents/:id/status
Get deploy status and logs for a team agent.
Auth Bearer JWT Status 200 OK, 404 Not found
// Response 200
{
"id": "uuid", "deploy_status": "ready", "agent_name": "Bot",
"logs": [
{ "step": "provisioning", "status": "completed", "message": "..." },
{ "step": "installing", "status": "completed", "message": "..." }
]
}
GET /api/v1/teams/:teamId/agents/:id/logs
Get deployment logs only.
Auth Bearer JWT Status 200 OK
GET /api/v1/teams/:teamId/agents/:id/metrics
Get agent metrics: uptime, status (online/degraded/offline/stopped), deploy duration.
Auth Bearer JWT Status 200 OK, 404 Not found
// Response 200
{
"uptime_seconds": 86400,
"last_seen": "2025-01-15T12:00:00.000Z",
"status": "online",
"deploy_duration_seconds": 45,
"deploy_status": "ready",
"agent_name": "Sales Bot",
"model": "claude-sonnet-4-20250514"
}
PUT /api/v1/teams/:teamId/agents/:id/config
Update agent configuration (soul, model, role, name).
Auth Bearer JWT Status 200 OK, 404 Not found
// Request (all optional)
{ "soul": "New personality text", "model": "claude-sonnet-4-20250514", "role": "support", "name": "New Name" }
POST /api/v1/teams/:teamId/agents/:id/stop
Stop a running agent. Must be in ready state.
Auth Bearer JWT Status 200 OK, 400 Not ready, 404 Not found
// Response 200
{ "id": "uuid", "deploy_status": "stopped" }
POST /api/v1/teams/:teamId/agents/:id/start
Start a stopped agent. Must be in stopped state.
Auth Bearer JWT Status 200 OK, 400 Not stopped, 404 Not found
// Response 200
{ "id": "uuid", "deploy_status": "ready" }
POST /api/v1/teams/:teamId/agents/:id/restart
Restart an agent (terminate + reset to pending). Must be in ready, stopped, or failed state.
Auth Bearer JWT Status 200 OK, 400 Invalid state, 404 Not found
// Response 200
{ "id": "uuid", "deploy_status": "pending", "message": "Agent reset. Deploy again to restart." }
DELETE /api/v1/teams/:teamId/agents/:id
Terminate an agent (stops EC2 instance, marks as terminated).
Auth Bearer JWT Status 204 No Content, 404 Not found
GET /api/v1/teams/:teamId/usage
Get team usage data with cost estimates.
Auth Bearer JWT Query from, to (ISO date, default last 30 days) Status 200 OK, 404 Team not found
// Response 200
{
"usage": [
{ "team_agent_id": "uuid", "date": "2025-01-15", "uptime_minutes": 60, "heartbeat_count": 12, "agent_name": "Bot" }
],
"summary": {
"total_uptime_minutes": 1440,
"total_heartbeats": 288,
"cost_estimate_usd": "14.40",
"from": "2024-12-16",
"to": "2025-01-15"
}
}
GET /api/v1/teams/:teamId/agents/:id/detail
Full agent detail for the agent detail page — includes skills, permissions, config, and metrics.
Auth Bearer JWT Status 200 OK, 404 Not found
// Response 200
{
"id": "uuid", "agent_name": "Sales Bot", "role": "sales",
"deploy_status": "ready", "model": "claude-sonnet-4-6",
"reported_skills": ["weather"], "reported_tools": ["web_search"],
"permissions": [...], "metrics": { "uptime_seconds": 86400, "status": "online" }
}
POST /api/v1/teams/:teamId/agents/:id/heartbeat
Team agent heartbeat. Updates last_seen_at and increments daily usage.
Auth None Status 200 OK, 404 Team agent not found
// Response 200
{ "status": "ok" }
Marketplace Skills
GET /api/v1/marketplace/skills
Browse marketplace skills with search, category filter, sorting, and pagination.
Auth None Query category, search, sort (popular|newest|rating), page, limit Status 200 OK
// Response 200
{
"skills": [
{ "id": "uuid", "name": "Translate Pro", "slug": "translate-pro", "category": "connectors", "install_count": 150, "rating": "4.50", ... }
],
"total": 42,
"page": 1,
"pages": 3
}
GET /api/v1/marketplace/skills/:slug
Get skill detail with versions, reviews, and publisher info.
Auth None Status 200 OK, 404 Not found
// Response 200
{
"id": "uuid", "name": "Translate Pro", ...,
"versions": [{ "version": "2.0.0", "changelog": "..." }],
"reviews": [{ "rating": 5, "comment": "Great!", "user_name": "Alice" }]
}
POST /api/v1/marketplace/skills
Create a new skill (must be a publisher).
Auth Bearer JWT (publisher) Status 201 Created, 400 Missing name, 403 Not publisher, 409 Slug taken
// Request
{
"name": "Translate Pro",
"description": "AI translation skill",
"category": "connectors",
"scopes_required": ["skill:execute:translate"],
"pricing_type": "free"
}
PUT /api/v1/marketplace/skills/:id
Update a skill (owner only).
Auth Bearer JWT (skill owner) Status 200 OK, 404 Not found
POST /api/v1/marketplace/skills/:id/versions
Publish a new version of a skill.
Auth Bearer JWT (skill owner) Status 201 Created, 400 Missing version, 404 Skill not found
// Request
{ "version": "2.0.0", "changelog": "Added batch translation", "package_url": "https://..." }
// Response 201
{ "id": "uuid", "skill_id": "uuid", "version": "2.0.0", "changelog": "..." }
GET /api/v1/marketplace/skills/:id/versions
List all versions of a skill.
Auth None Status 200 OK
Installs
POST /api/v1/agents/:agentId/skills/install
Install a skill on an agent. Auto-grants permissions for required scopes.
Auth Bearer JWT Status 201 Created, 404 Agent/Skill not found, 409 Already installed
// Request
{ "skill_id": "uuid" }
// Response 201
{ "ok": true, "skill": "Translate Pro", "version": "1.0.0" }
DELETE /api/v1/agents/:agentId/skills/:skillId
Uninstall a skill. Revokes auto-granted permissions and decrements install count.
Auth Bearer JWT Status 204 No Content, 404 Not found
GET /api/v1/agents/:agentId/skills
List skills installed on an agent.
Auth Bearer JWT Status 200 OK, 404 Agent not found
// Response 200
[
{ "agent_id": "uuid", "skill_id": "uuid", "name": "Translate Pro", "installed_version": "1.0.0", "publisher_name": "..." }
]
Reviews
POST /api/v1/marketplace/skills/:id/reviews
Add a review for a skill. Recalculates average rating.
Auth Bearer JWT Status 201 Created, 400 Invalid rating, 404 Skill not found, 409 Already reviewed
// Request
{ "rating": 5, "comment": "Great skill!" }
// Response 201
{ "id": "uuid", "skill_id": "uuid", "rating": 5, "comment": "Great skill!" }
GET /api/v1/marketplace/skills/:id/reviews
List reviews for a skill.
Auth None Status 200 OK
Publishers
POST /api/v1/publishers
Become a publisher (one per user).
Auth Bearer JWT Status 201 Created, 400 Missing name, 409 Already publisher / slug taken
// Request
{ "name": "My Org", "bio": "We build AI tools", "website": "https://example.com" }
// Response 201
{ "id": "uuid", "name": "My Org", "slug": "my-org", ... }
GET /api/v1/publishers/:slug
Get public publisher profile with skill count.
Auth None Status 200 OK, 404 Not found
GET /api/v1/publishers
Get the current user's publisher profile (or null if not a publisher).
Auth Bearer JWT Status 200 OK
PUT /api/v1/publishers/:id
Update publisher profile.
Auth Bearer JWT (owner) Status 200 OK, 404 Not found
// Request (all optional)
{ "name": "Updated Org", "bio": "...", "website": "..." }