{
  "openapi": "3.1.0",
  "info": {
    "title": "EarlyCore API",
    "version": "2026-04-29",
    "summary": "AI security platform for European MSSPs. Programmatic access to Red Team scans, Runtime findings, agents, integrations, and reports.",
    "description": "The EarlyCore API lets MSSP partners and their clients automate AI security workflows: launch Red Team scans, query Runtime findings, manage monitored agents, configure webhooks, and pull auditor-ready compliance reports. The API is REST over HTTPS with JSON bodies. All endpoints are EU-hosted and not subject to the US Cloud Act.\n\nAuthentication uses API keys via the `Authorization: Bearer <key>` header. Each key has a role (`viewer`, `analyst`, `admin`) and a list of scopes (e.g. `scans:read`, `findings:write`, `agents:admin`). Agents and clients should request the narrowest scope set they need.\n\nRate limit: 600 requests per minute per key. Exceeded requests return `429` with `Retry-After`.\n\nThe MCP server at `mcp.earlycore.dev` exposes the same surface for agentic clients (Claude Code, Cursor) over the Model Context Protocol.",
    "contact": {
      "name": "EarlyCore Developer Relations",
      "url": "https://earlycore.dev/developers",
      "email": "developers@earlycore.dev"
    },
    "license": {
      "name": "EarlyCore Terms of Service",
      "url": "https://earlycore.dev/terms"
    },
    "termsOfService": "https://earlycore.dev/terms"
  },
  "servers": [
    {
      "url": "https://api.earlycore.dev/v1",
      "description": "Production (EU, multi-tenant)"
    },
    {
      "url": "https://api.sandbox.earlycore.dev/v1",
      "description": "Sandbox (EU, free, mock data)"
    }
  ],
  "externalDocs": {
    "description": "Developer portal, quickstarts, SDKs",
    "url": "https://earlycore.dev/developers"
  },
  "tags": [
    { "name": "Scans", "description": "Red Team scans against AI agents and LLM endpoints. Maps to OWASP LLM Top 10, MITRE ATLAS, and EU AI Act controls." },
    { "name": "Findings", "description": "Runtime detections from monitored AI agents: prompt injection, data exfiltration, drift, secrets leakage." },
    { "name": "Agents", "description": "AI agents under monitoring. One agent represents one production model deployment." },
    { "name": "Reports", "description": "Auditor-ready compliance evidence packs for DORA, NIS2, EU AI Act, GDPR, ISO 42001." },
    { "name": "Webhooks", "description": "Push event delivery for findings, scan completion, and integration sync." },
    { "name": "Integrations", "description": "Configure data sources (Bedrock, SageMaker, Azure OpenAI, Vertex AI, Logfire, LangChain) and destinations (Slack, Teams, Jira)." }
  ],
  "security": [
    { "BearerApiKey": [] }
  ],
  "paths": {
    "/scans": {
      "get": {
        "tags": ["Scans"],
        "summary": "List Red Team scans",
        "operationId": "listScans",
        "security": [{ "BearerApiKey": ["scans:read"] }],
        "parameters": [
          { "name": "agent_id", "in": "query", "schema": { "type": "string" }, "description": "Filter by monitored agent." },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["queued", "running", "completed", "failed"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "cursor", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanList" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "post": {
        "tags": ["Scans"],
        "summary": "Launch a Red Team scan",
        "operationId": "createScan",
        "security": [{ "BearerApiKey": ["scans:write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ScanCreate" },
              "examples": {
                "owaspBaseline": {
                  "summary": "OWASP LLM Top 10 baseline",
                  "value": {
                    "agent_id": "agent_01HX...",
                    "scan_packs": ["owasp-llm-top-10", "mitre-atlas"],
                    "max_attempts": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Scan queued",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Scan" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/scans/{scan_id}": {
      "get": {
        "tags": ["Scans"],
        "summary": "Retrieve a scan",
        "operationId": "getScan",
        "security": [{ "BearerApiKey": ["scans:read"] }],
        "parameters": [
          { "name": "scan_id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Scan" } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/findings": {
      "get": {
        "tags": ["Findings"],
        "summary": "List Runtime findings",
        "operationId": "listFindings",
        "security": [{ "BearerApiKey": ["findings:read"] }],
        "parameters": [
          { "name": "agent_id", "in": "query", "schema": { "type": "string" } },
          { "name": "severity", "in": "query", "schema": { "type": "string", "enum": ["P0", "P1", "P2", "P3"] } },
          { "name": "framework", "in": "query", "schema": { "type": "string", "enum": ["dora", "nis2", "eu-ai-act", "gdpr", "iso-42001", "owasp-llm-top-10", "mitre-atlas"] } },
          { "name": "since", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "cursor", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FindingList" } } } }
        }
      }
    },
    "/findings/{finding_id}": {
      "get": {
        "tags": ["Findings"],
        "summary": "Retrieve a finding",
        "operationId": "getFinding",
        "security": [{ "BearerApiKey": ["findings:read"] }],
        "parameters": [
          { "name": "finding_id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Finding" } } } },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": ["Findings"],
        "summary": "Update finding triage state",
        "operationId": "updateFinding",
        "security": [{ "BearerApiKey": ["findings:write"] }],
        "parameters": [
          { "name": "finding_id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": { "type": "string", "enum": ["open", "acknowledged", "resolved", "false-positive"] },
                  "assignee_email": { "type": "string", "format": "email" },
                  "note": { "type": "string", "maxLength": 4000 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Finding" } } } }
        }
      }
    },
    "/agents": {
      "get": {
        "tags": ["Agents"],
        "summary": "List monitored agents",
        "operationId": "listAgents",
        "security": [{ "BearerApiKey": ["agents:read"] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentList" } } } }
        }
      },
      "post": {
        "tags": ["Agents"],
        "summary": "Register an agent for monitoring",
        "operationId": "createAgent",
        "security": [{ "BearerApiKey": ["agents:write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentCreate" } } }
        },
        "responses": {
          "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Agent" } } } }
        }
      }
    },
    "/reports": {
      "get": {
        "tags": ["Reports"],
        "summary": "List compliance reports",
        "operationId": "listReports",
        "security": [{ "BearerApiKey": ["reports:read"] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportList" } } } }
        }
      },
      "post": {
        "tags": ["Reports"],
        "summary": "Generate a compliance report",
        "operationId": "createReport",
        "security": [{ "BearerApiKey": ["reports:write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["framework", "agent_ids"],
                "properties": {
                  "framework": { "type": "string", "enum": ["dora", "nis2", "eu-ai-act", "gdpr", "iso-42001", "nist-ai-rmf"] },
                  "agent_ids": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
                  "period_start": { "type": "string", "format": "date" },
                  "period_end": { "type": "string", "format": "date" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Report queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Report" } } } }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List webhook subscriptions",
        "operationId": "listWebhooks",
        "security": [{ "BearerApiKey": ["webhooks:read"] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookList" } } } }
        }
      },
      "post": {
        "tags": ["Webhooks"],
        "summary": "Create a webhook subscription",
        "operationId": "createWebhook",
        "security": [{ "BearerApiKey": ["webhooks:write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookCreate" } } }
        },
        "responses": {
          "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Webhook" } } } }
        }
      }
    },
    "/integrations": {
      "get": {
        "tags": ["Integrations"],
        "summary": "List configured integrations",
        "operationId": "listIntegrations",
        "security": [{ "BearerApiKey": ["integrations:read"] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationList" } } } }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "API key issued in the EarlyCore developer portal. Send as `Authorization: Bearer ec_live_...`. Each key carries a role and a list of scopes; requests are denied if the scope is not granted. Sandbox keys are prefixed `ec_sandbox_`."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 for partner-facing integrations and agentic clients (MCP). Authorization Code with PKCE.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://auth.earlycore.dev/oauth/authorize",
            "tokenUrl": "https://auth.earlycore.dev/oauth/token",
            "refreshUrl": "https://auth.earlycore.dev/oauth/token",
            "scopes": {
              "scans:read": "Read Red Team scan results",
              "scans:write": "Launch and cancel Red Team scans",
              "findings:read": "Read Runtime findings",
              "findings:write": "Triage Runtime findings",
              "agents:read": "List monitored agents",
              "agents:write": "Register and update monitored agents",
              "agents:admin": "Delete monitored agents and rotate their keys",
              "reports:read": "Read compliance reports",
              "reports:write": "Generate compliance reports",
              "webhooks:read": "List webhook subscriptions",
              "webhooks:write": "Create and rotate webhook subscriptions",
              "integrations:read": "List configured integrations",
              "integrations:write": "Connect and disconnect integrations"
            }
          }
        }
      }
    },
    "schemas": {
      "Scan": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "example": "scan_01HX9..." },
          "agent_id": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "running", "completed", "failed"] },
          "scan_packs": { "type": "array", "items": { "type": "string" } },
          "started_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time", "nullable": true },
          "summary": {
            "type": "object",
            "properties": {
              "total_attempts": { "type": "integer" },
              "successful_attacks": { "type": "integer" },
              "success_rate": { "type": "number", "format": "float" }
            }
          }
        }
      },
      "ScanCreate": {
        "type": "object",
        "required": ["agent_id", "scan_packs"],
        "properties": {
          "agent_id": { "type": "string" },
          "scan_packs": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["owasp-llm-top-10", "owasp-api-top-10", "owasp-agentic-ai", "mitre-atlas", "eu-ai-act", "dora", "gdpr", "iso-42001", "nist-ai-rmf", "nis2", "rag", "mcp"]
            },
            "minItems": 1
          },
          "max_attempts": { "type": "integer", "minimum": 50, "maximum": 5000, "default": 500 }
        }
      },
      "ScanList": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Scan" } },
          "next_cursor": { "type": "string", "nullable": true }
        }
      },
      "Finding": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "agent_id": { "type": "string" },
          "severity": { "type": "string", "enum": ["P0", "P1", "P2", "P3"] },
          "category": {
            "type": "string",
            "enum": ["prompt-injection", "data-exfiltration", "sensitive-data-disclosure", "secrets-leakage", "model-drift", "prompt-drift", "latency-drift", "error-rate-drift"]
          },
          "frameworks": { "type": "array", "items": { "type": "string" } },
          "detected_at": { "type": "string", "format": "date-time" },
          "status": { "type": "string", "enum": ["open", "acknowledged", "resolved", "false-positive"] },
          "evidence_url": { "type": "string", "format": "uri" }
        }
      },
      "FindingList": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } },
          "next_cursor": { "type": "string", "nullable": true }
        }
      },
      "Agent": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "display_name": { "type": "string" },
          "client_id": { "type": "string", "description": "MSSP client tenant this agent belongs to." },
          "source": { "type": "string", "enum": ["bedrock", "sagemaker", "azure-openai", "vertex-ai", "logfire", "langchain", "custom"] },
          "model": { "type": "string", "example": "anthropic.claude-3-5-sonnet" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "AgentCreate": {
        "type": "object",
        "required": ["display_name", "source"],
        "properties": {
          "display_name": { "type": "string", "maxLength": 120 },
          "client_id": { "type": "string" },
          "source": { "type": "string", "enum": ["bedrock", "sagemaker", "azure-openai", "vertex-ai", "logfire", "langchain", "custom"] },
          "model": { "type": "string" },
          "tags": { "type": "object", "additionalProperties": { "type": "string" } }
        }
      },
      "AgentList": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Agent" } },
          "next_cursor": { "type": "string", "nullable": true }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "framework": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "rendering", "ready", "failed"] },
          "download_url": { "type": "string", "format": "uri", "nullable": true },
          "period_start": { "type": "string", "format": "date" },
          "period_end": { "type": "string", "format": "date" }
        }
      },
      "ReportList": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Report" } },
          "next_cursor": { "type": "string", "nullable": true }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "events": { "type": "array", "items": { "type": "string", "enum": ["finding.created", "finding.updated", "scan.completed", "report.ready"] } },
          "secret_last4": { "type": "string", "description": "Last four characters of the HMAC signing secret." }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": ["url", "events"],
        "properties": {
          "url": { "type": "string", "format": "uri" },
          "events": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
        }
      },
      "WebhookList": {
        "type": "object",
        "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Webhook" } } }
      },
      "Integration": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "type": { "type": "string", "enum": ["bedrock", "sagemaker", "azure-openai", "vertex-ai", "logfire", "langchain", "slack", "teams", "jira", "email"] },
          "status": { "type": "string", "enum": ["connected", "degraded", "disconnected"] },
          "connected_at": { "type": "string", "format": "date-time" }
        }
      },
      "IntegrationList": {
        "type": "object",
        "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Integration" } } }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "request_id": { "type": "string" }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "Key lacks the required scope",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
