{
  "openapi": "3.1.0",
  "info": {
    "title": "Lazarus AI API",
    "version": "1.0.0",
    "description": "REST API for the Lazarus AI platform. Chat with multi-character AI personas, manage conversations, and integrate the shared AI engine into any client (web, mobile, desktop, third-party).",
    "contact": {
      "name": "Lazarus AI"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://lazarus.rage.lat",
      "description": "Current deployment"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "Send messages to a character and get an AI reply."
    },
    {
      "name": "Conversations",
      "description": "Create and inspect conversation threads."
    },
    {
      "name": "Characters",
      "description": "List available AI characters."
    },
    {
      "name": "Models",
      "description": "Inspect the underlying AI providers."
    },
    {
      "name": "Balance",
      "description": "Balance and usage for the authenticated API key."
    }
  ],
  "paths": {
    "/api/v1/chat": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Send a message and receive an AI reply",
        "description": "Sends a user message to a character and returns the AI reply. If `conversation_id` is omitted, a new conversation is created automatically and returned in the response.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              },
              "examples": {
                "new_conversation": {
                  "summary": "Start a new conversation",
                  "value": {
                    "character_id": "b7c9e21e-7f19-4a41-8b4c-4b8c8c2d3e00",
                    "message": "Hello! Who are you?"
                  }
                },
                "continue_conversation": {
                  "summary": "Continue an existing conversation",
                  "value": {
                    "character_id": "b7c9e21e-7f19-4a41-8b4c-4b8c8c2d3e00",
                    "conversation_id": "9b1e4b0f-2a3d-4c5e-9a1b-8c7d6e5f4a3b",
                    "message": "Tell me more."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AI reply generated",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ChatResponse"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "conversation_id": "9b1e4b0f-2a3d-4c5e-9a1b-8c7d6e5f4a3b",
                    "character": {
                      "id": "b7c9e21e-7f19-4a41-8b4c-4b8c8c2d3e00",
                      "name": "Aria"
                    },
                    "reply": "Hi! I'm Aria — nice to meet you.",
                    "duration_ms": 842
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMedia"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/api/v1/conversations": {
      "post": {
        "tags": [
          "Conversations"
        ],
        "summary": "Create a new conversation",
        "description": "Creates an empty conversation. Optionally binds it to a character.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateConversationRequest"
              },
              "example": {
                "character_id": "b7c9e21e-7f19-4a41-8b4c-4b8c8c2d3e00"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Conversation created",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "conversation": {
                              "$ref": "#/components/schemas/Conversation"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/api/v1/conversations/{id}": {
      "get": {
        "tags": [
          "Conversations"
        ],
        "summary": "Get a conversation and its messages",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Conversation UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation returned",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "conversation": {
                              "$ref": "#/components/schemas/Conversation"
                            },
                            "messages": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/Message"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/api/v1/characters": {
      "get": {
        "tags": [
          "Characters"
        ],
        "summary": "List active characters",
        "responses": {
          "200": {
            "description": "Character list",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "characters": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/Character"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/models": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "List AI providers and models in the fallback chain",
        "responses": {
          "200": {
            "description": "Model list",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "models": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/Model"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/balance": {
      "get": {
        "tags": [
          "Balance"
        ],
        "summary": "Get the balance and today's usage for the authenticated API key",
        "responses": {
          "200": {
            "description": "Balance snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BalanceResponse"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "api_key": {
                      "id": "…",
                      "name": "my-app"
                    },
                    "balance": 87,
                    "subscription": {
                      "active": false,
                      "expires_at": null
                    },
                    "trial_active": false,
                    "today": {
                      "api_requests": 12,
                      "usage_count": 12
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key (lz_live_…)",
        "description": "Send your API key as `Authorization: Bearer lz_live_…`. Manage keys from the admin dashboard."
      }
    },
    "schemas": {
      "SuccessEnvelope": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "description": "Endpoint-specific payload"
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "status"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "unauthorized",
                  "forbidden",
                  "not_found",
                  "invalid_json",
                  "validation_error",
                  "method_not_allowed",
                  "internal_error",
                  "upstream_error",
                  "insufficient_credits"
                ]
              },
              "message": {
                "type": "string"
              },
              "status": {
                "type": "integer"
              },
              "details": {}
            }
          }
        }
      },
      "ChatRequest": {
        "type": "object",
        "required": [
          "character_id",
          "message"
        ],
        "properties": {
          "character_id": {
            "type": "string",
            "format": "uuid",
            "description": "Target character UUID"
          },
          "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          },
          "conversation_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Optional. Omit to start a new conversation."
          }
        }
      },
      "ChatResponse": {
        "type": "object",
        "required": [
          "conversation_id",
          "character",
          "reply",
          "duration_ms"
        ],
        "properties": {
          "conversation_id": {
            "type": "string",
            "format": "uuid"
          },
          "character": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "reply": {
            "type": "string"
          },
          "duration_ms": {
            "type": "integer"
          }
        }
      },
      "CreateConversationRequest": {
        "type": "object",
        "properties": {
          "character_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "Conversation": {
        "type": "object",
        "required": [
          "id",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "character_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "role",
          "content",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "assistant"
            ]
          },
          "content": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Character": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "uncensored": {
            "type": "boolean",
            "nullable": true
          },
          "sort_order": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "Model": {
        "type": "object",
        "required": [
          "provider",
          "id",
          "role"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "nvidia",
              "gemini",
              "gemini-gateway"
            ]
          },
          "id": {
            "type": "string"
          },
          "role": {
            "type": "string"
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "required": [
          "balance",
          "subscription",
          "trial_active",
          "today"
        ],
        "properties": {
          "api_key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "balance": {
            "type": "integer",
            "description": "Remaining API credit balance."
          },
          "subscription": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          },
          "trial_active": {
            "type": "boolean"
          },
          "today": {
            "type": "object",
            "properties": {
              "api_requests": {
                "type": "integer",
                "description": "Requests made today with this API key."
              },
              "usage_count": {
                "type": "integer",
                "description": "Daily chat usage counter for the API key owner."
              }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "unauthorized",
                "message": "Invalid API key",
                "status": 401
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "API key is disabled, revoked, or expired",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "forbidden",
                "message": "API key has been revoked",
                "status": 403
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "not_found",
                "message": "Conversation not found",
                "status": 404
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "HTTP method not supported for this endpoint",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "method_not_allowed",
                "message": "Method not allowed. Use: POST",
                "status": 405
              }
            }
          }
        }
      },
      "UnsupportedMedia": {
        "description": "Content-Type must be application/json",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "invalid_json",
                "message": "Content-Type must be application/json",
                "status": 415
              }
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request failed validation",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "validation_error",
                "message": "Request validation failed",
                "status": 422,
                "details": {
                  "fields": [
                    {
                      "field": "message",
                      "message": "Required non-empty string"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "UpstreamError": {
        "description": "AI provider unavailable",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "success": false,
              "error": {
                "code": "upstream_error",
                "message": "AI provider unavailable or character not found",
                "status": 502
              }
            }
          }
        }
      }
    }
  }
}