{
    "openapi": "3.1.0",
    "info": {
        "title": "BytePilot API",
        "description": "**Platform API** \u2014 https://bytepilot.ai/api/v1 \u2014 Read and control your account. Your agents, clients, calls, transcripts, credit balance and usage reports \u2014 the data behind the dashboard, in JSON. This is what you automate against: pull last month's usage per client and raise your own invoices, sync clients from your CRM, pause an agent from your own admin panel.\n\n**Model API** \u2014 https://models.bytepilot.ai/v1 \u2014 Call AI models directly, on your account. A drop-in replacement for the OpenAI API. Change two lines in any existing OpenAI-compatible app \u2014 the base URL and the key \u2014 and it runs on your BytePilot balance instead. Same request and response shapes, streaming included; we forward your request untouched and hand back exactly what came out.\n\nIt exists so the technical end of your book has somewhere to go. A client who wants to build their own thing gets a key from you, spends against your balance, and appears as a line on your usage report \u2014 so you can bill them for it at whatever margin you set. Give each client their own key, cap it, and read its spend separately.\n\nBilling is a multiple of what the request actually costs us, not a per-token rate \u2014 model prices move monthly and a fixed rate would be wrong within weeks. Fractions of a penny accumulate rather than rounding up, so a thousand tiny requests cost what a thousand tiny requests should.\n\nOne key works for both. Authenticate with an API key from your dashboard Developers page (`X-API-Key` header, or `Authorization: Bearer`). Scopes: `agents` (agents & clients), `calls` (calls & transcripts), `billing` (balance, ledger & usage reports), `models` (model API (the OpenAI-compatible endpoint)), `outbound` (outbound calls & schedules), `visibility` (aI visibility checks & reports), `leads` (lead intelligence campaigns & prospects). Keys also take optional daily and monthly spend caps \u2014 over-cap requests return 402.",
        "version": "0.3.0",
        "contact": {
            "email": "support@bytepilot.ai"
        }
    },
    "servers": [
        {
            "url": "https://bytepilot.ai",
            "description": "Platform API"
        }
    ],
    "tags": [
        {
            "name": "Platform API",
            "description": "Read and control your account."
        },
        {
            "name": "Model API",
            "description": "Call AI models directly, on your account."
        }
    ],
    "components": {
        "securitySchemes": {
            "apiKey": {
                "type": "apiKey",
                "in": "header",
                "name": "X-API-Key",
                "description": "Business API key from your dashboard Developers page"
            }
        }
    },
    "paths": {
        "/api/v1/agents": {
            "get": {
                "summary": "List your agents",
                "description": "Every agent on your account with its status, template, assigned phone number, and client grouping (external_ref round-trips your own CRM/accounting ids).\n\nRequired key scope: `agents`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Agent list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "agents": [
                                        {
                                            "agent_id": 12,
                                            "name": "Sophie",
                                            "template": "generic_reception",
                                            "status": "ACTIVE",
                                            "phone_number": "+441256222333",
                                            "client": {
                                                "client_id": 3,
                                                "name": "Harrison & Co",
                                                "external_ref": "CRM-1042"
                                            },
                                            "created_at": "2026-07-28 09:00:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    },
                    "402": {
                        "description": "Key spend cap reached"
                    }
                }
            }
        },
        "/api/v1/agents/{id}/status": {
            "post": {
                "summary": "Pause or resume an agent",
                "description": "Paused agents answer with a polite unavailable message. The change applies from the next call.\n\nRequired key scope: `agents`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Updated",
                        "content": {
                            "application/json": {
                                "example": {
                                    "agent_id": 12,
                                    "status": "PAUSED"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad status"
                    },
                    "404": {
                        "description": "Unknown agent"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Agent id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "status": "PAUSED"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/clients": {
            "get": {
                "summary": "List your clients",
                "description": "The client groupings your agents roll up to for billing.\n\nRequired key scope: `agents`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Client list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "clients": [
                                        {
                                            "client_id": 3,
                                            "name": "Harrison & Co",
                                            "external_ref": "CRM-1042",
                                            "created_at": "2026-07-01 10:00:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            },
            "post": {
                "summary": "Create a client (idempotent by name)",
                "description": "Creates a client grouping, or returns the existing one with that name (updating external_ref if supplied) \u2014 safe to call from sync jobs.\n\nRequired key scope: `agents`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Created or matched",
                        "content": {
                            "application/json": {
                                "example": {
                                    "client_id": 3,
                                    "name": "Harrison & Co",
                                    "external_ref": "CRM-1042",
                                    "created": true
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Missing name"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "name": "Harrison & Co",
                                "external_ref": "CRM-1042"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/visibility/targets": {
            "get": {
                "summary": "List tracked websites",
                "description": "Every website you track for AI visibility, with its latest score and the client it belongs to. AI visibility measures how often leading AI assistants (ChatGPT, Claude, Gemini, Perplexity) recommend a business when people ask the buying questions its customers actually ask.\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Target list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "targets": [
                                        {
                                            "target_id": 5,
                                            "url": "https://millerplumbing.co.uk",
                                            "domain": "millerplumbing.co.uk",
                                            "display_name": "Miller Plumbing",
                                            "category": "emergency plumber",
                                            "location": "Leeds",
                                            "client": {
                                                "client_id": 3,
                                                "name": "Miller Plumbing",
                                                "external_ref": "CRM-1042"
                                            },
                                            "latest_report_id": 41,
                                            "latest_score": 43,
                                            "created_at": "2026-08-01 09:00:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            },
            "post": {
                "summary": "Track a website (idempotent by domain)",
                "description": "Reads the website once to derive the business name, category, location and the set of buyer-style questions every report will measure against \u2014 so scores stay comparable over time. Returns the existing target if the domain is already tracked. Creating a target is free; running reports costs credit.\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Created or matched",
                        "content": {
                            "application/json": {
                                "example": {
                                    "target_id": 5,
                                    "domain": "millerplumbing.co.uk",
                                    "display_name": "Miller Plumbing",
                                    "category": "emergency plumber",
                                    "location": "Leeds",
                                    "created": true
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Missing url"
                    },
                    "422": {
                        "description": "Website unreadable"
                    },
                    "503": {
                        "description": "Feature unavailable"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "url": "https://millerplumbing.co.uk",
                                "client_name": "Miller Plumbing"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/visibility/targets/{id}/run": {
            "post": {
                "summary": "Run a visibility check",
                "description": "Queues a full report: every measured assistant is asked every buyer question, the website gets technical AI-readiness checks, and recommendations are drafted. Reports take a few minutes and you are only charged (flat rate per report, shown as price_pence) when one completes \u2014 a failed run is free. Optional send_to / copy_to email the finished report automatically under your branding with the PDF attached, exactly like the dashboard send.\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Queued",
                        "content": {
                            "application/json": {
                                "example": {
                                    "report_id": 42,
                                    "status": "QUEUED",
                                    "price_pence": 200,
                                    "note": "Reports take a few minutes. Poll GET /api/v1/visibility/reports/{report_id}. You are only charged when it completes."
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Balance below the report price"
                    },
                    "404": {
                        "description": "Unknown target"
                    },
                    "409": {
                        "description": "A check is already running"
                    },
                    "429": {
                        "description": "Daily check limit reached"
                    },
                    "503": {
                        "description": "Feature unavailable"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Target id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "send_to": "owner@millerplumbing.co.uk",
                                "copy_to": "you@youragency.co.uk"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/visibility/targets/{id}/reports": {
            "get": {
                "summary": "List a website's reports",
                "description": "Report history for one tracked website, newest first (up to 50) \u2014 the score trend an agency charts for its client.\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Report list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "reports": [
                                        {
                                            "report_id": 41,
                                            "status": "COMPLETE",
                                            "score": 43,
                                            "charged_pence": 200,
                                            "scheduled": false,
                                            "created_at": "2026-08-18 08:00:00",
                                            "completed_at": "2026-08-18 08:07:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown target"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Target id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/visibility/reports/{id}": {
            "get": {
                "summary": "Get a report",
                "description": "The full report: overall 0\u2013100 score, per-assistant breakdown, who the assistants recommend instead, the website's AI-readiness checks and the drafted recommendations. Completed reports also include agent_prompt \u2014 a ready-to-paste brief for an AI coding agent working on the measured website, containing the baseline, the buyer questions being lost and a prioritised task list; hand it to your own tooling or to the client's developer. Pass include_answers=1 for the question-by-question evidence. Poll this after queuing a run \u2014 status moves QUEUED \u2192 RUNNING \u2192 COMPLETE (or FAILED, uncharged).\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The report",
                        "content": {
                            "application/json": {
                                "example": {
                                    "report_id": 41,
                                    "target_id": 5,
                                    "status": "COMPLETE",
                                    "score": 43,
                                    "assistants": [
                                        {
                                            "assistant": "ChatGPT",
                                            "available": true,
                                            "questions_answered": 10,
                                            "times_recommended": 4,
                                            "score": 40
                                        }
                                    ],
                                    "competitors": [
                                        {
                                            "name": "Aqua Flow Plumbers",
                                            "mentions": 5
                                        }
                                    ],
                                    "site_checks": {
                                        "schema_org": false,
                                        "llms_txt": false,
                                        "blocked_crawlers": [
                                            "GPTBot"
                                        ]
                                    },
                                    "recommendations": {
                                        "summary": "Strong on emergency questions, invisible on boiler servicing.",
                                        "gaps": [
                                            "Blocked GPTBot means ChatGPT cannot read the site"
                                        ],
                                        "actions": [
                                            "Unblock GPTBot in robots.txt"
                                        ]
                                    },
                                    "agent_prompt": "You are working on the website for Miller Plumbing (https://millerplumbing.co.uk)\u2026\nTASKS, in priority order:\n1. robots.txt currently blocks GPTBot\u2026",
                                    "charged_pence": 200,
                                    "scheduled": false,
                                    "created_at": "2026-08-18 08:00:00",
                                    "completed_at": "2026-08-18 08:07:00"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown report"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Report id",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "include_answers",
                        "in": "query",
                        "required": false,
                        "description": "Set 1 to include every assistant answer excerpt",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ]
            }
        },
        "/api/v1/visibility/reports/{id}/pdf": {
            "get": {
                "summary": "Download a report as PDF",
                "description": "The client-ready PDF, carrying YOUR branding (name, logo, colour from your dashboard branding page) and nothing of ours \u2014 the same document the dashboard sends to clients. Binary application/pdf response.\n\nRequired key scope: `visibility`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "PDF document",
                        "content": {
                            "application/json": {
                                "example": {
                                    "note": "Binary PDF body, Content-Type: application/pdf"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown or unfinished report"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Report id (must be COMPLETE)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/leads/campaigns": {
            "get": {
                "summary": "List lead campaigns",
                "description": "Your lead-intelligence campaigns, newest first. A campaign finds businesses matching an industry and location, researches each one's website and web presence, scores how strong a prospect it is for the services you sell, and drafts the outreach \u2014 you are billed a flat rate per prospect scored, never for discovery or failed research.\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Campaign list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "campaigns": [
                                        {
                                            "campaign_id": 7,
                                            "label": "Dentists in Manchester",
                                            "industry": "dentists",
                                            "location": "Manchester",
                                            "services": [
                                                "Websites",
                                                "AI receptionist"
                                            ],
                                            "status": "COMPLETE",
                                            "target": 25,
                                            "discovered": 25,
                                            "scored": 23,
                                            "failed": 2,
                                            "created_at": "2026-08-27 09:00:00",
                                            "completed_at": "2026-08-27 09:41:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            },
            "post": {
                "summary": "Start a lead campaign",
                "description": "Queues discovery and research. Your balance must cover the campaign's maximum cost (count \u00d7 per-prospect rate) up front, but charges land per prospect actually scored. Optional send_to / copy_to email the finished white-label prospect report (your branding, PDF attached) when the campaign completes. exclude_previous (default true) skips businesses already found for the SAME client (campaigns with no client form their own scope) \u2014 so a monthly re-run stays fresh, while the same lead can still surface for a different client it also suits. Optional seller_context (a sentence or two on what the seller is and offers) tailors the scoring, pitches and drafts to what is genuinely on offer \u2014 the dashboard derives it automatically from the seller's website. Better still, pass profile_id (a seller profile created in the dashboard): the campaign then also carries the seller's confirmed proof points, ideal customer, sign-off name and booking link, and drafts come out ready to send. Profiles are read fresh at scoring time, so profile edits apply to every later run.\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Queued",
                        "content": {
                            "application/json": {
                                "example": {
                                    "campaign_id": 7,
                                    "status": "QUEUED",
                                    "price_per_prospect_pence": 25,
                                    "max_cost_pence": 625,
                                    "note": "Campaigns take several minutes. Poll GET /api/v1/leads/campaigns/{campaign_id}. You are only charged per prospect scored."
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Missing industry, location or services"
                    },
                    "402": {
                        "description": "Balance below the campaign ceiling"
                    },
                    "429": {
                        "description": "Daily research limit reached"
                    },
                    "503": {
                        "description": "Feature unavailable"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "industry": "dentists",
                                "location": "Manchester",
                                "count": 25,
                                "services": [
                                    "Websites",
                                    "AI receptionist"
                                ],
                                "client_name": "Smile Group",
                                "seller_context": "Smile Group: a dental marketing agency offering websites and AI reception for practices.",
                                "send_to": "owner@smilegroup.co.uk",
                                "copy_to": "you@youragency.co.uk"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/leads/campaigns/{id}": {
            "get": {
                "summary": "Get a campaign",
                "description": "Progress and totals for one campaign. Poll this after starting one \u2014 status moves QUEUED \u2192 DISCOVERING \u2192 RESEARCHING \u2192 COMPLETE (or FAILED, uncharged).\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The campaign",
                        "content": {
                            "application/json": {
                                "example": {
                                    "campaign_id": 7,
                                    "label": "Dentists in Manchester",
                                    "industry": "dentists",
                                    "location": "Manchester",
                                    "services": [
                                        "Websites",
                                        "AI receptionist"
                                    ],
                                    "status": "RESEARCHING",
                                    "target": 25,
                                    "discovered": 25,
                                    "scored": 11,
                                    "failed": 1,
                                    "charged_pence": 275,
                                    "created_at": "2026-08-27 09:00:00",
                                    "completed_at": null
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown campaign"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Campaign id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/leads/campaigns/{id}/prospects": {
            "get": {
                "summary": "List a campaign's scored prospects",
                "description": "Scored prospects, best first, with per-service fit scores and the recommended pitch. Filter with min_score to feed only strong prospects into your own tooling.\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Prospect list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "prospects": [
                                        {
                                            "prospect_id": 91,
                                            "name": "Smile Dental",
                                            "website": "https://smiledental.example",
                                            "domain": "smiledental.example",
                                            "phone": "0161 000 0000",
                                            "lead_score": 91,
                                            "fit_scores": {
                                                "Websites": 41,
                                                "AI receptionist": 96
                                            },
                                            "pitch": "Lead with the AI receptionist \u2014 no out-of-hours cover and no online booking."
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown campaign"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Campaign id",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "min_score",
                        "in": "query",
                        "required": false,
                        "description": "Only prospects scoring at least this (0-100)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/leads/prospects/{id}": {
            "get": {
                "summary": "Get a prospect in full",
                "description": "Everything the research produced: the observed website signals (deterministic), best-effort external notes, per-service fit scores, the personalised angle, and the outreach drafts (cold email and call script) ready to send from YOUR OWN tools \u2014 the platform never sends outreach itself.\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The prospect",
                        "content": {
                            "application/json": {
                                "example": {
                                    "prospect_id": 91,
                                    "campaign_id": 7,
                                    "name": "Smile Dental",
                                    "website": "https://smiledental.example",
                                    "domain": "smiledental.example",
                                    "contact_email": "hello@smiledental.example",
                                    "phone": "0161 000 0000",
                                    "status": "SCORED",
                                    "lead_score": 91,
                                    "fit_scores": {
                                        "Websites": 41,
                                        "AI receptionist": 96
                                    },
                                    "signals": [
                                        {
                                            "signal": "Online booking",
                                            "level": "warn",
                                            "detail": "No visible way to book online \u2014 customers must call during opening hours."
                                        }
                                    ],
                                    "external_notes": {
                                        "reviews": "around 23 Google reviews",
                                        "competitors": [
                                            "Brighter Smiles"
                                        ]
                                    },
                                    "pitch": "Lead with the AI receptionist.",
                                    "angle": "Their site asks patients to phone for appointments, with no way to book or ask questions outside opening hours.",
                                    "email_subject": "Out-of-hours enquiries at Smile Dental",
                                    "email_draft": "Hi, I was looking at smiledental.example and noticed\u2026",
                                    "call_script": "OPENER: \u2026",
                                    "charged_pence": 25
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown prospect"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Prospect id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/leads/campaigns/{id}/pdf": {
            "get": {
                "summary": "Download a campaign report as PDF",
                "description": "The client-ready prospect report, carrying YOUR branding and nothing of ours \u2014 the same document the dashboard emails to clients. Binary application/pdf response.\n\nRequired key scope: `leads`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "PDF document",
                        "content": {
                            "application/json": {
                                "example": {
                                    "note": "Binary PDF body, Content-Type: application/pdf"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown or unfinished campaign"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Campaign id (must be COMPLETE)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/calls": {
            "get": {
                "summary": "List calls in a date range",
                "description": "Filterable by agent_id and client_id; defaults to the current month. Latest 200.\n\nRequired key scope: `calls`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Call list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "from": "2026-07-01",
                                    "to": "2026-07-28",
                                    "calls": [
                                        {
                                            "call_id": 88,
                                            "agent_id": 12,
                                            "channel_id": 15,
                                            "client_id": 3,
                                            "caller_number": "+447712345678",
                                            "started_at": "2026-07-28 14:03:11",
                                            "duration_seconds": 151,
                                            "status": "COMPLETED",
                                            "outcome": "message_taken",
                                            "summary": "Quote request",
                                            "charged_pence": 26
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: first of this month)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: today)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "agent_id",
                        "in": "query",
                        "required": false,
                        "description": "Filter to one agent",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "client_id",
                        "in": "query",
                        "required": false,
                        "description": "Filter to one client",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/calls/{id}": {
            "get": {
                "summary": "One call with transcript and message",
                "description": "The full record: timings, outcome, the structured message taken (if any) and the conversation transcript (subject to your transcript retention window).\n\nRequired key scope: `calls`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Call detail",
                        "content": {
                            "application/json": {
                                "example": {
                                    "call_id": 88,
                                    "agent_id": 12,
                                    "channel_id": 15,
                                    "client_id": 3,
                                    "caller_number": "+447712345678",
                                    "to_number": "+441256222333",
                                    "started_at": "2026-07-28 14:03:11",
                                    "ended_at": "2026-07-28 14:05:42",
                                    "duration_seconds": 151,
                                    "status": "COMPLETED",
                                    "outcome": "message_taken",
                                    "summary": "Quote request",
                                    "message": {
                                        "caller_name": "John Peters",
                                        "reason": "Quote request",
                                        "details": "Ltd company, ~40 invoices/month"
                                    },
                                    "transcript": [
                                        "[0:01] Agent: Hi, this is Sophie\u2026"
                                    ],
                                    "charged_pence": 26,
                                    "rate_ppu_used": 10
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown call"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Call id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/balance": {
            "get": {
                "summary": "Current credit balance",
                "description": "Balance in pence, billing mode, and account status.\n\nRequired key scope: `billing`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Balance",
                        "content": {
                            "application/json": {
                                "example": {
                                    "balance_pence": 892,
                                    "billing_mode": "CREDITS",
                                    "account_status": "ACTIVE"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            }
        },
        "/api/v1/ledger": {
            "get": {
                "summary": "Credit ledger entries in a date range",
                "description": "Every balance movement: grants, top-ups, usage debits (with the API key that incurred them, where applicable), adjustments. Latest 500 in range.\n\nRequired key scope: `billing`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Ledger entries",
                        "content": {
                            "application/json": {
                                "example": {
                                    "from": "2026-07-01",
                                    "to": "2026-07-28",
                                    "entries": [
                                        {
                                            "entry_id": 14,
                                            "type": "USAGE",
                                            "amount_pence": -13,
                                            "service": "voice",
                                            "reference": "CA3f84\u2026",
                                            "balance_after_pence": 892,
                                            "api_key_id": null,
                                            "created_at": "2026-07-28 10:46:20"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: first of this month)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: today)",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/usage": {
            "get": {
                "summary": "Usage report: units + cost per client, agent and channel",
                "description": "The endpoint your billing automation calls monthly to invoice your clients: usage rolled up channel \u2192 agent \u2192 client with your external_ref on every row, filtered by date range and optionally client_id / agent_id / channel_id.\n\nRequired key scope: `billing`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Usage rows",
                        "content": {
                            "application/json": {
                                "example": {
                                    "from": "2026-07-01",
                                    "to": "2026-07-28",
                                    "usage": [
                                        {
                                            "service": "voice",
                                            "client_id": 3,
                                            "client_name": "Harrison & Co",
                                            "external_ref": "CRM-1042",
                                            "agent_id": 12,
                                            "agent_name": "Sophie",
                                            "channel_id": 15,
                                            "calls": 42,
                                            "seconds": 6510,
                                            "charged_pence": 1110
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: first of this month)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: today)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "client_id",
                        "in": "query",
                        "required": false,
                        "description": "Filter to one client",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "agent_id",
                        "in": "query",
                        "required": false,
                        "description": "Filter to one agent",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "channel_id",
                        "in": "query",
                        "required": false,
                        "description": "Filter to one channel",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/outbound/calls": {
            "post": {
                "summary": "Ring someone now",
                "description": "Places a call immediately \u2014 the endpoint your CRM hits when a customer asks to be called back. The permission that makes the call lawful is recorded from the `consent` object in the same request, so there is no way to schedule a call without saying why you may make it. Every call, from here or the scheduler, passes the same gate at the moment of dialling: do-not-call list, permission on file, calling hours, and the per-number and per-agent limits. A refused call answers **409 with the reason in plain words** \u2014 the request was fine, we simply must not make that call \u2014 and is still recorded so it shows in your history.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Call placed",
                        "content": {
                            "application/json": {
                                "example": {
                                    "outbound_id": 84,
                                    "status": "placed",
                                    "reason": ""
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "Refused, with the reason (do-not-call, no permission, outside hours, limit reached)"
                    },
                    "400": {
                        "description": "Bad number, or missing/invalid consent"
                    },
                    "404": {
                        "description": "Unknown agent"
                    },
                    "502": {
                        "description": "The call could not be placed"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "agent_id": 12,
                                "to_number": "+447712345678",
                                "reason": "Quote request from the website",
                                "consent": {
                                    "basis": "requested",
                                    "source": "Website callback form, 29 July",
                                    "tps_attested": false
                                }
                            }
                        }
                    }
                }
            },
            "get": {
                "summary": "Outbound call history, including refused ones",
                "description": "Every attempt in the range with what became of it. Refused attempts carry `block_reason`, which is the answer to \"why didn't it ring them\" \u2014 the commonest question this feature produces.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Attempt history",
                        "content": {
                            "application/json": {
                                "example": {
                                    "from": "2026-07-01",
                                    "to": "2026-07-29",
                                    "calls": [
                                        {
                                            "outbound_id": 84,
                                            "agent_id": 12,
                                            "agent_name": "Ellie",
                                            "client_id": 3,
                                            "schedule_id": null,
                                            "to_number": "+447712345678",
                                            "purpose": "callback",
                                            "status": "COMPLETED",
                                            "block_reason": null,
                                            "call_sid": "CA9f2\u2026",
                                            "created_at": "2026-07-29 10:14:02"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: first of this month)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "description": "YYYY-MM-DD (default: today)",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/outbound/schedules": {
            "post": {
                "summary": "Schedule recurring calls",
                "description": "Sets up a repeating call \u2014 a morning check-in, a weekly follow-up. `time_of_day` is in the RECIPIENT's timezone, so nine in the morning stays nine in the morning when the clocks change. Cadence is once, daily, weekdays or weekly (`day_of_week` 1\u20137, Monday first). As with an immediate call, the permission is recorded from `consent` in the same request, and re-checked every time the schedule fires rather than trusted from when it was created.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Scheduled (next_run_at is UTC)",
                        "content": {
                            "application/json": {
                                "example": {
                                    "schedule_id": 7,
                                    "next_run_at": "2026-07-30 08:00:00",
                                    "status": "ACTIVE"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad number, or missing/invalid consent"
                    },
                    "404": {
                        "description": "Unknown agent"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "agent_id": 12,
                                "to_number": "+447712345678",
                                "label": "Morning check-in with Doris",
                                "cadence": "daily",
                                "time_of_day": "09:00",
                                "timezone": "Europe/London",
                                "consent": {
                                    "basis": "requested",
                                    "source": "Arranged with her daughter, 12 July"
                                }
                            }
                        }
                    }
                }
            },
            "get": {
                "summary": "List your schedules",
                "description": "Every schedule on the account with its next call time in UTC.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Schedule list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "schedules": [
                                        {
                                            "schedule_id": 7,
                                            "agent_id": 12,
                                            "label": "Morning check-in with Doris",
                                            "to_number": "+447712345678",
                                            "cadence": "daily",
                                            "time_of_day": "09:00",
                                            "day_of_week": null,
                                            "timezone": "Europe/London",
                                            "next_run_at": "2026-07-30 08:00:00",
                                            "status": "ACTIVE"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            }
        },
        "/api/v1/outbound/schedules/{id}/cancel": {
            "post": {
                "summary": "Stop a schedule",
                "description": "No further calls are placed. Attempts already made stay in your history.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cancelled",
                        "content": {
                            "application/json": {
                                "example": {
                                    "schedule_id": 7,
                                    "status": "CANCELLED"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Unknown schedule"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Schedule id",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/v1/outbound/do-not-call": {
            "post": {
                "summary": "Add a number to the do-not-call list",
                "description": "Nothing overrides this: it is checked at the moment of dialling, and recording fresh permission afterwards does not undo it. `scope` is `account` (every client you run \u2014 the default) or `client` with a `client_id` (that one business only). Your agents add entries here themselves whenever somebody asks not to be called again, so you rarely need this.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Added",
                        "content": {
                            "application/json": {
                                "example": {
                                    "phone_number": "+447712345678",
                                    "scope": "account",
                                    "status": "suppressed"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad number"
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "phone_number": "+447712345678",
                                "scope": "account",
                                "note": "Asked by email"
                            }
                        }
                    }
                }
            },
            "get": {
                "summary": "List do-not-call entries",
                "description": "Who your agents will never ring, and why each one is on the list.\n\nRequired key scope: `outbound`.",
                "tags": [
                    "Platform API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Entries",
                        "content": {
                            "application/json": {
                                "example": {
                                    "entries": [
                                        {
                                            "phone_number": "+447712345678",
                                            "scope": "client",
                                            "client_id": 3,
                                            "reason": "asked_on_call",
                                            "note": "Asked during a call",
                                            "created_at": "2026-07-29 10:22:41"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Missing scope"
                    }
                }
            }
        },
        "/v1/chat/completions": {
            "post": {
                "summary": "Create a chat completion",
                "description": "The OpenAI `/v1/chat/completions` contract, unchanged: same request body, same response body, same SSE frames when you set `stream: true`. We do not rewrite your prompt, substitute your model or inject anything \u2014 an API that surprises you is worse than one that does less. Every request is attributed to the key that made it, so per-client cost reporting comes free, and a key over its spend cap gets a 402 rather than a surprise bill.\n\nRequired key scope: `models`.",
                "tags": [
                    "Model API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Completion (or an SSE stream when `stream: true`)",
                        "content": {
                            "application/json": {
                                "example": {
                                    "id": "chatcmpl-\u2026",
                                    "object": "chat.completion",
                                    "choices": [
                                        {
                                            "index": 0,
                                            "message": {
                                                "role": "assistant",
                                                "content": "Customer wants a quote for year-end accounts."
                                            },
                                            "finish_reason": "stop"
                                        }
                                    ],
                                    "usage": {
                                        "prompt_tokens": 24,
                                        "completion_tokens": 11,
                                        "total_tokens": 35
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Key lacks the models scope"
                    },
                    "402": {
                        "description": "Out of credit, or the key hit its spend cap"
                    },
                    "502": {
                        "description": "Upstream model service unreachable"
                    }
                },
                "servers": [
                    {
                        "url": "https://models.bytepilot.ai",
                        "description": "Model API"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "example": {
                                "model": "google/gemini-3.1-flash-lite",
                                "messages": [
                                    {
                                        "role": "user",
                                        "content": "Summarise this enquiry in one line."
                                    }
                                ],
                                "stream": false
                            }
                        }
                    }
                }
            }
        },
        "/v1/models": {
            "get": {
                "summary": "List the models you can call",
                "description": "The catalogue available through the Model API, in the same shape OpenAI clients expect \u2014 so a model picker built against OpenAI populates itself. Use the `id` from here as the `model` field in a completion.\n\nRequired key scope: `models`.",
                "tags": [
                    "Model API"
                ],
                "security": [
                    {
                        "apiKey": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Model list",
                        "content": {
                            "application/json": {
                                "example": {
                                    "object": "list",
                                    "data": [
                                        {
                                            "id": "google/gemini-3.1-flash-lite",
                                            "object": "model"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Invalid key"
                    },
                    "403": {
                        "description": "Key lacks the models scope"
                    }
                },
                "servers": [
                    {
                        "url": "https://models.bytepilot.ai",
                        "description": "Model API"
                    }
                ]
            }
        }
    }
}