REST API & Service

Interlace includes a built-in HTTP service that exposes a REST API for triggering runs, querying models, streaming real-time events, and serving an embedded web UI. The service is powered by aiohttp and runs as a long-lived process with an optional background scheduler.

Starting the Service

interlace serve                          # Start on localhost:8080
interlace serve --host 0.0.0.0 --port 9090
interlace serve --run                    # Run all models on startup
interlace serve --no-scheduler           # Disable background scheduler
interlace serve --no-ui                  # API only, no web UI

All flags:

FlagDefaultDescription
--host127.0.0.1Host to bind to
--port8080Port to bind to
--envNoneEnvironment (dev, staging, prod)
--runfalseRun all models on startup
--no-schedulerfalseDisable the background scheduler
--no-uifalseDisable the embedded web UI
--project-dir, -dCurrent directoryProject directory
--verbose, -vfalseVerbose logging

API Documentation

Interactive Swagger UI is available at /api/docs when the service is running. The OpenAPI 3.0 specification is served at /api/openapi.yaml.

Key Endpoints

All endpoints are under the /api/v1 prefix.

Health & Info

MethodPathDescription
GET/api/v1/healthHealth check with connection status and uptime
GET/api/v1/projectProject metadata (name, model count, connections)
GET/api/v1/infoAPI version and feature flags
GET/api/v1/schedulerScheduler status with per-model next fire times

Models

MethodPathDescription
GET/api/v1/modelsList all models (filterable by schema, type, tags)
GET/api/v1/models/{name}Model details (config, dependencies, fields)
GET/api/v1/models/{name}/lineageUpstream and downstream lineage graph
GET/api/v1/models/{name}/runsExecution history for a model
GET/api/v1/models/{name}/columnsColumn list
GET/api/v1/models/{name}/columns/{col}/lineageColumn-level lineage
GET/api/v1/models/{name}/schema/historySchema change history
GET/api/v1/models/{name}/schema/currentCurrent schema version
GET/api/v1/models/{name}/schema/diffCompare schema versions

Execution

MethodPathDescription
POST/api/v1/runsTrigger execution (returns 202 Accepted)
GET/api/v1/runs/{run_id}/statusRun status with per-task progress
POST/api/v1/runs/{run_id}/cancelCancel a running execution
GET/api/v1/flowsExecution history with pagination and filtering
GET/api/v1/flows/{flow_id}Flow details including all tasks
GET/api/v1/flows/{flow_id}/tasksTasks in a flow

Analysis

MethodPathDescription
GET/api/v1/graphFull dependency graph
GET/api/v1/graph/validateValidate graph for cycles and issues
GET/api/v1/planImpact analysis (what would run)
POST/api/v1/planImpact analysis with custom parameters
GET/api/v1/lineageFull lineage graph
POST/api/v1/lineage/refreshRefresh cached lineage data

Events

MethodPathDescription
GET/api/v1/eventsServer-Sent Events stream for real-time updates

Streams

MethodPathDescription
GET/api/v1/streamsList all streams
GET/api/v1/streams/{name}Stream details (fields, endpoints, row count)
POST/api/v1/streams/{name}Publish events to a stream
GET/api/v1/streams/{name}/subscribeSubscribe to stream events via SSE
POST/api/v1/streams/{name}/consumeConsume a batch of unprocessed events
POST/api/v1/streams/{name}/ackAcknowledge processed events

Triggering Runs via API

# Run all models
curl -X POST http://localhost:8080/api/v1/runs \
  -H "Content-Type: application/json" \
  -d '{"force": false}'

# Run specific models with backfill
curl -X POST http://localhost:8080/api/v1/runs \
  -H "Content-Type: application/json" \
  -d '{
    "models": ["users", "orders"],
    "since": "2024-01-01",
    "until": "2024-06-30"
  }'

The POST /runs endpoint accepts:

FieldTypeDescription
modelsstring[] \| nullModels to run (null or omitted = all)
forcebooleanForce re-execution even if no changes detected
sincestringOverride cursor start for backfill (implies force: true)
untilstringUpper bound for backfill cursor filter
trigger_metadataobjectArbitrary metadata attached to the flow

The response is 202 Accepted with a run_id you can poll for status:

# Check run status
curl http://localhost:8080/api/v1/runs/run_abc123def456/status

The status response includes per-task progress:

{
  "run_id": "run_abc123def456",
  "status": "running",
  "elapsed_seconds": 12.5,
  "progress": {
    "total_tasks": 8,
    "completed": 5,
    "failed": 0,
    "running": 2,
    "pending": 1
  }
}

Querying Execution History

List recent flows with optional filters:

# All flows
curl http://localhost:8080/api/v1/flows

# Filter by status and date range
curl "http://localhost:8080/api/v1/flows?status=failed&since=2024-01-01&limit=10"

# Get tasks for a specific flow
curl http://localhost:8080/api/v1/flows/{flow_id}/tasks

Query parameters for GET /flows:

ParamDescription
statusFilter by status (pending, running, completed, failed, cancelled)
trigger_typeFilter by trigger (cli, api, schedule, event, webhook)
sinceFlows started after this timestamp
untilFlows started before this timestamp
limitMax results (default: 50, max: 1000)
offsetPagination offset

Authentication

API key authentication is configured in config.yaml:

service:
  auth:
    enabled: true
    api_keys:
      - name: "production"
        key: "${INTERLACE_API_KEY}"
        permissions: [read, write, execute]
      - name: "monitoring"
        key: "${MONITORING_KEY}"
        permissions: [read]
    whitelist:
      - /health
      - /api/v1/health
      - /api/docs
      - /api/openapi.yaml

Authentication Methods

Include the API key in requests via either:

  • Authorization: Bearer <key> header
  • X-API-Key: <key> header
# Using Bearer token
curl -H "Authorization: Bearer $INTERLACE_API_KEY" \
  http://localhost:8080/api/v1/models

# Using X-API-Key header
curl -H "X-API-Key: $INTERLACE_API_KEY" \
  http://localhost:8080/api/v1/models

Permission Model

PermissionGrants Access To
readGET requests (models, flows, health, etc.)
writePOST/PUT requests (excluding runs and lineage refresh)
executePOST /runs, POST /lineage/refresh

Whitelisted paths bypass authentication entirely. Use wildcards for prefix matching (e.g. /api/docs*). Non-API paths (static files, web UI) are never subject to authentication.

Rate Limiting

Per-key rate limiting with a token bucket algorithm:

service:
  auth:
    rate_limit:
      requests_per_second: 100
      burst: 200

Returns 429 Too Many Requests with a retry_after value when the limit is exceeded.

Real-Time Events (SSE)

Subscribe to execution events via Server-Sent Events:

# Subscribe to all events
curl -N http://localhost:8080/api/v1/events

# Subscribe to events for a specific flow
curl -N "http://localhost:8080/api/v1/events?flow_id=run_abc123"

# Subscribe to specific event types
curl -N "http://localhost:8080/api/v1/events?types=flow.completed,flow.failed"

Event types include:

  • Flow events: flow.started, flow.completed, flow.failed, flow.cancelled
  • Task events: task.enqueued, task.waiting, task.ready, task.running, task.materialising, task.completed, task.failed, task.skipped, task.progress

Events are formatted as standard SSE with JSON data. A keepalive comment is sent every 30 seconds to prevent connection timeouts. Useful for building dashboards, CI integrations, or triggering downstream workflows.

Web UI

The service includes an embedded web UI (Svelte 5) accessible at the root URL. It provides:

  • Model browser with dependency graph visualisation
  • Execution history and run details
  • Real-time monitoring via SSE
  • Schema explorer and column lineage views
  • Backfill mode with date range inputs

Disable with --no-ui if running API-only.

CORS

The service automatically configures CORS for the Vite dev server (localhost:5173) and same-origin requests. Pass custom origins via the programmatic API:

from interlace.service.server import run_service

run_service(
    project_dir=".",
    env="prod",
    host="0.0.0.0",
    port=8080,
    cors_origins=["https://dashboard.example.com"],
)

Full Interactive Reference

For the complete request/response schemas, try the interactive Swagger UI at /api/docs when the service is running. It documents every endpoint, query parameter, and response body.