{
  "info": {
    "name": "Voxa API",
    "description": "Generated from the OpenAPI document (Voxa API 0.1.0) by npm run openapi. Set baseUrl to your console and apiKey to a secret key (sk_live_…).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://localhost:3000",
      "type": "string"
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "string"
    },
    {
      "key": "publicKey",
      "value": "",
      "type": "string"
    },
    {
      "key": "sessionAuth",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Assistants",
      "description": "Voice agent configurations.",
      "item": [
        {
          "name": "List assistants",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/assistants",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "assistants"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Every assistant of the key's organization (assistants created inline by the web SDK are left out), oldest first. Needs the `read` scope."
          }
        },
        {
          "name": "Create an assistant",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Taylor - Bookings\",\n  \"provider\": \"Anthropic\",\n  \"model\": \"claude-sonnet-4\",\n  \"firstMessage\": \"Hi, you have reached Acme Dental. How can I help?\",\n  \"tools\": {\n    \"book\": true\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/assistants",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "assistants"
              ]
            },
            "description": "Create from a partial body; the console's defaults fill the rest. Price and latency are computed. Created Published, the configuration becomes version 1. Needs the `write` scope."
          }
        },
        {
          "name": "Get an assistant",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/assistants/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "assistants",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Assistant id."
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        },
        {
          "name": "Update an assistant",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"Published\",\n  \"maxDuration\": 15,\n  \"tools\": {\n    \"query\": true\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/assistants/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "assistants",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Assistant id."
                }
              ]
            },
            "description": "Change any writable fields; `tools` is merged with the current value. Draft → Published saves the configuration as a new version. Needs the `write` scope."
          }
        },
        {
          "name": "Delete an assistant",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/assistants/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "assistants",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Assistant id."
                }
              ]
            },
            "description": "Same cleanup as the console: numbers it answered become unassigned; squads, workflows, campaigns and test suites lose the reference. Its calls are kept. Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Calls",
      "description": "Call logs, transcripts, recordings, and browser calls started from your server.",
      "item": [
        {
          "name": "List calls",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/calls",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "calls"
              ],
              "query": [
                {
                  "key": "assistantId",
                  "value": "",
                  "description": "Only calls answered by this assistant.",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "description": "Only calls started at or after this time: ISO-8601 or a unix timestamp in seconds or milliseconds.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..200 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Newest first, without transcripts. Calls are listed from the moment they start (status live). Needs the `read` scope."
          }
        },
        {
          "name": "Get a call",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/calls/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "calls",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Call id."
                }
              ]
            },
            "description": "One call with its transcript. Needs the `read` scope."
          }
        },
        {
          "name": "Download a call recording",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/calls/:id/recording",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "calls",
                ":id",
                "recording"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "",
                  "description": "1 asks for an attachment named {id}.wav.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Call id."
                }
              ]
            },
            "description": "The recording as audio/wav (16-bit PCM, mono, 24 kHz). With bucket storage: 302 to a signed URL valid for at least 15 minutes (follow redirects, do not store it); on local disk: streamed, with single byte-range support. Needs the `read` scope."
          }
        },
        {
          "name": "Check a call recording",
          "request": {
            "method": "HEAD",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/calls/:id/recording",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "calls",
                ":id",
                "recording"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "",
                  "description": "1 asks for an attachment named {id}.wav.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Call id."
                }
              ]
            },
            "description": "The recording as audio/wav (16-bit PCM, mono, 24 kHz). With bucket storage: 302 to a signed URL valid for at least 15 minutes (follow redirects, do not store it); on local disk: streamed, with single byte-range support. Needs the `read` scope."
          }
        },
        {
          "name": "Start a web call",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assistantId\": \"asst_7f3a91c2\",\n  \"customerId\": \"cus_8f2k1\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/web-calls",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "web-calls"
              ]
            },
            "description": "A short-lived call token and the voice server's WebSocket URL for a browser to connect to. Hand both to the browser. `customerId` names the caller in your own system: it is stored on the call and lets assistants with memory on recognize a returning caller (minted with your secret key, it is the trusted way to pass it). Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Do-not-call",
      "description": "Numbers campaigns never dial.",
      "item": [
        {
          "name": "List do-not-call numbers",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dnc",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dnc"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "",
                  "description": "Matches the number's digits or the reason.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Newest first. Campaigns never dial a listed number. Needs the `read` scope."
          }
        },
        {
          "name": "Add a number to the do-not-call list",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"number\": \"+14155550100\",\n  \"reason\": \"Opted out by email\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/dnc",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dnc"
              ]
            },
            "description": "Needs the `write` scope."
          }
        },
        {
          "name": "Get a do-not-call entry",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dnc/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dnc",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Entry id."
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        },
        {
          "name": "Remove a number from the do-not-call list",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dnc/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dnc",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Entry id."
                }
              ]
            },
            "description": "Campaigns may dial the number again. Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Privacy",
      "description": "Erasure of a caller's data on request.",
      "item": [
        {
          "name": "Erase a caller's data",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"number\": \"+14155550100\",\n  \"dryRun\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/privacy/erase",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "privacy",
                "erase"
              ]
            },
            "description": "Erases one caller's data in the key's organization: their calls lose transcript, summary, caller data and recording (the customer becomes \"[erased]\"; duration, cost, outcome and evaluation stay for billing), their returning-caller contact is deleted, campaign contacts with their number are erased, log entries and activity log entries naming them are redacted, stored webhook deliveries mentioning them deleted and Twilio-held recordings of their calls deleted; with `cancelBookings` the calendar bookings their calls made are cancelled. Do-not-call entries are kept. Calls still running are skipped. `dryRun` only counts. Idempotent: a second run finds nothing left. Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Campaigns",
      "description": "Outbound campaigns: list them, add contacts, start the dialer.",
      "item": [
        {
          "name": "List campaigns",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Outbound campaigns and their progress. Contacts (personal data) are left out; contactCount says how many there are. Needs the `read` scope."
          }
        },
        {
          "name": "Add contacts to a campaign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"contacts\": [\n    {\n      \"phone\": \"+14155550100\",\n      \"vars\": {\n        \"name\": \"Ada\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/:id/contacts",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                ":id",
                "contacts"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id."
                }
              ]
            },
            "description": "Appends contacts to a Paused or Scheduled campaign (the automation action \"add a contact to a campaign\"). Phones are cleaned like the console's; numbers the organization may not dial (dial policy), repeats and phones already on the campaign are skipped. A campaign holds at most 10,000 contacts. A Scheduled campaign dials them at its start time; start one now with POST /api/v1/campaigns/{id}/start. Test keys: 403 test_mode_phone. Needs the `write` scope."
          }
        },
        {
          "name": "Start a campaign's outbound calls",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/:id/start",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                ":id",
                "start"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id."
                }
              ]
            },
            "description": "Starts the dialer now with the console's checks: Twilio connected, credits and the monthly limit, the assistant and the caller ID; per contact the calling window (08:00-21:00 callee time) and the do-not-call list. Every dial spends credits. Test keys: 403 test_mode_phone. Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Automation",
      "description": "REST hooks for Zapier, Make and n8n: subscribe a URL to an event, unsubscribe it. Deliveries are signed like webhooks.",
      "item": [
        {
          "name": "List hook subscriptions",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/hooks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "hooks"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        },
        {
          "name": "Subscribe a URL to an event",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"event\": \"call.ended\",\n  \"url\": \"https://hooks.zapier.com/hooks/standard/123/abc/\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/hooks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "hooks"
              ]
            },
            "description": "REST hook subscribe (Zapier performSubscribe, Make, n8n). Events: call.ended, booking.created, voicemail.received, campaign.finished, lead.created, callback.requested. The same URL and event again answers the existing subscription (200). Deliveries carry x-voxa-signature like every webhook. At most 50 subscriptions per organization. Test keys: 403 test_mode_scope. Needs the `write` scope."
          }
        },
        {
          "name": "Unsubscribe by id or URL",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/hooks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "hooks"
              ],
              "query": [
                {
                  "key": "id",
                  "value": "",
                  "description": "A subscription id.",
                  "disabled": true
                },
                {
                  "key": "url",
                  "value": "",
                  "description": "Remove every subscription of this URL (optionally of one `event`).",
                  "disabled": true
                },
                {
                  "key": "event",
                  "value": "",
                  "description": "With `url`: only this event.",
                  "disabled": true
                }
              ]
            },
            "description": "Send `{ id }` or `{ url, event? }` as the JSON body, or as query parameters. Make and n8n call this when a scenario or workflow is turned off. Needs the `write` scope."
          }
        },
        {
          "name": "Get a hook subscription",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/hooks/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "hooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Subscription id."
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        },
        {
          "name": "Unsubscribe one hook",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/hooks/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "hooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Subscription id."
                }
              ]
            },
            "description": "Zapier's performUnsubscribe: call it with the id the subscribe answered. Needs the `write` scope."
          }
        }
      ]
    },
    {
      "name": "Knowledge",
      "description": "Knowledge files and bases (read-only).",
      "item": [
        {
          "name": "List knowledge files",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/files",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "files"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Metadata only; the content is not returned. Needs the `read` scope."
          }
        },
        {
          "name": "List knowledge bases",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/knowledge-bases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "knowledge-bases"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Numbers",
      "description": "Phone numbers (read-only).",
      "item": [
        {
          "name": "List phone numbers",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/numbers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "numbers"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Tools",
      "description": "Tools assistants can call (read-only).",
      "item": [
        {
          "name": "List tools",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tools",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tools"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "Items per page, 1..100 (default 50).",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's nextCursor. Opaque: pass it back unchanged, with the same filters. A cursor this API did not issue answers 400.",
                  "disabled": true
                }
              ]
            },
            "description": "Tools available to assistants. Request headers (often credentials) are never returned. Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Analytics",
      "description": "Call totals for a window (read-only).",
      "item": [
        {
          "name": "Call totals for a window",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/analytics/summary",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "analytics",
                "summary"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "description": "Start of the window: ISO-8601 or a unix timestamp. Default: 30 days before `to`.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "",
                  "description": "End of the window (exclusive). Default: now. At most 366 days after `from`.",
                  "disabled": true
                },
                {
                  "key": "assistantId",
                  "value": "",
                  "description": "Only calls answered by this assistant.",
                  "disabled": true
                }
              ]
            },
            "description": "Counts, minutes, cost, outcomes, end reasons and per-assistant totals of the organization's calls started in [from, to). Test calls are left out (counted in testCalls). Calls still in progress count toward `calls` only; minutes, cost and the rates use finished calls. Reads at most 20,000 calls (newest first); past that `truncated` is true. Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Logs",
      "description": "The organization's log entries, redacted (read-only).",
      "item": [
        {
          "name": "List log entries",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/logs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "logs"
              ],
              "query": [
                {
                  "key": "callId",
                  "value": "",
                  "description": "Only entries about this call.",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "description": "Only entries at or after this time: ISO-8601 or a unix timestamp.",
                  "disabled": true
                },
                {
                  "key": "until",
                  "value": "",
                  "description": "Only entries strictly before this time.",
                  "disabled": true
                },
                {
                  "key": "level",
                  "value": "",
                  "description": "Comma list of debug, info, warn, error.",
                  "disabled": true
                },
                {
                  "key": "kind",
                  "value": "",
                  "description": "Comma list of api, webhook, event, error, metric, call.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "Entries per page, 1..500 (default 100).",
                  "disabled": true
                }
              ]
            },
            "description": "The organization's log entries (the console's Logs page), newest first. Contexts are redacted (secrets, phone numbers, card numbers, query strings); the person behind a console request is never named. Page back with `until` = the previous page's `nextUntil`; follow new entries with `since` (entries at the same instant may repeat: de-duplicate by id). Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Account",
      "description": "The key itself.",
      "item": [
        {
          "name": "The current key",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "me"
              ]
            },
            "description": "The key making the request (with its effective scopes) and its organization. Handy for checking a key works. Needs the `read` scope."
          }
        }
      ]
    },
    {
      "name": "Meta",
      "description": "This document.",
      "item": [
        {
          "name": "This OpenAPI document",
          "request": {
            "method": "GET",
            "header": [],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/openapi.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "openapi.json"
              ]
            },
            "description": "Public, no key needed. Cached for five minutes."
          }
        }
      ]
    },
    {
      "name": "Client (public key)",
      "description": "Routes the widget and the web SDK call from browsers with the organization's public key (pk_...) instead of a secret key. They live outside /api/v1, answer CORS preflights, follow the organization's allowed origins and are rate limited per address and per key. Errors are `{ error, reason? }`.",
      "item": [
        {
          "name": "Get a call token with a public key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"publicKey\": \"{{publicKey}}\",\n  \"assistantId\": \"asst_7f3a91c2\",\n  \"via\": \"sdk\",\n  \"variableValues\": {\n    \"name\": \"Sam\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/voice/token",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "voice",
                "token"
              ]
            },
            "description": "What the widget and web SDK call from the browser: a call token for the voice server. Published assistants only; an inline `assistant` needs the organization's allowInlineAssistants switch. A Lite-mode `videoAgentId` adds the avatar (the answer carries `video`); Full-mode agents start through POST /api/video/sessions. Rate limited per public key and per address (60 per 10 minutes each). `customerId` is stored on the call and keys returning-caller memory only with a valid `customerIdSignature` from your server (HMAC-SHA256 of `${customerId}.${expires}` with the organization's customer id secret, sent as `<expires>.<hex>`); without one it is ignored and the answer says why in `customerIdIgnored`. A signed-in console session may call it without a public key (not covered here)."
          }
        },
        {
          "name": "Text chat with an assistant",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"publicKey\": \"{{publicKey}}\",\n  \"assistantId\": \"asst_7f3a91c2\",\n  \"text\": \"Do you open on Sundays?\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/chat/messages",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "chat",
                "messages"
              ]
            },
            "description": "What the widget's chat view (data-mode=\"chat\") and the web SDK's voxa.chat() call: start a chat with a Published assistant (assistantId) and send messages with the `session` each answer returns. The same assistant, knowledge and tools as on calls; each reply is billed per message plus model usage on Voxa's keys. The same public-key checks and limits as call tokens, plus per-chat message limits. A chat closes after 24 hours without messages (410 afterwards: start a new one)."
          }
        },
        {
          "name": "Get a video agent's public facts",
          "request": {
            "method": "GET",
            "header": [],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/api/video/agents/:id?publicKey={{publicKey}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "video",
                "agents",
                ":id"
              ],
              "query": [
                {
                  "key": "publicKey",
                  "value": "{{publicKey}}",
                  "description": "The organization's public key (pk_...)."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Video agent id."
                }
              ]
            },
            "description": "Which start route to take (mode) and the avatar to show."
          }
        },
        {
          "name": "Start a Full-mode video session",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"publicKey\": \"{{publicKey}}\",\n  \"videoAgentId\": \"vide_a88d176f\",\n  \"via\": \"sdk\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/video/sessions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "video",
                "sessions"
              ]
            },
            "description": "HeyGen runs speech recognition, the model and the voice. Start the session in the browser with HeyGen's web SDK, POST /alive every 30 seconds and /end when it is over. The call record is written In progress at this point."
          }
        },
        {
          "name": "Heartbeat of a Full-mode video session",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-voxa-session-auth",
                "value": "{{sessionAuth}}"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/api/video/sessions/:callId/alive",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "video",
                "sessions",
                ":callId",
                "alive"
              ],
              "variable": [
                {
                  "key": "callId",
                  "value": "",
                  "description": "The callId the start answered."
                }
              ]
            },
            "description": "Every 30 seconds while the session runs; a call that stops beating for three minutes is closed as interrupted."
          }
        },
        {
          "name": "End a Full-mode video session",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "x-voxa-session-auth",
                "value": "{{sessionAuth}}"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"user\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/api/video/sessions/:callId/end",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "video",
                "sessions",
                ":callId",
                "end"
              ],
              "variable": [
                {
                  "key": "callId",
                  "value": "",
                  "description": "The callId the start answered."
                }
              ]
            },
            "description": "Stops the HeyGen session, imports its transcript (the body's lines are the fallback), charges the organization and finishes the call. Idempotent. The body is parsed as JSON whatever its content-type (navigator.sendBeacon sends text/plain)."
          }
        }
      ]
    }
  ]
}
