{
  "openapi": "3.1.0",
  "info": {
    "title": "Vozon Public Voice AI API",
    "version": "1.0.0",
    "description": "Production REST and Streaming API for Vozon voice agents. Start outbound calls, retrieve normalized call logs, stream live call state over Server-Sent Events (SSE), download call recordings, and receive verified call lifecycle webhooks.",
    "contact": {
      "name": "Vozon Developer Support",
      "email": "hello@vozon.ai",
      "url": "https://www.vozon.ai/docs"
    }
  },
  "servers": [
    {
      "url": "https://api.vozon.ai/api/v1",
      "description": "Production API Gateway"
    },
    {
      "url": "https://api.yourbrand.com/api/v1",
      "description": "White-Label Custom Branded API Gateway"
    }
  ],
  "security": [
    { "BearerAuth": [] },
    { "ApiKeyHeader": [] }
  ],
  "tags": [
    { "name": "Agents", "description": "Inspect voice agents configured for the active organization." },
    { "name": "Outbound Calls", "description": "Trigger automated phone calls using AI voice agents." },
    { "name": "Call Logs", "description": "Query, filter, and inspect normalized call records and transcripts." },
    { "name": "Streaming", "description": "Stream call state changes in real time via Server-Sent Events." },
    { "name": "Recordings", "description": "Stream or download authorized call audio recordings." },
    { "name": "Exports", "description": "Bulk export historical call records." }
  ],
  "paths": {
    "/agents": {
      "get": {
        "tags": ["Agents"],
        "summary": "List voice agents",
        "description": "Retrieve all voice agents available to the authenticated organization. Requires read scope.",
        "operationId": "listAgents",
        "responses": {
          "200": {
            "description": "List of voice agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "agents": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Agent" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/calls/outbound": {
      "post": {
        "tags": ["Outbound Calls"],
        "summary": "Create an outbound call",
        "description": "Initiates an outbound phone call connecting an approved destination number with an assigned voice agent. Requires calls:trigger scope and owner, admin, or member organization role.",
        "operationId": "createOutboundCall",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateOutboundCallRequest" },
              "example": {
                "agentId": "6701a2b3c4d5e6f7a8b9c0d1",
                "phoneNumber": "+919876543210",
                "metadata": {
                  "customerId": "cust_8829",
                  "appointmentDate": "2026-09-25T14:30:00Z"
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Call accepted and queued for SIP dispatch.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateOutboundCallResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": { "$ref": "#/components/responses/Conflict" }
        }
      }
    },
    "/calls": {
      "get": {
        "tags": ["Call Logs"],
        "summary": "List call records",
        "description": "Query normalized call history with comprehensive pagination, status, direction, sentiment, date ranges, and full-text search.",
        "operationId": "listCalls",
        "parameters": [
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } },
          { "name": "agentId", "in": "query", "schema": { "type": "string" } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["completed", "failed", "in-progress", "ringing", "busy", "no-answer", "canceled"] } },
          { "name": "direction", "in": "query", "schema": { "type": "string", "enum": ["inbound", "outbound", "web"] } },
          { "name": "sentiment", "in": "query", "schema": { "type": "string", "enum": ["positive", "neutral", "negative"] } },
          { "name": "minDuration", "in": "query", "schema": { "type": "number" } },
          { "name": "maxDuration", "in": "query", "schema": { "type": "number" } },
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "phoneNumber", "in": "query", "schema": { "type": "string" } },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date-time" } }
        ],
        "responses": {
          "200": {
            "description": "Paginated call records.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ListCallsResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/calls/{callId}": {
      "get": {
        "tags": ["Call Logs"],
        "summary": "Retrieve a single call record",
        "description": "Retrieves full normalized details for a specific call, including transcripts, latencies, tokens, and billing.",
        "operationId": "getCall",
        "parameters": [{ "$ref": "#/components/parameters/CallId" }],
        "responses": {
          "200": {
            "description": "Call record details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "call": { "$ref": "#/components/schemas/Call" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/calls/{callId}/recording": {
      "get": {
        "tags": ["Recordings"],
        "summary": "Stream or download call audio recording",
        "description": "Directly streams or downloads audio recording with HTTP Range support.",
        "operationId": "streamCallRecording",
        "parameters": [{ "$ref": "#/components/parameters/CallId" }],
        "responses": {
          "200": { "description": "Audio media payload." },
          "206": { "description": "Partial content range." },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/calls/stream": {
      "get": {
        "tags": ["Streaming"],
        "summary": "Stream call updates in real time (SSE)",
        "description": "Server-Sent Events connection emitting calls_changed whenever call states update.",
        "operationId": "streamCallEvents",
        "responses": {
          "200": {
            "description": "Event stream.",
            "content": { "text/event-stream": {} }
          }
        }
      }
    },
    "/calls/export.csv": {
      "get": {
        "tags": ["Exports"],
        "summary": "Export calls to CSV",
        "description": "Streams matching call records as a downloadable CSV.",
        "operationId": "exportCallsCsv",
        "responses": {
          "200": {
            "description": "CSV export.",
            "content": { "text/csv": {} }
          }
        }
      }
    },
    "/campaigns": {
      "get": {
        "tags": ["Campaigns"],
        "summary": "List outbound campaigns",
        "operationId": "listCampaigns",
        "responses": { "200": { "description": "List of campaigns." } }
      },
      "post": {
        "tags": ["Campaigns"],
        "summary": "Create an outbound campaign",
        "operationId": "createCampaign",
        "responses": { "201": { "description": "Campaign created." } }
      }
    },
    "/campaigns/{campaignId}/leads": {
      "post": {
        "tags": ["Campaigns"],
        "summary": "Upload campaign leads",
        "operationId": "addCampaignLeads",
        "responses": { "201": { "description": "Leads queued." } }
      }
    },
    "/campaigns/{campaignId}/launch": {
      "post": {
        "tags": ["Campaigns"],
        "summary": "Launch campaign",
        "operationId": "launchCampaign",
        "responses": { "200": { "description": "Campaign started." } }
      }
    },
    "/phone-numbers": {
      "get": {
        "tags": ["Phone Numbers"],
        "summary": "List provisioned phone numbers",
        "operationId": "listPhoneNumbers",
        "responses": { "200": { "description": "List of phone numbers." } }
      }
    },
    "/knowledge-bases": {
      "get": {
        "tags": ["Knowledge Bases"],
        "summary": "List knowledge bases",
        "operationId": "listKnowledgeBases",
        "responses": { "200": { "description": "List of knowledge collections." } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Vozon API Key (avp_...)"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "parameters": {
      "CallId": {
        "name": "callId",
        "in": "path",
        "required": true,
        "schema": { "type": "string" }
      }
    },
    "schemas": {
      "Agent": {
        "type": "object",
        "properties": {
          "_id": { "type": "string" },
          "name": { "type": "string" },
          "status": { "type": "string" },
          "language": { "type": "string" },
          "voice": { "type": "string" }
        }
      },
      "CreateOutboundCallRequest": {
        "type": "object",
        "required": ["agentId", "phoneNumber"],
        "properties": {
          "agentId": { "type": "string" },
          "phoneNumber": { "type": "string" },
          "phoneNumberId": { "type": "string" },
          "metadata": { "type": "object" }
        }
      },
      "CreateOutboundCallResponse": {
        "type": "object",
        "properties": {
          "callId": { "type": "string" },
          "roomName": { "type": "string" },
          "participantId": { "type": "string" },
          "dispatchId": { "type": "string" }
        }
      },
      "Call": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "agentId": { "type": "string" },
          "direction": { "type": "string" },
          "status": { "type": "string" },
          "durationSeconds": { "type": "integer" },
          "transcription_text": { "type": "string" },
          "transcript": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "role": { "type": "string" },
                "text": { "type": "string" },
                "timestamp": { "type": "string" }
              }
            }
          },
          "recordingUrl": { "type": "string" },
          "recording_url": { "type": "string" },
          "recording": {
            "type": "object",
            "properties": {
              "url": { "type": "string" },
              "downloadUrl": { "type": "string" },
              "status": { "type": "string" },
              "durationSeconds": { "type": "integer" },
              "contentType": { "type": "string" }
            }
          }
        }
      },
      "ListCallsResponse": {
        "type": "object",
        "properties": {
          "calls": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Call" }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": { "type": "integer" },
              "limit": { "type": "integer" },
              "total": { "type": "integer" },
              "pages": { "type": "integer" }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "message": { "type": "string" },
          "statusCode": { "type": "integer" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid input parameters.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Forbidden": {
        "description": "Insufficient scope or organization role.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Conflict": {
        "description": "State conflict preventing operation.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      }
    }
  }
}
