REST API
The Hot REST API provides programmatic access to manage projects, builds, runs, events, and more.
Base URL
https://api.hot.dev/api/v1
For local development:
http://localhost:4681/v1
Authentication
All API requests (except health checks) require authentication via an API key:
curl https://api.hot.dev/api/v1/projects \
-H "Authorization: Bearer $HOT_API_KEY"
Creating API Keys
Create API keys in the dashboard under Settings → API Keys.
API keys are scoped to environments. All resources accessed through an API key are automatically filtered to that environment.
Response Format
All responses use a consistent envelope format.
Success Response (Single Item)
{
"data": {
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "my-project"
},
"meta": {
"request_id": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2024-01-15T10:30:00Z"
}
}
Success Response (List)
{
"data": [...],
"pagination": {
"total": 42,
"limit": 20,
"offset": 0,
"has_more": true
},
"meta": {
"request_id": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2024-01-15T10:30:00Z"
}
}
Error Response
{
"error": {
"code": "not_found",
"message": "Project not found",
"request_id": "123e4567-e89b-12d3-a456-426614174000"
}
}
Pagination
List endpoints support pagination via query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 20 | Maximum results to return |
offset | int | 0 | Number of results to skip |
Endpoints
Health & Status
Get API Status
GET /status
Returns API server health information. No authentication required.
Response:
{
"status": "ok",
"service": "hot.dev api server",
"start_time": "2024-01-15T10:00:00Z",
"git_sha": "abc123"
}
Projects
List Projects
GET /v1/projects
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | int | Max results (default: 20) |
offset | int | Pagination offset |
Response:
{
"data": [
{
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"env_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "my-project",
"active": true,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"pagination": {...},
"meta": {...}
}
Create Project
POST /v1/projects
Request Body:
{
"name": "my-project"
}
Response: 201 Created with project data.
Get Project
GET /v1/projects/{project_id_or_slug}
Supports both UUID and project name (slug) in the URL.
Update Project
PATCH /v1/projects/{project_id_or_slug}
Request Body:
{
"name": "new-project-name"
}
Delete Project
DELETE /v1/projects/{project_id_or_slug}
Response: 204 No Content
Builds
List Builds (All in Environment)
GET /v1/builds
Lists all builds across all projects in the environment.
Response includes project_name for each build.
List Builds (By Project)
GET /v1/projects/{project_id_or_slug}/builds
Get Build
GET /v1/projects/{project_id_or_slug}/builds/{build_id}
Response:
{
"data": {
"build_id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": "660e8400-e29b-41d4-a716-446655440000",
"hash": "abc123def456",
"size": 102400,
"build_type": "bundle",
"deployed": false,
"active": true,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"storage_path": "s3://builds/...",
"storage_backend": "s3"
},
"meta": {...}
}
Get Deployed Build
GET /v1/projects/{project_id_or_slug}/builds/deployed
Returns the currently deployed build for the project, or 404 if none.
Get Live Build
GET /v1/projects/{project_id_or_slug}/builds/live
Returns the live (development) build for the project, or 404 if none.
Upload Build
POST /v1/projects/{project_id_or_slug}/builds
Content-Type: multipart/form-data
Form Fields:
| Field | Required | Description |
|---|---|---|
file | Yes | The build zip file |
hash | Yes | SHA hash of the build for validation |
build_id | No | Optional UUID; if provided, enables idempotent uploads |
Response: 201 Created
{
"data": {
"build_id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": "660e8400-e29b-41d4-a716-446655440000",
"hash": "abc123def456",
"size": 102400,
"storage_path": "s3://builds/...",
"storage_backend": "s3",
"created_at": "2024-01-15T10:30:00Z"
},
"meta": {...}
}
If the build_id already exists, returns 200 OK with header X-Build-Exists: true.
Download Build
GET /v1/projects/{project_id_or_slug}/builds/{build_id}/download
Returns the build as a zip file with Content-Type: application/zip.
Deploy Build
POST /v1/projects/{project_id_or_slug}/builds/{build_id}/deploy
Marks the build as deployed and queues it for worker processing.
Context Variables (Secrets)
Context variables are encrypted secrets stored per-project. Values are encrypted at rest using AES-256-GCM.
Security: Values are never returned via API—only metadata (key, description, timestamps).
List Context Variables
GET /v1/projects/{project_id_or_slug}/context
Response:
{
"data": [
{
"key": "DATABASE_URL",
"description": "Production database connection",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"pagination": {...},
"meta": {...}
}
Create Context Variable
POST /v1/projects/{project_id_or_slug}/context
Request Body:
{
"key": "DATABASE_URL",
"value": "postgres://user:pass@host/db",
"description": "Production database connection"
}
Response: 201 Created (value is not returned).
Update Context Variable
PUT /v1/projects/{project_id_or_slug}/context/{key}
Request Body:
{
"value": "postgres://user:newpass@host/db",
"description": "Updated description"
}
Delete Context Variable
DELETE /v1/projects/{project_id_or_slug}/context/{key}
Response: 204 No Content
Events
Publish Event
POST /v1/events
Publishes an event that can trigger event handlers.
Request Body:
{
"event_type": "user.signup",
"event_data": {
"user_id": "123",
"email": "alice@example.com"
}
}
Response: 201 Created
{
"data": {
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"env_id": "660e8400-e29b-41d4-a716-446655440000",
"stream_id": "770e8400-e29b-41d4-a716-446655440000",
"event_type": "user.signup",
"event_data": {...},
"event_time": "2024-01-15T10:30:00Z",
"created_at": "2024-01-15T10:30:00Z"
},
"meta": {...}
}
List Events
GET /v1/events
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | int | Max results (default: 20) |
offset | int | Pagination offset |
Get Event
GET /v1/events/{event_id}
Get Runs for Event
GET /v1/events/{event_id}/runs
Returns all runs triggered by this event.
Runs
List Runs
GET /v1/runs
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | int | Max results (default: 20) |
offset | int | Pagination offset |
status | string | Filter: running, succeeded, failed, cancelled |
type | string | Filter: call, event, schedule, run, eval, repl |
time_range | string | ISO 8601 duration: P7D, P30D, etc. |
Response:
{
"data": [
{
"run_id": "550e8400-e29b-41d4-a716-446655440000",
"env_id": "660e8400-e29b-41d4-a716-446655440000",
"stream_id": "770e8400-e29b-41d4-a716-446655440000",
"build_id": "880e8400-e29b-41d4-a716-446655440000",
"run_type": "event",
"status": "succeeded",
"start_time": "2024-01-15T10:30:00Z",
"stop_time": "2024-01-15T10:30:45Z",
"origin_run_id": null,
"event_id": "990e8400-e29b-41d4-a716-446655440000",
"result": {...},
"project_id": "aa0e8400-e29b-41d4-a716-446655440000",
"project_name": "my-project"
}
],
"pagination": {...},
"meta": {...}
}
Get Run
GET /v1/runs/{run_id}
Get Run Variables
GET /v1/runs/{run_id}/vars
Returns variables captured during run execution.
Response:
{
"data": [
{
"var_id": "550e8400-e29b-41d4-a716-446655440000",
"run_id": "660e8400-e29b-41d4-a716-446655440000",
"ns": "::myapp::users",
"var": "current-user",
"value": {...},
"meta": {...},
"start_time": "2024-01-15T10:30:00Z",
"stop_time": "2024-01-15T10:30:01Z"
}
],
"pagination": {...},
"meta": {...}
}
Get Run Statistics
GET /v1/runs/stats
Response:
{
"data": {
"total_runs": 1234,
"running": 5,
"succeeded": 1200,
"failed": 25,
"cancelled": 4
},
"meta": {...}
}
Event Handlers
Event handlers are registered in your Hot code and loaded when builds are uploaded.
List Event Handlers
GET /v1/projects/{project_id_or_slug}/event-handlers
Returns event handlers from the project's deployed build.
Response:
{
"data": [
{
"event_handler_id": "550e8400-e29b-41d4-a716-446655440000",
"build_id": "660e8400-e29b-41d4-a716-446655440000",
"event_type": "user.signup",
"ns": "::myapp::handlers",
"var": "on-user-signup"
}
],
"pagination": {...},
"meta": {...}
}
Schedules
Schedules are cron-based triggers defined in your Hot code.
List Schedules
GET /v1/projects/{project_id_or_slug}/schedules
Returns schedules from the project's deployed build.
Response:
{
"data": [
{
"schedule_id": "550e8400-e29b-41d4-a716-446655440000",
"build_id": "660e8400-e29b-41d4-a716-446655440000",
"cron": "0 0 * * *",
"ns": "::myapp::tasks",
"var": "daily-cleanup"
}
],
"pagination": {...},
"meta": {...}
}
Environment
Get Environment Info
GET /v1/env
Response:
{
"data": {
"env_id": "550e8400-e29b-41d4-a716-446655440000",
"org_id": "660e8400-e29b-41d4-a716-446655440000",
"name": "production",
"active": true
},
"meta": {...}
}
Get Quota Info
GET /v1/env/quota
Response:
{
"data": {
"compute_used_percent": 15,
"storage_used_percent": 8,
"requests_per_hour": 1000,
"max_concurrent_runs": 50
},
"meta": {...}
}
Streams (Server-Sent Events)
Subscribe to real-time updates for a run's execution stream.
Subscribe to Stream
GET /v1/streams/{stream_id}/subscribe
Returns a text/event-stream response for real-time updates.
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
unauthorized | 401 | Invalid or missing API key |
not_found | 404 | Resource not found |
bad_request | 400 | Invalid request body or parameters |
internal_server_error | 500 | Server error |
rate_limit_exceeded | 429 | Too many requests |
Code Examples
JavaScript/Node.js
const HOT_API_KEY = process.env.HOT_API_KEY;
const BASE_URL = 'https://api.hot.dev/api/v1';
// List projects
const response = await fetch(`${BASE_URL}/projects`, {
headers: {
'Authorization': `Bearer ${HOT_API_KEY}`
}
});
const { data: projects } = await response.json();
// Publish an event
await fetch(`${BASE_URL}/events`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${HOT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_type: 'user.signup',
event_data: { user_id: '123', email: 'alice@example.com' }
})
});
Python
import os
import requests
HOT_API_KEY = os.environ['HOT_API_KEY']
BASE_URL = 'https://api.hot.dev/api/v1'
headers = {
'Authorization': f'Bearer {HOT_API_KEY}',
'Content-Type': 'application/json'
}
# List projects
response = requests.get(f'{BASE_URL}/projects', headers=headers)
projects = response.json()['data']
# Publish an event
requests.post(
f'{BASE_URL}/events',
headers=headers,
json={
'event_type': 'user.signup',
'event_data': {'user_id': '123', 'email': 'alice@example.com'}
}
)
cURL
# List projects
curl https://api.hot.dev/api/v1/projects \
-H "Authorization: Bearer $HOT_API_KEY"
# Publish an event
curl -X POST https://api.hot.dev/api/v1/events \
-H "Authorization: Bearer $HOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event_type": "user.signup", "event_data": {"user_id": "123"}}'
# Upload a build
curl -X POST https://api.hot.dev/api/v1/projects/my-project/builds \
-H "Authorization: Bearer $HOT_API_KEY" \
-F "file=@build.hot.zip" \
-F "hash=abc123def456"