Light Dark

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:

ParameterTypeDefaultDescription
limitint20Maximum results to return
offsetint0Number 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:

ParameterTypeDescription
limitintMax results (default: 20)
offsetintPagination 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:

FieldRequiredDescription
fileYesThe build zip file
hashYesSHA hash of the build for validation
build_idNoOptional 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:

ParameterTypeDescription
limitintMax results (default: 20)
offsetintPagination 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:

ParameterTypeDescription
limitintMax results (default: 20)
offsetintPagination offset
statusstringFilter: running, succeeded, failed, cancelled
typestringFilter: call, event, schedule, run, eval, repl
time_rangestringISO 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

CodeHTTP StatusDescription
unauthorized401Invalid or missing API key
not_found404Resource not found
bad_request400Invalid request body or parameters
internal_server_error500Server error
rate_limit_exceeded429Too 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"