{
  "openapi": "3.1.0",
  "info": {
    "title": "Capsule Security LiteLLM Hooks API",
    "description": "Webhook endpoints for the Capsule LiteLLM gateway plugin.\n\nThe plugin calls `events/pre` synchronously before forwarding a\ncompletion/chat request to the upstream model provider, blocking on the\nallow/deny verdict. After the upstream call settles (success or failure),\nit calls `events/post` for token and latency telemetry. Both endpoints are\nJWT-authenticated; the token is scoped to a single tenant and environment.\n",
    "version": "1.0.0",
    "contact": {
      "name": "Capsule Security Support",
      "email": "support@capsule.security"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://capsule.security/license"
    }
  },
  "servers": [
    {
      "url": "https://agents.capsule.security",
      "description": "Production agentsecurity server"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/litellm/hooks/events/pre": {
      "post": {
        "summary": "Pre-call policy check",
        "description": "Sent before LiteLLM forwards a completion request to the upstream model\nprovider. Capsule evaluates the model and messages against tenant\npolicies and returns an allow/deny verdict. The plugin rejects the\nrequest when `decision` is `deny` and blocking is enabled.\n",
        "operationId": "liteLlmPreHook",
        "tags": [
          "LiteLLM Hooks"
        ],
        "parameters": [
          {
            "name": "x-correlation-id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Trace ID for request correlation"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreHookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Policy verdict for the completion request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreHookResponse"
                },
                "examples": {
                  "allowed": {
                    "summary": "Request allowed",
                    "value": {
                      "decision": "allow"
                    }
                  },
                  "denied": {
                    "summary": "Request denied",
                    "value": {
                      "decision": "deny",
                      "reason": "Policy violation: prompt references restricted data",
                      "triggeredPolicyIds": [
                        "pol_01HZX9..."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or expired JWT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://api.capsule.security/problems/unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "detail": "The provided JWT token is invalid or expired."
                }
              }
            }
          },
          "408": {
            "description": "Request timeout — the plugin treats this as allow when fail-open is enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://api.capsule.security/problems/timeout",
                  "title": "Request Timeout",
                  "status": 408,
                  "detail": "The request exceeded the processing timeout."
                }
              }
            }
          }
        }
      }
    },
    "/v1/litellm/hooks/events/post": {
      "post": {
        "summary": "Post-call telemetry",
        "description": "Fire-and-forget telemetry sent after the upstream model call settles.\nCarries token usage, latency, and success/error detail. Always returns\n`200` with `{ \"ok\": true }` once accepted.\n",
        "operationId": "liteLlmPostHook",
        "tags": [
          "LiteLLM Hooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostHookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Telemetry accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostHookResponse"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "401": {
            "description": "Invalid or expired JWT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "https://api.capsule.security/problems/unauthorized",
                  "title": "Unauthorized",
                  "status": 401,
                  "detail": "The provided JWT token is invalid or expired."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "PreHookRequest": {
        "type": "object",
        "required": [
          "requestId",
          "model"
        ],
        "properties": {
          "requestId": {
            "type": "string",
            "description": "LiteLLM-issued request id, propagated for end-to-end tracing",
            "example": "chatcmpl-abc123"
          },
          "model": {
            "type": "string",
            "description": "Foundational model being called",
            "example": "gpt-4o"
          },
          "messages": {
            "type": "array",
            "description": "Chat messages submitted with the request",
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            }
          },
          "user": {
            "type": "string",
            "description": "End-user identifier forwarded by the calling application, if any",
            "example": "user@example.com"
          }
        },
        "example": {
          "requestId": "chatcmpl-abc123",
          "model": "gpt-4o",
          "messages": [
            {
              "role": "user",
              "content": "Summarize the attached customer records"
            }
          ],
          "user": "user@example.com"
        }
      },
      "ChatMessage": {
        "type": "object",
        "required": [
          "role",
          "content"
        ],
        "properties": {
          "role": {
            "type": "string",
            "description": "Message role (e.g. system, user, assistant)",
            "example": "user"
          },
          "content": {
            "type": "string",
            "description": "Message content",
            "example": "Summarize the attached customer records"
          }
        }
      },
      "PreHookResponse": {
        "type": "object",
        "required": [
          "decision"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "allow",
              "deny"
            ],
            "description": "Whether the completion request is allowed or denied"
          },
          "reason": {
            "type": "string",
            "description": "Reason for denial (present when decision is \"deny\")",
            "example": "Policy violation: prompt references restricted data"
          },
          "triggeredPolicyIds": {
            "type": "array",
            "description": "Identifiers of the policies that produced the verdict",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PostHookRequest": {
        "type": "object",
        "required": [
          "requestId",
          "model",
          "durationMs",
          "success"
        ],
        "properties": {
          "requestId": {
            "type": "string",
            "example": "chatcmpl-abc123"
          },
          "model": {
            "type": "string",
            "example": "gpt-4o"
          },
          "durationMs": {
            "type": "integer",
            "description": "Wall-clock milliseconds spent on the upstream model call",
            "example": 842
          },
          "promptTokens": {
            "type": "integer",
            "example": 128
          },
          "completionTokens": {
            "type": "integer",
            "example": 256
          },
          "totalTokens": {
            "type": "integer",
            "example": 384
          },
          "success": {
            "type": "boolean",
            "example": true
          },
          "errorCode": {
            "type": "string",
            "description": "Error class/code (present when success is false)",
            "example": "RateLimitError"
          },
          "errorMessage": {
            "type": "string",
            "description": "Error detail (present when success is false)"
          }
        },
        "example": {
          "requestId": "chatcmpl-abc123",
          "model": "gpt-4o",
          "durationMs": 842,
          "promptTokens": 128,
          "completionTokens": 256,
          "totalTokens": 384,
          "success": true
        }
      },
      "PostHookResponse": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true,
            "example": true
          }
        }
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "A URI reference that identifies the problem type.",
            "example": "https://api.capsule.security/problems/unauthorized"
          },
          "title": {
            "type": "string",
            "description": "A short, human-readable summary of the problem type.",
            "example": "Unauthorized"
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code.",
            "example": 401
          },
          "detail": {
            "type": "string",
            "description": "A human-readable explanation specific to this occurrence of the problem.",
            "example": "The provided JWT token is invalid or expired."
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT Bearer token scoped to a tenant and environment"
      }
    }
  }
}