REST API
Gentity exposes a small REST surface for instance lifecycle, logs, terminal, and catalog browsing. The same endpoints back the dashboard and the CLI— there's no separate internal API.
Base URL
https://gentity.ai. Override with GENTITY_API_URL when targeting a non-prod control plane.
Authentication
Every endpoint except /api/catalog/agents requires either:
- A NextAuth session cookie (set automatically when you sign in to the dashboard).
- A Bearer token:
Authorization: Bearer gn_live_…. Mint at /dashboard/settings/tokens.
Bearer wins when both are present. A missing or revoked token returns 401 Unauthorized.
Endpoints
GET /api/catalog/agents
Public. Returns the agent catalog.
200 OK
{
"agents": [
{
"id": "claude-code",
"name": "Claude Code",
"description": "Anthropic's agentic coding CLI…",
"defaultCpus": 1,
"defaultMemoryMb": 2048,
"defaultVolumeGb": 5,
"models": [
{ "provider": "anthropic", "name": "claude-sonnet-4-5", "label": "…" }
]
}
]
}GET /api/instances
List your instances.
200 OK
{
"instances": [
{
"id": "cmp8w6wf...",
"name": "Claude Code - claude-sonnet-4-5",
"subdomain": "cl-x7k2m9",
"agentType": "claude-code",
"modelProvider": "anthropic",
"modelName": "claude-sonnet-4-5",
"status": "running",
"errorMessage": null,
"createdAt": "...",
"updatedAt": "..."
}
]
}POST /api/instances
Create a new instance. Blocks until the machine is started.
Body
{
"name": "optional label",
"agentType": "claude-code",
"modelProvider": "anthropic",
"modelName": "claude-sonnet-4-5",
"apiKey": "sk-ant-...",
"region": "iad" // optional
}
200 OK
{ "id": "cmp...", "subdomain": "cl-x7k2m9", "status": "running" }GET /api/instances/<id>
Fetch one instance.
DELETE /api/instances/<id>
Destroy machine + volume.
POST /api/instances/<id>/action
Drive a lifecycle transition.
Body
{ "action": "start" | "stop" | "restart" }
200 OK
{ "ok": true }GET /api/instances/<id>/logs
One-shot logs (last ?lines=N, default 200, max 1000):
200 OK
{
"logs": [
{ "timestamp": "...", "level": "info", "message": "..." },
...
]
}With ?follow=1, returns a text/event-stream response: one Fly log line per data: frame, until the client disconnects.
GET /api/instances/<id>/terminal (WebSocket)
Upgrade to a WebSocket and pipe to flyctl ssh console inside the machine. The CLI's gentity compute ssh wraps this.
- Authentication:
?token=gn_live_...query parameter (WebSocket clients can't set Authorization headers portably). - Protocol (JSON messages):
# Client → Server
{ "type": "input", "data": "<keystrokes>" }
{ "type": "resize", "cols": N, "rows": N }
# Server → Client
{ "type": "output", "data": "..." }
{ "type": "exit", "exitCode": N, "signal": "..." }GET /api/tokens
List your active (non-revoked) tokens.
POST /api/tokens
Mint a new token. The plaintext is returned once — we only store its sha256 hash.
Body
{ "name": "laptop" }
200 OK
{
"token": "gn_live_...", ← shown once, save it now
"record": { "id": "...", "name": "laptop", "prefix": "gn_live_abc12345", "createdAt": "..." }
}DELETE /api/tokens/<id>
Revoke a token. Soft-deleted (kept for audit, but reads fail with 401).
Errors
| Status | Body | When |
|---|---|---|
400 | { "error": "..." } | Validation failure (missing fields, bad action). |
401 | { "error": "Unauthorized" } | Missing or revoked token. |
404 | { "error": "Not Found" } | Instance / token belongs to another user, or doesn't exist. |
409 | { "error": "..." } | Instance is in a state that doesn't allow the action (e.g. stop on a never-booted row). |
5xx | { "error": "<upstream message>" } | Fly Machines API or Cloudflare API failures bubbled up. |