{
  "openapi": "3.1.0",
  "info": {
    "title": "Tanzanite API",
    "version": "0.1.0",
    "description": "Programmatic surface for the Tanzanite AI agent platform. The `/v1` endpoints are the public, API-key-authenticated surface used by `@tanzanite/sdk`: create and control agent sessions, respond to human-in-the-loop input, and read messages. `/api/auth/signup` is the unauthenticated onboarding endpoint. Generated to mirror apps/api/src/routes/sdk.ts and auth.ts — keep in sync when those routes change.",
    "contact": { "name": "Tanzanite", "url": "https://docs.tanzanite.dev" }
  },
  "servers": [
    { "url": "https://api.tanzanite.dev", "description": "Production" }
  ],
  "tags": [
    { "name": "Auth", "description": "Account onboarding (no API key required)." },
    { "name": "Sessions", "description": "Create and control agent sessions (API key required)." }
  ],
  "paths": {
    "/api/auth/signup": {
      "post": {
        "tags": ["Auth"],
        "summary": "Create an account",
        "description": "Programmatic signup. Returns a Firebase ID token and refresh token. Works without a human in the loop; errors are returned as JSON.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SignupRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created and signed in",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SignupResponse" }
              }
            }
          },
          "400": {
            "description": "Validation error (missing fields, email exists, weak password, invalid email)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/v1/sessions": {
      "post": {
        "tags": ["Sessions"],
        "summary": "Create a session",
        "description": "Create a new agent session from the calling integration. The session is queued and executed asynchronously; poll GET /v1/sessions/{id} and GET /v1/sessions/{id}/messages for progress. Real-time WebSocket streaming is planned but not yet available.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateSessionRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created and queued",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateSessionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": {
            "description": "Integration not found",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/sessions/{id}": {
      "get": {
        "tags": ["Sessions"],
        "summary": "Get session status",
        "parameters": [{ "$ref": "#/components/parameters/SessionId" }],
        "responses": {
          "200": {
            "description": "Session status, cost, and rounds",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SessionStatus" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/sessions/{id}/signal": {
      "post": {
        "tags": ["Sessions"],
        "summary": "Send a control signal",
        "description": "Pause, resume, cancel, or redirect a running session. `redirect` requires `message`. `resume` may include `newBudget`; resuming a cost-limited session requires a `newBudget` greater than the current spend.",
        "parameters": [{ "$ref": "#/components/parameters/SessionId" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SignalRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Signal accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SignalResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/sessions/{id}/human-input/{inputId}": {
      "post": {
        "tags": ["Sessions"],
        "summary": "Respond to a human-input request",
        "description": "Submit a response to a pending human-input request emitted by the agent. Provide whichever fields the request expects: an approval, a single or multi choice, free text, or per-question answers.",
        "parameters": [
          { "$ref": "#/components/parameters/SessionId" },
          {
            "name": "inputId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "The human-input request ID from the human_input_needed event."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/HumanInputResponse" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Input recorded (session resumes if it was waiting)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/HumanInputAck" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/sessions/{id}/messages": {
      "get": {
        "tags": ["Sessions"],
        "summary": "List session messages",
        "description": "Return messages across the session's rounds, oldest first. Paginate with `after` (a roundId cursor) and `limit` (max 200).",
        "parameters": [
          { "$ref": "#/components/parameters/SessionId" },
          {
            "name": "limit",
            "in": "query",
            "schema": { "type": "integer", "default": 50, "maximum": 200 },
            "description": "Max messages to return (capped at 200)."
          },
          {
            "name": "after",
            "in": "query",
            "schema": { "type": "string" },
            "description": "Pagination cursor — a roundId to start after."
          }
        ],
        "responses": {
          "200": {
            "description": "Messages and pagination cursor",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessagesResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Tanzanite API key as a Bearer token: `Authorization: Bearer tanzanite_xxx`."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Tanzanite-Key",
        "description": "Tanzanite API key as a raw header value (alternative to Bearer)."
      }
    },
    "parameters": {
      "SessionId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": { "type": "string" },
        "description": "Session ID (returned as `sessionId` from POST /v1/sessions)."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "Not authorized to access this session",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Session not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ServerError": {
        "description": "Internal error",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Human-readable error message." }
        },
        "required": ["error"]
      },
      "SignupRequest": {
        "type": "object",
        "required": ["email", "password"],
        "properties": {
          "email": { "type": "string", "format": "email" },
          "password": { "type": "string", "description": "At least 6 characters." },
          "displayName": { "type": "string" }
        }
      },
      "SignupResponse": {
        "type": "object",
        "properties": {
          "user": {
            "type": "object",
            "properties": {
              "uid": { "type": "string" },
              "email": { "type": "string" },
              "displayName": { "type": "string", "nullable": true },
              "photoURL": { "type": "string", "nullable": true },
              "emailVerified": { "type": "boolean" }
            }
          },
          "idToken": { "type": "string" },
          "refreshToken": { "type": "string" },
          "expiresIn": { "type": "string" }
        }
      },
      "CreateSessionRequest": {
        "type": "object",
        "required": ["goal"],
        "properties": {
          "goal": { "type": "string", "description": "The objective for the agent." },
          "context": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Arbitrary structured context passed to the agent."
          },
          "guardrails": {
            "$ref": "#/components/schemas/Guardrails",
            "description": "Optional limits for this session."
          }
        }
      },
      "Guardrails": {
        "type": "object",
        "properties": {
          "maxCostPerSession": { "type": "number", "description": "USD ceiling for the session." },
          "maxIterations": { "type": "integer", "description": "Max agent iterations per round (default 50)." }
        },
        "additionalProperties": true
      },
      "CreateSessionResponse": {
        "type": "object",
        "properties": {
          "sessionId": { "type": "string" },
          "roundId": { "type": "string" },
          "status": { "type": "string", "example": "queued" }
        }
      },
      "SessionStatus": {
        "type": "object",
        "properties": {
          "sessionId": { "type": "string" },
          "status": {
            "type": "string",
            "description": "e.g. queued, orchestrating, running, waiting_human, paused, cost_limit, completed, cancelled, error.",
            "example": "running"
          },
          "message": { "type": "string", "description": "The original goal." },
          "cost": { "$ref": "#/components/schemas/Cost" },
          "rounds": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "createdAt": {},
          "updatedAt": {},
          "completedAt": { "nullable": true },
          "error": { "type": "string", "nullable": true },
          "completionReport": { "nullable": true }
        }
      },
      "Cost": {
        "type": "object",
        "properties": {
          "totalCost": { "type": "number" },
          "totalTokens": { "type": "integer" },
          "promptTokens": { "type": "integer" },
          "completionTokens": { "type": "integer" }
        }
      },
      "SignalRequest": {
        "type": "object",
        "required": ["type"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["pause", "resume", "cancel", "redirect"]
          },
          "reason": { "type": "string", "description": "Optional note for pause/cancel." },
          "message": { "type": "string", "description": "Required for redirect; optional context for resume." },
          "newBudget": { "type": "number", "description": "New per-session USD ceiling when resuming." }
        }
      },
      "SignalResponse": {
        "type": "object",
        "properties": {
          "sessionId": { "type": "string" },
          "signal": { "type": "string" },
          "roundId": { "type": "string", "description": "Present when a resume creates a new round." },
          "message": { "type": "string" }
        }
      },
      "HumanInputResponse": {
        "type": "object",
        "description": "Provide the field(s) matching the request type.",
        "properties": {
          "approved": { "type": "boolean", "description": "For approval requests." },
          "choiceId": { "type": "string", "description": "For single-select." },
          "choiceIds": { "type": "array", "items": { "type": "string" }, "description": "For multi-select." },
          "freeText": { "type": "string", "description": "For free-text answers." },
          "answers": { "type": "object", "additionalProperties": true, "description": "For multi-question prompts." }
        }
      },
      "HumanInputAck": {
        "type": "object",
        "properties": {
          "inputId": { "type": "string" },
          "status": { "type": "string", "example": "responded" },
          "roundId": { "type": "string", "description": "Present when the session resumes." },
          "message": { "type": "string" }
        }
      },
      "MessagesResponse": {
        "type": "object",
        "properties": {
          "sessionId": { "type": "string" },
          "messages": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Message" }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "count": { "type": "integer" },
              "hasMore": { "type": "boolean" },
              "lastRoundId": { "type": "string", "nullable": true }
            }
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "roundId": { "type": "string" },
          "role": { "type": "string", "example": "assistant" },
          "content": { "type": "string" },
          "name": { "type": "string" },
          "reasoning": { "type": "string" },
          "reasoningDurationMs": { "type": "integer" },
          "toolCallId": { "type": "string" },
          "toolCalls": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "timestamp": {}
        }
      }
    }
  },
  "security": [{ "bearerAuth": [] }, { "apiKeyHeader": [] }]
}
