{
  "openapi": "3.0.3",
  "info": {
    "title": "Intertrace API",
    "version": "0.1.0",
    "description": "Public and authenticated API surface for Intertrace telemetry, gateway enrollment, runtime tool decisions, MCP inventory, workload identity, and security exports. API-key routes use Authorization: Bearer with an Intertrace API key (prefix bst_ or itr_); dashboard routes use the session cookie. Gateway routes (/v1/*, /mcp, /healthz) are served by the Intertrace edge at https://intertrace.fly.dev (Fly agentgateway + Go enforcer), not the Next.js app origin; each of those operations lists that server so requests from this reference go there. Runtime routes authenticate with Bearer itr_rt_*; tenancy comes from the key."
  },
  "servers": [
    {
      "url": "/",
      "description": "Same origin as the Next.js app"
    }
  ],
  "paths": {
    "/api/gateway/verify-key": {
      "post": {
        "summary": "Verify a gateway API key and return its org binding",
        "description": "Internal: called by the Go gateway, authenticated with the shared INTERTRACE_INTERNAL_SECRET in the X-Intertrace-Internal header. Not for browser or customer clients.",
        "security": [
          {
            "internalSecret": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["raw_key"],
                "properties": {
                  "raw_key": { "type": "string", "description": "Org API key (itr_\u2026; legacy bst_\u2026 accepted)" },
                  "provider": { "type": "string", "default": "openai" },
                  "metadata": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Always 200 once the caller is authenticated: { valid: true, org_id, key_id } for a valid key, { valid: false } for an unknown or expired key, or { valid: false, denied: true, status_code, reason } when enforcement denies it"
          },
          "401": {
            "description": "Missing or wrong internal secret"
          },
          "500": {
            "description": "Internal error"
          }
        }
      }
    },
    "/api/gateway/event": {
      "post": {
        "summary": "Ingest a gateway security event (HMAC or internal secret)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event accepted"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/gateway/ingest-credentials": {
      "get": {
        "summary": "Resolve hosted gateway ingest credentials",
        "description": "First-party hosted gateways use the internal shared secret to fetch or create per-org ingest signing material. Clients must not call this route directly.",
        "parameters": [
          {
            "name": "orgId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID that owns the ingest credentials"
          },
          {
            "name": "environment",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Gateway environment for newly-created hosted credentials; defaults to production"
          },
          {
            "name": "x-intertrace-internal",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "First-party gateway shared secret"
          }
        ],
        "responses": {
          "200": {
            "description": "Hosted gateway ingest credentials",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["org_id", "key_id", "secret", "created"],
                  "properties": {
                    "org_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "key_id": {
                      "type": "string"
                    },
                    "secret": {
                      "type": "string",
                      "description": "Plaintext ingest signing secret returned only to the first-party gateway."
                    },
                    "created": {
                      "type": "boolean",
                      "description": "True when the route minted hosted credentials for the org."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "orgId must be a UUID"
          },
          "401": {
            "description": "Unauthorized"
          },
          "503": {
            "description": "Internal secret not configured"
          },
          "500": {
            "description": "Failed to resolve ingest credentials"
          }
        }
      }
    },
    "/api/runtime/mcp-servers": {
      "get": {
        "summary": "List MCP servers for the authenticated org (optional name filter)",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional MCP server name filter"
          },
          {
            "name": "org_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Org scope (required for gateway/internal callers)"
          }
        ],
        "responses": {
          "200": {
            "description": "MCP server inventory including trust_tier"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      },
      "patch": {
        "summary": "Update MCP server trust tier or metadata",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "trust_tier": {
                    "type": "string",
                    "enum": ["trusted", "restricted", "untrusted"]
                  },
                  "blocked_tools": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "When trust_tier is restricted, tool names that must be blocked"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/api/v1/telemetry/traces": {
      "post": {
        "summary": "Ingest a trace",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Optional idempotency token for safe retries"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelemetryTraceBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay \u2014 trace already existed"
          },
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        }
      },
      "get": {
        "summary": "List recent traces (session cookie)",
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/v1/telemetry/traces/{id}": {
      "get": {
        "summary": "Trace detail with spans (session cookie)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/api/v1/telemetry/test-connection": {
      "post": {
        "summary": "Verify API key",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok: true"
          },
          "401": {
            "description": "Invalid key"
          }
        }
      }
    },
    "/api/cron/baseline-rollup": {
      "post": {
        "summary": "Daily baseline rollup (CRON_SECRET)",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Bearer CRON_SECRET"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/gateway/keys": {
      "get": {
        "summary": "List org-scoped gateway ingest keys",
        "description": "Returns ingest key metadata for the signed-in user's organization. Revoked keys are included so admins can audit key history.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GatewayIngestKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Failed to list ingest keys"
          }
        }
      },
      "post": {
        "summary": "Mint an org-scoped gateway ingest key",
        "description": "Creates a dashboard-managed ingest signing key. The secret is returned once and must be copied into the gateway secret manager.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayIngestKeyCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayIngestKeyCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid ingest key payload"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Failed to create ingest key"
          }
        }
      }
    },
    "/api/gateway/keys/{id}": {
      "delete": {
        "summary": "Revoke a gateway ingest key",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "revoked": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Key not found or already revoked"
          },
          "500": {
            "description": "Failed to revoke ingest key"
          }
        }
      }
    },
    "/api/gateway/instances": {
      "get": {
        "summary": "List gateway instances",
        "description": "Returns gateway instances with associated cluster, active config version, and latest heartbeat metadata.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "instances": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GatewayInstance"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Failed to load gateway instances"
          }
        }
      },
      "post": {
        "summary": "Register a gateway instance",
        "description": "Creates or reuses a gateway cluster, registers an instance, creates a config version, and returns a one-time enrollment token.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayInstanceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayInstanceCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid gateway instance payload"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Failed to create gateway instance"
          }
        }
      }
    },
    "/api/gateway/federation/token": {
      "post": {
        "summary": "Exchange workload identity for an ingest key",
        "description": "Issues a short-lived gateway ingest signing key from a configured OIDC or mTLS federation trust. This route does not require a dashboard session.",
        "parameters": [
          {
            "name": "x-client-cert-fingerprint",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "mTLS client certificate SHA-256 fingerprint when using certificate federation"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FederationTokenRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Short-lived ingest key issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FederationTokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          },
          "401": {
            "description": "Untrusted identity"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Federation exchange failed"
          }
        }
      }
    },
    "/api/exports/agent-run/{runId}": {
      "get": {
        "summary": "Export an agent run",
        "description": "Returns a SIEM-friendly JSON export with the agent-run rollup and gateway-event hop summaries for the signed-in user's organization.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentRunExport"
                }
              }
            }
          },
          "400": {
            "description": "runId required"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Export failed"
          }
        }
      }
    },
    "/v1/runtime/tool_calls/decision": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Request a runtime tool-call allow/block/review decision",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decision (allow, block, or review)"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        },
        "tags": ["Runtime Gateway"],
        "description": "Canonical path uses underscores (tool_calls). Hosted on the Go gateway."
      }
    },
    "/healthz": {
      "get": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Public gateway liveness probe",
        "description": "Returns only process liveness. Tenant and control-plane diagnostic state is available from the authenticated /v1/runtime/health endpoint.",
        "tags": ["Gateway Edge"],
        "responses": {
          "200": { "description": "Gateway process is live" }
        }
      }
    },
    "/v1/models": {
      "get": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "List models and Intertrace model aliases exposed by the gateway",
        "tags": ["LLM Gateway"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OpenAI-compatible model list" },
          "401": { "description": "Missing or invalid runtime key" }
        }
      }
    },
    "/v1/chat/completions": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Create a governed OpenAI-compatible chat completion",
        "description": "Supports buffered and streamed responses. Malformed JSON is rejected at the edge with HTTP 400 and is never reported as an upstream availability failure.",
        "tags": ["LLM Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenAICompatibleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Completion JSON or text/event-stream when stream=true"
          },
          "400": {
            "description": "Malformed or invalid client request",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OpenAIError" }
              }
            }
          },
          "401": { "description": "Missing or invalid runtime key" },
          "403": {
            "description": "Request blocked by an enforced Intertrace policy"
          },
          "429": { "description": "Rate or concurrency limit exceeded" },
          "502": {
            "description": "Provider returned an invalid or unavailable response"
          },
          "503": {
            "description": "A required gateway dependency is unavailable"
          }
        }
      }
    },
    "/v1/responses": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Create a governed OpenAI Responses API response",
        "description": "OpenAI-compatible Responses API surface, including streaming. Malformed JSON returns HTTP 400 before provider selection.",
        "tags": ["LLM Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenAICompatibleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response JSON or text/event-stream when stream=true"
          },
          "400": {
            "description": "Malformed or invalid client request",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OpenAIError" }
              }
            }
          },
          "401": { "description": "Missing or invalid runtime key" },
          "403": {
            "description": "Request blocked by an enforced Intertrace policy"
          },
          "429": { "description": "Rate or concurrency limit exceeded" },
          "502": {
            "description": "Provider returned an invalid or unavailable response"
          },
          "503": {
            "description": "A required gateway dependency is unavailable"
          }
        }
      }
    },
    "/v1/embeddings": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Create governed embeddings",
        "tags": ["LLM Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenAICompatibleRequest"
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OpenAI-compatible embeddings response" },
          "400": {
            "description": "Malformed or invalid client request",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OpenAIError" }
              }
            }
          },
          "401": { "description": "Missing or invalid runtime key" },
          "403": {
            "description": "Request blocked by an enforced Intertrace policy"
          },
          "503": {
            "description": "A required gateway dependency is unavailable"
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Send a governed MCP Streamable HTTP JSON-RPC message",
        "description": "MCP initialize, tools/list, and tools/call traffic. tools/call authorization can return an MCP error when policy blocks execution or approval is required.",
        "tags": ["MCP Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "additionalProperties": true }
            }
          }
        },
        "responses": {
          "200": {
            "description": "MCP JSON-RPC result or Streamable HTTP response"
          },
          "400": { "description": "Malformed MCP request" },
          "401": { "description": "Missing or invalid runtime key" },
          "403": { "description": "MCP server or tool blocked by policy" },
          "503": { "description": "MCP plane unavailable" }
        }
      },
      "get": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Open an authenticated MCP Streamable HTTP event stream",
        "tags": ["MCP Gateway"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "MCP event stream" },
          "401": { "description": "Missing or invalid runtime key" }
        }
      },
      "delete": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Close an authenticated MCP session",
        "tags": ["MCP Gateway"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "MCP session closed" },
          "401": { "description": "Missing or invalid runtime key" }
        }
      }
    },
    "/v1/security/inspect": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Inspect content for hidden or conflicting instructions",
        "description": "Performs deterministic dual-view inspection without sending content to a model.",
        "tags": ["Runtime Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": { "type": "string" },
                  "prompt": { "type": "string" },
                  "content_type": { "type": "string" }
                }
              }
            },
            "text/plain": { "schema": { "type": "string" } }
          }
        },
        "responses": {
          "200": { "description": "Inspection verdict and human/agent views" },
          "400": { "description": "Invalid payload" },
          "401": { "description": "Missing or invalid runtime key" },
          "413": { "description": "Body exceeds 8 MiB" }
        }
      }
    },
    "/v1/decisions/{decision_id}": {
      "get": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Retrieve a non-expired authorization decision",
        "tags": ["Runtime Gateway"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          {
            "name": "decision_id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Authorization decision",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActionAuthorizeDecision"
                }
              }
            }
          },
          "401": { "description": "Missing or invalid runtime key" },
          "404": { "description": "Decision not found or expired" }
        }
      }
    },
    "/v1/actions/permits/verify": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Verify and optionally consume a scoped execution permit",
        "description": "The caller must repeat the exact tenant, agent, session, tool, operation, resource, and argument digest bound into the permit. Consumption defaults to true and is replay-protected.",
        "tags": ["Runtime Gateway"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecutionPermitVerifyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Permit is valid; returns claims and consumed state"
          },
          "400": { "description": "Invalid JSON payload" },
          "401": { "description": "Missing or invalid runtime key" },
          "403": {
            "description": "PERMIT_INVALID, PERMIT_EXPIRED, PERMIT_REPLAY, PERMIT_SCOPE_MISMATCH, or PERMIT_NOT_YET_VALID",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RuntimeError" }
              }
            }
          },
          "503": { "description": "Permit signer unavailable" }
        }
      }
    },
    "/v1/actions/authorize": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Authorize an agent action before execution",
        "description": "Canonical pre-execution authorization on the Fly Go enforcer (`POST /v1/actions/authorize`). Supported `schema_version` is `intertrace.action.v1`. Omitting it is accepted and treated as that version; any other value returns `UNSUPPORTED_SCHEMA`. Tenant, project, and agent identity are derived from the authenticated runtime key when omitted; supplied identity must match. A supplied environment must match the key-bound environment or the request fails closed with `ENVIRONMENT_MISMATCH`.\n\nWhen `INTERTRACE_AGT_ENABLED=true`, the pinned Microsoft Agent Governance Toolkit Go policy engine and MCP scanner are active decision inputs. AGT can strengthen a verdict to approval, rate-limit, or block; it cannot soften Intertrace/OPA. MCP clients should provide `action.tool_description` for semantic tool scanning. Send `action.purpose` and `action.target_resources` so reviewers see the exact business reason and affected resources.\n\nArguments and their hash: the gateway hashes `action.arguments` itself (SHA-256 of the RFC 8785 canonical JSON) and binds approvals, permits and records to that hash. With `arguments`, `arguments_sha256` is optional; when sent it must equal that hash or the call is refused with 400 `ARGUMENTS_HASH_MISMATCH`. Without `arguments`, `arguments_sha256` is required and stands as sent.\n\nHITL re-entry: send the same `approval_id` plus the same `trace_id`, agent, action/tool identity, arguments, and target. Correlation is explicit. Failures return `APPROVAL_EXPIRED`, `APPROVAL_MISMATCH`, or `APPROVAL_NOT_FOUND` and never mint a second approval request. A successful re-entry returns `ALLOW` plus a scoped `execution_permit`, and echoes `original_approval_id` / `original_decision_id`.\n\nTool policy: `allowed_tools` is the execution grant (server-qualified names such as `e2e-server/health` match). `expected_tools` is drift/baseline only. `denied_tools` always wins.\n\nPermit verify failures: `PERMIT_SCOPE_MISMATCH`, `PERMIT_REPLAY`, `PERMIT_EXPIRED`. The permit token is never written to ingest logs.",
        "tags": ["Runtime Gateway"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "required": ["action"],
                "properties": {
                  "schema_version": {
                    "type": "string",
                    "example": "intertrace.action.v1",
                    "description": "Supported value intertrace.action.v1. Omission is accepted."
                  },
                  "tenant_id": {
                    "type": "string",
                    "description": "Optional; tenancy comes from the runtime key. A supplied value must equal the key's organization id or the call fails with 403 TENANT_MISMATCH."
                  },
                  "trace_id": {
                    "type": "string"
                  },
                  "session_id": {
                    "type": "string"
                  },
                  "environment": {
                    "type": "string",
                    "enum": ["production", "staging", "development"],
                    "description": "Defaults to the runtime key environment and cannot override it. A mismatch returns ENVIRONMENT_MISMATCH."
                  },
                  "approval_id": {
                    "type": "string",
                    "description": "Exact-match re-entry after a human approval."
                  },
                  "agent": {
                    "type": "object",
                    "additionalProperties": true,
                    "required": ["id"],
                    "properties": {
                      "id": {
                        "type": "string",
                        "description": "Slug (agent key) of the agent the runtime key is bound to. Any other value is 403 AGENT_NOT_FOUND."
                      },
                      "declared_purpose": {
                        "type": "string",
                        "description": "The agent's broader declared job; used as a fallback when action.purpose is omitted."
                      }
                    }
                  },
                  "action": {
                    "type": "object",
                    "additionalProperties": true,
                    "required": ["tool_id", "operation"],
                    "description": "Send arguments, arguments_sha256, or both. arguments_sha256 is required only when arguments is omitted.",
                    "properties": {
                      "tool_id": { "type": "string" },
                      "tool_description": {
                        "type": "string",
                        "maxLength": 16384,
                        "description": "Optional MCP/framework tool description scanned by the active governance engine."
                      },
                      "purpose": {
                        "type": "string",
                        "maxLength": 4000,
                        "description": "Business justification for this exact action, shown to human reviewers. Prefer this over a generic agent purpose."
                      },
                      "operation": { "type": "string" },
                      "category": { "type": "string" },
                      "arguments": {
                        "type": "object",
                        "additionalProperties": true,
                        "description": "The tool's arguments. The gateway hashes them itself (SHA-256 of RFC 8785 canonical JSON)."
                      },
                      "arguments_sha256": {
                        "type": "string",
                        "pattern": "^[0-9a-f]{64}$",
                        "description": "Lowercase hex SHA-256 of the RFC 8785 canonical JSON of arguments. Optional when arguments is sent; if sent it must match the gateway's hash (400 ARGUMENTS_HASH_MISMATCH otherwise). Required when arguments is omitted."
                      },
                      "target_resources": {
                        "type": "array",
                        "items": { "type": "string" },
                        "description": "Resources this exact action can affect."
                      },
                      "data_boundary": { "type": "string" },
                      "data_classes": {
                        "type": "array",
                        "items": { "type": "string" }
                      },
                      "expected_side_effect": { "type": "string" },
                      "mcp_server_name": { "type": "string" },
                      "mcp_tool_name": { "type": "string" },
                      "destination": { "type": "string" }
                    }
                  }
                }
              },
              "examples": {
                "requireApproval": {
                  "summary": "High-risk action pauses",
                  "value": {
                    "schema_version": "intertrace.action.v1",
                    "trace_id": "trace-1",
                    "agent": { "id": "YOUR_AGENT_SLUG" },
                    "action": {
                      "tool_id": "refund.create",
                      "purpose": "Refund an approved customer claim after a reviewer verifies the amount and claim identifier.",
                      "operation": "write",
                      "arguments": { "claim_id": "claim-8", "amount": 40 },
                      "target_resources": ["customer-claim:claim-8"],
                      "expected_side_effect": "transact"
                    }
                  }
                },
                "reentry": {
                  "summary": "Same approval id after human approve",
                  "value": {
                    "schema_version": "intertrace.action.v1",
                    "trace_id": "trace-1",
                    "approval_id": "appr-1",
                    "agent": { "id": "YOUR_AGENT_SLUG" },
                    "action": {
                      "tool_id": "refund.create",
                      "purpose": "Refund an approved customer claim after a reviewer verifies the amount and claim identifier.",
                      "operation": "write",
                      "arguments": { "claim_id": "claim-8", "amount": 40 },
                      "target_resources": ["customer-claim:claim-8"]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authorization decision. ALLOW / TRANSFORM_ALLOW may include execution_permit. REQUIRE_APPROVAL includes approval_request_id. Re-entry echoes original_approval_id and original_decision_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActionAuthorizeDecision"
                }
              }
            }
          },
          "400": {
            "description": "ARGUMENTS_HASH_MISMATCH (arguments_sha256 does not equal the SHA-256 of the RFC 8785 canonical JSON of arguments), APPROVAL_EXPIRED, APPROVAL_MISMATCH, APPROVAL_NOT_FOUND, APPROVAL_ALREADY_USED, UNSUPPORTED_SCHEMA, or INVALID_PAYLOAD. Error object includes request_id and original_approval_id when known.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RuntimeError" }
              }
            }
          },
          "401": {
            "description": "INVALID_API_KEY, REVOKED_API_KEY or EXPIRED_API_KEY; also PROJECT_NOT_FOUND or AGENT_NOT_FOUND when X-Intertrace-Project-Id / X-Intertrace-Agent-Id do not match the key's binding",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RuntimeError" }
              }
            }
          },
          "403": {
            "description": "TENANT_MISMATCH (tenant_id or X-Intertrace-Org-Id names another organization), AGENT_NOT_FOUND (agent.id or project_id does not match the key's binding), or ENVIRONMENT_MISMATCH",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RuntimeError" }
              }
            }
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/runtime/approvals/{id}": {
      "get": {
        "summary": "Look up one approval by id",
        "description": "Canonical approval queue lookup for the signed-in workspace. Returns lifecycle (pending → approved/denied/expired → permit_issued → consumed), action fingerprint, argument digest, agent, server, tool, target, approver, timestamps, policy version, and reason codes. Approvals are never deleted.",
        "tags": ["Runtime Gateway"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Approval record with lifecycle and fingerprint"
          },
          "404": {
            "description": "APPROVAL_NOT_FOUND"
          }
        }
      }
    },
    "/api/runtime/approvals/{id}/approve": {
      "post": {
        "summary": "Approve or cast an allow vote for a pending runtime action",
        "description": "Requires the runtime:operate capability. Approval records are retained; this changes lifecycle state and does not itself mint a permit. The agent must re-enter /v1/actions/authorize with the same approval_id and exact action fingerprint to receive a scoped permit.",
        "tags": ["Runtime Gateway"],
        "security": [{ "cookieAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "constraints": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vote recorded or approval resolved",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApprovalResolution" }
              }
            }
          },
          "401": { "description": "Not signed in" },
          "403": { "description": "Insufficient capability" },
          "404": { "description": "Approval not found" },
          "409": {
            "description": "Approval is already resolved incompatibly or expired"
          }
        }
      }
    },
    "/api/runtime/approvals/{id}/deny": {
      "post": {
        "summary": "Deny or cast a deny vote for a pending runtime action",
        "description": "Requires the runtime:operate capability. The immutable approval record remains available for audit.",
        "tags": ["Runtime Gateway"],
        "security": [{ "cookieAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Vote recorded or denial resolved",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApprovalResolution" }
              }
            }
          },
          "401": { "description": "Not signed in" },
          "403": { "description": "Insufficient capability" },
          "404": { "description": "Approval not found" },
          "409": {
            "description": "Approval is already resolved incompatibly or expired"
          }
        }
      }
    },
    "/v1/runtime/approvals/{id}/redeem": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Validate an approved action fingerprint (compatibility endpoint)",
        "description": "Deprecated compatibility endpoint. It validates an approval but does not mint an execution permit. New clients must re-enter /v1/actions/authorize with approval_id and the identical action contract.",
        "deprecated": true,
        "tags": ["Runtime Gateway"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "argument_hash",
                  "agent_id",
                  "tool_name",
                  "action_type"
                ],
                "properties": {
                  "argument_hash": { "type": "string" },
                  "agent_id": { "type": "string" },
                  "session_id": { "type": "string" },
                  "tool_name": { "type": "string" },
                  "action_type": { "type": "string" },
                  "destination": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Approval fingerprint validated" },
          "400": {
            "description": "Approval missing, expired, used, or mismatched"
          },
          "401": { "description": "Missing or invalid runtime key" },
          "503": { "description": "Approval service unavailable" }
        }
      }
    },
    "/v1/runtime/events/batch": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Batch-ingest runtime telemetry events via the Go gateway",
        "description": "Public gateway path. Dashboard persistence uses internal POST /api/runtime/ingest.",
        "tags": ["Runtime Gateway"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/v1/runtime/sessions/start": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Start a runtime protection session",
        "tags": ["Runtime Gateway"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session started"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/v1/runtime/sessions/{id}/complete": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Complete a runtime protection session",
        "tags": ["Runtime Gateway"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session completed"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/v1/runtime/tool_calls/{id}/outcome": {
      "post": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Report the outcome of a previously decided tool call",
        "tags": ["Runtime Gateway"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "properties": {
                  "execution_status": { "type": "string", "description": "succeeded, failed, not_executed or unknown" },
                  "executed": { "type": "boolean" },
                  "redacted_result_summary": {
                    "description": "Optional short summary of what the tool returned (text or JSON). The gateway redacts secrets and personal data and clips it to 2,000 characters before storing it."
                  },
                  "execution_error_redacted": {
                    "type": "string",
                    "description": "Optional error the tool returned. Redacted and clipped to 1,000 characters by the gateway."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Outcome recorded"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/v1/runtime/health": {
      "get": {
        "servers": [{ "url": "https://intertrace.fly.dev", "description": "Intertrace edge (Fly agentgateway + Go enforcer)" }],
        "summary": "Authenticated gateway runtime diagnostic health",
        "description": "Returns agent-context freshness, snapshot state, control and registry versions, and containment version for authenticated runtime operators. Use /healthz for public liveness.",
        "tags": ["Runtime Gateway"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Authenticated runtime diagnostics"
          },
          "401": {
            "description": "Missing or invalid runtime key",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RuntimeError" }
              }
            }
          },
          "403": {
            "description": "Authenticated org does not match the requested org"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "summary": "Dashboard health check",
        "tags": ["Platform"],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/integration-tool-calls": {
      "post": {
        "summary": "Ingest an integration tool-call event",
        "tags": ["Telemetry"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/v1/agent/tool-intent": {
      "post": {
        "summary": "Ingest an agent tool-intent signal",
        "tags": ["Telemetry"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/v1/agent/event": {
      "post": {
        "summary": "Ingest an agent lifecycle event",
        "tags": ["Telemetry"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/assessments/start": {
      "post": {
        "summary": "Start a probe assessment",
        "tags": ["Security"],
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Queued"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/assessments": {
      "get": {
        "summary": "List assessments for the signed-in org",
        "tags": ["Security"],
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/reports/generate": {
      "post": {
        "summary": "Generate a security report export",
        "tags": ["Security"],
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/runtime/verify-key": {
      "post": {
        "summary": "Verify a runtime API key",
        "tags": ["Runtime"],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Key valid"
          },
          "401": {
            "description": "Invalid key"
          }
        }
      }
    },
    "/api/findings/{id}/history": {
      "get": {
        "summary": "List structured status history for a finding",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status timeline rows for the finding"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Finding not found"
          }
        }
      }
    },
    "/api/findings/{id}/evidence": {
      "get": {
        "summary": "List structured evidence attached to a finding",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evidence rows for the finding"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Finding not found"
          }
        }
      },
      "post": {
        "summary": "Attach analyst evidence to a finding",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["evidence_type"],
                "properties": {
                  "evidence_type": {
                    "type": "string",
                    "enum": [
                      "prompt",
                      "response",
                      "tool_call",
                      "policy_rule",
                      "trace",
                      "gateway_event",
                      "screenshot",
                      "log",
                      "other"
                    ]
                  },
                  "evidence_uri": {
                    "type": "string",
                    "format": "uri",
                    "nullable": true
                  },
                  "content_hash": {
                    "type": "string",
                    "nullable": true
                  },
                  "label": {
                    "type": "string",
                    "nullable": true
                  },
                  "content_preview": {
                    "type": "string",
                    "nullable": true
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Evidence stored"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Finding not found"
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/assets/discovery-runs": {
      "get": {
        "summary": "List recent discovery runs for the authenticated org",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "ISO timestamp cursor (created_at of last item)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Discovery runs plus enterprise discovery status"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/findings/{id}/remediation": {
      "get": {
        "summary": "List remediation plans for a finding",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Remediation rows"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "post": {
        "summary": "Create a remediation plan for a finding",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "planned",
                      "in_progress",
                      "blocked",
                      "verified",
                      "accepted_risk",
                      "cancelled"
                    ]
                  },
                  "plan_summary": {
                    "type": "string"
                  },
                  "owner_email": {
                    "type": "string",
                    "format": "email"
                  },
                  "work_item_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/remediation/work-items": {
      "get": {
        "summary": "List remediation work items for the org",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Work items"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      },
      "post": {
        "summary": "Create a remediation work item",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/gateway/runtime-config": {
      "get": {
        "summary": "Org gateway runtime config (session or internal secret)",
        "description": "Internal callers with X-Intertrace-Internal receive mcpProxyPolicy for the MCP wire proxy plus vault credentials.",
        "parameters": [
          {
            "name": "orgId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "assetId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Runtime config including mcpRegistry and mcpProxyPolicy"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/scim/v2/Users": {
      "get": {
        "summary": "SCIM Users (not offered \u2014 use WorkOS Directory Sync)",
        "responses": {
          "410": {
            "description": "Gone \u2014 configure SCIM via WorkOS"
          }
        }
      },
      "post": {
        "summary": "SCIM Users create (not offered)",
        "responses": {
          "410": {
            "description": "Gone"
          }
        }
      }
    },
    "/api/events/ingest": {
      "post": {
        "summary": "Canonical SecurityEventEnvelope ingest (internal)",
        "description": "Authenticated with x-intertrace-internal. Applies org retention and data residency controls when configured.",
        "responses": {
          "200": { "description": "Accepted" },
          "400": { "description": "Invalid envelope or DLQ" },
          "401": { "description": "Unauthorized" },
          "403": { "description": "Data residency violation" }
        }
      }
    },
    "/api/policy/simulate": {
      "post": {
        "summary": "Replay policy simulation on historical-like OPA inputs",
        "security": [{ "cookieAuth": [] }],
        "responses": {
          "200": {
            "description": "Simulation result with recommended_policy_changes"
          },
          "401": { "description": "Unauthorized" }
        }
      }
    },
    "/api/posture/evaluate": {
      "get": {
        "summary": "Evaluate posture checks for org assets",
        "security": [{ "cookieAuth": [] }],
        "responses": {
          "200": { "description": "Posture evaluation summary" },
          "401": { "description": "Unauthorized" }
        }
      },
      "post": {
        "summary": "Run posture evaluation and upsert findings",
        "security": [{ "cookieAuth": [] }],
        "responses": {
          "200": { "description": "Evaluation complete" },
          "401": { "description": "Unauthorized" }
        }
      }
    },
    "/api/otel/ingest": {
      "post": {
        "summary": "OTEL / MLflow GenAI span ingest — warehouse + runtime session film",
        "description": "Accepts GenAI OTLP JSON (resourceSpans or spans[]). Auth: Bearer itr_rt_*, dashboard API key, internal secret, or session. Films one Estate/Sessions job even when hops were not on Fly.",
        "security": [{ "bearerAuth": [] }, { "cookieAuth": [] }],
        "responses": {
          "200": {
            "description": "Accepted — warehouse + optional session id"
          },
          "401": { "description": "Unauthorized" }
        }
      }
    },
    "/api/v1/traces": {
      "post": {
        "summary": "MLflow / OTel traces alias (same as /api/otel/ingest)",
        "description": "Point OTEL_EXPORTER_OTLP_TRACES_ENDPOINT at this URL. JSON GenAI resourceSpans. Slim tracing client analogue of mlflow-tracing.",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Accepted — session filmed when spans include session.id / gen_ai.conversation.id"
          },
          "401": { "description": "Unauthorized" }
        }
      }
    },
    "/api/v1/eval/scores": {
      "post": {
        "summary": "Attach Assure eval / LLM-judge scores to a session",
        "description": "Dataset + scorer loop for Labs/Guardian quality. A failing judge never becomes HTTP 401/403 — blocks stay at the kernel.",
        "security": [{ "bearerAuth": [] }, { "cookieAuth": [] }],
        "responses": {
          "200": { "description": "Attached; enforcement is always none" },
          "400": { "description": "Missing session_id or scores" },
          "401": { "description": "Unauthorized" },
          "404": { "description": "Session not found" }
        }
      }
    },
    "/api/discovery/coverage": {
      "get": {
        "summary": "Connector fidelity and coverage report",
        "security": [{ "cookieAuth": [] }],
        "responses": {
          "200": { "description": "Coverage report" },
          "401": { "description": "Unauthorized" }
        }
      }
    },
    "/api/incidents/correlate": {
      "post": {
        "summary": "Multi-event incident correlator",
        "security": [{ "cookieAuth": [] }],
        "responses": {
          "200": { "description": "Correlation candidates" },
          "401": { "description": "Unauthorized" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "itr_rt_* runtime key or dashboard API key"
      },
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "Supabase session"
      },
      "internalSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Intertrace-Internal",
        "description": "Shared INTERTRACE_INTERNAL_SECRET. Gateway-to-dashboard calls only."
      }
    },
    "schemas": {
      "OpenAICompatibleRequest": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "model": { "type": "string" },
          "stream": { "type": "boolean", "default": false }
        }
      },
      "OpenAIError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["message", "type"],
            "properties": {
              "message": { "type": "string" },
              "type": { "type": "string", "example": "invalid_request_error" },
              "code": { "type": "string", "nullable": true }
            }
          }
        }
      },
      "RuntimeError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "request_id"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "request_id": { "type": "string" },
              "retryable": { "type": "boolean" },
              "original_approval_id": { "type": "string", "nullable": true }
            }
          }
        }
      },
      "ActionAuthorizeDecision": {
        "type": "object",
        "required": ["schema_version", "decision", "decision_id", "trace_id"],
        "properties": {
          "pending_approval": {
            "type": "object",
            "required": ["id", "status", "status_url", "resume"],
            "description": "Present when decision is REQUIRE_APPROVAL, and only for an approval that is stored and visible to approvers. Resume by resending the same authorize request with approval_id set; every must_match field is compared with what was approved (APPROVAL_MISMATCH otherwise). A second use is APPROVAL_ALREADY_USED; an expired approval is APPROVAL_EXPIRED. A successful resume returns ALLOW with an execution_permit; the action counts as executed only once the executor reports its outcome.",
            "properties": {
              "id": { "type": "string" },
              "status": { "type": "string", "enum": ["pending"] },
              "expires_at": { "type": "string", "format": "date-time" },
              "status_url": { "type": "string", "description": "GET on the gateway with the runtime key: pending | approved | denied | expired." },
              "resume": {
                "type": "object",
                "required": ["method", "path", "set", "must_match"],
                "properties": {
                  "method": { "type": "string", "enum": ["POST"] },
                  "path": { "type": "string" },
                  "set": { "type": "object", "additionalProperties": { "type": "string" } },
                  "must_match": { "type": "array", "items": { "type": "string" } },
                  "outcome": { "type": "string" }
                }
              }
            }
          },
          "schema_version": {
            "type": "string",
            "example": "intertrace.action-decision.v1"
          },
          "decision": {
            "type": "string",
            "enum": [
              "ALLOW",
              "ALLOW_MONITOR",
              "BLOCK",
              "REQUIRE_APPROVAL",
              "TRANSFORM_ALLOW"
            ]
          },
          "decision_id": { "type": "string" },
          "trace_id": { "type": "string" },
          "execution_permit": {
            "type": "string",
            "description": "Short-lived scoped permit. Present only when the action is authorized for execution. Never log this value."
          },
          "expires_at": { "type": "string", "format": "date-time" },
          "approval_request_id": {
            "type": "string",
            "description": "Present for REQUIRE_APPROVAL. Re-enter authorization with this value as approval_id after approval."
          },
          "original_approval_id": { "type": "string" },
          "original_decision_id": { "type": "string" },
          "reason_codes": { "type": "array", "items": { "type": "string" } },
          "policy_ids": { "type": "array", "items": { "type": "string" } },
          "risk": {
            "type": "object",
            "properties": {
              "severity": { "type": "string" },
              "score": { "type": "integer" },
              "confidence": { "type": "number" }
            }
          }
        }
      },
      "ExecutionPermitVerifyRequest": {
        "type": "object",
        "required": [
          "execution_permit",
          "session_id",
          "tool_id",
          "operation",
          "arguments_sha256"
        ],
        "properties": {
          "execution_permit": { "type": "string" },
          "tenant_id": { "type": "string" },
          "agent_id": { "type": "string" },
          "session_id": { "type": "string" },
          "tool_id": { "type": "string" },
          "operation": { "type": "string" },
          "resource": { "type": "string" },
          "arguments_sha256": { "type": "string" },
          "consume": { "type": "boolean", "default": true }
        }
      },
      "ApprovalResolution": {
        "type": "object",
        "required": ["ok", "approval_id", "status"],
        "properties": {
          "ok": { "type": "boolean" },
          "approval_id": { "type": "string" },
          "status": {
            "type": "string",
            "enum": ["pending", "approved", "denied"]
          },
          "already_resolved": { "type": "boolean" },
          "votes_allow": { "type": "integer" },
          "votes_deny": { "type": "integer" },
          "quorum_required": { "type": "integer" }
        }
      },
      "TelemetryTraceBody": {
        "type": "object",
        "required": ["trace", "spans"],
        "properties": {
          "trace": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "metadata": {
                "type": "object",
                "additionalProperties": true
              },
              "asset_id": {
                "type": "string",
                "format": "uuid"
              },
              "intent": {
                "type": "object",
                "additionalProperties": true
              }
            }
          },
          "spans": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["name", "kind", "start_time", "end_time"],
              "properties": {
                "name": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": ["llm", "tool", "chain", "retrieval"]
                },
                "start_time": {
                  "type": "string",
                  "format": "date-time"
                },
                "end_time": {
                  "type": "string",
                  "format": "date-time"
                },
                "attributes": {
                  "type": "object",
                  "additionalProperties": true
                },
                "parent_span_id": {
                  "type": "string",
                  "format": "uuid",
                  "nullable": true
                }
              }
            }
          },
          "policy": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "GatewayIngestKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "key_id": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "nullable": true
          },
          "environment": {
            "type": "string",
            "nullable": true
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["ingest", "config:read", "admin"]
            }
          },
          "instance_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "GatewayIngestKeyCreate": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "environment": {
            "type": "string",
            "maxLength": 64,
            "nullable": true
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["ingest", "config:read", "admin"]
            },
            "default": ["ingest"]
          },
          "instance_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "expires_in_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650,
            "nullable": true
          }
        }
      },
      "GatewayIngestKeyCreateResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "key_id": {
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "Returned once. Store it in the gateway secret manager."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "env": {
            "type": "object",
            "properties": {
              "INTERTRACE_GATEWAY_KEY_ID": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_SIGNING_SECRET": {
                "type": "string"
              }
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "GatewayInstance": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "cluster_id": {
            "type": "string",
            "format": "uuid"
          },
          "display_name": {
            "type": "string"
          },
          "gateway_type": {
            "type": "string",
            "example": "go"
          },
          "status": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "nullable": true
          },
          "base_url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "capabilities": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "cluster": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "config_version": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "latest_heartbeat": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          }
        }
      },
      "GatewayInstanceCreate": {
        "type": "object",
        "properties": {
          "display_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "default": "Production gateway"
          },
          "environment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "default": "production"
          },
          "base_url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "region": {
            "type": "string",
            "maxLength": 120,
            "nullable": true
          },
          "gateway_type": {
            "type": "string",
            "maxLength": 64,
            "default": "go"
          },
          "capabilities": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          }
        }
      },
      "GatewayInstanceCreateResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "gateway_cluster": {
            "type": "object",
            "additionalProperties": true
          },
          "gateway_instance": {
            "type": "object",
            "additionalProperties": true
          },
          "gateway_config_version": {
            "type": "object",
            "additionalProperties": true
          },
          "enrollment": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "One-time enrollment token returned once."
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "exchange_url": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "env": {
            "type": "object",
            "properties": {
              "INTERTRACE_GATEWAY_CLUSTER_ID": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_INSTANCE_ID": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_CONFIG_VERSION_ID": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_SCHEMA_VERSION": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_ENROLLMENT_TOKEN": {
                "type": "string"
              }
            }
          }
        }
      },
      "FederationTokenRequest": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "OIDC JWT from a configured trusted issuer."
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "environment": {
            "type": "string",
            "maxLength": 64,
            "nullable": true
          }
        }
      },
      "FederationTokenResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "key_id": {
            "type": "string"
          },
          "ingest_secret": {
            "type": "string",
            "description": "Short-lived secret returned once."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "env": {
            "type": "object",
            "properties": {
              "INTERTRACE_GATEWAY_KEY_ID": {
                "type": "string"
              },
              "INTERTRACE_GATEWAY_SIGNING_SECRET": {
                "type": "string"
              }
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "AgentRunExport": {
        "type": "object",
        "properties": {
          "schema": {
            "type": "string",
            "example": "intertrace.agent_run_export.v1"
          },
          "exported_at": {
            "type": "string",
            "format": "date-time"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "run_id": {
            "type": "string"
          },
          "rollup": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "hops": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentRunHop"
            }
          },
          "hop_count": {
            "type": "integer"
          }
        }
      },
      "AgentRunHop": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "inbound_verdict": {
            "type": "string",
            "nullable": true
          },
          "outbound_verdict": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string",
            "nullable": true
          },
          "asset_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "hop_index": {
            "type": "integer",
            "nullable": true
          },
          "tooling_summary": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "rail_timings_ms": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "nullable": true
          },
          "latency_gateway_ms": {
            "type": "number",
            "nullable": true
          },
          "classifier_used": {
            "type": "string",
            "nullable": true
          }
        }
      }
    }
  }
}
