Skip to content
Critique/docs
Platform

Merge Gate API

Machine-readable PR review for agents — queue reviews over REST or MCP, receive structured verdicts and findings via webhooks or poll.

The Merge Gate API is Critique’s Platform API v1 surface for orchestrators and coding-agent stacks. It answers one question programmatically: should this pull request merge?

Critique is not a coding agent host in this story — your writer agent (Cursor, Devin, Codex, internal bot) opens the PR; Critique judges it and returns structured evidence agents can act on without scraping GitHub comments.

Marketing overview, cookbooks, and signed-in key generation: /merge-gate-api.

Long-form essay — why, benefits, and where Critique sits in the agent wave: The Merge Gate API: Why Agent Teams Need a Judge That Is Not the Writer.

Need a sandbox that writes code? See the sibling Coding Agent API. Need raw tokens only? See Inference API.

What this API is (and is not)

Merge Gate APICoding Agent API
JobInspect a PR; return PASS / WARN / FAIL + findingsRun OpenCode in E2B; return patch / draft PR
Primary callerCI orchestrator, agent supervisor, merge botAutomation that needs a sandboxed coder
Typical loopAgent opens PR → Critique gate → fix agent reads findingsPrompt → sandbox → optional draft PR
Scopesread:reviews, write:reviews, manage:webhooksread:builder, write:builder

Critique’s product principle: the agent that wrote the code should not be the only thing that approves it. The merge gate is a separate role with separate success criteria.

Architecture: agent merge loop

sequenceDiagram
  participant Writer as Writer agent
  participant GH as GitHub
  participant Orch as Your orchestrator
  participant CG as Critique merge gate
  participant Fix as Fix agent

  Writer->>GH: Open / update PR
  Orch->>CG: POST /api/v1/reviews
  CG->>GH: Check run + comments (parallel)
  CG-->>Orch: Webhook review.completed + findings[]
  alt verdict FAIL or WARN
    Orch->>Fix: findings[] as blockers
    Fix->>GH: Push fix commit
    Orch->>CG: POST /api/v1/reviews (new headSha)
  else verdict PASS
    Orch->>GH: Approve / merge (your policy)
  end

Host-agnostic: today Critique reads PRs from GitHub. The REST contract (repositoryFullName, pullRequestNumber, headSha) stays stable if you add other hosts later — orchestrators should not depend on HTML check pages.

Authentication

ItemValue
AuthAuthorization: Bearer crt_…
Create keysSettings → ConnectionsCritique API keys
OpenAPIGET /api/v1/openapi (YAML)

Keys authenticate as your Critique user. The repository must already be on a GitHub App installation you control. Browser session cookies also work on v1 routes when signed in.

Scopes you need

ScopeMerge gate use
write:reviewsPOST /api/v1/reviews, MCP queue_review, MCP queue_remedy
read:reviewsGET /api/v1/review-runs/:id, MCP get_review_run, MCP list_review_runs
read:passportsGET /api/v1/passports, MCP list_passports / get_passport
manage:webhooksInstallation lifecycle subscriptions (POST /api/v1/webhook-endpoints)

New keys include these scopes by default. Rotate older keys if automation returns 403.

REST endpoints

MethodPathScopePurpose
POST/api/v1/reviewswrite:reviewsQueue a PR review
GET/api/v1/review-runs/{id}read:reviewsPoll status, verdict, findings
GET/api/v1/passportsread:passportsChange passport queue
GET/api/v1/passports/{id}/exportread:passportsCompliance bundle JSON
GET/POST/DELETE/api/v1/webhook-endpointsmanage:webhooksInstallation lifecycle subscriptions
POST/api/mcpvariesMCP JSON-RPC for IDE agents

Queue a review

Request body

FieldRequiredNotes
repositoryFullNameYesowner/repo
pullRequestNumberYesInteger ≥ 1
headShaYesCommit SHA on the PR head (min 7 chars)
pullRequestTitleNoStored on the review run for dashboards
webhookNoPer-run callback — see Per-run webhooks

Returns 202 with:

{
  "review": {
    "reviewRunId": "clx…",
    "status": "QUEUED",
    "repository": "acme/web",
    "pullRequestNumber": 42,
    "headSha": "abc123…"
  }
}

Critique deduplicates by (repository, pullRequestNumber, headSha). Re-queuing the same SHA with forceRerun semantics (API always forces rerun on terminal runs) updates the run and enqueues pipeline work.

Example — queue with per-run webhook

curl https://critique.sh/api/v1/reviews \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "repositoryFullName": "acme/web",
    "pullRequestNumber": 42,
    "headSha": "abc123def4567890abcdef1234567890abcdef12",
    "webhook": {
      "url": "https://example.com/hooks/critique-review",
      "secret": "replace-with-at-least-32-random-characters",
      "events": ["review.completed", "review.failed"]
    }
  }'

Example — poll until terminal

RUN_ID="clx…"

until true; do
  BODY=$(curl -s "https://critique.sh/api/v1/review-runs/$RUN_ID?findings=all" \
    -H "Authorization: Bearer crt_YOUR_KEY")
  STATUS=$(echo "$BODY" | jq -r '.reviewRun.status')
  echo "status=$STATUS"
  case "$STATUS" in
    COMPLETED|FAILED)
      echo "$BODY" | jq '{verdict: .reviewRun.verdict, findingsTotal: .reviewRun.findingsTotal, findings: .reviewRun.findings}'
      break
      ;;
  esac
  sleep 20
done

Review run snapshot

GET /api/v1/review-runs/{id} returns { "reviewRun": { … } }.

Query parameters

ParamEffect
(default)Up to 5 findings (chat-sized payload)
?findings=allAll findings, sorted by severity then confidence

When truncated, findingsTruncated: true and findingsTotal report the full count.

Response fields (automation-relevant)

FieldTypeDescription
reviewRunIdstringStable id for polls and webhooks
statusstringQUEUED, IN_PROGRESS, COMPLETED, FAILED, CANCELLED
verdictstring | nullPASS, WARN, FAIL when completed
summarystring | nullHuman-readable lead summary
riskBandstring | nullRisk tier from change-control scoring
riskScorenumber | nullNumeric risk score when computed
headShastringSHA this run reviewed
changePassportIdstring | nullLinked Change Passport
findingsarrayStructured findings (see below)
findingsTotalnumberCount in database
findingsTruncatedbooleanTrue when default cap applied
urls.reviewRunWithFindingsstringPath with ?findings=all
latestRemedyRunobject | nullRemedy status if a fix was queued

Finding object

Each finding is machine-readable — designed for fix agents, not dashboard prose:

FieldDescription
idFinding id (when persisted)
specialistSECURITY, TESTS, ARCHITECTURE, PERFORMANCE, CODE_QUALITY, …
severityINFO, WARNING, FAIL
confidence0–1 model/heuristic confidence
titleShort label
summaryEvidence-oriented explanation
filePathFile path or null
startLine, endLineLine range or null
fingerprintStable id for dedupe / memory

Example:

{
  "id": "clf…",
  "specialist": "SECURITY",
  "severity": "FAIL",
  "confidence": 0.91,
  "title": "Missing authorization on admin route",
  "summary": "POST /api/admin/users accepts requests without session check.",
  "filePath": "src/app/api/admin/users/route.ts",
  "startLine": 14,
  "endLine": 28,
  "fingerprint": "sec:admin-route-no-auth"
}

Webhooks

Critique supports two webhook channels for reviews. They can fire in parallel for the same run.

Comparison

Installation lifecyclePer-run (on POST /reviews)
RegisterPOST /api/v1/webhook-endpointswebhook field on queue request
User-AgentCritique-Lifecycle-Webhook/1.0Critique-Review-Webhook/1.0
Eventsreview.run.completed, review.run.failed, …review.completed, review.failed, review.queued
ScopeAll reviews on installationSingle queued run
RetriesV1: single attempt, 8s timeoutSame

Shared headers on every delivery:

HeaderValue
X-Critique-Webhook-IDUnique delivery id
X-Critique-Webhook-EventEvent name
X-Critique-Webhook-Signaturesha256=<hex HMAC> over raw JSON body

Verify before trusting:

import crypto from 'node:crypto'

export function verifyCritiqueWebhook(secret: string, rawBody: string, signature: string) {
  const expected = `sha256=${crypto.createHmac('sha256', secret).update(rawBody).digest('hex')}`
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}

Lifecycle: review.run.completed payload

{
  "event": "review.run.completed",
  "timestamp": "2026-06-17T12:00:00.000Z",
  "id": "clx…",
  "object": "review.run",
  "status": "completed",
  "installationId": "inst_…",
  "repository": "acme/web",
  "pullRequest": { "number": 42, "headSha": "abc123…" },
  "changePassportId": "clp…",
  "verdict": "FAIL",
  "riskBand": "high",
  "riskScore": 78,
  "summary": "One blocking security finding.",
  "findingsCount": 3,
  "findings": [
    {
      "specialist": "SECURITY",
      "severity": "FAIL",
      "confidence": 0.91,
      "title": "Missing authorization on admin route",
      "summary": "…",
      "filePath": "src/app/api/admin/users/route.ts",
      "startLine": 14,
      "endLine": 28,
      "fingerprint": "sec:admin-route-no-auth"
    }
  ],
  "urls": {
    "reviewRun": "/api/v1/review-runs/clx…",
    "reviewRunWithFindings": "/api/v1/review-runs/clx…?findings=all",
    "dashboard": "/dashboard/review-runs/clx…"
  }
}

On failure, review.run.failed includes failureReason and summary (no findings).

Per-run webhooks

EventWhen
review.queuedRun accepted from API
review.completedPipeline finished — verdict + findings[]
review.failedPipeline error

Default events when omitted: review.completed, review.failed.

Other lifecycle events (installation)

Subscribe explicitly when building agent supervisors:

EventAgent use
checkpoint.gate.evaluatedCheap pre-filter before full review — see Checkpoint
merge_policy.evaluatedProgrammatic merge-policy outcome after review
passport.snapshot.createdAudit / compliance hooks
remedy.run.completedFix agent finished — new SHA may need re-review

Full catalog: Connections & Platform API — lifecycle webhooks.

MCP for IDE agents

External clients (Cursor, Claude Desktop, custom LangGraph apps) call Critique over MCP:

ItemValue
URLhttps://critique.sh/api/mcp
AuthAuthorization: Bearer crt_…
Methodsinitialize, tools/list, tools/call, ping

Merge-gate tools

ToolScopeNotes
queue_reviewwrite:reviewsSame body as POST /api/v1/reviews (including optional webhook in schema where supported)
get_review_runread:reviewsReturns all findings (not capped at 5)
list_review_runsread:reviewsRecent runs for your installations
queue_remedywrite:reviewsQueue bounded fix run for a review
get_remedy_statusread:reviewsPoll Remedy progress
list_passports / get_passportread:passportsChange-control context

Example tools/call:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "queue_review",
    "arguments": {
      "repositoryFullName": "acme/web",
      "pullRequestNumber": 42,
      "headSha": "abc123def4567890abcdef1234567890abcdef12"
    }
  }
}

Configure MCP in Cursor with the Critique URL and a crt_ key. MCP does not replace GitHub App install.

See Connections & Platform API — MCP for the full ten-tool list and scope enforcement.

Checkpoint first (for agent PR floods)

When coding agents open many PRs per day, run Checkpoint before paying for full multi-agent review:

  1. Subscribe to checkpoint.gate.evaluated on your installation webhook.
  2. On outcome: block — stop the merge loop; do not queue review (or only queue after human override).
  3. On outcome: warn — queue POST /api/v1/reviews for full findings.
  4. On outcome: pass — queue review only if your policy requires Critique on every agent PR.

Checkpoint is deterministic and fast; the merge gate is evidence-heavy. Together they mirror “lint then test” for agent-generated code.

After FAIL: fix paths

PathWhen to use
Your fix agentFeed findings[] to Cursor / Codex / Devin with file paths and summaries
MCP queue_remedyCritique-managed Remedy sandbox (Remedy blueprint)
BYOA handoffGET /api/review-runs/:id/byoa/cursor (session) — requires keys in Settings → Agents

Re-queue review after the head SHA changes:

curl https://critique.sh/api/v1/reviews \
  -H "Authorization: Bearer crt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "repositoryFullName": "acme/web",
    "pullRequestNumber": 42,
    "headSha": "NEW_HEAD_SHA_AFTER_FIX"
  }'

HTTP errors

StatusMeaning
401Missing or invalid crt_ key
403Valid key but missing scope (e.g. write:reviews)
404Repository not on your installation, or review run not visible
422Validation error (bad SHA, missing fields)
500Queue or pipeline failure — check failureReason on run or webhook

Responses use { "error": "…" } and Cache-Control: no-store.

Credits

Each full review run consumes credits like an automated GitHub-triggered review. Checkpoint-only paths are cheaper. See Billing & credits.

Security

  • Treat crt_ keys like passwords — revoke in Connections if leaked.
  • Use separate keys per orchestrator environment.
  • Webhook secrets must be ≥ 32 characters; stored encrypted at rest (CRITIQUE_SECRETS_ENCRYPTION_KEY).
  • Critique never exposes full secrets after save.