> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prvue.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Orchestrator API

> HTTP endpoints exposed by the orchestrator for health checks, webhooks, and debugging

The orchestrator is an Express service that listens on **ORCHESTRATOR\_PORT** (default **3000**). It is typically not exposed publicly: nginx proxies `/webhook/github` to it; other endpoints are for health checks and debugging from the server (e.g. `curl` on the droplet or via SSH).

**Base URL**: `http://localhost:3000` (on the server) or `http://SERVER_IP:3000` if the port is forwarded. Replace `SERVER_IP` with your droplet IP when running `curl` from your machine (only if port 3000 is reachable; by default it is internal).

**OpenAPI / Swagger UI**: The API spec is available at `GET /openapi.json` and interactive docs at `GET /api-docs` for exploration (e.g. `http://localhost:3000/openapi.json`, `http://localhost:3000/api-docs`).

## Endpoints

### GET /health

Liveness check. Returns basic orchestrator status and uptime.

**Request**: No body or headers required.

**Response** (200 OK):

```json theme={null}
{
  "status": "ok",
  "timestamp": "2026-02-04T12:00:00.000Z",
  "uptime": 3600.5
}
```

**Example** (from server):

```bash theme={null}
curl http://localhost:3000/health
```

Use this to confirm the orchestrator process is running (e.g. in [Troubleshooting](/troubleshooting)).

***

### POST /webhook/github

Receives GitHub pull request webhook events. Validates the request signature, then triggers deploy, update, or cleanup.

**Headers**:

| Header                | Required | Description                                           |
| --------------------- | -------- | ----------------------------------------------------- |
| `Content-Type`        | Yes      | `application/json`                                    |
| `X-Hub-Signature-256` | Yes      | HMAC SHA256 of the raw body using your webhook secret |

**Body**: GitHub [pull\_request](https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request) webhook payload (JSON). Relevant fields include `action` (`opened`, `synchronize`, `closed`, `reopened`), `pull_request`, and `repository`.

**Response**:

* **200 OK**: `{ "status": "ok" }` — webhook accepted and processed (or queued).
* **401 Unauthorized**: `{ "error": "Invalid signature" }` — `X-Hub-Signature-256` missing or does not match.
* **500 Internal Server Error**: `{ "error": "<message>" }` — processing failed (e.g. clone, build, or cleanup error).

**Example** (from server; replace secret and payload):

```bash theme={null}
curl -X POST http://localhost:3000/webhook/github \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: sha256=<hmac-hex>" \
  -d '{"action":"opened","pull_request":{...},"repository":{...}}'
```

In production, GitHub sends requests to `http://YOUR_SERVER_IP/webhook/github`; nginx proxies to the orchestrator. Do not call this endpoint manually unless you are replaying or testing webhooks with a valid signature.

***

### GET /api/previews

Returns all tracked preview deployments. Useful for debugging: see which deployments exist, their status, ports, and URLs.

**Request**: No body or headers required.

**Response** (200 OK):

```json theme={null}
{
  "deployments": [
    {
      "prNumber": 12,
      "repoName": "my-app",
      "repoOwner": "my-org",
      "projectSlug": "my-org-my-app",
      "deploymentId": "my-org-my-app-12",
      "branch": "feature-branch",
      "commitSha": "abc123...",
      "framework": "nestjs",
      "dbType": "postgres",
      "appPort": 3000,
      "exposedAppPort": 8012,
      "exposedDbPort": 9012,
      "status": "running",
      "createdAt": "2026-02-04T10:00:00.000Z",
      "updatedAt": "2026-02-04T10:05:00.000Z",
      "url": "http://SERVER_IP/my-org-my-app/pr-12/",
      "commentId": 456789
    }
  ]
}
```

**Response** (500): `{ "error": "<message>" }` — e.g. tracker read failed.

**Example** (from server):

```bash theme={null}
curl http://localhost:3000/api/previews
```

***

### DELETE /api/previews/:deploymentId

Manually cleanup a single preview: stops and removes Docker containers, removes nginx config, and deletes the deployment from the tracker. Use for debugging stuck previews or reclaiming resources.

**Parameters**:

| Parameter      | Location | Description                                                                       |
| -------------- | -------- | --------------------------------------------------------------------------------- |
| `deploymentId` | path     | Full deployment id (e.g. `my-org-my-app-12`). Format: `{projectSlug}-{prNumber}`. |

**Response**:

* **200 OK**: `{ "status": "ok", "message": "Preview <deploymentId> cleaned up" }`
* **400 Bad Request**: `{ "error": "Invalid deployment id" }` — missing or empty `deploymentId`.
* **404 Not Found**: `{ "error": "Deployment not found" }` — no tracked deployment with that id.
* **500 Internal Server Error**: `{ "error": "<message>" }` — cleanup failed (Docker, nginx, or tracker).

**Example** (from server; use a real `deploymentId` from `GET /api/previews`):

```bash theme={null}
curl -X DELETE http://localhost:3000/api/previews/my-org-my-app-12
```

<Warning>
  This endpoint immediately tears down the preview. Use it when you need to force-clean a deployment (e.g. after a failed build or for testing). For normal cleanup, rely on PR close or TTL.
</Warning>

***

## Debugging tips

1. **Orchestrator not responding**: Check that the service is running (`journalctl -u preview-orchestrator -f`) and that **ORCHESTRATOR\_PORT** (default 3000) is correct. Call `GET /health` from the server.
2. **List current previews**: Use `GET /api/previews` to see all deployments, their `deploymentId`, `status`, and `exposedAppPort`/`exposedDbPort`. Compare with `docker ps` and nginx configs.
3. **Force-clean a preview**: If a preview is stuck or you need to free a port, use `DELETE /api/previews/:deploymentId` with the id from `GET /api/previews`. Then verify with `GET /api/previews` and `docker ps`.
4. **Webhook signature**: Manual `POST /webhook/github` calls must include a valid `X-Hub-Signature-256` header (HMAC SHA256 of the raw JSON body with your `GITHUB_WEBHOOK_SECRET`). See [GitHub webhook signature verification](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries).

For more debugging steps, see [Troubleshooting](/troubleshooting).
