API endpoints reference¶
All endpoints live under /api/cra/. When MERIDIAN_AUTH_ENABLED=true, requests must carry a bearer token unless noted otherwise. See Authentication & RBAC for the full auth model.
Base URL in examples: http://localhost:3011
Health¶
GET /api/cra/health¶
Liveness/readiness probe. Unauthenticated. Safe for Kubernetes/Docker health checks.
What it does not check: LLM tier availability, MinIO/S3 reachability, custom rule parsing errors. Use /api/cra/dispatcher/status for a deeper view.
RFC lifecycle¶
POST /api/cra/analyze¶
Submit a diff for analysis. Creates an RFC and runs the 3-gate pipeline (risk patterns → AST → LLM). Returns immediately; status may be DRAFT if Gate 3 is still running — poll GET /api/cra/rfc/<id> for terminal status.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
repo_name |
string | yes | Repository identifier |
branch |
string | yes | Branch being changed |
commit_message |
string | yes | Commit or change description |
diff |
string | yes | Unified diff (git diff --cached) |
diffSource |
local | pre-commit | github-pr | github-compare |
no | Origin of the diff |
commitSha |
string | no | Commit SHA (for VCS status posting) |
repoFullName |
string | no | owner/repo form (for GitHub status) |
postGithubStatus |
boolean | no | Post a commit status to GitHub |
curl -s -X POST http://localhost:3011/api/cra/analyze \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{
"repo_name": "my-api",
"branch": "feature/login",
"commit_message": "add login route",
"diff": "--- a/auth.js\n+++ b/auth.js\n@@\n+app.post(\"/login\",(req,res)=>{});\n"
}'
Response
{
"rfc_id": "RFC-9F2C4A1B",
"diff_hash": "9f2c4a1b...",
"overall_status": "BLOCKED",
"risk_score": 24,
"gates": {
"risk": {
"status": "fail",
"findings": [
{ "id": "secret-aws-key", "severity": "critical", "message": "Hardcoded AWS access key" }
]
},
"ast": { "status": "pass", "findings": [] },
"llm": { "status": "skipped", "findings": [] }
}
}
Note
analyze does not post a VCS status check by itself. Set postGithubStatus: true or use the webhook endpoint for push-driven flows.
GET /api/cra/rfc/<rfc_id>¶
Retrieve a single RFC with its gate results and override history.
curl -s http://localhost:3011/api/cra/rfc/RFC-9F2C4A1B \
-H "Authorization: Bearer $CRA_API_TOKEN" | jq
Response
{
"rfc_id": "RFC-9F2C4A1B",
"repo_name": "my-api",
"branch": "feature/login",
"commit_message": "add login route",
"diff_hash": "9f2c4a1b...",
"overall_status": "BLOCKED",
"risk_score": 24,
"created_at": "2026-06-08T10:00:00Z",
"gates": { ... },
"override": null
}
Poll until terminal:
while true; do
STATUS=$(curl -s http://localhost:3011/api/cra/rfc/RFC-9F2C4A1B \
-H "Authorization: Bearer $CRA_API_TOKEN" | jq -r '.overall_status')
[ "$STATUS" != "DRAFT" ] && break
sleep 2
done
echo "$STATUS"
GET /api/cra/rfcs¶
List the 50 most recent RFCs, sorted by status priority (BLOCKED first).
curl -s http://localhost:3011/api/cra/rfcs \
-H "Authorization: Bearer $CRA_API_TOKEN" | jq '.[0:5]'
POST /api/cra/rfc/<rfc_id>/override¶
Record an override on a BLOCKED RFC. Moves it to OVERRIDDEN and writes to the WORM audit trail. Requires the override token (or admin session).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
actor |
string | yes | Identity of the person overriding |
reason |
string | yes | Permanent justification — choose words carefully |
curl -s -X POST http://localhost:3011/api/cra/rfc/RFC-9F2C4A1B/override \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CRA_OVERRIDE_TOKEN" \
-d '{
"actor": "alice@example.com",
"reason": "False positive — query uses parameterised placeholder, not string concatenation"
}'
Response
POST /api/cra/approve/<rfc_id>¶
Approve or override an RFC via the dashboard-style flow. Equivalent to /override but accepts additional fields used by the dashboard.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Justification |
action |
approve | override |
no | Default: approve |
force_commit_sha |
string | no | Pin the approval to a specific SHA |
force_repo_full_name |
string | no | owner/repo used for GitHub status post |
POST /api/cra/reject/<rfc_id>¶
Explicitly mark an RFC as rejected (used by CAB workflow).
Request body: { "reason": "..." }
POST /api/cra/bulk-override¶
Override multiple RFCs at once. Requires override token.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Shared justification for all overrides |
repo |
string | no | Filter to a specific repo |
before_date |
ISO 8601 string | no | Override RFCs created before this date |
rfc_ids |
string[] | no | Explicit list of RFC IDs |
DELETE /api/cra/rfc/<rfc_id>¶
Delete an RFC and its approvals. Requires admin session. Irreversible — use only to remove test/erroneous records.
Production readiness¶
GET /api/cra/prod-check/<repo>¶
Check whether a repository is cleared for a production deploy. Returns the latest RFC and a deploy decision.
curl -s "http://localhost:3011/api/cra/prod-check/my-api" \
-H "Authorization: Bearer $CRA_API_TOKEN" | jq
Response
{
"allowed": false,
"rfcId": "RFC-9F2C4A1B",
"riskScore": 24,
"reason": "RFC is BLOCKED — 1 critical finding in Gate 1",
"approveUrl": "http://localhost:3011/cra#approve-RFC-9F2C4A1B"
}
Wire this as the first step of any production deploy script.
Webhooks¶
POST /api/cra/webhook¶
Receives push events from VCS providers (Forgejo, Gitea, GitHub, GitLab). Meridian validates the HMAC signature, computes the diff, and triggers the analysis pipeline.
Authentication: HMAC signature only (not bearer token). See Authentication.
# Typically configured in VCS settings, not called by hand.
# Payload format: standard GitHub/Forgejo push event JSON
GET /api/cra/webhook-status/<repo>¶
Return the RFC created by the most recent webhook push for a given repository.
Operations log¶
POST /api/cra/ops-log¶
Record an operational event that has no code diff — deployment, test run, config change, infrastructure action.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | yes | Short action name, e.g. deploy-staging |
description |
string | yes | Human-readable detail |
command |
string | no | Shell command run (for audit) |
repo |
string | no | Associated repository |
curl -s -X POST http://localhost:3011/api/cra/ops-log \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{
"action": "deploy-staging",
"description": "Deployed v1.4.2 to staging for smoke test",
"repo": "my-api"
}'
Worker task queue¶
The task queue lets agents (Claude Code, custom bots) pick up remediation tasks and report back. It is the backbone of agentic fix-and-verify loops.
GET /api/cra/pending-tasks¶
Fetch all tasks that are in pending state. Token-only auth (session cookies not accepted).
Response
[
{
"taskId": "task_01HX...",
"findingId": "finding_01HX...",
"title": "SQL injection in search route",
"severity": "high",
"description": "Unsanitised input passed directly to pool.query()",
"suggestedFix": "Use parameterised query: pool.query('SELECT ... WHERE id=?', [id])",
"filePath": "src/routes/search.js",
"lineHint": 42
}
]
POST /api/cra/task-status¶
Update the status of a task. Token-only auth.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
taskId |
string | yes | Task ID from pending-tasks |
status |
pending | picked | done | failed |
yes | New status |
markFixed |
boolean | no | If true, also marks the finding as resolved |
# Mark task as picked up
curl -s -X POST http://localhost:3011/api/cra/task-status \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{"taskId":"task_01HX...","status":"picked"}'
# Mark task as done + mark finding fixed
curl -s -X POST http://localhost:3011/api/cra/task-status \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CRA_API_TOKEN" \
-d '{"taskId":"task_01HX...","status":"done","markFixed":true}'
POST /api/cra/claude-task¶
Create a new remediation task from a finding.
Request body: { "findingId": "finding_01HX..." }
LLM usage tracking¶
If you integrate external LLM calls (e.g. your own agents calling Claude or DeepSeek), you can log their costs to the shared Meridian usage tracker.
POST /api/cra/usage/log¶
Token-only auth.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
provider |
string | yes | anthropic, deepseek, ollama, etc. |
model |
string | yes | Model ID |
input_tokens |
integer | yes | |
output_tokens |
integer | yes | |
cache_creation_tokens |
integer | no | Anthropic prompt-cache write tokens |
cache_read_tokens |
integer | no | Anthropic prompt-cache read tokens |
cost_usd |
number | yes | Actual cost in USD |
context |
string | no | What the call was for |
GET /api/cra/usage/total¶
Query params: ?hours=24 (default: 24)
Returns total cost and token counts for the window.
GET /api/cra/usage/summary¶
Query params: ?since=YYYY-MM-DD
Returns daily breakdown by provider and model.
Rules management¶
GET /api/cra/rules¶
Return the current rules configuration (risk patterns, secret patterns, vuln patterns, pipeline settings).
PUT /api/cra/rules¶
Replace the entire rules configuration. Requires admin session. Accepts the same JSON schema as MERIDIAN_RULES_PATH. See Rules schema.
Status codes¶
| Code | Meaning |
|---|---|
200 |
Success |
400 |
Malformed request (invalid JSON, missing field) |
401 |
Auth enabled and token missing or invalid |
403 |
Token valid but insufficient privileges |
404 |
RFC, finding, or task not found |
409 |
Conflict (e.g. cycle already closed) |
500 |
Server error |
Response envelope:
API checklist for agent authors¶
Before writing a new agent integration against the Meridian API:
- Read
GET /api/cra/healthfirst; bail if not{"status":"ok"}. - Use
MERIDIAN_AUTH_ENABLED=falseonly in local dev; always pass a token in CI/prod. - After
POST /api/cra/analyze, pollGET /api/cra/rfc/<id>until status is notDRAFT. - Use
GET /api/cra/pending-tasks(not your own task store) for work dispatch. - Mark tasks
pickedimmediately when starting,doneorfailedwhen finished. - Check
GET /api/cra/prod-check/<repo>before any production deploy. - Log LLM calls via
POST /api/cra/usage/logif running your own LLM agents.
Next: MCP tools · Authentication & RBAC · AST rules catalog