API Reference
StateAnchor exposes REST endpoints for the GitHub Action, programmatic integrations, and public project status. All endpoints return JSON.
Authentication
StateAnchor uses two authentication methods depending on the caller:
| Method | Used by | How it works |
|---|---|---|
| Clerk session | Browser / dashboard | Automatic via cookie. Used by all /api/projects/* and dashboard routes. |
| GitHub OIDC action token | GitHub Action (machine) | Short-lived token minted via /api/action/oidc/exchange. Passed as Bearer token in the Authorization header. Used by /api/action/* endpoints. |
The action token flow: GitHub provides an OIDC JWT → the action exchanges it with StateAnchor → StateAnchor returns a scoped action token bound to the repo, ref, and event type. This token is valid for 5 minutes.
Base URL
https://stateanchor.devAll endpoint paths below are relative to this base URL.
POST /api/action/validate
Validates a stateanchor.yaml spec file. Returns validation result and parsed config summary.
Authentication
Required. Action token via Authorization: Bearer <action_token>.
Request body
{
"config_content": "<raw YAML string>",
"repo": "owner/repo",
"ref": "refs/heads/main",
"commit_sha": "abc123..."
}Success response (200)
{
"valid": true,
"config_summary": {
"service": "payments-api",
"version": "1.0.0",
"endpoint_count": 3,
"outputs": ["typescript", "python", "mcp"]
}
}Error responses
| Status | Error code | Description |
|---|---|---|
| 401 | invalid_action_token | Token missing, expired, or invalid. |
| 403 | repo_not_linked | Repository is not connected in StateAnchor. |
| 403 | ref_not_allowed | Branch/ref is not in the allowed mappings. |
| 422 | invalid_config | YAML parse error or schema validation failure. Includes errors array. |
| 429 | rate_limited | Too many requests. Retry after the Retry-After header value. |
POST /api/action/gate-check
Diffs the incoming spec against the previous IR, scores breaking changes, evaluates the gate policy, creates a sync run, and returns the gate decision. This is the primary endpoint the GitHub Action calls after validation passes.
Authentication
Required. Action token via Authorization: Bearer <action_token>.
Request body
{
"config_content": "<raw YAML string>",
"repo": "owner/repo",
"ref": "refs/heads/main",
"commit_sha": "abc123...",
"mode": "sync"
}Success response (200)
{
"gate_action": "allow",
"gate_score": 0,
"gate_reason": "No breaking changes detected",
"sync_run_id": "fb87c28a-4509-4463-9fc0-ac35e2438c3b",
"breaking_operations": [],
"diff_summary": {
"total_changes": 1,
"breaking_changes": 0,
"additions": 1,
"removals": 0
}
}Blocked response (200 with gate_action: block)
{
"gate_action": "block",
"gate_score": 40,
"gate_reason": "Breaking changes exceed block threshold (60)",
"sync_run_id": "a1b2c3d4-...",
"breaking_operations": [
{
"kind": "endpoint_removed",
"path": "/users",
"score": 40,
"severity": "error",
"description": "Endpoint GET /users was removed"
}
]
}Error responses
| Status | Error code | Description |
|---|---|---|
| 401 | invalid_action_token | Token missing, expired, or invalid. |
| 403 | repo_not_linked | Repository is not connected in StateAnchor. |
| 403 | ref_not_allowed | Branch/ref is not in the allowed mappings. |
| 422 | invalid_config | Spec failed validation. |
| 429 | rate_limited | Too many requests. |
POST /api/waitlist
Public endpoint. Adds an email to the StateAnchor waitlist. No authentication required.
Request body
{
"email": "user@example.com"
}Success response (200)
{
"ok": true
}Error responses
| Status | Error code | Description |
|---|---|---|
| 400 | missing_email | Email field is missing or empty. |
| 409 | already_registered | Email is already on the waitlist. |
Rate limits
| Endpoint | Limit | Scope |
|---|---|---|
/api/action/validate | 10 requests / minute | Per repository |
/api/action/gate-check | 5 requests / minute | Per sync run |
/api/waitlist | 5 requests / minute | Per IP |
Rate-limited responses return 429 with a Retry-After header indicating seconds to wait before retrying.
Error format
All error responses use a consistent JSON shape:
{
"error": "error_code_string"
}The error field is a machine-readable snake_case code. Some endpoints include additional fields like errors (array of validation issues) ordetail (human-readable explanation).
// Example: validation failure with details
{
"error": "invalid_config",
"errors": [
"endpoints[0]: missing required field 'method'",
"outputs: at least one output must be enabled"
]
}