API Reference
Thermidora API Everything you need to launch managed AI agents, send messages, and receive real-time events — all via REST.
BASE URL https://core.thermidora.com/v1
All endpoints (except /auth/* and GET /skills) require authentication. Pass your API key as X-API-Key: tc_live_... or a JWT token as Authorization: Bearer eyJ...
All endpoints require authentication via API key or JWT token.
POST /auth/register
Create a new account. An invite code is required during the beta period.
Request Body
{
"name": "string (required)",
"email": "string (required)",
"inviteCode": "string (required)"
} Response
{
"accountId": "acc_...",
"email": "user@example.com",
"name": "User Name",
"token": "eyJ..."
} POST /auth/login
Request a one-time login code sent to your email.
Request Body
{
"email": "string (required)"
} Response
{
"message": "OTP sent to email"
} POST /auth/verify
Verify the OTP code and receive a JWT token.
Request Body
{
"email": "string (required)",
"code": "string (required, 6-digit OTP)"
} Response
{
"accountId": "acc_...",
"token": "eyJ..."
} GET /auth/me
Get current account info including balance.
Response
{
"accountId": "acc_...",
"email": "user@example.com",
"name": "User Name",
"balanceUsd": 50.00
} POST /auth/keys
Create an API key for programmatic access.
Request Body
{
"name": "string (required)"
} Response
{
"keyId": "key_...",
"apiKey": "tc_live_...",
"name": "my-key"
} The apiKey value is only returned once at creation time. Store it securely.
GET /auth/keys
List all API keys for your account.
Instances An instance is a fully isolated OpenClaw runtime with dedicated compute and storage. Multiple agents can share one instance.
POST /instances
Create a new instance. Provisioning is async — poll GET /instances/:id until status is "running" (~90 seconds).
Request Body
{
"name": "string (required)"
} Response
{
"instanceId": "inst_...",
"name": "my-agents",
"status": "provisioning",
"agents": []
} GET /instances
List all instances. Status is resolved live from the underlying infrastructure.
GET /instances/:instanceId
Get instance details including live status and agent list.
Response
{
"instanceId": "inst_...",
"name": "my-agents",
"status": "running",
"agents": [
{ "agentId": "agt_...", "slug": "support-bot", "status": "active" }
],
"startedAt": "2026-04-07T...",
"totalRuntimeMs": 3600000,
"billedMs": 3600000
} Possible status values: provisioning, running, stopped, destroying, error
POST /instances/:instanceId/start
Start a stopped instance. Resumes compute — billing restarts.
Response
{ "instanceId": "inst_...", "status": "running" } POST /instances/:instanceId/stop
Stop an instance. Compute is deallocated — no charges while stopped. Storage persists.
Response
{ "instanceId": "inst_...", "status": "stopped" } DELETE /instances/:instanceId
Permanently delete an instance and all its data.
Response
{ "instanceId": "inst_...", "status": "destroying" } Agents are AI personas running inside an instance. Each gets its own workspace with persona files, memory, and skills.
POST /instances/:instanceId/agents
Create a new agent. Use useDefaults: true to seed standard workspace files, or provide custom files for full control over persona.
Request Body
{
"name": "string (required)",
"slug": "string (required, 2-32 chars, lowercase + hyphens)",
"displayName": "string (required)",
"model": "string (optional, default: moonshotai.kimi-k2.5)",
"useDefaults": true,
"files": {
"SOUL.md": "Be helpful and concise...",
"IDENTITY.md": "Name: Support Bot"
}
} Response
{
"agentId": "agt_...",
"slug": "support-bot",
"displayName": "Support Bot",
"model": "moonshotai.kimi-k2.5",
"status": "active"
} Model cannot be changed after creation. Create a new agent to use a different model.
Available models: moonshotai.kimi-k2.5, anthropic.claude-sonnet-4-20250514-v1:0
GET /instances/:instanceId/agents
List all agents in an instance.
GET /instances/:instanceId/agents/:agentId
PATCH /instances/:instanceId/agents/:agentId
Update agent name, displayName, or workspace files.
Request Body
{
"displayName": "string (optional)",
"files": {
"SOUL.md": "Updated persona..."
}
} DELETE /instances/:instanceId/agents/:agentId
Delete an agent and its workspace.
Send messages to agents and receive replies. Supports both synchronous JSON responses and real-time SSE streaming.
POST /instances/:instanceId/agents/:agentId/messages
Send a message to an agent. Include stream: true for Server-Sent Events streaming.
Request Body
{
"message": "string (required)",
"sender": {
"type": "human",
"id": "user-123",
"name": "Jeff"
},
"stream": false
} Response
{
"messageId": "msg_...",
"content": "Here's what I found...",
"sender": {
"type": "agent",
"id": "support-bot",
"name": "Support Bot"
},
"timestamp": "2026-04-07T..."
} When stream: true, the response is an SSE stream of OpenAI-compatible chat completion chunks.
Agents have persistent memory — they remember previous conversations.
GET /instances/:instanceId/agents/:agentId/messages
Get message history for an agent.
Query Parameters
limit max messages (default 50) Subscribe to real-time events from your instances. Thermidora delivers events via HTTP POST with HMAC-SHA256 signatures.
POST /webhooks
Create a webhook subscription. Optionally scope to a specific instance or agent.
Request Body
{
"url": "https://example.com/webhook (required, HTTPS only)",
"events": ["cron.completed", "agent.message"],
"instanceId": "inst_... (optional)",
"description": "string (optional)"
} Response
{
"webhookId": "wh_...",
"url": "https://example.com/webhook",
"events": ["cron.completed", "agent.message"],
"secret": "whsec_...",
"enabled": true
} Store the secret securely — it is used to verify webhook signatures.
Valid events: cron.completed, agent.message, agent.error, * (wildcard)
GET /webhooks
List all webhook subscriptions. Secrets are partially masked.
GET /webhooks/:webhookId
Get full webhook details including unmasked secret.
PATCH /webhooks/:webhookId
Enable or disable a webhook.
Request Body
{
"enabled": false
} DELETE /webhooks/:webhookId
Delete a webhook subscription.
POST /webhooks/:webhookId/test
Send a test event to verify your endpoint is reachable.
Response
{ "message": "Test event dispatched" } Query historical events for an instance — cron job results, agent messages, and errors.
GET /instances/:instanceId/events
List recent events for an instance. Filter by agent or source type.
Query Parameters
limit max events, default 50, max 200
agent filter by agent slug
source filter by source: cron, agent Response
{
"events": [
{
"messageId": "msg_...",
"content": "Bitcoin price: $69,327",
"sender": { "type": "agent", "id": "my-agent", "name": "my-agent" },
"source": "cron",
"createdAt": "2026-04-07T09:00:00.000Z",
"agentSlug": "my-agent"
}
],
"total": 1
} Skills extend what agents can do — weather, web search, code execution, and more. Install built-in skills or upload custom ones.
GET /skills
List all available built-in skills. No authentication required.
Response
[
{
"id": "weather",
"name": "Weather",
"description": "Get current weather and forecasts",
"type": "built-in"
}
] POST /instances/:instanceId/skills
Install a built-in skill or upload a custom skill with files.
Request Body
// Built-in:
{ "name": "weather", "type": "built-in" }
// Custom:
{
"name": "my-skill",
"description": "Custom skill",
"files": {
"SKILL.md": "# My Skill\n...",
"scripts/run.py": "#!/usr/bin/env python3\n..."
}
} Custom skills must include a SKILL.md file. All agents in the instance share installed skills.
GET /instances/:instanceId/skills
List skills installed on an instance.
DELETE /instances/:instanceId/skills/:name
Store integration secrets (API keys, tokens) securely. Secrets are injected as environment variables into the instance runtime.
GET /instances/:instanceId/secrets
List secret keys. Values are never exposed.
Response
{
"secrets": [
{ "key": "OPENAI_API_KEY" },
{ "key": "SLACK_TOKEN" }
]
} POST /instances/:instanceId/secrets
Store one or more secrets. Triggers an instance restart to inject them.
Request Body
{
"secrets": {
"OPENAI_API_KEY": "sk-...",
"SLACK_TOKEN": "xoxb-..."
}
} Response
{ "stored": 2, "restarting": true } DELETE /instances/:instanceId/secrets/:key
Events are delivered as HTTP POST requests to your registered URL with HMAC-SHA256 signatures for verification.
Delivery Headers
X-Thermidora-SignatureHMAC-SHA256 hash of the request body
X-Thermidora-EventEvent type (e.g. cron.completed)
X-Thermidora-Webhook-IdYour webhook subscription ID
Example Payload
{
"eventType": "cron.completed",
"instanceId": "inst_a1b2c3d4e5f6",
"agentSlug": "my-agent",
"data": {
"content": "Bitcoin price: $69,327 USD",
"jobName": "bitcoin-price-check"
},
"timestamp": "2026-04-07T09:00:00.000Z"
} Signature Verification (Node.js)
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(body))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Usage:
const sig = req.headers['x-thermidora-signature'];
const valid = verifySignature(req.body, sig, webhookSecret); Errors All errors follow a consistent format:
{
"error": {
"code": "not_found",
"message": "Instance not found",
"status": 404
}
} 400 invalid_requestMissing or invalid parameters
401 unauthorizedMissing or invalid auth token
404 not_foundResource not found or not owned by you
409 conflictDuplicate resource (e.g. agent slug exists)
503 instance_not_readyInstance is not running
500 internal_errorUnexpected server error
Rate Limits During beta, rate limits are generous. If you hit limits, you'll receive a 429 Too Many Requests response with a Retry-After header.
Ready to build? Get your API key and launch your first agent in under a minute.