Release Manager API
The Release Manager worker exposes HTTP endpoints for GitHub webhooks, Slack interactions, and agent-to-agent communication.
Endpoints
Section titled “Endpoints”GET /health
Section titled “GET /health”Health check endpoint. No authentication required.
Response:
{ "ok": true, "agent": "release-manager", "version": "1.0.0" }POST /webhook/github
Section titled “POST /webhook/github”Receives GitHub webhook events for pull_request actions (opened, synchronize, reopened).
Authentication: X-Hub-Signature-256 header verified against GITHUB_WEBHOOK_SECRET.
Headers:
| Header | Required | Description |
|---|---|---|
X-Hub-Signature-256 | Yes | HMAC-SHA256 signature of the request body |
X-GitHub-Event | Yes | GitHub event type (e.g. pull_request) |
Response:
{ "ok": true }POST /slack/actions
Section titled “POST /slack/actions”Receives Slack interactive action payloads (Approve/Reject button presses).
Authentication: Slack request signature (x-slack-signature + x-slack-request-timestamp).
Supported actions:
release_approve— Approve a PR for mergerelease_reject— Reject a PR
POST /slack/commands
Section titled “POST /slack/commands”Receives Slack slash command invocations.
Authentication: Slack request signature.
Supported commands:
/release status— view release queue (default)/release merge <pr-number> [skip-qa]/release block <pr-number> [reason]/release unblock <pr-number>/release rollback/release help
POST /api/release
Section titled “POST /api/release”Trigger a release for a specific PR. Used for agent-to-agent communication.
Authentication: X-Agent-Token header must match AGENT_SECRET.
Request body:
{ "prNumber": 42, "skipQA": false}| Field | Type | Required | Description |
|---|---|---|---|
prNumber | number | Yes | The PR number to release |
skipQA | boolean | No | Skip QA gate (default: false) |
Response:
{ "ok": true, "message": "Release triggered for PR #42" }Error responses:
401— Missing or invalidX-Agent-Token400— MissingprNumber
GET /api/status/:pr
Section titled “GET /api/status/:pr”Query the release state for a specific PR.
Authentication: X-Agent-Token header must match AGENT_SECRET.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
pr | number | The PR number |
Response:
{ "prNumber": 42, "state": "awaiting-approval", "notifiedBlocked": false, "notifiedReady": true, "qaUxPassed": true, "qaTechPassed": true, "readyAt": "2026-03-15T10:30:00.000Z"}Error responses:
401— Missing or invalidX-Agent-Token400— Invalid PR number
Scheduled Handler
Section titled “Scheduled Handler”The worker runs a cron trigger every 30 minutes (*/30 * * * *) that:
- Checks in-flight deployments for completion
- Fetches all open PRs targeting
main - Evaluates QA status and advances the state machine
- Merges approved PRs and starts deploy monitoring
KV State Schema
Section titled “KV State Schema”release:pr:{number} — PR Record
Section titled “release:pr:{number} — PR Record”{ state: "open" | "qa-pending" | "blocked-p1" | "awaiting-approval" | "approved" | "deploying" | "deployed" | "merge-failed" | "deploy-failed" | "user-blocked", notifiedBlocked: boolean, notifiedReady: boolean, qaUxPassed?: boolean, qaTechPassed?: boolean, p1Count?: number, p2Count?: number, p3Count?: number, approvedBy?: string, approvedAt?: string, blockedAt?: string, blockedBy?: string, readyAt?: string, sha?: string, deployUrl?: string, deployedAt?: string, error?: string, deployError?: string, reverted?: boolean, failedAt?: string, userBlockedReason?: string}release:approval:{number} — Approval State
Section titled “release:approval:{number} — Approval State”{ prNumber: number, prTitle: string, prUrl: string, requestedAt: string, approvedAt?: string, rejectedAt?: string, approvedBy?: string, rejectedBy?: string, slackMessageTs?: string, slackChannel?: string}deploy:monitor:{number} — Deploy Monitor State
Section titled “deploy:monitor:{number} — Deploy Monitor State”{ sha: string, prNumber: number, owner: string, repo: string, startedAt: number, workflowRunId?: number}