Skip to content

HeliosDB Nano Branch REST API Specification

HeliosDB Nano Branch REST API Specification

Version: 1.0.0 Status: Draft Created: 2025-12-01


Overview

This document specifies the RESTful API for managing database branches in HeliosDB Nano. The API enables creating, managing, and working with data across branches via HTTP.


Base URL

Production: https://api.heliosdb.local/v1
Development: http://localhost:8080/v1

Authentication

All endpoints require authentication via one of:

Bearer Token (JWT)

Authorization: Bearer <jwt_token>

API Key

X-API-Key: <api_key>

Common Response Formats

Success Response

{
"success": true,
"data": { ... },
"meta": {
"request_id": "req_abc123",
"execution_time_ms": 45
}
}

Error Response

{
"success": false,
"error": {
"code": "BRANCH_NOT_FOUND",
"message": "Branch 'feature-xyz' does not exist",
"details": { ... }
},
"meta": {
"request_id": "req_abc123"
}
}

Error Codes

CodeHTTP StatusDescription
BRANCH_NOT_FOUND404Branch does not exist
BRANCH_EXISTS409Branch name already in use
BRANCH_PROTECTED403Cannot modify protected branch
MERGE_CONFLICT409Unresolved merge conflicts
INVALID_SQL400SQL syntax error
UNAUTHORIZED401Invalid or missing auth
FORBIDDEN403Insufficient permissions
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server error

Endpoints

Branch Management

List All Branches

GET /v1/branches

Query Parameters:

ParameterTypeDefaultDescription
statusstringallFilter: active, merged, deleted, all
pageinteger1Page number
limitinteger20Results per page (max 100)
sortstringcreated_atSort field: name, created_at, updated_at
orderstringdescSort order: asc, desc

Response:

{
"success": true,
"data": {
"branches": [
{
"id": "br_main_001",
"name": "main",
"display_name": "Main Branch",
"status": "active",
"is_default": true,
"is_protected": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-12-01T10:00:00Z",
"stats": {
"tables": 15,
"rows": 125000,
"size_bytes": 52428800
}
},
{
"id": "br_feat_abc123",
"name": "feature-auth",
"display_name": "Authentication Feature",
"status": "active",
"is_default": false,
"is_protected": false,
"source_branch": "main",
"source_snapshot": "snap_xyz789",
"created_at": "2025-12-01T08:00:00Z",
"updated_at": "2025-12-01T09:30:00Z",
"stats": {
"tables": 15,
"rows": 125050,
"size_bytes": 52430000,
"changes_from_source": 50
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 2,
"total_pages": 1
}
}
}

Create Branch

POST /v1/branches

Request Body:

{
"name": "feature-auth",
"display_name": "Authentication Feature",
"source_branch": "main",
"as_of": {
"type": "timestamp",
"value": "2025-12-01T08:00:00Z"
},
"metadata": {
"owner": "alice@example.com",
"ticket": "JIRA-1234",
"description": "Implementing OAuth2 authentication"
}
}

As-Of Options:

// Current state
{ "type": "now" }
// Specific timestamp
{ "type": "timestamp", "value": "2025-12-01T08:00:00Z" }
// After specific transaction
{ "type": "transaction", "value": 12345 }
// Specific SCN (System Change Number)
{ "type": "scn", "value": 987654 }
// Specific snapshot
{ "type": "snapshot", "value": "snap_xyz789" }

Response:

{
"success": true,
"data": {
"id": "br_feat_abc123",
"name": "feature-auth",
"display_name": "Authentication Feature",
"status": "active",
"source_branch": "main",
"source_snapshot": "snap_xyz789",
"created_at": "2025-12-01T10:00:00Z"
}
}

Get Branch Details

GET /v1/branches/{branch_name}

Path Parameters:

ParameterTypeDescription
branch_namestringBranch name or ID

Query Parameters:

ParameterTypeDefaultDescription
include_statsbooleantrueInclude statistics
include_historybooleanfalseInclude recent history

Response:

{
"success": true,
"data": {
"id": "br_feat_abc123",
"name": "feature-auth",
"display_name": "Authentication Feature",
"status": "active",
"is_default": false,
"is_protected": false,
"source_branch": "main",
"source_snapshot": "snap_xyz789",
"created_at": "2025-12-01T08:00:00Z",
"updated_at": "2025-12-01T09:30:00Z",
"metadata": {
"owner": "alice@example.com",
"ticket": "JIRA-1234",
"description": "Implementing OAuth2 authentication"
},
"stats": {
"tables": 15,
"rows": 125050,
"size_bytes": 52430000,
"changes_from_source": 50,
"inserts": 30,
"updates": 15,
"deletes": 5
},
"divergence": {
"source_branch": "main",
"commits_ahead": 5,
"commits_behind": 2,
"can_fast_forward": false
}
}
}

Update Branch

PATCH /v1/branches/{branch_name}

Request Body:

{
"display_name": "Updated Display Name",
"is_protected": true,
"metadata": {
"owner": "bob@example.com"
}
}

Response:

{
"success": true,
"data": {
"id": "br_feat_abc123",
"name": "feature-auth",
"display_name": "Updated Display Name",
"is_protected": true,
"updated_at": "2025-12-01T11:00:00Z"
}
}

Delete Branch

DELETE /v1/branches/{branch_name}

Query Parameters:

ParameterTypeDefaultDescription
forcebooleanfalseForce delete even with uncommitted changes

Response:

{
"success": true,
"data": {
"deleted": true,
"branch_name": "feature-auth",
"deleted_at": "2025-12-01T12:00:00Z"
}
}

Merge Branches

POST /v1/branches/{branch_name}/merge

Request Body:

{
"target_branch": "main",
"conflict_resolution": "source_wins",
"delete_source_after_merge": true,
"merge_message": "Merge feature-auth into main",
"dry_run": false
}

Conflict Resolution Options:

  • source_wins - Source branch values take precedence
  • target_wins - Target branch values take precedence
  • manual - Return conflicts for manual resolution
  • abort - Fail if any conflicts exist

Response (Success):

{
"success": true,
"data": {
"status": "merged",
"source_branch": "feature-auth",
"target_branch": "main",
"merge_commit": "mc_def456",
"changes_merged": 50,
"conflicts_resolved": 3,
"source_deleted": true,
"merged_at": "2025-12-01T13:00:00Z"
}
}

Response (Conflicts):

{
"success": false,
"error": {
"code": "MERGE_CONFLICT",
"message": "Merge has conflicts requiring resolution",
"details": {
"conflicts": [
{
"table": "users",
"row_id": "123",
"column": "email",
"source_value": "alice@new.com",
"target_value": "alice@old.com",
"conflict_type": "update_update"
}
]
}
}
}

Data Operations

List Tables in Branch

GET /v1/branches/{branch_name}/tables

Response:

{
"success": true,
"data": {
"tables": [
{
"name": "users",
"schema": "public",
"row_count": 10000,
"columns": [
{"name": "id", "type": "INTEGER", "nullable": false, "primary_key": true},
{"name": "name", "type": "TEXT", "nullable": false},
{"name": "email", "type": "TEXT", "nullable": false},
{"name": "created_at", "type": "TIMESTAMP", "nullable": false}
],
"indexes": ["idx_users_email"],
"created_at": "2025-01-01T00:00:00Z"
}
]
}
}

Query Table Data

GET /v1/branches/{branch_name}/tables/{table_name}/data

Query Parameters:

ParameterTypeDefaultDescription
columnsstring*Comma-separated column names
filterstring-WHERE clause (URL encoded)
order_bystring-ORDER BY clause
pageinteger1Page number
limitinteger100Rows per page (max 1000)
as_of_typestringnowTime-travel type
as_of_valuestring-Time-travel value

Example:

GET /v1/branches/main/tables/users/data?columns=id,name,email&filter=active%3Dtrue&limit=50

Response:

{
"success": true,
"data": {
"columns": ["id", "name", "email"],
"rows": [
[1, "Alice", "alice@example.com"],
[2, "Bob", "bob@example.com"]
],
"pagination": {
"page": 1,
"limit": 50,
"total": 2,
"total_pages": 1
}
}
}

Insert Data

POST /v1/branches/{branch_name}/tables/{table_name}/data

Request Body:

{
"rows": [
{"name": "Charlie", "email": "charlie@example.com"},
{"name": "Diana", "email": "diana@example.com"}
],
"on_conflict": "error"
}

On Conflict Options:

  • error - Return error on conflict
  • ignore - Skip conflicting rows
  • update - Update existing rows

Response:

{
"success": true,
"data": {
"inserted": 2,
"ids": [3, 4]
}
}

Update Data

PUT /v1/branches/{branch_name}/tables/{table_name}/data

Request Body:

{
"filter": "id = 1",
"updates": {
"email": "alice@newdomain.com",
"updated_at": "2025-12-01T14:00:00Z"
}
}

Response:

{
"success": true,
"data": {
"updated": 1
}
}

Delete Data

DELETE /v1/branches/{branch_name}/tables/{table_name}/data

Query Parameters:

ParameterTypeRequiredDescription
filterstringYesWHERE clause (required for safety)

Response:

{
"success": true,
"data": {
"deleted": 5
}
}

SQL Operations

Execute Query (Read-Only)

POST /v1/branches/{branch_name}/query

Request Body:

{
"sql": "SELECT u.name, COUNT(o.id) as order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.name ORDER BY order_count DESC LIMIT 10",
"params": [],
"as_of": {
"type": "timestamp",
"value": "2025-12-01T08:00:00Z"
},
"timeout_ms": 30000
}

Response:

{
"success": true,
"data": {
"columns": ["name", "order_count"],
"column_types": ["TEXT", "BIGINT"],
"rows": [
["Alice", 150],
["Bob", 120],
["Charlie", 95]
],
"row_count": 3,
"execution_plan": "...",
"execution_time_ms": 45
}
}

Execute Statement (DDL/DML)

POST /v1/branches/{branch_name}/execute

Request Body:

{
"sql": "CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price DECIMAL(10,2))",
"params": [],
"timeout_ms": 30000
}

Response:

{
"success": true,
"data": {
"statement_type": "CREATE_TABLE",
"affected_rows": 0,
"execution_time_ms": 12
}
}

Time-Travel Operations

Get Branch History

GET /v1/branches/{branch_name}/history

Query Parameters:

ParameterTypeDefaultDescription
fromstring-Start timestamp
tostring-End timestamp
limitinteger50Max results

Response:

{
"success": true,
"data": {
"history": [
{
"id": "tx_001",
"type": "transaction",
"timestamp": "2025-12-01T10:00:00Z",
"scn": 1000,
"summary": "INSERT INTO users (5 rows)",
"user": "alice@example.com"
},
{
"id": "snap_001",
"type": "snapshot",
"timestamp": "2025-12-01T09:00:00Z",
"scn": 900,
"summary": "Automatic snapshot",
"size_bytes": 52428800
}
]
}
}

List Snapshots

GET /v1/branches/{branch_name}/snapshots

Response:

{
"success": true,
"data": {
"snapshots": [
{
"id": "snap_xyz789",
"timestamp": "2025-12-01T09:00:00Z",
"scn": 900,
"type": "automatic",
"size_bytes": 52428800,
"tables": 15,
"rows": 125000
}
]
}
}

Restore to Snapshot

POST /v1/branches/{branch_name}/restore/{snapshot_id}

Request Body:

{
"create_backup_branch": true,
"backup_branch_name": "backup-before-restore"
}

Response:

{
"success": true,
"data": {
"restored": true,
"snapshot_id": "snap_xyz789",
"restored_to_scn": 900,
"backup_branch": "backup-before-restore"
}
}

Rate Limiting

Endpoint CategoryRate Limit
Read operations1000/minute
Write operations100/minute
Query execution60/minute
Branch creation10/minute

Rate limit headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1701432060

Webhooks (Future)

Branch events can trigger webhooks:

{
"event": "branch.created",
"timestamp": "2025-12-01T10:00:00Z",
"data": {
"branch_id": "br_feat_abc123",
"branch_name": "feature-auth",
"source_branch": "main"
}
}

Events:

  • branch.created
  • branch.deleted
  • branch.merged
  • branch.protected
  • branch.data_changed

SDK Examples

Rust

use heliosdb_nano_client::{Client, BranchCreateOptions};
let client = Client::new("http://localhost:8080")
.with_api_key("your-api-key");
// Create branch
let branch = client.branches()
.create("feature-auth")
.from_branch("main")
.as_of_now()
.send()
.await?;
// Query data
let results = client.branches()
.get("feature-auth")
.query("SELECT * FROM users WHERE active = true")
.send()
.await?;
// Merge branch
client.branches()
.get("feature-auth")
.merge_into("main")
.with_conflict_resolution(ConflictResolution::SourceWins)
.delete_after_merge(true)
.send()
.await?;

JavaScript/TypeScript

import { HeliosDBClient } from '@heliosdb/client';
const client = new HeliosDBClient({
baseUrl: 'http://localhost:8080',
apiKey: 'your-api-key'
});
// Create branch
const branch = await client.branches.create({
name: 'feature-auth',
sourceBranch: 'main',
asOf: { type: 'now' }
});
// Query data
const results = await client.branches.query('feature-auth', {
sql: 'SELECT * FROM users WHERE active = true'
});
// Merge branch
await client.branches.merge('feature-auth', {
targetBranch: 'main',
conflictResolution: 'source_wins',
deleteAfterMerge: true
});

Python

from heliosdb import HeliosDBClient
client = HeliosDBClient(
base_url="http://localhost:8080",
api_key="your-api-key"
)
# Create branch
branch = client.branches.create(
name="feature-auth",
source_branch="main",
as_of={"type": "now"}
)
# Query data
results = client.branches.query(
"feature-auth",
sql="SELECT * FROM users WHERE active = true"
)
# Merge branch
client.branches.merge(
"feature-auth",
target_branch="main",
conflict_resolution="source_wins",
delete_after_merge=True
)

OpenAPI Specification

Full OpenAPI 3.0 specification available at:

  • /v1/openapi.json
  • /v1/openapi.yaml

Interactive documentation at:

  • /v1/docs (Swagger UI)
  • /v1/redoc (ReDoc)

Document Version: 1.0.0 Last Updated: 2025-12-01