Skip to main content
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):
{
  "status": "ok",
  "timestamp": "2026-02-04T12:00:00.000Z",
  "uptime": 3600.5
}
Example (from server):
curl http://localhost:3000/health
Use this to confirm the orchestrator process is running (e.g. in Troubleshooting).

POST /webhook/github

Receives GitHub pull request webhook events. Validates the request signature, then triggers deploy, update, or cleanup. Headers:
HeaderRequiredDescription
Content-TypeYesapplication/json
X-Hub-Signature-256YesHMAC SHA256 of the raw body using your webhook secret
Body: GitHub 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):
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):
{
  "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):
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:
ParameterLocationDescription
deploymentIdpathFull 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):
curl -X DELETE http://localhost:3000/api/previews/my-org-my-app-12
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.

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.
For more debugging steps, see Troubleshooting.