{"openapi":"3.1.0","info":{"title":"BazaarLink API","version":"1.0.0","description":"OpenAI-compatible AI model relay for Taiwan. Base URL https://bazaarlink.ai/api/v1 for OpenAI-shaped endpoints. Full prose documentation: https://bazaarlink.ai/docs/api (markdown mirror: https://bazaarlink.ai/docs/api.md).","contact":{"url":"https://bazaarlink.ai/contact"}},"servers":[{"url":"https://bazaarlink.ai","description":"Production"}],"paths":{"/api/v1/chat/completions":{"post":{"operationId":"postApiV1ChatCompletions","summary":"Chat Completions","description":"Send a chat completion request to any supported model via a single endpoint. Pass an OpenAI-shaped request body — messages, temperature, stream, tools, response_format are all supported. BazaarLink routes to the underlying provider (OpenAI, Anthropic, Google, DeepSeek, Meta, and more) transparently. Use reserved model IDs like auto:free to route to the cheapest available free model, or pass a models array for fallback routing.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/chat/completions \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"openai/gpt-4o\",\n    \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]\n  }'"},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nresp = client.chat.completions.create(\n    model=\"openai/gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n)\nprint(resp.choices[0].message.content)"}]}},"/api/v1/embeddings":{"post":{"operationId":"postApiV1Embeddings","summary":"Embeddings","description":"Generate dense vector embeddings for text using OpenAI, Voyage, Cohere, or other embedding model providers via a single unified interface. Request and response shapes are identical to OpenAI's embeddings API, so drop-in replacement with existing SDKs is straightforward. Supports single string or array-of-strings input.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/embeddings \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"openai/text-embedding-3-large\",\n    \"input\": \"The quick brown fox\"\n  }'"},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nresp = client.embeddings.create(\n    model=\"openai/text-embedding-3-large\",\n    input=\"The quick brown fox\",\n)\nprint(resp.data[0].embedding[:8])"}]}},"/api/v1/models":{"get":{"operationId":"getApiV1Models","summary":"List Models","description":"Lists every model available through BazaarLink with pricing (prompt + completion per million tokens), maximum context length, supported modalities (text, vision, audio), and provider routing metadata. The response is OpenAI-shaped (data: array of model objects) with additional BazaarLink-specific fields. Use this endpoint to discover available models programmatically.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/models"},{"lang":"typescript","label":"TypeScript (fetch)","source":"const res = await fetch(\"https://bazaarlink.ai/api/v1/models\");\nconst { data } = await res.json();\nconsole.log(`${data.length} models available`);"}]}},"/api/v1/models/:slug":{"get":{"operationId":"getApiV1ModelsSlug","summary":"Get a Model","description":"Looks up one model by its URL slug (the canonical id with \"/\" replaced by \"-\", e.g. openai/gpt-4o -> openai-gpt-4o — the same slug used by the model detail page). Works for any public model without auth; with an organization's Bearer key, a model outside that org's model allowlist answers 404 (not 403) so the response never reveals whether a disallowed model exists. A retired model answers 410 using the same model_retired error convention as other endpoints.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/models/openai-gpt-4o"},{"lang":"typescript","label":"TypeScript (fetch)","source":"const res = await fetch(\"https://bazaarlink.ai/api/v1/models/openai-gpt-4o\");\nconst model = await res.json();\nconsole.log(model.pricing);"}]}},"/api/v1/agents/register":{"post":{"operationId":"postApiV1AgentsRegister","summary":"Register Agent","description":"Public, unauthenticated endpoint for autonomous agents that don't have a key yet. Accepts only name (truncated to 100 chars) and description (currently accepted but not stored or used). Returns a fresh api_key plus credits, claim_token, upgrade_url, and referral_code — the agent can start calling auto:free immediately, and a human can later visit upgrade_url to claim and fund the account. Rate limited to one registration per IP per 24 hours.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/agents/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"research-agent\",\n    \"description\": \"Long-running research assistant\"\n  }'"},{"lang":"typescript","label":"TypeScript (fetch)","source":"const res = await fetch(\"https://bazaarlink.ai/api/v1/agents/register\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ name: \"research-agent\" }),\n});\nconst { api_key, credits, claim_token, upgrade_url } = await res.json();"}]}},"/api/v1/messages":{"post":{"operationId":"postApiV1Messages","summary":"Anthropic Messages","description":"Mirrors Anthropic's /v1/messages API shape (system, messages, max_tokens, tools). Point the official Anthropic SDK at BazaarLink's base URL and existing code works unchanged. BazaarLink transparently translates to the chosen underlying provider if the model is not native Anthropic, preserving tool_use blocks and stop reasons.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/messages \\\n  -H \"x-api-key: $BAZAARLINK_API_KEY\" \\\n  -H \"anthropic-version: 2023-06-01\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"anthropic/claude-sonnet-4.6\",\n    \"max_tokens\": 1024,\n    \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]\n  }'"},{"lang":"python","label":"Python (Anthropic SDK)","source":"from anthropic import Anthropic\nimport os\n\nclient = Anthropic(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nmsg = client.messages.create(\n    model=\"anthropic/claude-sonnet-4.6\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n)\nprint(msg.content[0].text)"}]}},"/api/v1/images/generations":{"post":{"operationId":"postApiV1ImagesGenerations","summary":"Image Generations","description":"Generate images from a text prompt using any supported image model. Request shape matches OpenAI's /v1/images/generations — prompt, model, n, size. BazaarLink always returns hosted URLs (via a signed proxy); response_format=b64_json is not supported on this endpoint.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/images/generations \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"openai/gpt-5.4-image-2\",\n    \"prompt\": \"A serene mountain lake at sunset\",\n    \"size\": \"1024x1024\",\n    \"n\": 1\n  }'"},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nimg = client.images.generate(\n    model=\"openai/gpt-5.4-image-2\",\n    prompt=\"A serene mountain lake at sunset\",\n    size=\"1024x1024\",\n)\nprint(img.data[0].url)"}]}},"/api/v1/images/edits":{"post":{"operationId":"postApiV1ImagesEdits","summary":"Image Edits","description":"Edit or transform existing images with a text prompt. Multipart adapter over the image-to-image pipeline: each uploaded `image` file (up to 8, 10 MB each) is passed as an input image alongside `prompt` and optional `model`. Response matches OpenAI's sync JSON shape ({ created, data: [{ url }] }) so `client.images.edit()` works unchanged. Not yet supported: `mask` and `response_format=b64_json` (URLs are always returned).","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/images/edits \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -F \"image=@photo.png\" \\\n  -F \"model=gpt-5.4-image-2\" \\\n  -F \"prompt=Replace the sky with a starry night\""},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nimg = client.images.edit(\n    model=\"gpt-5.4-image-2\",\n    image=open(\"photo.png\", \"rb\"),\n    prompt=\"Replace the sky with a starry night\",\n)\nprint(img.data[0].url)"}]}},"/api/v1/videos":{"post":{"operationId":"postApiV1Videos","summary":"Submit Video Generation","description":"Submit an async video generation job. Returns a BazaarLink job id; poll GET /api/v1/videos/{id} until status=completed. Supports duration, resolution, aspect_ratio, size, frame_images, input_references, generate_audio, watermark, and seed.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/videos \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"bytedance/seedance-2.0\",\n    \"prompt\": \"a cat walking through a field\",\n    \"duration\": 2,\n    \"resolution\": \"720p\",\n    \"generate_audio\": false\n  }'"}]}},"/api/v1/videos/:id":{"get":{"operationId":"getApiV1VideosId","summary":"Poll Video Generation Status","description":"Returns status (pending/in_progress/completed/failed). When completed, usage.cost and unsigned_urls are populated. Clients should poll with >=5s interval.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/videos/vjob_xxx \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/videos/:id/content":{"get":{"operationId":"getApiV1VideosIdContent","summary":"Download Generated Video","description":"Stream the generated MP4 bytes. Query param ?index=0 selects which output when a job returns multiple.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/videos/vjob_xxx/content?index=0 \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  --output out.mp4"}]}},"/api/v1/video/generations":{"post":{"operationId":"postApiV1VideoGenerations","summary":"Submit Video Generation (OpenAI-style)","description":"Identical behavior to POST /api/v1/videos — accepted to ease migration from OpenAI-style SDKs that namespace under /video/generations. Returns a BazaarLink job id; poll GET /api/v1/video/generations/:id (or /api/v1/videos/:id) until status=completed.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/video/generations \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"bytedance/seedance-2.0\",\n    \"prompt\": \"a cat walking through a field\",\n    \"duration\": 2,\n    \"resolution\": \"720p\",\n    \"generate_audio\": false\n  }'"}]}},"/api/v1/video/generations/:id":{"get":{"operationId":"getApiV1VideoGenerationsId","summary":"Poll Video Generation Status (OpenAI-style)","description":"Identical behavior to GET /api/v1/videos/:id. Returns status (pending/in_progress/completed/failed); when completed, usage.cost and unsigned_urls are populated. Clients should poll with >=5s interval.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/video/generations/vjob_xxx \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/video/generations/:id/content":{"get":{"operationId":"getApiV1VideoGenerationsIdContent","summary":"Download Generated Video (OpenAI-style)","description":"Identical behavior to GET /api/v1/videos/:id/content. Streams the generated MP4 bytes. Query param ?index=0 selects which output when a job returns multiple.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/video/generations/vjob_xxx/content?index=0 \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  --output out.mp4"}]}},"/api/v1/responses":{"post":{"operationId":"postApiV1Responses","summary":"Responses","description":"Mirrors OpenAI's /v1/responses API request/response shape (input, model, instructions, tools) with function tools, structured output, and reasoning passthrough. Stateless by design: sending store: true or previous_response_id returns HTTP 400 rather than silently ignoring them — send the full input array on every call.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/responses \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"openai/gpt-4o\",\n    \"input\": \"What is the capital of France?\"\n  }'"},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(\n    api_key=os.environ[\"BAZAARLINK_API_KEY\"],\n    base_url=\"https://bazaarlink.ai/api/v1\",\n)\n\nresp = client.responses.create(\n    model=\"openai/gpt-4o\",\n    input=\"What is the capital of France?\",\n)\nprint(resp.output_text)"}]}},"/api/v1/generation":{"get":{"operationId":"getApiV1Generation","summary":"Generation Metadata","description":"After receiving a chat completion or streaming response, pass the generation ID returned in the response to retrieve authoritative usage and billing information. This is the best source for exact cost accounting because the streaming response may report pre-finalized token counts. Returns tokens, cost, model, provider, and timing.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://bazaarlink.ai/api/v1/generation?id=gen_abc123\" \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""},{"lang":"typescript","label":"TypeScript (fetch)","source":"const res = await fetch(\n  `https://bazaarlink.ai/api/v1/generation?id=${generationId}`,\n  { headers: { Authorization: `Bearer ${apiKey}` } },\n);\nconst { data } = await res.json();\nconsole.log(data.cost_breakdown.total);"}]}},"/api/v1/key":{"get":{"operationId":"getApiV1Key","summary":"Current Key Info","description":"Introspect the API key that authenticated the current request. Useful for clients that need to display their own quota or confirm which key is active. Returns label, spend limit and remaining budget, limit reset period, expiry, free-tier flag, and rate-limit tier.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/key \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/auth/key":{"get":{"operationId":"getApiV1AuthKey","summary":"Auth Key Probe","description":"Lightweight auth probe that confirms an API key is valid without consuming any token budget. Returns { data: { label, usage, limit, is_free_tier, rate_limit } } — a label and usage summary in the industry-conventional key-info shape, not a user/org/agent identity object. Use as a health check before issuing expensive completion calls.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/auth/key \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/credits":{"get":{"operationId":"getApiV1Credits","summary":"Credit Balance","description":"Shows the current prepaid credit balance and lifetime usage for the authenticated user. Expressed in USD. Updates in near-real-time as completions settle.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/credits \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/usage":{"get":{"operationId":"getApiV1Usage","summary":"Usage History","description":"Paginated access to per-request usage history: timestamp, model, prompt tokens, completion tokens, cost, latency. Supports date-range and model filters via query parameters. Internal billing endpoint.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://bazaarlink.ai/api/v1/usage?period=custom&from=2026-04-01&to=2026-04-13\" \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/keys":{"get":{"operationId":"getApiV1Keys","summary":"List API Keys","description":"Returns the set of API keys created by the authenticated user, including label, creation date, last-used timestamp, and usage-to-date. Key secrets are never returned — only a prefix hint.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/keys \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]},"post":{"operationId":"postApiV1Keys","summary":"Create API Key","description":"Creates a new API key under the authenticated account. The secret is returned exactly once in the creation response and cannot be retrieved later. Supports per-key spend limits and optional expiration date.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/keys \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"label\": \"production-worker\", \"limit\": 100}'"}]}},"/api/v1/keys/:id":{"patch":{"operationId":"patchApiV1KeysId","summary":"Update API Key","description":"Modifies an existing API key's enabled flag, spend limit (spendLimitUsd), or limit reset period (spendLimitPeriod). There is no rename operation — the label is set at creation and is immutable. The secret itself is also immutable; rotate by creating a new key and deleting the old one.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X PATCH https://bazaarlink.ai/api/v1/keys/KEY_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"enabled\": true, \"spendLimitUsd\": 250, \"spendLimitPeriod\": \"monthly\"}'"}]},"delete":{"operationId":"deleteApiV1KeysId","summary":"Delete API Key","description":"Revokes an API key. The key becomes immediately invalid for new requests; already-authenticated in-flight completions finish normally. Usage history is retained for billing.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE https://bazaarlink.ai/api/v1/keys/KEY_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/management/byok-keys":{"get":{"operationId":"getApiV1ManagementByokKeys","summary":"List BYOK Keys","description":"Returns every BYOK upstream key of the organization the management key is bound to, including protocol, fallback mode, per-model mappings, scoped platform keys, and health fields. The upstream key value only ever appears masked (keyMask) — the full value is never retrievable after creation.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/management/byok-keys \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]},"post":{"operationId":"postApiV1ManagementByokKeys","summary":"Create BYOK Key","description":"Registers an upstream provider key (OpenAI- or Anthropic-protocol) for the organization. The plaintext apiKey appears only in this request — encrypted at rest, masked thereafter. Private/local baseUrl addresses are rejected (400, SSRF guard); scopedApiKeyIds must reference keys the org owns. Answers 201 with the key object plus a sync result (matched/unmatched/stale).","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/management/byok-keys \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"team-upstream\", \"baseUrl\": \"https://api.example-upstream.com/v1\", \"apiKey\": \"'$UPSTREAM_API_KEY'\"}'"}]}},"/api/v1/management/byok-keys/:id":{"get":{"operationId":"getApiV1ManagementByokKeysId","summary":"Get BYOK Key","description":"Returns one BYOK key of the calling organization. A key that does not exist or belongs to another organization answers 404 in both cases — existence is never leaked.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/management/byok-keys/BYOK_KEY_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]},"patch":{"operationId":"patchApiV1ManagementByokKeysId","summary":"Update BYOK Key","description":"All fields optional. modelToggles flips routing per canonical model id (unlisted models keep their state); scopedApiKeyIds replaces the whole scope list (empty array restores org-wide applicability; foreign key ids answer 400). The upstream key value itself cannot be replaced — delete and recreate to rotate it.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X PATCH https://bazaarlink.ai/api/v1/management/byok-keys/BYOK_KEY_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"enabled\": false}'"}]},"delete":{"operationId":"deleteApiV1ManagementByokKeysId","summary":"Delete BYOK Key","description":"Irreversible. Model mappings cascade-delete with the key; traffic that routed through this key falls back to platform routing afterwards.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE https://bazaarlink.ai/api/v1/management/byok-keys/BYOK_KEY_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/images/proxy/:token":{"get":{"operationId":"getApiV1ImagesProxyToken","summary":"Image Proxy","description":"When /api/v1/images/generations returns a URL response_format, BazaarLink issues a signed token that fronts the underlying provider storage. This endpoint resolves the token, fetches the upstream image, and streams it back — keeping the provider URL private and enabling auth + caching.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/images/proxy/SIGNED_TOKEN -o image.png"}]}},"/api/v1/images/models":{"get":{"operationId":"getApiV1ImagesModels","summary":"List Image Generation Models","description":"Returns every image-output model with pricing, modalities, and supported_parameters. Use it to discover which models honor normalized image parameters (aspect_ratio, resolution, quality, …) natively and which accept input_references for image-to-image. No auth required; sending an organization API key filters the list by the org's model allowlist.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/images/models"}]}},"/api/v1/orgs":{"get":{"operationId":"getApiV1Orgs","summary":"List Organizations","description":"Returns every organization the authenticated user is a member of, including role and joined date, plus each org's credit balance. Bearer auth only accepts a management-type key (keyType: \"management\"); a standard sk-bl-... key is rejected.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/orgs/:orgId":{"get":{"operationId":"getApiV1OrgsOrgId","summary":"Get Organization","description":"Returns full details for a specific organization, including billing plan, seat count, credit balance, and admin-configurable settings. Requires an org-admin role — a plain member's key gets 403. As with all /api/v1/orgs/* routes, Bearer auth only accepts a management-type key (keyType: \"management\"); a standard sk-bl-... key is rejected.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs/ORG_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/orgs/:orgId/teams":{"get":{"operationId":"getApiV1OrgsOrgIdTeams","summary":"List Organization Teams","description":"Returns the list of teams belonging to the specified organization, with metadata including team name, member count, and permission scopes. Requires an org-admin role and a management-type Bearer key (a standard sk-bl-... key is rejected).","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs/ORG_ID/teams \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]},"post":{"operationId":"postApiV1OrgsOrgIdTeams","summary":"Create Organization Team","description":"Creates a team scoped to the organization. Teams partition members into permission groups for shared keys and spend limits. Requires an org-admin role and a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs/ORG_ID/teams \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"ml-research\"}'"}]}},"/api/v1/orgs/:orgId/teams/:teamId":{"patch":{"operationId":"patchApiV1OrgsOrgIdTeamsTeamId","summary":"Update Organization Team","description":"Modifies metadata on an existing team — name, description, or permission scope. Does not change member list (use the members endpoints for that). Requires a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X PATCH https://bazaarlink.ai/api/v1/orgs/ORG_ID/teams/TEAM_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"ml-research-renamed\"}'"}]},"delete":{"operationId":"deleteApiV1OrgsOrgIdTeamsTeamId","summary":"Delete Organization Team","description":"Deletes a team. Members of the team remain members of the parent organization but lose any team-scoped keys or permissions. Requires an org-admin role and a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE https://bazaarlink.ai/api/v1/orgs/ORG_ID/teams/TEAM_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/orgs/:orgId/members":{"get":{"operationId":"getApiV1OrgsOrgIdMembers","summary":"List Organization Members","description":"Returns the full membership of an organization. Each entry includes user identity, role (owner / admin / member), join date, and usage-to-date. Requires an org-admin role and a management-type Bearer key (a standard sk-bl-... key is rejected).","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs/ORG_ID/members \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]},"post":{"operationId":"postApiV1OrgsOrgIdMembers","summary":"Invite Organization Member","description":"Creates an invitation for a new org member. The invitee receives an email with a signed join link. Role is one of owner / admin / member and determines permission scope. Requires an org-admin role and a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/orgs/ORG_ID/members \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\": \"colleague@example.com\", \"role\": \"member\"}'"}]}},"/api/v1/orgs/:orgId/members/:memberId":{"patch":{"operationId":"patchApiV1OrgsOrgIdMembersMemberId","summary":"Update Organization Member","description":"Changes the role (owner / admin / member) of an existing organization member. Used to promote or demote users. Cannot remove the last owner. Requires a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X PATCH https://bazaarlink.ai/api/v1/orgs/ORG_ID/members/MEMBER_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"role\": \"admin\"}'"}]},"delete":{"operationId":"deleteApiV1OrgsOrgIdMembersMemberId","summary":"Remove Organization Member","description":"Revokes a user's membership in an organization. Their personal account and personal API keys remain; they lose access to org-scoped resources immediately. Requires an org-admin role and a management-type Bearer key.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE https://bazaarlink.ai/api/v1/orgs/ORG_ID/members/MEMBER_ID \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}},"/api/v1/cursor/chat/completions":{"post":{"operationId":"postApiV1CursorChatCompletions","summary":"Cursor Chat Completions (Compat)","description":"Cursor appends /chat/completions to the configured Override URL, so users who set their base to .../v1/cursor land here. This route re-exports the same POST handler as /api/v1/chat/completions with identical behavior. All request/response shapes, streaming, and tool calling work identically. New integrations should use /api/v1/chat/completions directly.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/cursor/chat/completions \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"model\": \"openai/gpt-4o\", \"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]}'"}]}},"/api/v1/audio/transcriptions":{"post":{"operationId":"postApiV1AudioTranscriptions","summary":"Audio Transcriptions","description":"Accepts audio input in two formats: multipart/form-data with a file field (OpenAI SDK compatible) or a JSON body with input_audio.data (base64) and input_audio.format (OR-native). Forwards to the upstream provider's /audio/transcriptions endpoint as JSON. Settles credits from usage.cost in the response. Supports language, response_format, prompt, and temperature fields.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL (file upload)","source":"curl https://bazaarlink.ai/api/v1/audio/transcriptions \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -F \"file=@audio.mp3\" \\\n  -F \"model=mistralai/voxtral-small-24b-2507\""},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(api_key=os.environ[\"BAZAARLINK_API_KEY\"], base_url=\"https://bazaarlink.ai/api/v1\")\nwith open(\"audio.mp3\", \"rb\") as f:\n    resp = client.audio.transcriptions.create(model=\"mistralai/voxtral-small-24b-2507\", file=f)\nprint(resp.text)"}]}},"/api/v1/audio/speech":{"post":{"operationId":"postApiV1AudioSpeech","summary":"Audio Speech (Text-to-Speech)","description":"Generate speech from text. Accepts the OpenAI-compatible JSON body (model, input, voice, response_format, speed) and streams the binary audio response back unchanged. Billing is per input character using the model's catalog price (TTS providers return no usage envelope). Select a currently available speech-capable model from GET /api/v1/models?output_modalities=speech — the model below is a placeholder, not a fixed default.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl https://bazaarlink.ai/api/v1/audio/speech \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"YOUR_TTS_MODEL\",\n    \"input\": \"Hello from BazaarLink!\",\n    \"voice\": \"YOUR_VOICE\"\n  }' --output speech.mp3"},{"lang":"python","label":"Python (OpenAI SDK)","source":"from openai import OpenAI\nimport os\n\nclient = OpenAI(api_key=os.environ[\"BAZAARLINK_API_KEY\"], base_url=\"https://bazaarlink.ai/api/v1\")\nresp = client.audio.speech.create(\n    model=\"YOUR_TTS_MODEL\",\n    voice=\"YOUR_VOICE\",\n    input=\"Hello from BazaarLink!\",\n)\nresp.write_to_file(\"speech.mp3\")"}]}},"/api/v1/insights":{"get":{"operationId":"getApiV1Insights","summary":"Usage Insights","description":"Returns aggregated usage insights for the authenticated user (session cookie or Bearer sk-bl-... key). Query params: period (7d default | 30d | ytd | all), heatmap_metric (spend default | tokens | requests), plus optional page-wide filters model, api_key_id, app. Responses are cached for 5 minutes per (user, period, metric, filters) combination. The userId is always derived from the verified caller — it can never be overridden via query string.","tags":["v1"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Rate limited"}},"security":[{"bearerAuth":[]}],"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://bazaarlink.ai/api/v1/insights?period=30d&heatmap_metric=tokens\" \\\n  -H \"Authorization: Bearer $BAZAARLINK_API_KEY\""}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"sk-bl-...","description":"BazaarLink API key from https://bazaarlink.ai/dashboard — pass as `Authorization: Bearer sk-bl-...`."}}}}