Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

REST API Reference

The Horizon Epoch REST API provides HTTP endpoints for all version control operations. This reference documents all available endpoints, their parameters, and response formats.

Overview

Base URL

http://localhost:8000/api/v1

The API prefix is configurable via the EPOCH_API_PREFIX environment variable (default: /api/v1).

Content Type

All requests and responses use JSON format:

Content-Type: application/json

Running the API Server

# Start the server
uv run uvicorn horizon_epoch.api:app --reload --host 0.0.0.0 --port 8000

# With debug mode (enables Swagger UI)
EPOCH_DEBUG=true uv run uvicorn horizon_epoch.api:app --reload

Authentication

Current Status: The API does not currently implement authentication. All endpoints are open.

When authentication is implemented, the following methods will be supported:

Planned: API Key Authentication

curl -H "Authorization: Bearer <api-key>" \
  http://localhost:8000/api/v1/repositories

Planned: Basic Auth

curl -u username:password \
  http://localhost:8000/api/v1/repositories

For production deployments, we recommend placing the API behind a reverse proxy (nginx, Traefik) that handles authentication.


Health Endpoints

Health check endpoints are available at the root level (not under /api/v1).

Health Check

Check if the API server is running.

GET /health

Response:

{
  "status": "healthy",
  "version": "0.1.0",
  "connected": true
}

curl Example:

curl http://localhost:8000/health

Readiness Check

Check if the API is ready to handle requests.

GET /ready

Response:

{
  "ready": true,
  "metadata_connected": true,
  "repository": "my-repo"
}

curl Example:

curl http://localhost:8000/ready

API Root

Get basic API information.

GET /

Response:

{
  "name": "Horizon Epoch API",
  "version": "0.1.0",
  "api_prefix": "/api/v1",
  "docs": "/docs"
}

curl Example:

curl http://localhost:8000/

Repository Endpoints

Manage repositories and their configuration.

Create Repository

Initialize a new Horizon Epoch repository.

POST /api/v1/repositories

Request Body:

{
  "name": "my-data-repo",
  "storage_configs": {
    "primary": {
      "backend": "postgresql",
      "url": "postgresql://user:pass@localhost/mydb"
    }
  }
}
FieldTypeRequiredDescription
namestringYesRepository name (min 1 character)
storage_configsobjectNoOptional storage backend configurations

Response: 201 Created

{
  "name": "my-data-repo",
  "default_branch": "main",
  "metadata_url": "postgresql://localhost/horizon_epoch"
}

curl Example:

curl -X POST http://localhost:8000/api/v1/repositories \
  -H "Content-Type: application/json" \
  -d '{"name": "my-data-repo"}'

Open Repository

Open an existing repository.

POST /api/v1/repositories/{name}/open

Path Parameters:

ParameterTypeDescription
namestringRepository name

Response: 200 OK

{
  "name": "my-data-repo",
  "default_branch": "main",
  "metadata_url": "postgresql://localhost/horizon_epoch"
}

curl Example:

curl -X POST http://localhost:8000/api/v1/repositories/my-data-repo/open

Get Repository Status

Get the current status of the repository.

GET /api/v1/repositories/status

Query Parameters:

ParameterTypeRequiredDescription
repositorystringNoRepository name (uses current if not specified)

Response:

{
  "branch": "main",
  "commit_id": "abc123def456789",
  "is_detached": false,
  "is_clean": true,
  "staged_count": 0,
  "unstaged_count": 0,
  "merge_in_progress": false
}

curl Example:

# Current repository
curl http://localhost:8000/api/v1/repositories/status

# Specific repository
curl "http://localhost:8000/api/v1/repositories/status?repository=my-data-repo"

List Tracked Tables

List all tables being tracked for version control.

GET /api/v1/repositories/tables

Query Parameters:

ParameterTypeRequiredDescription
repositorystringNoRepository name

Response:

["users", "orders", "products"]

curl Example:

curl http://localhost:8000/api/v1/repositories/tables

Add Storage Backend

Add a new storage backend to the repository.

POST /api/v1/repositories/storage

Request Body:

{
  "name": "warehouse",
  "backend": "postgresql",
  "config": {
    "url": "postgresql://user:pass@warehouse-host/analytics"
  }
}
FieldTypeRequiredDescription
namestringYesStorage configuration name
backendstringYesBackend type (see below)
configobjectYesBackend-specific configuration

Supported Backend Types:

BackendValueRequired Config Fields
PostgreSQLpostgresqlurl or (host, database)
MySQLmysqlurl or (host, database)
SQL Servermssqlurl or (host, database)
SQLitesqlitepath
S3s3bucket
Azure Blobazureaccount, container
GCSgcsbucket
Local Filesystemlocalpath

Backend Configuration Examples:

// PostgreSQL
{
  "name": "prod-pg",
  "backend": "postgresql",
  "config": {
    "host": "db.example.com",
    "port": 5432,
    "database": "production",
    "schema": "public"
  }
}

// MySQL
{
  "name": "analytics-mysql",
  "backend": "mysql",
  "config": {
    "host": "mysql.example.com",
    "port": 3306,
    "database": "analytics"
  }
}

// SQL Server
{
  "name": "warehouse-mssql",
  "backend": "mssql",
  "config": {
    "host": "sqlserver.example.com",
    "port": 1433,
    "database": "warehouse"
  }
}

// SQLite
{
  "name": "local-sqlite",
  "backend": "sqlite",
  "config": {
    "path": "/data/local.db"
  }
}

// S3
{
  "name": "datalake",
  "backend": "s3",
  "config": {
    "bucket": "company-datalake",
    "region": "us-west-2",
    "prefix": "epoch/"
  }
}

// Azure Blob
{
  "name": "azure-store",
  "backend": "azure",
  "config": {
    "account": "myaccount",
    "container": "data",
    "prefix": "epoch/"
  }
}

// GCS
{
  "name": "gcs-store",
  "backend": "gcs",
  "config": {
    "bucket": "my-bucket",
    "project": "my-project",
    "prefix": "epoch/"
  }
}

// Local Filesystem
{
  "name": "local-fs",
  "backend": "local",
  "config": {
    "path": "/data/epoch"
  }
}

Response: 201 Created

{
  "status": "created",
  "name": "warehouse"
}

curl Examples:

# PostgreSQL
curl -X POST http://localhost:8000/api/v1/repositories/storage \
  -H "Content-Type: application/json" \
  -d '{
    "name": "warehouse",
    "backend": "postgresql",
    "config": {"host": "db.example.com", "database": "warehouse"}
  }'

# S3
curl -X POST http://localhost:8000/api/v1/repositories/storage \
  -H "Content-Type: application/json" \
  -d '{
    "name": "datalake",
    "backend": "s3",
    "config": {"bucket": "company-datalake", "region": "us-west-2"}
  }'

# Azure Blob
curl -X POST http://localhost:8000/api/v1/repositories/storage \
  -H "Content-Type: application/json" \
  -d '{
    "name": "azure-store",
    "backend": "azure",
    "config": {"account": "myaccount", "container": "data"}
  }'

Track Table

Start tracking a table for version control.

POST /api/v1/repositories/tables/track

Request Body:

{
  "table_name": "users",
  "storage_name": "primary",
  "primary_key": ["id"]
}
FieldTypeRequiredDescription
table_namestringYesTable name to track
storage_namestringYesStorage backend containing the table
primary_keyarrayYesPrimary key column(s)

Response: 201 Created

{
  "status": "tracking",
  "table": "users"
}

curl Example:

curl -X POST http://localhost:8000/api/v1/repositories/tables/track \
  -H "Content-Type: application/json" \
  -d '{
    "table_name": "users",
    "storage_name": "primary",
    "primary_key": ["id"]
  }'

Branch Endpoints

Create, list, and manage branches.

Create Branch

Create a new branch.

POST /api/v1/branches

Request Body:

{
  "name": "feature/add-preferences",
  "start_point": "main",
  "checkout": true
}
FieldTypeRequiredDefaultDescription
namestringYes-Branch name (min 1 character)
start_pointstringNoHEADCommit ID or branch to start from
checkoutbooleanNotrueWhether to checkout the new branch

Response: 201 Created

{
  "name": "feature/add-preferences",
  "head_commit_id": "abc123def456789",
  "is_protected": false,
  "created_at": "2024-12-18T10:30:00Z"
}

curl Example:

# Create and checkout a new branch
curl -X POST http://localhost:8000/api/v1/branches \
  -H "Content-Type: application/json" \
  -d '{"name": "feature/add-preferences"}'

# Create from specific commit without checkout
curl -X POST http://localhost:8000/api/v1/branches \
  -H "Content-Type: application/json" \
  -d '{"name": "hotfix/urgent", "start_point": "abc123", "checkout": false}'

List Branches

List all branches in the repository.

GET /api/v1/branches

Query Parameters:

ParameterTypeRequiredDescription
repositorystringNoRepository name

Response:

{
  "branches": [
    {
      "name": "main",
      "head_commit_id": "abc123def456789",
      "is_protected": true,
      "created_at": "2024-12-01T00:00:00Z"
    },
    {
      "name": "feature/add-preferences",
      "head_commit_id": "def456abc789012",
      "is_protected": false,
      "created_at": "2024-12-18T10:30:00Z"
    }
  ],
  "current": "main"
}

curl Example:

curl http://localhost:8000/api/v1/branches

Checkout Branch

Switch to a different branch.

POST /api/v1/branches/{name}/checkout

Path Parameters:

ParameterTypeDescription
namestringBranch name to checkout

Response:

{
  "status": "checked_out",
  "branch": "feature/add-preferences",
  "commit_id": "def456abc789012"
}

curl Example:

curl -X POST http://localhost:8000/api/v1/branches/feature%2Fadd-preferences/checkout

Note: URL-encode branch names containing / (e.g., feature/xyz becomes feature%2Fxyz).

Delete Branch

Delete a branch.

DELETE /api/v1/branches/{name}

Path Parameters:

ParameterTypeDescription
namestringBranch name to delete

Query Parameters:

ParameterTypeRequiredDefaultDescription
forcebooleanNofalseForce delete even if unmerged
repositorystringNo-Repository name

Response: 204 No Content

curl Example:

# Normal delete (fails if unmerged)
curl -X DELETE http://localhost:8000/api/v1/branches/feature%2Fadd-preferences

# Force delete
curl -X DELETE "http://localhost:8000/api/v1/branches/feature%2Fadd-preferences?force=true"

Compare Branches

Compare two branches to see how they’ve diverged.

GET /api/v1/branches/compare

Query Parameters:

ParameterTypeRequiredDescription
sourcestringYesSource branch
targetstringYesTarget branch
repositorystringNoRepository name

Response:

{
  "source_branch": "feature/add-preferences",
  "target_branch": "main",
  "ahead_count": 3,
  "behind_count": 1,
  "can_fast_forward": false,
  "merge_base_id": "abc123def456789"
}

curl Example:

curl "http://localhost:8000/api/v1/branches/compare?source=feature/add-preferences&target=main"

Merge Branch

Merge a branch into the current branch.

POST /api/v1/branches/merge

Request Body:

{
  "source": "feature/add-preferences",
  "strategy": "THREE_WAY",
  "message": "Merge feature/add-preferences into main",
  "no_commit": false
}
FieldTypeRequiredDefaultDescription
sourcestringYes-Source branch to merge from
strategystringNoTHREE_WAYMerge strategy: THREE_WAY, FAST_FORWARD, OURS, THEIRS
messagestringNoautoCustom merge commit message
no_commitbooleanNofalseStage but don’t commit merge

Response:

{
  "source_branch": "feature/add-preferences",
  "target_branch": "main",
  "is_fast_forward": false,
  "has_conflicts": false,
  "conflict_count": 0,
  "result_commit_id": "ghi789jkl012345"
}

Response (with conflicts): 409 Conflict

{
  "error": "MergeConflictError",
  "message": "Merge conflict in 1 table(s)",
  "details": {
    "conflict_tables": ["users"],
    "conflict_count": 3
  }
}

curl Examples:

# Standard merge
curl -X POST http://localhost:8000/api/v1/branches/merge \
  -H "Content-Type: application/json" \
  -d '{"source": "feature/add-preferences"}'

# Fast-forward only
curl -X POST http://localhost:8000/api/v1/branches/merge \
  -H "Content-Type: application/json" \
  -d '{"source": "feature/add-preferences", "strategy": "FAST_FORWARD"}'

# Merge without committing
curl -X POST http://localhost:8000/api/v1/branches/merge \
  -H "Content-Type: application/json" \
  -d '{"source": "feature/add-preferences", "no_commit": true}'

Abort Merge

Abort an in-progress merge operation.

POST /api/v1/branches/merge/abort

Response:

{
  "status": "aborted"
}

curl Example:

curl -X POST http://localhost:8000/api/v1/branches/merge/abort

Commit Endpoints

Create commits and view commit history.

Create Commit

Create a new commit with staged changes.

POST /api/v1/commits

Request Body:

{
  "message": "Add user preferences feature",
  "author_name": "Jane Developer",
  "author_email": "jane@example.com"
}
FieldTypeRequiredDescription
messagestringYesCommit message (min 1 character)
author_namestringNoAuthor name (uses config default)
author_emailstringNoAuthor email (uses config default)

Response: 201 Created

{
  "id": "abc123def456789abcdef0123456789abcdef01",
  "short_id": "abc123d",
  "message": "Add user preferences feature",
  "author_name": "Jane Developer",
  "author_email": "jane@example.com",
  "created_at": "2024-12-18T10:45:00Z",
  "parent_count": 1
}

curl Example:

curl -X POST http://localhost:8000/api/v1/commits \
  -H "Content-Type: application/json" \
  -d '{"message": "Add user preferences feature"}'

List Commits

Get commit history.

GET /api/v1/commits

Query Parameters:

ParameterTypeRequiredDefaultDescription
refstringNoHEADBranch or commit reference
limitintegerNo100Max commits to return (1-1000)
offsetintegerNo0Offset for pagination
repositorystringNo-Repository name

Response:

{
  "commits": [
    {
      "id": "abc123def456789abcdef0123456789abcdef01",
      "short_id": "abc123d",
      "message": "Add user preferences feature",
      "author_name": "Jane Developer",
      "author_email": "jane@example.com",
      "created_at": "2024-12-18T10:45:00Z",
      "parent_count": 1
    }
  ],
  "total": 42,
  "has_more": true
}

curl Examples:

# Get recent commits
curl http://localhost:8000/api/v1/commits

# Get commits from specific branch
curl "http://localhost:8000/api/v1/commits?ref=feature/add-preferences"

# Pagination
curl "http://localhost:8000/api/v1/commits?limit=10&offset=20"

Get Commit

Get details of a specific commit.

GET /api/v1/commits/{commit_id}

Path Parameters:

ParameterTypeDescription
commit_idstringFull or short commit ID

Response:

{
  "id": "abc123def456789abcdef0123456789abcdef01",
  "short_id": "abc123d",
  "message": "Add user preferences feature",
  "author_name": "Jane Developer",
  "author_email": "jane@example.com",
  "created_at": "2024-12-18T10:45:00Z",
  "parent_count": 1
}

curl Example:

curl http://localhost:8000/api/v1/commits/abc123def456789

Get Diff

Show differences between commits or branches.

GET /api/v1/commits/diff

Query Parameters:

ParameterTypeRequiredDescription
basestringNoBase commit/branch (defaults to parent)
targetstringNoTarget commit/branch (defaults to HEAD)
repositorystringNoRepository name

Response:

{
  "base_commit_id": "abc123def456789",
  "target_commit_id": "def456ghi789012",
  "tables_changed": 2,
  "total_inserts": 15,
  "total_updates": 8,
  "total_deletes": 3
}

curl Examples:

# Diff working state vs HEAD
curl http://localhost:8000/api/v1/commits/diff

# Diff between branches
curl "http://localhost:8000/api/v1/commits/diff?base=main&target=feature/add-preferences"

# Diff between commits
curl "http://localhost:8000/api/v1/commits/diff?base=abc123&target=def456"

Stage All Changes

Stage all pending changes for commit.

POST /api/v1/commits/stage

Response:

{
  "status": "staged",
  "count": 5
}

curl Example:

curl -X POST http://localhost:8000/api/v1/commits/stage

Unstage All Changes

Remove all changes from the staging area.

POST /api/v1/commits/unstage

Response:

{
  "status": "unstaged",
  "count": 5
}

curl Example:

curl -X POST http://localhost:8000/api/v1/commits/unstage

Error Responses

All errors follow a consistent format:

{
  "error": "ErrorClassName",
  "message": "Human-readable error description",
  "details": {
    "additional": "context information"
  }
}

HTTP Status Codes

CodeMeaningWhen Used
200OKSuccessful GET/POST operations
201CreatedResource successfully created
204No ContentSuccessful DELETE operations
400Bad RequestInvalid request format or parameters
404Not FoundResource not found
409ConflictMerge conflicts, duplicate resources
422Unprocessable EntityValidation errors
503Service UnavailableDatabase connection issues

Error Types

ErrorHTTP StatusDescription
BranchNotFoundError404Specified branch doesn’t exist
CommitNotFoundError404Specified commit doesn’t exist
RepositoryNotInitializedError404Repository not initialized or opened
BranchAlreadyExistsError409Branch name already in use
MergeConflictError409Merge has unresolved conflicts
ConnectionFailedError503Unable to connect to metadata database
ValidationError422Request body validation failed

Example Error Responses

Branch Not Found:

{
  "error": "BranchNotFoundError",
  "message": "Branch 'feature/nonexistent' not found",
  "details": {
    "branch": "feature/nonexistent"
  }
}

Validation Error:

{
  "detail": [
    {
      "type": "string_too_short",
      "loc": ["body", "name"],
      "msg": "String should have at least 1 character",
      "input": "",
      "ctx": {"min_length": 1}
    }
  ]
}

Connection Error:

{
  "error": "ConnectionFailedError",
  "message": "Failed to connect to metadata database",
  "details": {
    "url": "postgresql://localhost/horizon_epoch"
  }
}

Pagination

List endpoints support pagination via limit and offset query parameters.

GET /api/v1/commits?limit=10&offset=20
ParameterTypeDefaultRangeDescription
limitinteger1001-1000Maximum items per page
offsetinteger00+Number of items to skip

Paginated responses include metadata:

{
  "items": [...],
  "total": 150,
  "has_more": true
}

OpenAPI Specification

The API provides auto-generated OpenAPI 3.0 documentation:

EndpointDescription
GET /openapi.jsonRaw OpenAPI specification
GET /docsSwagger UI (interactive, debug mode only)
GET /redocReDoc (alternative UI, debug mode only)

Enable debug mode to access Swagger UI:

EPOCH_DEBUG=true uv run uvicorn horizon_epoch.api:app --reload

Then visit: http://localhost:8000/docs

Export OpenAPI Spec

You can export the OpenAPI specification using the provided script:

# Export as JSON
cd python
uv run python scripts/export_openapi.py --output ../docs/openapi.json

# Export as YAML
uv run python scripts/export_openapi.py --format yaml --output ../docs/openapi.yaml

Environment Configuration

The API can be configured via environment variables:

VariableDefaultDescription
EPOCH_METADATA_URLpostgresql://localhost:5432/horizon_epochMetadata database URL
EPOCH_DEFAULT_BRANCHmainDefault branch name
EPOCH_API_PREFIX/api/v1API route prefix
EPOCH_DEBUGfalseEnable debug mode (exposes Swagger UI)
EPOCH_LOG_LEVELINFOLogging level
EPOCH_AUTHOR_NAME-Default author name for commits
EPOCH_AUTHOR_EMAIL-Default author email for commits

Example:

export EPOCH_METADATA_URL="postgresql://user:pass@localhost:5432/horizon_epoch"
export EPOCH_DEBUG=true
export EPOCH_AUTHOR_NAME="API User"
export EPOCH_AUTHOR_EMAIL="api@example.com"

uv run uvicorn horizon_epoch.api:app --host 0.0.0.0 --port 8000

Rate Limiting

Current Status: Rate limiting is not currently implemented.

When rate limiting is implemented, limits will be returned in response headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1705312200

CORS

Cross-Origin Resource Sharing is enabled for all origins by default. For production, configure allowed origins appropriately.

Current configuration:

  • Origins: * (all)
  • Methods: All HTTP methods
  • Headers: All headers
  • Credentials: Allowed

See Also