{
  "openapi": "3.1.0",
  "info": {
    "title": "Codevidence — Evidence Ingestion API",
    "version": "0.1.0",
    "description": "Endpoint the Codevidence build plugins post evidence records to.\n\n`@ComplianceControl` produces a **declared** record; each `@VerifiesControl` assertion produces a **verified** record. Phase 1 authenticates and validates the record, then acknowledges it with `202` — nothing is persisted yet."
  },
  "servers": [
    {
      "url": "/",
      "description": "This deployment"
    },
    {
      "url": "https://app.codevidence.com/",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "evidence",
      "description": "Evidence ingestion"
    },
    {
      "name": "meta"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Per-tenant API key as `Authorization: Bearer <key>`."
      },
      "headerApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "Per-tenant API key as `X-Api-Key: <key>` (alternative to bearer)."
      }
    },
    "schemas": {
      "DeclaredRecord": {
        "type": "object",
        "required": [
          "schemaVersion",
          "kind",
          "control",
          "artifact",
          "provenance"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "example": "0.1"
          },
          "kind": {
            "type": "string",
            "const": "declared"
          },
          "control": {
            "type": "object",
            "required": [
              "id",
              "framework"
            ],
            "properties": {
              "id": {
                "type": "string",
                "example": "consent.capture"
              },
              "framework": {
                "type": "string",
                "example": "GDPR:Art.30"
              }
            }
          },
          "artifact": {
            "type": "object",
            "required": [
              "sha256",
              "class",
              "method",
              "descriptor"
            ],
            "properties": {
              "sha256": {
                "type": "string"
              },
              "class": {
                "type": "string",
                "example": "com.acme.consent.ConsentService"
              },
              "method": {
                "type": "string",
                "example": "recordConsent"
              },
              "descriptor": {
                "type": "string",
                "example": "(Ljava/lang/String;)V"
              }
            }
          },
          "provenance": {
            "type": "object",
            "required": [
              "commit",
              "commitSource",
              "buildId",
              "buildEnvironment",
              "timestamp",
              "serviceId"
            ],
            "properties": {
              "commit": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "a3f9e21"
              },
              "commitSource": {
                "type": "string",
                "example": "ci-env:GITHUB_SHA"
              },
              "buildId": {
                "type": "string",
                "example": "ci-4821"
              },
              "buildEnvironment": {
                "type": "string",
                "example": "ci"
              },
              "timestamp": {
                "type": "string",
                "format": "date-time"
              },
              "serviceId": {
                "type": "string",
                "example": "consent-service"
              }
            }
          }
        }
      },
      "VerifiedRecord": {
        "type": "object",
        "required": [
          "schemaVersion",
          "kind",
          "verifiesControl",
          "test",
          "result"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "example": "0.1"
          },
          "kind": {
            "type": "string",
            "const": "verified"
          },
          "verifiesControl": {
            "type": "string",
            "example": "consent.capture"
          },
          "test": {
            "type": "object",
            "required": [
              "testClass",
              "testMethod",
              "assertionType"
            ],
            "properties": {
              "testClass": {
                "type": "string",
                "example": "com.acme.consent.ConsentServiceTest"
              },
              "testMethod": {
                "type": "string",
                "example": "consentIsRecordedWithLawfulBasis"
              },
              "assertionType": {
                "type": "string",
                "example": "assertConsentRecorded"
              }
            }
          },
          "result": {
            "type": "object",
            "required": [
              "status",
              "buildId",
              "commit",
              "timestamp"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "passed",
                  "failed"
                ]
              },
              "buildId": {
                "type": "string",
                "example": "ci-4822"
              },
              "commit": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "a3f9e21"
              },
              "timestamp": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/evidence": {
      "post": {
        "tags": [
          "evidence"
        ],
        "summary": "Submit an evidence record",
        "description": "Accepts one declared or verified evidence record (≤ 64 KiB). Requires a valid per-tenant API key; if the tenant has an IP allowlist, the source IP must match.",
        "security": [
          {
            "bearerApiKey": []
          },
          {
            "headerApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/DeclaredRecord"
                  },
                  {
                    "$ref": "#/components/schemas/VerifiedRecord"
                  }
                ]
              },
              "examples": {
                "declared": {
                  "summary": "Declared (@ComplianceControl)",
                  "value": {
                    "schemaVersion": "0.1",
                    "kind": "declared",
                    "control": {
                      "id": "consent.capture",
                      "framework": "GDPR:Art.30"
                    },
                    "artifact": {
                      "sha256": "a1b2c3d4e5f6",
                      "class": "com.acme.consent.ConsentService",
                      "method": "recordConsent",
                      "descriptor": "(Ljava/lang/String;)V"
                    },
                    "provenance": {
                      "commit": "a3f9e21",
                      "commitSource": "ci-env:GITHUB_SHA",
                      "buildId": "ci-4821",
                      "buildEnvironment": "ci",
                      "timestamp": "2026-09-05T08:57:01Z",
                      "serviceId": "consent-service"
                    }
                  }
                },
                "verified": {
                  "summary": "Verified (@VerifiesControl)",
                  "value": {
                    "schemaVersion": "0.1",
                    "kind": "verified",
                    "verifiesControl": "consent.capture",
                    "test": {
                      "testClass": "com.acme.consent.ConsentServiceTest",
                      "testMethod": "consentIsRecordedWithLawfulBasis",
                      "assertionType": "assertConsentRecorded"
                    },
                    "result": {
                      "status": "passed",
                      "buildId": "ci-4822",
                      "commit": "a3f9e21",
                      "timestamp": "2026-09-05T08:57:12Z"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. The record is acknowledged (not stored in phase 1).",
            "content": {
              "application/json": {
                "example": {
                  "status": "accepted",
                  "tenant": "acme",
                  "kind": "declared",
                  "receivedAt": "2026-09-07T01:12:07.336Z",
                  "note": "Evidence acknowledged. Storage and dashboard ingestion arrive in a later phase."
                }
              }
            }
          },
          "400": {
            "description": "Body is not valid JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`missing_api_key` or `invalid_api_key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`ip_not_allowed` — key valid but source IP not in the tenant allowlist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (use POST).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds 64 KiB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Content-Type is not application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`invalid_evidence` — the record failed shape validation; see `details`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "meta"
        ],
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up.",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "service": "codevidence-app",
                  "time": "2026-09-07T01:12:07.087Z"
                }
              }
            }
          }
        }
      }
    }
  }
}