Public API
This documents the HTTP endpoints Mergen's runtime already accepts authenticated calls on today. It exists because the website listed "Public API" as a shipped capability while nothing described these endpoints as a product surface: the routes were real, just undocumented as a set. This page closes that gap by describing what's actually callable, not by promising a separate, packaged API product that doesn't exist yet. See What this is not (yet) at the bottom before you build production tooling against it.
For the full local runtime (every route, mergen-server internals), see
CLI_REFERENCE.md. This page covers only the routes
meant to be called by an external system with an API key or admin secret,
not the local dashboard/IDE-extension traffic, which talks to 127.0.0.1
without one.
Authentication: two independent layers
Which one applies depends on deployment mode and route. Both are described in full in the main README's Security section; this is the short version for API callers specifically.
1. x-mergen-secret: admin mutation guard (local and cloud).
Every mutating route, including
POST /incident, requires this header to match
~/.mergen/secret (auto-generated on first run) or MERGEN_ADMIN_SECRET if
you've set one. This exists so that an AI agent with plain filesystem access
on the machine can't forge an admin action by hitting the HTTP API directly:
it is not a "public" credential to hand out to arbitrary integrations.
curl -s http://127.0.0.1:3000/incident \
-H "x-mergen-secret: $(cat ~/.mergen/secret)" \
-H 'Content-Type: application/json' \
-d '{"title":"api is down","service":"api"}'
2. x-api-key: tenant-scoped cloud auth (MERGEN_CLOUD_MODE=true only).
On the multi-tenant cloud deployment, the routes below are additionally
wrapped in tenant authentication, which
validates a plain-text key against its SHA-256 hash, enforces a per-key rate
limit (default 1000 events/minute), and sets req.tenantId so every read and
write is isolated to your organization's data; see the Deployment
boundary note in the main README for exactly which routes are
tenant-partitioned versus process-global.
curl -s https://your-cloud-instance/incident \
-H 'x-api-key: mrgn_live_...' \
-H 'Content-Type: application/json' \
-d '{"title":"api is down","service":"api"}'
Getting a key today is an operator action, not self-service. POST /api-keys (below) itself requires x-mergen-secret; there is no public
sign-up flow that mints a key without admin access to the instance. This is
intentional: keys are provisioned by whoever runs the cloud instance, the
same way mergen-server config set requires the same secret.
curl -s -X POST https://your-cloud-instance/api-keys \
-H "x-mergen-secret: ..." -H 'Content-Type: application/json' \
-d '{"tenantId":"acme-corp","label":"ci-pipeline"}'
# → { "ok": true, "id": "...", "key": "mrgn_live_...", "note": "Store this key securely; it will not be shown again." }
GET /api-keys (list, no plain text) and DELETE /api-keys/:id (revoke) are
also admin-secret-guarded.
Endpoints
Capability policy
Capability policy resolves configurable Gate A rules through the fixed precedence
immutable rule floor > organization policy > developer preference > built-in default.
All mutating endpoints require x-mergen-secret; when RBAC is configured they also require
an admin identity in x-mergen-member. Agent-scoped tokens cannot call these endpoints.
GET|POST|DELETE /capability-policy/preferencesreads or changes the local developer policy.GET|POST|DELETE /capability-policy/organizationreads or changes the separately signed organization policy floor. POST accepts{ "posture": "custom", "capabilities": { "git.force_push": "ask" } }. Invalid or externally replaced policy files fail closed; runtime changes must go through this admin API.GET /capability-policy/effectivereturns the resolved action for every capability-tagged rule plusdeveloperPolicySetandorganizationPolicySet.
The same organization document is distributed with shared enterprise rules as the optional
organizationCapabilityPolicy member of the versioned policy. GET /policies/sync signs and
ETags the combined document for self-hosted fleets; cloud drafts/publishes store both under one
version; POST /policies/import validates and applies both before a cloud sync marker or
acknowledgment advances. Legacy documents without the member preserve the current local
organization floor, while an explicit null clears it.
CLI administrators can use mergen-server policy organization [show],
policy organization set <capability> <allow|ask|block>,
policy organization posture <balanced|strict>, and
policy organization clear. Add --member <id> when local RBAC is configured.
Incident intake: POST /incident
Feeds the incident autopilot, which is off by default (MERGEN_AUTOPILOT) and
not part of agent governance: nothing here affects a PASS / HOLD / BLOCK
verdict. It runs the same triage pipeline as a PagerDuty webhook, for any
monitoring tool that can POST JSON.
curl -X POST http://127.0.0.1:3000/incident \
-H "x-mergen-secret: $(cat ~/.mergen/secret)" \
-H 'Content-Type: application/json' \
-d '{"title":"api is down","service":"api"}'
# → { "ok": true, "pid": "<uuid>", "message": "Autopilot started" }
Edit-time change gate: POST /gate/evaluate-edit
Runs the deterministic diff-content detectors (secret introduction, deleted
tests, auth-bypass, CI-check removal, permission/config weakening) against a
single pending file edit, before the write lands. Returns pass, hold or
block plus the findings. This is the endpoint the IDE Edit/Write/MultiEdit hooks
and the Cursor/VS Code self-heal integrations call. Each detector has its
own rung (MERGEN_EDIT_GATE_DETECTOR_MODES, <id>:shadow|hold|enforce);
MERGEN_EDIT_GATE_MODE is only an on/off kill switch (default on).
Telemetry ingest: POST /ingest, POST /v1/traces, POST /v1/logs
/ingest accepts Mergen's native event shapes (console, network, terminal,
diagnostic). /v1/traces and /v1/logs speak OTLP over HTTP, JSON
encoding only; see the main README's Backend instrumentation section
for the exact OTEL_EXPORTER_OTLP_PROTOCOL=http/json requirement most SDKs
need set explicitly. /v1/metrics returns 200 but stores nothing today.
Service topology: GET /service-graph, GET /route-reachability
Read-only views of the live service dependency graph built from observed
OTLP spans, the same data GET /topology renders as an interactive D3
graph. /route-reachability narrows this to which routes are provably
reachable, used to suppress hypotheses about unreachable code paths during
diagnosis.
What this is not (yet)
Being straightforward about maturity, since the whole point of this page is to stop overclaiming:
- No stable versioning scheme. There is no
/v1/-prefixed convention for Mergen's own endpoints (OTLP's/v1/tracespath is OTLP's own spec, not ours); a breaking change to a route's shape is not yet fenced by a version number. - No official client SDKs, beyond the one-line Node auto-instrumentation
(
import 'mergen-server/sdk/node.js'). Every example above is a rawcurlcall. - No published, guaranteed rate-limit contract beyond the per-API-key default (1000 events/minute, configurable per key at creation).
- No OpenAPI/Swagger spec. This document is hand-maintained against the
route source files, not generated, unlike
CONFIGURATION.md, which a census test keeps in sync with the code automatically. If this page drifts from the routes, the running server's behavior is the source of truth.