# HTTP API Reference<no value>

The ztick HTTP API provides a RESTful interface for managing scheduled jobs and rules. This is an optional interface that runs alongside the native TCP protocol.

## OpenAPI Specification

The complete API contract is defined in **[openapi.json](../../src/infrastructure/openapi.json)**, written in OpenAPI v3.1.1 format. The spec is colocated with the HTTP server that embeds it, and is also served live at `GET /openapi.json`. You can import it into:

- **Swagger Editor** — https://editor.swagger.io/ (paste the raw JSON)
- **Postman** — File → Import → paste `openapi.json`
- **Code generation tools** — Generate client SDKs in your language
- **API documentation tools** — Swagger UI, ReDoc, etc.

## Server Configuration

The HTTP API listens on a separate port from the native TCP protocol:

```toml
[controller]
listen = "127.0.0.1:5680"     # HTTP API port (separate from TCP)
```

## Concurrency Model

The HTTP server spawns a dedicated thread per accepted connection, enabling parallel request processing without head-of-line blocking. This concurrency model ([F022](../../.specify/implementation/F022/)):

- **Thread-per-connection**: Each HTTP request is handled in its own thread, allowing multiple clients to make requests simultaneously
- **Atomic connection tracking**: An atomic counter tracks active connections, enabling safe shutdown without a global mutex
- **Graceful shutdown**: On server shutdown, in-flight connections are given up to 5 seconds to complete before the server exits. Any connections that don't complete within the timeout are forcefully closed
- **Throughput scaling**: Throughput scales linearly with concurrent clients (tested up to 8 concurrent workers achieving >2000 requests/second)
- **Stable latency**: Per-request latency remains predictable under concurrent load (p50 latency <5ms at 8 concurrent workers)

## Authentication

All API endpoints require Bearer token authentication, configurable via the `auth_file`:

```bash
# Request with token
curl -H "Authorization: Bearer YOUR_TOKEN" http://127.0.0.1:5680/jobs
```

The `/health` and `/openapi.json` endpoints do not require authentication.

## Core Endpoints

### Jobs (CRUD)

| Method | Endpoint | Purpose |
|--------|----------|---------|
| `PUT` | `/jobs/{id}` | Create or update a job |
| `GET` | `/jobs/{id}` | Retrieve a specific job |
| `DELETE` | `/jobs/{id}` | Delete a job |
| `GET` | `/jobs?prefix=<string>` | List jobs matching a prefix |

**Example: Create a job**

```bash
curl -X PUT http://127.0.0.1:5680/jobs/deploy.v1 \
  -H "Authorization: Bearer token123" \
  -H "Content-Type: application/json" \
  -d '{
    "execution": "2026-04-10T12:00:00Z"
  }'
```

**Response:**
```json
{
  "id": "deploy.v1",
  "status": "planned",
  "execution": 1744286400000000000
}
```

### Rules (CRUD)

| Method | Endpoint | Purpose |
|--------|----------|---------|
| `PUT` | `/rules/{id}` | Create or update a rule |
| `DELETE` | `/rules/{id}` | Delete a rule |
| `GET` | `/rules?prefix=<string>` | List rules matching a prefix |

**Example: Create a rule**

```bash
curl -X PUT http://127.0.0.1:5680/rules/notify-slack \
  -H "Authorization: Bearer token123" \
  -H "Content-Type: application/json" \
  -d '{
    "pattern": "deploy.",
    "runner": {
      "type": "direct",
      "executable": "/usr/bin/curl",
      "args": ["-X", "POST", "https://hooks.slack.com/..."]
    }
  }'
```

### Health & Discovery

| Endpoint | Purpose | Auth Required |
|----------|---------|----------------|
| `GET /health` | Server health check | No |
| `GET /openapi.json` | OpenAPI specification as JSON | No |

**Example: Check health**

```bash
curl http://127.0.0.1:5680/health
```

**Response:**
```json
{
  "status": "ok"
}
```

## Runner Types

The API supports four runner types for rule execution:

### Shell Runner

Execute a shell command (requires shell configured in `[shell]` section):

```json
{
  "type": "shell",
  "command": "/usr/bin/notify --channel ops"
}
```

### Direct Runner

Execute a binary directly without shell invocation (safer, more predictable):

```json
{
  "type": "direct",
  "executable": "/usr/bin/curl",
  "args": ["-s", "http://example.com/webhook"]
}
```

### HTTP Runner

Trigger an external webhook via HTTP/HTTPS request:

```json
{
  "type": "http",
  "method": "POST",
  "url": "https://hooks.example.com/webhook"
}
```

**Methods**: GET, POST, PUT, DELETE

**Behavior**:
- POST and PUT requests include a JSON body: `{"job_id":"<identifier>","execution":<timestamp_ns>}`
- GET and DELETE requests send no body
- HTTP 2xx status codes indicate success; all others indicate failure
- TLS is automatically used for `https://` URLs
- Connection and read timeouts are 30 seconds

**Example: POST with webhook**

```bash
curl -X PUT http://127.0.0.1:5680/rules/notify-deploy \
  -H "Authorization: Bearer token123" \
  -H "Content-Type: application/json" \
  -d '{
    "pattern": "deploy.",
    "runner": {
      "type": "http",
      "method": "POST",
      "url": "https://hooks.example.com/webhook"
    }
  }'
```

**Example: GET request**

```json
{
  "type": "http",
  "method": "GET",
  "url": "https://api.internal/trigger"
}
```

### AWF Runner

Execute an AWF (AI Workflow) via the `awf` CLI. Useful for automating AI agent pipelines on a schedule:

```json
{
  "pattern": "code-review.",
  "runner": "awf",
  "args": ["code-review"]
}
```

With optional input parameters (key=value pairs passed via `--input` flags):

```json
{
  "pattern": "report.",
  "runner": "awf",
  "args": ["generate-report", "--input", "format=pdf", "--input", "target=main"]
}
```

Spawns `awf run <workflow>` (or `awf run <workflow> --input key1=value1 --input key2=value2` when inputs are provided). Requires the `awf` CLI binary in `$PATH`.

## Error Responses

All error responses follow this format:

```json
{
  "error": "human-readable error message"
}
```

Common HTTP status codes:

| Status | Scenario |
|--------|----------|
| `200 OK` | Success |
| `400 Bad Request` | Invalid request body (malformed JSON, missing required fields) |
| `404 Not Found` | Job or rule does not exist |
| `500 Internal Server Error` | Server error |

## Timestamp Format

Job execution timestamps are specified as **ISO 8601 strings** in requests:

```json
{
  "execution": "2026-04-10T12:00:00Z"
}
```

In responses, timestamps are represented as **nanoseconds since Unix epoch**:

```json
{
  "execution": 1744286400000000000
}
```

## See Also

- [TCP Protocol Reference](protocol.md) — Native binary protocol
- [Data Types](types.md) — Job, Rule, and Runner structures
- [Configuration](configuration.md) — Server setup
