{
  "openapi": "3.0.3",
  "info": {
    "title": "KryptaLogs API",
    "description": "End-to-end encrypted logging API. All log content is encrypted client-side before ingestion. The server stores only ciphertext.",
    "version": "1.0.0"
  },
  "servers": [
    { "url": "/", "description": "Current instance" }
  ],
  "paths": {
    "/api/v1/logs": {
      "post": {
        "summary": "Ingest a single encrypted log",
        "description": "Stores one encrypted log entry. Requires write scope.",
        "tags": ["Logs"],
        "security": [{ "apiKey": [] }, { "session": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/IngestLogRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Log created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "id": { "type": "string" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/v1/logs/batch": {
      "post": {
        "summary": "Ingest a batch of encrypted logs",
        "description": "Stores multiple encrypted log entries in a single transaction. Max 500 per batch. Requires write scope.",
        "tags": ["Logs"],
        "security": [{ "apiKey": [] }, { "session": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["logs"],
                "properties": {
                  "logs": {
                    "type": "array",
                    "maxItems": 500,
                    "items": { "$ref": "#/components/schemas/IngestLogRequest" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Batch created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ids": { "type": "array", "items": { "type": "string" } },
                    "count": { "type": "integer" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/v1/keys/public": {
      "get": {
        "summary": "Get user's active public key",
        "description": "Returns the user's active ECDH P-256 public key for encrypting logs. Requires read scope.",
        "tags": ["Keys"],
        "security": [{ "apiKey": [] }, { "session": [] }],
        "responses": {
          "200": {
            "description": "Public key found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "public_key": { "type": "string", "description": "Base64-encoded 65-byte uncompressed P-256 public key" },
                    "key_type": { "type": "string", "example": "ecdh-p256" }
                  }
                }
              }
            }
          },
          "404": { "description": "No active key" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "summary": "Store a new public key",
        "description": "Stores a new ECDH P-256 public key and deactivates the previous one. Requires write scope.",
        "tags": ["Keys"],
        "security": [{ "apiKey": [] }, { "session": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["public_key"],
                "properties": {
                  "public_key": { "type": "string", "description": "Base64-encoded 65-byte uncompressed P-256 key (0x04 prefix)" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key stored",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "id": { "type": "string" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/v1/apikeys": {
      "post": {
        "summary": "Create an API key",
        "description": "Creates a new API key. The raw key is returned only once. Requires session authentication.",
        "tags": ["API Keys"],
        "security": [{ "session": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string" },
                  "scopes": { "type": "string", "enum": ["read", "write", "read,write"], "default": "read,write" },
                  "expires": { "type": "string", "format": "date", "description": "Expiration date (YYYY-MM-DD), blank for never" }
                }
              }
            }
          }
        },
        "responses": {
          "303": { "description": "Redirects to settings page with new key" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "Health check",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "version": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "IngestLogRequest": {
        "type": "object",
        "required": ["ciphertext", "iv", "ephemeral_public_key"],
        "properties": {
          "source": { "type": "string", "description": "Log source identifier (e.g., app name)", "example": "my-app" },
          "level": { "type": "string", "enum": ["debug", "info", "warning", "error", "critical"], "default": "info" },
          "timestamp": { "description": "RFC3339 string or Unix epoch (seconds). Defaults to server time.", "oneOf": [{ "type": "string", "format": "date-time" }, { "type": "number" }] },
          "ciphertext": { "type": "string", "description": "Base64-encoded AES-256-GCM ciphertext" },
          "iv": { "type": "string", "description": "Base64-encoded 12-byte AES-GCM initialization vector" },
          "ephemeral_public_key": { "type": "string", "description": "Base64-encoded 65-byte uncompressed ECDH P-256 ephemeral public key" }
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key (format: kl_<hex>). Create in Settings."
      },
      "session": {
        "type": "apiKey",
        "in": "cookie",
        "name": "kl_session",
        "description": "Session cookie (set after login)"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } }
      },
      "Unauthorized": {
        "description": "Authentication required",
        "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } }
      },
      "Forbidden": {
        "description": "Insufficient permissions (scope)",
        "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } }
      }
    }
  }
}
