{
  "openapi": "3.1.0",
  "info": {
    "title": "LemonSlice",
    "description": "An API that gives access to a LemonSlice agent via a Daily room.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://lemonslice.com/api"
    }
  ],
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/liveai/rooms": {
      "get": {
        "summary": "List hosted sessions",
        "description": "Returns paginated hosted sessions for the authenticated account.",
        "operationId": "listRooms",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Page number (1-indexed).",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of rooms per page.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rooms retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rooms": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "agent_id": {
                            "type": "string"
                          },
                          "session_id": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "session_status": {
                            "type": "string"
                          },
                          "credits_used": {
                            "type": [
                              "number",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "agent_id",
                          "session_id",
                          "created_at",
                          "session_status"
                        ]
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "total_pages": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_more"
                      ]
                    }
                  },
                  "required": [
                    "rooms",
                    "pagination"
                  ]
                },
                "example": {
                  "rooms": [
                    {
                      "agent_id": "agent_abc123",
                      "session_id": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a",
                      "created_at": "2026-04-29T20:34:56.000Z",
                      "session_status": "COMPLETED",
                      "credits_used": 10.5
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "limit": 25,
                    "total": 1,
                    "total_pages": 1,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Requested page is too deep. Maximum offset is 1000."
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create hosted session",
        "description": "Creates a hosted session for the specified LemonSlice agent.",
        "operationId": "createRoom",
        "requestBody": {
          "description": "The LemonSlice agent to use in the session.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentInfo"
              },
              "example": {
                "agent_id": "agent_abc123"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Room created successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Room"
                },
                "example": {
                  "room_url": "https://lemonslice.daily.co/abc123",
                  "token": "eyJhbGciOiJIUzI1NiIsInR5a...",
                  "image_url": "https://cdn.lemonslice.com/agents/agent_abc123.png",
                  "session_id": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a"
                }
              }
            }
          },
          "400": {
            "description": "Invalid arguments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Missing required fields"
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "402": {
            "description": "Agent owner has insufficient funds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Agent agent_123abc owner has insufficient funds"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/sessions": {
      "get": {
        "summary": "List self-managed sessions",
        "description": "Returns paginated self-managed sessions for the authenticated account.",
        "operationId": "listSessions",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Page number (1-indexed).",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of sessions per page.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sessions retrieved successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "session_id": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "session_status": {
                            "type": "string"
                          },
                          "credits_used": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "provider": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "session_id",
                          "created_at",
                          "session_status"
                        ]
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "total_pages": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "page",
                        "limit",
                        "total",
                        "total_pages",
                        "has_more"
                      ]
                    }
                  },
                  "required": [
                    "sessions",
                    "pagination"
                  ]
                },
                "example": {
                  "sessions": [
                    {
                      "session_id": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a",
                      "created_at": "2026-04-29T20:34:56.000Z",
                      "session_status": "COMPLETED",
                      "credits_used": 10.5,
                      "provider": "LIVEKIT"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "limit": 25,
                    "total": 1,
                    "total_pages": 1,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid pagination request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Requested page is too deep. Maximum offset is 1000."
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create self-managed session",
        "description": "Creates a self-managed session that takes in avatar audio and returns synchronized video/audio.",
        "operationId": "createSession",
        "x-mint": {
          "content": "<Warning>\n**Do not call this endpoint directly.** Use an official plugin such as [LiveKit](/livekit) or [Pipecat](/pipecat) instead to ensure proper session lifecycle management.\n</Warning>\n\n<Note>\nTo upload an avatar image file directly, switch the request body content type to `multipart/form-data` below.\n</Note>"
        },
        "requestBody": {
          "description": "The properties used to create a self-managed session. Use `application/json` to reference an agent_id or agent_image_url, or `multipart/form-data` to upload an image file directly.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionInput"
              },
              "examples": {
                "by_agent_image_url": {
                  "summary": "Create a session using an agent_image_url",
                  "value": {
                    "agent_image_url": "https://cdn.lemonslice.com/agents/custom_agent.png",
                    "agent_prompt": "a person talking",
                    "transport_type": "livekit",
                    "properties": {
                      "livekit_url": "wss://lemonslice-pb123.livekit.cloud",
                      "livekit_token": "eyJhbGciOiJIUzI1NiIsInR5a..."
                    }
                  }
                },
                "by_agent_id": {
                  "summary": "Create a session using an agent_id",
                  "value": {
                    "agent_id": "agent_abc123",
                    "transport_type": "livekit",
                    "properties": {
                      "livekit_url": "wss://lemonslice-pb123.livekit.cloud",
                      "livekit_token": "eyJhbGciOiJIUzI1NiIsInR5a..."
                    }
                  }
                },
                "daily_transport": {
                  "summary": "Create a session using Daily transport",
                  "value": {
                    "agent_id": "agent_abc123",
                    "transport_type": "daily",
                    "properties": {
                      "daily_room_url": "https://your-domain.daily.co/your-room",
                      "daily_token": "eyJhbGciOiJIUzI1NiIsInR5a..."
                    }
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "image",
                  "payload"
                ],
                "properties": {
                  "image": {
                    "description": "The avatar image file. The image should be 368x560 pixels with a maximum size of 4 MB. LemonSlice will automatically center-crop to the target aspect ratio if the dimensions do not match.",
                    "type": "string",
                    "format": "binary"
                  },
                  "payload": {
                    "$ref": "#/components/schemas/SessionFormDataPayload"
                  }
                }
              },
              "encoding": {
                "payload": {
                  "contentType": "application/json"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Session created successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                },
                "example": {
                  "session_id": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a"
                }
              }
            }
          },
          "400": {
            "description": "Invalid arguments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Missing required fields"
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "402": {
            "description": "Agent owner has insufficient funds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Agent agent_123abc owner has insufficient funds"
                }
              }
            }
          },
          "403": {
            "description": "Agent not owned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Agent agent_123abc is not owned by the authenticated user"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/sessions/{session_id}": {
      "get": {
        "summary": "Get self-managed session",
        "description": "Retrieves the current status of a self-managed session. When the session is completed, returns additional metadata about the session.",
        "operationId": "getSession",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "description": "The ID of the session to retrieve.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session status retrieved successfully. Returns basic status for all states. When completed, includes the total cost in credits.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_status": {
                      "type": "string",
                      "enum": [
                        "QUEUED",
                        "ACTIVE",
                        "COMPLETED",
                        "TIMED_OUT",
                        "FAILED"
                      ],
                      "description": "Current status of the session:\n\n- **QUEUED**: session is waiting for a GPU container. Typically completes in seconds when warm containers are available. If all warm containers are in use, a cold start is required which may take up to 2.5 minutes.\n- **ACTIVE**: agent is live.\n- **COMPLETED**: session ended successfully.\n- **TIMED_OUT**: GPU container timed out.\n- **FAILED**: session ended with an error."
                    },
                    "cost": {
                      "type": "number",
                      "description": "Number of credits used for this session. Only returned when session_status is COMPLETED."
                    }
                  },
                  "required": [
                    "session_status"
                  ]
                },
                "examples": {
                  "queued": {
                    "summary": "Session is queued",
                    "value": {
                      "session_status": "QUEUED"
                    }
                  },
                  "active": {
                    "summary": "Session is active",
                    "value": {
                      "session_status": "ACTIVE"
                    }
                  },
                  "completed": {
                    "summary": "Session completed",
                    "value": {
                      "session_status": "COMPLETED",
                      "cost": 10.5
                    }
                  },
                  "timed_out": {
                    "summary": "Session timed out",
                    "value": {
                      "session_status": "TIMED_OUT"
                    }
                  },
                  "failed": {
                    "summary": "Session failed",
                    "value": {
                      "session_status": "FAILED"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "403": {
            "description": "Session not owned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Session does not belong to this account"
                }
              }
            }
          },
          "404": {
            "description": "Session not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Session not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/sessions/{session_id}/control": {
      "post": {
        "summary": "Control self-managed session",
        "description": "Send a control event to an active session.",
        "operationId": "controlSession",
        "security": [],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "description": "The ID of the session to control.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/TerminateEvent",
                    "title": "Terminate",
                    "description": "Immediately shuts down the LemonSlice avatar and removes it from the WebRTC room."
                  },
                  {
                    "$ref": "#/components/schemas/UpdateImageEvent",
                    "title": "Update Image",
                    "description": "Update the avatar's base image with a new image. This resets the model, so any audio currently playing will be cut off — best called when the avatar is silent. The image swap takes up to 5 seconds."
                  },
                  {
                    "$ref": "#/components/schemas/UpdateAgentPromptEvent",
                    "title": "Update Agent Prompt",
                    "description": "A high-level system prompt that subtly influences the avatar's expressions while speaking. This prompt is best used to suggest general demeanor (for example, 'feel excited' or 'look sad') rather than precise or deterministic actions."
                  },
                  {
                    "$ref": "#/components/schemas/UpdateIdlePromptEvent",
                    "title": "Update Idle Prompt",
                    "description": "A high-level system prompt that subtly influences the avatar's expressions during the idle state."
                  },
                  {
                    "$ref": "#/components/schemas/PoseTriggerEvent",
                    "title": "Action Trigger",
                    "description": "Trigger a specific action sequence on the active avatar."
                  },
                  {
                    "$ref": "#/components/schemas/ResetIdleTimeoutEvent",
                    "title": "Reset Idle Timeout",
                    "description": "Resets the idle timeout timer on the session. Useful to keep the session alive when the user is still engaged but the avatar is not currently speaking."
                  }
                ],
                "discriminator": {
                  "propertyName": "event",
                  "mapping": {
                    "update-image": "#/components/schemas/UpdateImageEvent",
                    "terminate": "#/components/schemas/TerminateEvent",
                    "update-agent-prompt": "#/components/schemas/UpdateAgentPromptEvent",
                    "update-idle-prompt": "#/components/schemas/UpdateIdlePromptEvent",
                    "pose-trigger": "#/components/schemas/PoseTriggerEvent",
                    "reset-idle-timeout": "#/components/schemas/ResetIdleTimeoutEvent"
                  }
                }
              },
              "examples": {
                "terminate": {
                  "summary": "Terminate session",
                  "value": {
                    "event": "terminate"
                  }
                },
                "update_image": {
                  "summary": "Swap the avatar image",
                  "description": "Replace the avatar's base image.",
                  "value": {
                    "event": "update-image",
                    "image_url": "https://example.com/avatar.jpg"
                  }
                },
                "update_agent_prompt": {
                  "summary": "Update the agent prompt (for speaking periods)",
                  "description": "Replace the agent prompt used when the avatar is speaking.",
                  "value": {
                    "event": "update-agent-prompt",
                    "agent_prompt": "a person talking"
                  }
                },
                "update_idle_prompt": {
                  "summary": "Update the idle prompt (for idle periods)",
                  "description": "Replace the idle prompt used when the avatar is idle.",
                  "value": {
                    "event": "update-idle-prompt",
                    "idle_prompt": "a serious person"
                  }
                },
                "pose_trigger": {
                  "summary": "Trigger an action",
                  "description": "Trigger the requested action.",
                  "value": {
                    "event": "pose-trigger",
                    "pose_trigger": {
                      "name": "<ACTION_NAME>"
                    }
                  }
                },
                "reset_idle_timeout": {
                  "summary": "Reset the idle timeout",
                  "description": "Reset the idle timeout timer to keep the session alive.",
                  "value": {
                    "event": "reset-idle-timeout"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Control event accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                },
                "example": {
                  "success": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid event or missing required fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "image_url required for update-image event"
                }
              }
            }
          },
          "404": {
            "description": "Session not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Session not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/sessions/{session_id}/join-meeting": {
      "post": {
        "summary": "Join third party meeting platform",
        "description": "Have your LemonSlice avatar join a third party meeting platform (Zoom, Google Meet, Microsoft Teams, or Webex)\n\n**Important notes:**\n\n- We recommend using our [LiveKit plugin](/livekit) rather than calling this endpoint directly (PR in progress).\n- This feature currently works only with LiveKit-based self-managed sessions.\n- Use this endpoint to have your avatar join third party meeting platforms. Do **not** use this endpoint for regular LiveKit sessions.",
        "operationId": "joinMeeting",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "description": "The ID of the active LemonSlice session whose avatar should join the third party meeting platform.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JoinMeetingInput"
              },
              "example": {
                "meeting_url": "https://meet.google.com/abc-defg-hij",
                "livekit_url": "wss://lemonslice-pb123.livekit.cloud",
                "broadcast_token": "<LIVEKIT_BROADCAST_TOKEN>",
                "bot_name": "LemonSlice Avatar"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Avatar is joining the third party meeting platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JoinMeetingResponse"
                },
                "example": {
                  "meeting_bot_id": "meeting-bot-abc123",
                  "websocket_url": "wss://example.com/agent-audio/session-id?token=..."
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. unrecognized meeting URL or invalid LiveKit token)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Unrecognized meeting link — paste a Zoom, Google Meet, Microsoft Teams, or Webex URL."
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Failed to join meeting"
                }
              }
            }
          },
          "502": {
            "description": "Could not join the meeting",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Could not join the meeting — check the meeting link and try again."
                }
              }
            }
          },
          "503": {
            "description": "Meeting service unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Meeting audio tunnel failed to start"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Request timed out"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/sessions/{session_id}/leave-meeting": {
      "post": {
        "summary": "Leave third party meeting platform",
        "description": "Remove your LemonSlice avatar from a third party meeting platform (Zoom, Google Meet, Microsoft Teams, or Webex)\n\n**Important notes:**\n\n- We recommend using our [LiveKit plugin](/livekit) rather than calling this endpoint directly (PR in progress).\n- This feature currently works only with LiveKit-based self-managed sessions.\n- Use this endpoint to remove your avatar from third party meeting platforms. Do **not** use this endpoint for regular LiveKit sessions.",
        "operationId": "leaveMeeting",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "description": "The ID of the LemonSlice session associated with the third party meeting platform.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeaveMeetingInput"
              },
              "example": {
                "meeting_bot_id": "meeting-bot-abc123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Avatar removed from the third party meeting platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeaveMeetingResponse"
                },
                "example": {
                  "status": "left"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. missing meeting_bot_id)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "meeting_bot_id is required"
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Failed to leave meeting"
                }
              }
            }
          },
          "502": {
            "description": "Could not leave the meeting",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Could not leave the meeting."
                }
              }
            }
          },
          "503": {
            "description": "Meeting service unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Meeting service is not configured"
                }
              }
            }
          },
          "504": {
            "description": "Request timed out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Request timed out"
                }
              }
            }
          }
        }
      }
    },
    "/liveai/rooms/{session_id}": {
      "get": {
        "summary": "Get hosted session",
        "description": "Retrieves the current status of a hosted session. Includes additional metadata when the session is completed.",
        "operationId": "getRoomStatus",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "description": "The session identifier returned upon creation.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns basic status of session. When completed, includes additional metadata such as cost, timestamps, end reason, and conversation messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_status": {
                      "type": "string",
                      "enum": [
                        "QUEUED",
                        "ACTIVE",
                        "COMPLETED",
                        "TIMED_OUT",
                        "FAILED"
                      ],
                      "description": "Current status of the session:\n\n- **QUEUED**: session is waiting for a GPU container. Typically completes in seconds when warm containers are available. If all warm containers are in use, a cold start is required which may take up to 2.5 minutes.\n- **ACTIVE**: agent is live.\n- **COMPLETED**: session ended successfully.\n- **TIMED_OUT**: GPU container timed out.\n- **FAILED**: session ended with an error."
                    },
                    "cost": {
                      "type": "number",
                      "description": "Number of credits used for this session. Only returned when session_status is COMPLETED."
                    },
                    "llm_ended_reason": {
                      "type": "string",
                      "description": "Reason the LLM session ended. Only returned when session_status is COMPLETED."
                    },
                    "llm_started_at": {
                      "type": "integer",
                      "description": "Unix timestamp when the LLM session started. Only returned when session_status is COMPLETED."
                    },
                    "llm_ended_at": {
                      "type": "integer",
                      "description": "Unix timestamp when the LLM session ended. Only returned when session_status is COMPLETED."
                    },
                    "messages": {
                      "type": "array",
                      "description": "Array of messages exchanged during the session. Only returned when session_status is COMPLETED.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "role": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ],
                            "description": "Role of the message sender."
                          },
                          "message": {
                            "type": "string",
                            "description": "Content of the message."
                          },
                          "seconds_from_start": {
                            "type": "integer",
                            "description": "Number of seconds from the start of the session when this message was sent."
                          }
                        },
                        "required": [
                          "role",
                          "message",
                          "seconds_from_start"
                        ]
                      }
                    }
                  },
                  "required": [
                    "session_status"
                  ]
                },
                "examples": {
                  "queued": {
                    "summary": "Session is queued",
                    "value": {
                      "session_status": "QUEUED"
                    }
                  },
                  "active": {
                    "summary": "Session is active",
                    "value": {
                      "session_status": "ACTIVE"
                    }
                  },
                  "completed": {
                    "summary": "Session completed with full details",
                    "value": {
                      "session_status": "COMPLETED",
                      "cost": 10.5,
                      "llm_ended_reason": "Client disconnected: 1000",
                      "llm_started_at": 1772746376,
                      "llm_ended_at": 1772746535,
                      "messages": [
                        {
                          "role": "user",
                          "message": "hello",
                          "seconds_from_start": 0
                        },
                        {
                          "role": "agent",
                          "message": "Hello! How can I assist you today?",
                          "seconds_from_start": 10
                        }
                      ]
                    }
                  },
                  "timed_out": {
                    "summary": "Session timed out",
                    "value": {
                      "session_status": "TIMED_OUT"
                    }
                  },
                  "failed": {
                    "summary": "Session failed",
                    "value": {
                      "session_status": "FAILED"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Authentication denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "403": {
            "description": "Room does not belong to this account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Room does not belong to this account"
                }
              }
            }
          },
          "404": {
            "description": "Room not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": "Room not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "detail": "Internal server error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AgentInfo": {
        "type": "object",
        "required": [
          "agent_id"
        ],
        "properties": {
          "agent_id": {
            "description": "The ID of the LemonSlice agent.",
            "type": "string",
            "example": "agent_abc123"
          }
        }
      },
      "Room": {
        "type": "object",
        "required": [
          "room_url",
          "token",
          "image_url",
          "session_id"
        ],
        "properties": {
          "room_url": {
            "description": "The Daily room URL.",
            "type": "string",
            "format": "uri",
            "example": "https://your-subdomain.daily.co/abc123"
          },
          "token": {
            "description": "The Daily user token.",
            "type": "string"
          },
          "image_url": {
            "description": "The placeholder agent image.",
            "type": "string",
            "format": "uri",
            "example": "https://cdn.lemonslice.com/agents/agent_abc123.png"
          },
          "session_id": {
            "description": "A unique identifier for the room's session.",
            "type": "string",
            "format": "string",
            "example": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a"
          }
        }
      },
      "SessionInput": {
        "description": "Input to create an agent session. Exactly one of `agent_id` or `agent_image_url` must be provided.",
        "type": "object",
        "required": [
          "transport_type"
        ],
        "properties": {
          "agent_prompt": {
            "description": "A high-level system prompt that subtly influences the avatar's movements, expressions, and emotional demeanor. This prompt is best used to suggest general affect or demeanor (for example, 'feel excited' or 'look sad') rather than precise or deterministic actions.",
            "type": "string",
            "default": "a person talking"
          },
          "agent_idle_prompt": {
            "description": "A high-level system prompt that influences the avatar's movements, expressions, and emotional demeanor during the idle state.",
            "type": "string",
            "default": "a serious person"
          },
          "idle_timeout": {
            "description": "Idle timeout in seconds. If a negative number is provided, the session will have no idle timeout.",
            "type": "integer",
            "default": 60
          },
          "response_done_timeout": {
            "description": "Time in seconds to wait without receiving new audio bytes before marking the response as complete. Some TTS models do not send an end response event, or do not send it in a timely manner. This parameter enables detection of response completion when such events are missing or delayed. This parameter can also be used to ensure proper conversation flow with multi-message LLMs (e.g. `gpt-realtime-2`).",
            "type": [
              "number",
              "null"
            ],
            "default": null,
            "x-mint": {
              "post": [
                "default: null"
              ]
            }
          },
          "aspect_ratio": {
            "description": "Output aspect ratio for the avatar video.",
            "type": "string",
            "enum": [
              "2x3",
              "9x16",
              "1x1"
            ],
            "default": "2x3"
          },
          "model": {
            "description": "Model variant. Leave `null` to use the normal flagship model.",
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "lite",
              "flash",
              "pro",
              null
            ],
            "default": null,
            "x-mint": {
              "post": [
                "default: null"
              ]
            }
          },
          "simulcast": {
            "description": "Enable WebRTC simulcast, which publishes multiple resolutions of the avatar video so subscribers receive the best quality their bandwidth allows. LiveKit transport only.",
            "type": "boolean",
            "default": false
          },
          "transport_type": {
            "description": "The interface type for how the audio is sent and how the A/V is returned.",
            "type": "string",
            "enum": [
              "livekit",
              "daily"
            ]
          },
          "properties": {
            "description": "Additional properties needed to connect to the transport layer.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/LiveKitTransportProperties",
                "title": "LiveKit"
              },
              {
                "$ref": "#/components/schemas/DailyTransportProperties",
                "title": "Daily"
              }
            ]
          }
        },
        "oneOf": [
          {
            "title": "By agent_image_url",
            "type": "object",
            "required": [
              "agent_image_url"
            ],
            "properties": {
              "agent_image_url": {
                "description": "A URL to an agent image to use. The image should be 368x560 pixels. LemonSlice will automatically center-crop your image to the target aspect ratio if the dimensions do not match the expected values. Provide either agent_image_url or agent_id, but not both.",
                "type": "string",
                "format": "uri",
                "example": "https://example.com/custom_agent.png"
              }
            },
            "not": {
              "required": [
                "agent_id"
              ]
            }
          },
          {
            "title": "By agent_id",
            "type": "object",
            "required": [
              "agent_id"
            ],
            "properties": {
              "agent_id": {
                "description": "The ID of the LemonSlice agent. Provide either `agent_id` or `agent_image_url`, but not both.",
                "type": "string",
                "example": "agent_abc123"
              }
            },
            "not": {
              "required": [
                "agent_image_url"
              ]
            }
          }
        ],
        "unevaluatedProperties": false
      },
      "SessionFormDataPayload": {
        "description": "The properties used to create a self-managed session alonside an image upload.",
        "type": "object",
        "required": [
          "transport_type"
        ],
        "properties": {
          "agent_prompt": {
            "description": "A high-level system prompt that subtly influences the avatar's movements, expressions, and emotional demeanor.",
            "type": "string",
            "default": "a person talking"
          },
          "agent_idle_prompt": {
            "description": "A high-level system prompt that influences the avatar's movements, expressions, and emotional demeanor during the idle state.",
            "type": "string",
            "default": "a serious person"
          },
          "idle_timeout": {
            "description": "Idle timeout in seconds. If a negative number is provided, the session will have no idle timeout.",
            "type": "integer",
            "default": 60
          },
          "response_done_timeout": {
            "description": "Time in seconds to wait without receiving new audio bytes before marking the response as complete.",
            "type": [
              "number",
              "null"
            ],
            "default": null,
            "x-mint": {
              "post": [
                "default: null"
              ]
            }
          },
          "aspect_ratio": {
            "description": "Output aspect ratio for the avatar video.",
            "type": "string",
            "enum": [
              "2x3",
              "9x16",
              "1x1"
            ],
            "default": "2x3"
          },
          "model": {
            "description": "Model variant. Leave `null` to use the normal flagship model.",
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "lite",
              "flash",
              "pro",
              null
            ],
            "default": null,
            "x-mint": {
              "post": [
                "default: null"
              ]
            }
          },
          "simulcast": {
            "description": "Enable WebRTC simulcast. LiveKit transport only.",
            "type": "boolean",
            "default": false
          },
          "transport_type": {
            "description": "The interface type for how the audio is sent and how the A/V is returned.",
            "type": "string",
            "enum": [
              "livekit",
              "daily"
            ],
            "example": "livekit"
          },
          "properties": {
            "description": "Additional properties needed to connect to the transport layer.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/LiveKitTransportProperties",
                "title": "LiveKit"
              },
              {
                "$ref": "#/components/schemas/DailyTransportProperties",
                "title": "Daily"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "LiveKitTransportProperties": {
        "type": "object",
        "required": [
          "livekit_url",
          "livekit_token"
        ],
        "properties": {
          "livekit_url": {
            "type": "string",
            "format": "uri",
            "example": "wss://lemonslice-pb123.livekit.cloud"
          },
          "livekit_token": {
            "type": "string",
            "example": "eyJhbGciOiJIUzI1NiIsInR5a..."
          }
        },
        "additionalProperties": true,
        "example": {
          "livekit_url": "wss://lemonslice-pb123.livekit.cloud",
          "livekit_token": "eyJhbGciOiJIUzI1NiIsInR5a..."
        }
      },
      "DailyTransportProperties": {
        "type": "object",
        "properties": {
          "daily_room_url": {
            "description": "Daily room URL to use. If not provided, LemonSlice will create a new room at an additional cost of 0.51 credits per participant minute.",
            "type": "string",
            "format": "uri",
            "example": "https://your-domain.daily.co/your-room"
          },
          "daily_token": {
            "description": "Daily token for authenticating with the room.",
            "type": "string",
            "example": "eyJhbGciOiJIUzI1NiIsInR5a..."
          },
          "enable_recording": {
            "description": "Enable Daily call recording. If set, recordings_bucket must also be provided. Enabling recording incurs an additional charge of 0.378 credits per minute.",
            "type": "string",
            "enum": [
              "cloud",
              "cloud-audio-only",
              "local",
              "raw-tracks"
            ]
          },
          "recordings_bucket": {
            "description": "The S3 bucket configuration where recordings will be saved. Follows the Daily recording bucket specification.",
            "type": "object",
            "properties": {
              "bucket_name": {
                "description": "The name of the S3 bucket.",
                "type": "string"
              },
              "bucket_region": {
                "description": "The AWS region of the S3 bucket.",
                "type": "string"
              },
              "assume_role_arn": {
                "description": "The ARN of the IAM role for Daily to assume for storage.",
                "type": "string"
              },
              "allow_api_access": {
                "description": "Whether Daily's recording access link API should allow downloading the recording.",
                "type": "boolean"
              }
            },
            "required": [
              "bucket_name",
              "bucket_region",
              "assume_role_arn"
            ]
          }
        },
        "dependentRequired": {
          "enable_recording": [
            "recordings_bucket"
          ]
        },
        "additionalProperties": true,
        "example": {
          "daily_room_url": "https://your-domain.daily.co/your-room",
          "daily_token": "eyJhbGciOiJIUzI1NiIsInR5a..."
        }
      },
      "Session": {
        "type": "object",
        "required": [
          "session_id"
        ],
        "properties": {
          "session_id": {
            "description": "The ID of the session.",
            "type": "string",
            "example": "3f7c2b91-9e1f-4a6a-8e9d-2c7c3e7d9b5a"
          }
        }
      },
      "UpdateImageEvent": {
        "type": "object",
        "required": [
          "event",
          "image_url"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "update-image",
            "default": "update-image",
            "description": "update-image"
          },
          "image_url": {
            "type": "string",
            "format": "uri",
            "description": "URL of the new avatar image. Must be publicly accessible.",
            "example": "https://example.com/avatar.jpg"
          }
        }
      },
      "TerminateEvent": {
        "type": "object",
        "required": [
          "event"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "terminate",
            "default": "terminate",
            "description": "terminate"
          }
        }
      },
      "ResetIdleTimeoutEvent": {
        "type": "object",
        "required": [
          "event"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "reset-idle-timeout",
            "default": "reset-idle-timeout",
            "description": "reset-idle-timeout"
          }
        }
      },
      "UpdateAgentPromptEvent": {
        "type": "object",
        "required": [
          "event",
          "agent_prompt"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "update-agent-prompt",
            "default": "update-agent-prompt",
            "description": "update-agent-prompt"
          },
          "agent_prompt": {
            "type": "string",
            "description": "A high-level system prompt that subtly influences the avatar's expressions while speaking.",
            "example": "a person talking"
          }
        }
      },
      "UpdateIdlePromptEvent": {
        "type": "object",
        "required": [
          "event",
          "idle_prompt"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "update-idle-prompt",
            "default": "update-idle-prompt",
            "description": "update-idle-prompt"
          },
          "idle_prompt": {
            "type": "string",
            "description": "A high-level system prompt that subtly influences the avatar's expressions during the idle state.",
            "example": "a serious person"
          }
        }
      },
      "PoseTriggerEvent": {
        "type": "object",
        "required": [
          "event",
          "pose_trigger"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "pose-trigger",
            "default": "pose-trigger",
            "description": "pose-trigger"
          },
          "pose_trigger": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "Name of action to trigger.",
                "example": "wave"
              }
            }
          }
        }
      },
      "JoinMeetingInput": {
        "type": "object",
        "required": [
          "meeting_url",
          "livekit_url",
          "broadcast_token"
        ],
        "properties": {
          "meeting_url": {
            "type": "string",
            "description": "HTTPS URL for the third party meeting platform. Supported platforms: Zoom, Google Meet, Microsoft Teams, and Webex. For platforms that support it (e.g. Zoom), include the meeting password in the URL.",
            "example": "https://meet.google.com/abc-defg-hij"
          },
          "livekit_url": {
            "type": "string",
            "description": "The LiveKit server URL (wss://) for the session.",
            "example": "wss://lemonslice-pb123.livekit.cloud"
          },
          "broadcast_token": {
            "type": "string",
            "description": "A LiveKit JWT with room permissions used to publish the avatar video stream to the third party meeting platform.",
            "example": "<LIVEKIT_BROADCAST_TOKEN>"
          },
          "bot_name": {
            "type": "string",
            "description": "Optional display name for the avatar in the third party meeting platform.",
            "example": "LemonSlice Avatar"
          }
        }
      },
      "JoinMeetingResponse": {
        "type": "object",
        "required": [
          "meeting_bot_id",
          "websocket_url"
        ],
        "properties": {
          "meeting_bot_id": {
            "type": "string",
            "description": "ID for the joined third party meeting platform. Pass this to the leave-meeting endpoint when removing the avatar from the third party meeting platform.",
            "example": "meeting-bot-abc123"
          },
          "websocket_url": {
            "type": "string",
            "description": "WebSocket URL for receiving agent audio from the third party meeting platform.",
            "example": "wss://example.com/agent-audio/session-id?token=..."
          }
        }
      },
      "LeaveMeetingInput": {
        "type": "object",
        "required": [
          "meeting_bot_id"
        ],
        "properties": {
          "meeting_bot_id": {
            "type": "string",
            "description": "The third party meeting platform ID returned by the join-meeting endpoint.",
            "example": "meeting-bot-abc123"
          }
        }
      },
      "LeaveMeetingResponse": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "left",
            "description": "Confirmation that the avatar has left the third party meeting platform."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "example": "Agent not found"
          }
        }
      },
      "ServerError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "example": "Internal server error"
          }
        }
      }
    },
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Your LemonSlice API token."
      }
    }
  }
}