BazaarLinkBazaarLink
Sign in
DocsAPI ReferenceSDK ReferenceAgentic UsageAI Skills

API Reference

An overview of BazaarLink’s API

BazaarLink provides one OpenAI-compatible request and response schema across models and providers, so you can integrate once and switch models without rewriting your application.

OpenAPI Specification

The complete BazaarLink API is documented with the OpenAPI specification. You can access it in YAML or JSON format:

Use these specifications with Swagger UI, Postman, or any OpenAPI-compatible code generator to explore the API or generate client libraries.

Requests

Completions Request Format

The request body for chat completions is sent to the following endpoint:

POST/api/v1/chat/completions

For the complete list of supported fields, see Parameters

Request Schema
// Definitions of subtypes are below
type Request = {
  // Required by BazaarLink Chat Completions
  model: string;                    // Use a provider-qualified catalog ID
  messages: Message[];             // Must contain at least one message

  // Generation
  stream?: boolean;
  temperature?: number;            // Range: [0, 2]
  max_tokens?: number;             // Positive integer
  max_completion_tokens?: number;  // Alias mapped to max_tokens upstream
  n?: number;
  seed?: number;
  stop?: string | string[];

  // Sampling
  top_p?: number;
  top_k?: number;
  frequency_penalty?: number;      // Range: [-2, 2]
  presence_penalty?: number;       // Range: [-2, 2]
  repetition_penalty?: number;     // Range: (0, 2]
  min_p?: number;                  // Range: [0, 1]
  top_a?: number;                  // Range: [0, 1]

  // Token probabilities
  logit_bias?: Record<number, number>;
  logprobs?: boolean;
  top_logprobs?: number;

  // Stable end-user identifier for abuse prevention
  user?: string;

  // Tool calling
  tools?: Tool[];
  tool_choice?: ToolChoice;
  parallel_tool_calls?: boolean;

  // Structured output
  response_format?: ResponseFormat;
  structured_outputs?: boolean;

  // Plugin configuration — forwarded to upstreams that support plugins.
  plugins?: Plugin[];

  // Multimodal and image-generation options
  modalities?: Array<"text" | "image">;
  image_config?: Record<string, unknown>;
  input_audio?: InputAudio;

  // Provider-specific reasoning controls
  reasoning_effort?: "low" | "medium" | "high";
  reasoning?: ReasoningConfig;
  thinking?: ThinkingConfig;
  enable_thinking?: boolean;

  // BazaarLink message transforms and fallback routing
  transforms?: Array<"middle-out">;
  models?: string[];             // Fallback list — this drives waterfall routing, not route
  route?: "fallback";            // Passthrough only; forwarded as-is, no local effect
  provider?: ProviderPreferences;
};

// Message types
type Message =
  | SystemMessage
  | UserMessage
  | AssistantMessage
  | ToolMessage;

type SystemMessage = {
  role: "system";
  content: string | ContentPart[];
  name?: string;
};

type UserMessage = {
  role: "user";
  content: string | ContentPart[];
  name?: string;
};

type AssistantMessage = {
  role: "assistant";
  content?: string | ContentPart[] | null;
  name?: string;
  tool_calls?: ToolCall[];
};

type ToolMessage = {
  role: "tool";
  content: string;
  tool_call_id: string;
  name?: string;
};

// Multimodal content parts
type ContentPart =
  | TextContentPart
  | ImageContentPart
  | FileContentPart
  | AudioContentPart
  | VideoContentPart;

type TextContentPart = {
  type: "text";
  text: string;
};

type ImageContentPart = {
  type: "image_url";
  image_url: {
    url: string;                    // Remote URL or base64 data URI
    detail?: string;
  };
};

type FileContentPart = {
  type: "file";
  file: {
    filename?: string;
    file_data: string;              // Base64 data URI
  };
};

type AudioContentPart = {
  type: "input_audio";
  input_audio: InputAudio;
};

type InputAudio = {
  data: string;                     // Raw base64 without a data URI prefix
  format: string;                   // For example "wav" or "mp3"
};

type VideoContentPart = {
  type: "video_url";
  video_url: {
    url: string;                    // Remote URL or base64 data URI
  };
};

// Tool calling subtypes
type FunctionDescription = {
  name: string;
  description?: string;
  parameters: object;               // JSON Schema object
};

type Tool = {
  type: "function";
  function: FunctionDescription;
};

type ToolChoice =
  | "none"
  | "auto"
  | "required"
  | {
      type: "function";
      function: {
        name: string;
      };
    };

type ToolCall = {
  id: string;
  type: "function";
  function: {
    name: string;
    arguments: string;
  };
};

// Structured output
type ResponseFormat =
  | {
      type: "json_object";
    }
  | {
      type: "json_schema";
      json_schema: {
        name: string;
        strict?: boolean;
        schema: object;
      };
    };

// Upstream plugin configuration
type Plugin = {
  id: string;
  enabled?: boolean;
  [key: string]: unknown;
};

// Reasoning controls vary by model family
type ReasoningConfig = {
  effort?: "low" | "medium" | "high";
  max_tokens?: number;
  exclude?: boolean;
};

type ThinkingConfig = {
  type?: "enabled" | "disabled";
  budget_tokens?: number;
};

// Provider routing preferences
type ProviderPreferences = {
  order?: string[];
  only?: string[];
  ignore?: string[];
  allow_fallbacks?: boolean;
  sort?:
    | "price"
    | "latency"
    | "throughput"
    | {
        by: string;
        partition?: string;
      };
  require_parameters?: boolean;
  data_collection?: "allow" | "deny";
  quantizations?: string[];
  max_price?: Record<string, number>;
};

Structured Output

Force the model to return valid JSON matching a schema. This is essential for building reliable applications that parse model outputs programmatically.

  • json_objectbasic JSON mode; the model returns valid JSON.
  • json_schemastrict schema mode; the model output must match the supplied JSON Schema.

Plugins

BazaarLink forwards the plugins array to the selected upstream route. Plugin availability depends on the chosen model and provider; the web plugin is also enabled by the :online model variant.

JSON
{
  "model": "openai/gpt-4.1",
  "messages": [
    { "role": "user", "content": "What happened today?" }
  ],
  "plugins": [
    { "id": "web" }
  ]
}

Optional Headers

Identify your application in request headers to enable usage tracking, dashboard visibility, and fine-grained analytics.

TypeScript
await fetch("https://bazaarlink.ai/api/v1/chat/completions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <BAZAARLINK_API_KEY>",
    "Content-Type": "application/json",
    "HTTP-Referer": "https://your-app.example",
    "X-Title": "Your App"
  },
  body: JSON.stringify({
    model: "openai/gpt-4.1",
    messages: [{ role: "user", content: "Hello!" }]
  })
});

Assistant Prefill

Add a partial assistant message as the last item to request continuation on compatible model routes.

How it works
BazaarLink preserves and forwards the final assistant message. Continuation behavior is implemented by the selected upstream model and provider, so it is not guaranteed on every route.
TypeScript
const response = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-4.6",
  messages: [
    { role: "user", content: "What is the meaning of life?" },
    // Intentional partial response; compatible routes continue from here.
    { role: "assistant", content: "My best answer is" }
  ]
});

Responses

BazaarLink normalizes completion responses across models and providers into one OpenAI-compatible shape.

CompletionsResponse Format

The choices field is always an array. Streaming responses use delta; non-streaming responses use message. Usage and cost details are returned when available.

Response Schema
type Response = {
  id: string;
  object: "chat.completion" | "chat.completion.chunk";
  created: number;
  model: string;
  choices: Array<NonStreamingChoice | StreamingChoice>;
  usage?: {
    prompt_tokens: number;
    completion_tokens: number;
    total_tokens: number;
    cost?: number;
    prompt_tokens_details?: {
      cached_tokens: number;
      cache_write_tokens?: number;
      audio_tokens?: number;
    };
    completion_tokens_details?: {
      reasoning_tokens?: number;
      image_tokens?: number;
    };
  };
};

type NonStreamingChoice = {
  index: number;
  finish_reason: string | null;
  native_finish_reason: string | null;
  message: {
    role: "assistant";
    content: string | null;
    tool_calls?: ToolCall[];
  };
};

type StreamingChoice = {
  index: number;
  finish_reason: string | null;
  native_finish_reason: string | null;
  delta: {
    role?: string;
    content?: string | null;
    tool_calls?: ToolCall[];
  };
};

Finish Reason

finish_reason uses normalized values such as stop, length, tool_calls, content_filter, and error. native_finish_reason preserves the provider’s original value.

JSON
{
  "finish_reason": "stop",
  "native_finish_reason": "stop"
}

Querying Cost and Stats

Retrieve detailed statistics for a single completion by generation ID (from chat/completions response id or streaming x-bz-gen-id header).

TypeScript
const generation = await fetch(
  "https://bazaarlink.ai/api/v1/generation?id=<GENERATION_ID>",
  {
    headers: {
      Authorization: "Bearer <BAZAARLINK_API_KEY>"
    }
  }
).then((response) => response.json());

Chat Completions

The primary endpoint. Compatible with the OpenAI Chat Completions API.

POST/api/v1/chat/completions

Request Body

modelrequired
string
Model ID, e.g. "openai/gpt-4o" or "anthropic/claude-3.5-sonnet"
messagesrequired
Message[]
Array of message objects with role and content
stream
boolean
If true, returns a Server-Sent Events stream. Default: false
temperature
number
Sampling temperature 0–2. Higher = more random. Default: 1
max_tokens
integer
Maximum number of tokens to generate
max_completion_tokens
integer
Alias for max_tokens (OpenAI o-series compatible). Both are accepted; whichever is provided takes effect
top_p
number
Nucleus sampling probability mass. Default: 1
top_k
integer
Limit token choices to top-K. 0 = disabled (consider all). Default: 0
frequency_penalty
number
Penalize repeated tokens. Range: [-2, 2]. Default: 0
presence_penalty
number
Penalize tokens based on presence. Range: [-2, 2]. Default: 0
repetition_penalty
number
Reduce token repetition from input. Range: (0, 2]. Default: 1
min_p
number
Minimum probability relative to the top token. Range: [0, 1]. Default: 0
top_a
number
Dynamic top-P based on highest-probability token. Range: [0, 1]. Default: 0
seed
integer
Integer seed for deterministic sampling. Not guaranteed for all models
n
integer
Number of completions to generate. Default: 1
user
string
End-user identifier for monitoring and abuse detection. Has no effect on billing. OpenAI-family models only — see note below.
stop
string | string[]
Stop sequences — generation halts when encountered
logit_bias
object
Map token IDs to bias values [-100, 100] added before sampling. OpenAI-family models only — see note below.
logprobs
boolean
Return log probabilities of each output token. OpenAI-family models only — see note below.
top_logprobs
integer
Number of most-likely tokens to return per position (requires logprobs: true). Range: 0–20. OpenAI-family models only — see note below.
tools
Tool[]
List of tools (functions) the model may call
tool_choice
string | object
Controls tool use: "auto", "none", or specific tool
parallel_tool_calls
boolean
Enable parallel function calling when tools are provided. Default: true. OpenAI-family models only — see note below.
response_format
object
Force structured JSON output. See Structured Output section
structured_outputs
boolean
Request strict JSON-schema-conformant output on providers that support it. Passed through as-is
reasoning
object
Provider-specific reasoning/thinking configuration. Passed through as-is
reasoning_effort
string
OpenAI o-series style reasoning effort: "low", "medium", or "high". Passed through as-is
transforms
string[]
Message transforms to apply, e.g. ["middle-out"]. Omit to auto-apply on ≤8k-context models
models
string[]
Fallback model list — BazaarLink tries each in order if primary fails
route
string
Advanced routing compatibility field — most users don't need this. Use "models" for fallback.
provider
object
Advanced routing preferences — most users don't need this.
user, logprobs, top_logprobs, logit_bias, and parallel_tool_calls only reach OpenAI-family models
These five parameters are stripped from the upstream request whenever the resolved model isn't recognized as OpenAI's own — sending them to anthropic/claude-*, google/gemini-*, or any other non-OpenAI target returns 200 with the parameter silently ignored, not an error. If you're setting one of these and the effect isn't showing up, check whether the target model is OpenAI's.

Request Schema (TypeScript)

// Definitions of subtypes are below
type Request = {
  // Required by BazaarLink Chat Completions
  model: string;                    // Use a provider-qualified catalog ID
  messages: Message[];             // Must contain at least one message

  // Generation
  stream?: boolean;
  temperature?: number;            // Range: [0, 2]
  max_tokens?: number;             // Positive integer
  max_completion_tokens?: number;  // Alias mapped to max_tokens upstream
  n?: number;
  seed?: number;
  stop?: string | string[];

  // Sampling
  top_p?: number;
  top_k?: number;
  frequency_penalty?: number;      // Range: [-2, 2]
  presence_penalty?: number;       // Range: [-2, 2]
  repetition_penalty?: number;     // Range: (0, 2]
  min_p?: number;                  // Range: [0, 1]
  top_a?: number;                  // Range: [0, 1]

  // Token probabilities
  logit_bias?: Record<number, number>;
  logprobs?: boolean;
  top_logprobs?: number;

  // Stable end-user identifier for abuse prevention
  user?: string;

  // Tool calling
  tools?: Tool[];
  tool_choice?: ToolChoice;
  parallel_tool_calls?: boolean;

  // Structured output
  response_format?: ResponseFormat;
  structured_outputs?: boolean;

  // Plugin configuration — forwarded to upstreams that support plugins.
  plugins?: Plugin[];

  // Multimodal and image-generation options
  modalities?: Array<"text" | "image">;
  image_config?: Record<string, unknown>;
  input_audio?: InputAudio;

  // Provider-specific reasoning controls
  reasoning_effort?: "low" | "medium" | "high";
  reasoning?: ReasoningConfig;
  thinking?: ThinkingConfig;
  enable_thinking?: boolean;

  // BazaarLink message transforms and fallback routing
  transforms?: Array<"middle-out">;
  models?: string[];             // Fallback list — this drives waterfall routing, not route
  route?: "fallback";            // Passthrough only; forwarded as-is, no local effect
  provider?: ProviderPreferences;
};

// Message types
type Message =
  | SystemMessage
  | UserMessage
  | AssistantMessage
  | ToolMessage;

type SystemMessage = {
  role: "system";
  content: string | ContentPart[];
  name?: string;
};

type UserMessage = {
  role: "user";
  content: string | ContentPart[];
  name?: string;
};

type AssistantMessage = {
  role: "assistant";
  content?: string | ContentPart[] | null;
  name?: string;
  tool_calls?: ToolCall[];
};

type ToolMessage = {
  role: "tool";
  content: string;
  tool_call_id: string;
  name?: string;
};

// Multimodal content parts
type ContentPart =
  | TextContentPart
  | ImageContentPart
  | FileContentPart
  | AudioContentPart
  | VideoContentPart;

type TextContentPart = {
  type: "text";
  text: string;
};

type ImageContentPart = {
  type: "image_url";
  image_url: {
    url: string;                    // Remote URL or base64 data URI
    detail?: string;
  };
};

type FileContentPart = {
  type: "file";
  file: {
    filename?: string;
    file_data: string;              // Base64 data URI
  };
};

type AudioContentPart = {
  type: "input_audio";
  input_audio: InputAudio;
};

type InputAudio = {
  data: string;                     // Raw base64 without a data URI prefix
  format: string;                   // For example "wav" or "mp3"
};

type VideoContentPart = {
  type: "video_url";
  video_url: {
    url: string;                    // Remote URL or base64 data URI
  };
};

// Tool calling subtypes
type FunctionDescription = {
  name: string;
  description?: string;
  parameters: object;               // JSON Schema object
};

type Tool = {
  type: "function";
  function: FunctionDescription;
};

type ToolChoice =
  | "none"
  | "auto"
  | "required"
  | {
      type: "function";
      function: {
        name: string;
      };
    };

type ToolCall = {
  id: string;
  type: "function";
  function: {
    name: string;
    arguments: string;
  };
};

// Structured output
type ResponseFormat =
  | {
      type: "json_object";
    }
  | {
      type: "json_schema";
      json_schema: {
        name: string;
        strict?: boolean;
        schema: object;
      };
    };

// Upstream plugin configuration
type Plugin = {
  id: string;
  enabled?: boolean;
  [key: string]: unknown;
};

// Reasoning controls vary by model family
type ReasoningConfig = {
  effort?: "low" | "medium" | "high";
  max_tokens?: number;
  exclude?: boolean;
};

type ThinkingConfig = {
  type?: "enabled" | "disabled";
  budget_tokens?: number;
};

// Provider routing preferences
type ProviderPreferences = {
  order?: string[];
  only?: string[];
  ignore?: string[];
  allow_fallbacks?: boolean;
  sort?:
    | "price"
    | "latency"
    | "throughput"
    | {
        by: string;
        partition?: string;
      };
  require_parameters?: boolean;
  data_collection?: "allow" | "deny";
  quantizations?: string[];
  max_price?: Record<string, number>;
};

Example Request

curl https://bazaarlink.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4.1",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Explain quantum computing in one paragraph."}
    ],
    "temperature": 0.7,
    "max_tokens": 512
  }'

Response

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1740000000,
  "model": "openai/gpt-4.1",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Quantum computing leverages quantum mechanics..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 28,
    "completion_tokens": 74,
    "total_tokens": 102,
    "cost": 0.0006480,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0
    }
  }
}

Response Schema (TypeScript)

BazaarLink normalizes exactly two fields — model and the removal of a provider field — and forwards the rest of the upstream response as-is. Fields like native_finish_reason, system_fingerprint, and reasoning are only present when the specific upstream provider populates them; don't rely on their presence across every model. usage.cost is the exception — it's always BazaarLink's own settled/billed amount, not a value relayed from upstream.

type Response = {
  id: string;
  object: "chat.completion" | "chat.completion.chunk";
  created: number;                 // Unix timestamp
  model: string;
  choices: (NonStreamingChoice | StreamingChoice)[];
  usage?: ResponseUsage;
  cost?: number;                   // Total cost in USD
};

type NonStreamingChoice = {
  index: number;
  finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
  native_finish_reason: string | null;  // Provider's original finish reason
  message: {
    role: "assistant";
    content: string | null;
    tool_calls?: ToolCall[];
  };
};

type StreamingChoice = {
  index: number;
  finish_reason: string | null;
  native_finish_reason: string | null;  // Provider's original finish reason
  delta: {
    role?: string;
    content?: string | null;
    tool_calls?: ToolCall[];
  };
};

type ResponseUsage = {
  prompt_tokens: number;
  completion_tokens: number;
  total_tokens: number;
  cost: number;                      // Total cost for this request in USD
  prompt_tokens_details?: {
    cached_tokens: number;           // Tokens served from prompt cache (reduced cost)
    cache_write_tokens?: number;     // Tokens written to cache in this request
    audio_tokens?: number;
  };
  completion_tokens_details?: {
    reasoning_tokens?: number;       // Thinking/reasoning tokens (e.g. o3, Qwen3, DeepSeek R1)
    image_tokens?: number;
  };
};

type ToolCall = {
  id: string;
  type: "function";
  function: { name: string; arguments: string };
};

Image Generation

BazaarLink offers two image-generation paths: (A) /v1/chat/completions with modalities: ["image"] — the native path, supports SSE streaming and mixed text+image output; recommended for new integrations. (B) /v1/images/generations — OpenAI DALL·E-compatible request shape, but responses are SSE event streams (required for slow models to dodge the 100 s upstream timeout). Both paths emit the same SSE event protocol — endpoint choice is purely a request-shape preference. Image EDITING (modifying an existing image) uses POST /v1/images/edits — OpenAI images.edit compatible, multipart/form-data with your source image(s). Edit-capable models have modality text+image->image (e.g. qwen/qwen-image-edit); pure-generation models are text->image — check each model's modality in GET /v1/models.

Response format

/api/v1/images/generations returns OpenAI-compatible sync JSON by default (since 2026-07-25) — client.images.generate() works with no wrapper. Pass stream: true to opt into the SSE event stream instead, which delivers progress for models with long generation times.

A. /v1/chat/completions (native, recommended)

POST/api/v1/chat/completions

The canonical streaming path. Recommended for any new integration.

curl -N https://bazaarlink.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $BL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4-image-2",
    "messages": [{"role":"user","content":"a red cat on a sofa"}],
    "modalities": ["image","text"],
    "stream": true
  }'

Image-to-image: include an image_url part in the content array. Supports data URIs or https image URLs (http:// is rejected), up to 8 images, ~10MB per data URI. The message carrying images must also include a text part (the edit instruction). Some models additionally support image_config (e.g. {"strength": 0.7}, 0–1 — lower stays closer to the source image), passed through to the upstream as-is.

curl -N https://bazaarlink.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $BL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4-image-2",
    "messages": [{"role":"user","content":[
      {"type":"image_url","image_url":{"url":"data:image/png;base64,..."}},
      {"type":"text","text":"change the background to a night city"}
    ]}],
    "modalities": ["image"],
    "stream": true
  }'

Image Edits (OpenAI-compatible)

POST/api/v1/images/edits

The OpenAI SDK's client.images.edit() works directly (multipart upload, sync JSON response returning data: [{ url }]). Same limits as image-to-image: up to 8 images, 10MB each; mask and response_format=b64_json are not supported yet.

curl https://bazaarlink.ai/api/v1/images/edits \
  -H "Authorization: Bearer $BL_API_KEY" \
  -F model="openai/gpt-5.4-image-2" \
  -F image=@cat.png \
  -F prompt="change the background to a night city"

B. /v1/images/generations (DALL·E-compatible)

POST/api/v1/images/generations

OpenAI DALL-E request shape. Sync JSON ({ created, data: [{ url }] }) is the default and works with client.images.generate() out of the box; pass stream: true to get the SSE event stream documented below instead.

curl https://bazaarlink.ai/api/v1/images/generations \
  -H "Authorization: Bearer $BL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-image-2",
    "prompt": "a red cat on a sofa",
    "size": "1024x1024"
  }'
modelrequired
string
Model id, e.g. google/gemini-2.5-flash-image
promptrequired
string
Text prompt
size
string
Output size (auto-mapped)
n
integer
Number of images (default 1)
# Streaming variant — progressive delivery for long generations
curl -N https://bazaarlink.ai/api/v1/images/generations \
  -H "Authorization: Bearer $BL_API_KEY" \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-5.4-image-2","prompt":"a red cat on a sofa","stream":true}'

SSE event protocol

Both endpoints emit the same event types:

event: heartbeat        # every 60 s, keeps Cloudflare happy
data: {}

event: image            # upstream URL, fastest path
data: {"index": 0, "url": "https://upstream/a.png"}

event: image-cached     # bazaarlink Redis-backed proxy URL (1 hr TTL)
data: {"index": 0, "url": "https://bazaarlink.ai/api/v1/images/proxy/<token>"}

event: usage            # final cost / token count
data: {"promptTokens": 12, "completionTokens": 7080, "cost": 0.226, "durationMs": 163400, "imageCount": 1}

event: done
data: {}

Supported image models

Model IDModalityi2i (edits)

Video Generation

Asynchronous three-step flow (submit → poll → content). Video generation takes 30 s–5 min, which doesn't fit the synchronous request/response shape of chat-completions — so BazaarLink exposes it as a dedicated /api/v1/videos endpoint using a job-id pattern: submit returns a vjob_* ID → poll status → fetch bytes on completion. Calling a video model via /chat/completions or /images/generations returns 400 (code: wrong_endpoint_for_video). Billing settles against real usage.cost when the job reaches completed.

Video tasks

One endpoint covers several tasks. Which task runs is decided by which fields you send — a single model can do image-to-video, keyframes, and continuation. Not every model supports every task; an unsupported request returns 400.

Text-to-video
prompt
Generate from a text prompt alone — no input media.
Image-to-video
frame_images: [ first frame ]
Your image IS the picture: it becomes the first frame and gets animated, staying faithful to the original. E.g. a photo of a cat → that same cat turns its head in the same scene.
Keyframes (first + last)
frame_images: [ first, last ]
Give a start and an end image; the model interpolates the motion in between.
Continuation
input_video
Extend an existing clip. The requested duration must be greater than the source video's length.
Reference-to-video
input_references: [ images ]
Your images are REFERENCES, not frames: the model keeps the subject/style and generates a brand-new scene. E.g. a cat photo + "dancing in a forest" → a new video where the cat's look is preserved but the scene and motion are new (1–9 references). Difference from image-to-video: i2v stays faithful to the exact picture; r2v re-casts the subject into new footage.
Video editing
input_video + prompt
Edit an existing video — change the scene, style, or motion. Billed on input-video seconds + output seconds.

1. Submit job (returns vjob_xxx immediately)

POST/api/v1/videos
modelrequired
string
Model id, e.g. alibaba/wan2.7-t2v
promptrequired
string
Text prompt
duration
integer
Duration in seconds (model-dependent)
resolution
string
Resolution — 480p / 720p / 1080p etc.
generate_audio
boolean
Generate audio track (true/false)
frame_images
array
First/last frame images (image-to-video, keyframes). Objects { type: "image_url", image_url: { url }, frame_type: "first_frame" | "last_frame" } or plain URL strings.
input_references
array
Reference images for reference-to-video — subject/style guidance, not exact frames.
input_video
string|object
Source video URL for continuation and video editing. Must be publicly fetchable by the upstream.
aspect_ratio
string
Aspect ratio, e.g. 16:9 or 9:16. Ignored when an input image dictates the ratio.
watermark
boolean
Add a watermark. Default false.
callback_url
string
Webhook URL called once the job reaches a terminal state — HTTPS only, SSRF-checked. No signature in v1; treat it as a hint and confirm via GET /videos/{id}.
curl https://bazaarlink.ai/api/v1/videos \
  -H "Authorization: Bearer $BL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "alibaba/wan2.7-t2v",
    "prompt": "a bird flying over mountains",
    "duration": 3,
    "resolution": "720p",
    "generate_audio": false
  }'
# → 202 { "id": "vjob_xxx", "status": "pending" }
Note
Submit reserves worst-case × duration × multiplier; on completion the real upstream `usage.cost` settles the delta.

2. Poll status

GET/api/v1/videos/{id}
curl -H "Authorization: Bearer $BL_API_KEY" \
  https://bazaarlink.ai/api/v1/videos/vjob_xxx
Note
Each GET must be ≥ 8 s apart to actually hit the upstream (avoids rate limits).
Note
When status=failed, the full reserve amount is refunded to the user.

3. Fetch video content (MP4)

GET/api/v1/videos/{id}/content
curl -H "Authorization: Bearer $BL_API_KEY" \
  -o output.mp4 \
  https://bazaarlink.ai/api/v1/videos/vjob_xxx/content

Good to know

  • Allowed resolutions differ per model — an unsupported value returns 400 listing the supported ones.
  • Input images/videos must be reachable from a public URL. Hotlink-protected hosts (e.g. some wikis) fail.
  • Input media passes upstream content moderation and can occasionally be rejected.
  • For continuation, the requested duration must exceed the source video length.
  • Output aspect ratio follows the input image — a square image yields a square video.
  • Video editing is billed on the input video's seconds plus the generated output's seconds.
  • input_video (editing / continuation) must be a PUBLIC URL. Videos you generate here are served behind your API key, so the upstream can't fetch them — host your source video on a publicly-reachable URL.
  • Webhook payloads are unsigned — verify status/amount via GET /videos/{id} before acting, and note unsigned_urls there are absolute (unlike the relative paths in the poll response).

Supported video models

Model IDModalityTasks
bytedance/seedance-2.0text+image+audio+video->videot2v, i2v
bytedance/seedance-2.0-fasttext+image+audio+video->videot2v, i2v
google/veo-3.1text+image->videot2v, i2v
openai/sora-2-protext+image->videot2v, i2v
bytedance/seedance-1-5-protext+image->videot2v, i2v
alibaba/wan2.6-r2v-flashtext+image+video->videor2v
alibaba/wan2.5-i2v-previewtext+image->videoi2v
alibaba/wan2.7-i2vtext+image+video->videoi2v, kf2v, continuation
alibaba/wan2.6-t2vtext->videot2v
alibaba/wan2.5-t2v-previewtext->videot2v
alibaba/wan2.2-t2v-plustext->videot2v
alibaba/wan2.7-r2vtext+image+video->videor2v
alibaba/wan2.7-t2vtext->videot2v
alibaba/happyhorse-1.0text+image->videot2v, i2v
alibaba/happyhorse-1.1text->videot2v
alibaba/wan2.2-i2v-plustext+image->videoi2v
alibaba/wan2.1-t2v-plustext->videot2v
alibaba/wan2.2-i2v-flashtext+image->videoi2v
alibaba/wan2.6-r2vtext+image+video->videor2v
alibaba/wan2.7-videoedittext+image+video->videovideoedit
alibaba/wan2.1-t2v-turbotext->videot2v
alibaba/wan2.6-i2v-flashtext+image->videoi2v
alibaba/wan2.6-i2vtext+image->videoi2v

Video Inputs

Send video files to models that support video input for analysis, captioning, or questions about scenes and events. Works with a direct URL or a base64 data URI — a URL is more efficient for publicly accessible video; base64 is for local files or private video.

Supported Formats

MP4 (H.264)MPEGMOVWebM
response = client.chat.completions.create(
    model="google/gemini-2.5-flash",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "video_url",
                "video_url": {"url": "https://example.com/video.mp4"},
            },
            {"type": "text", "text": "What is happening in this video?"},
        ],
    }],
)

Full API reference →

PDF Inputs

Send PDF documents directly in messages for models that support PDF input natively (e.g. Claude, Gemini). BazaarLink forwards the file straight to the model — billed as ordinary input tokens, no extra charge or processing step.

Supported Formats

  • PDF documents (text, images, tables, scanned)
  • Base64-encoded data URL (`data:application/pdf;base64,...`)
  • Multi-page documents
  • Password-free PDFs only
import base64

with open("document.pdf", "rb") as f:
    pdf_data = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="anthropic/claude-sonnet-4.6",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "file",
                "file": {
                    "filename": "document.pdf",
                    "file_data": f"data:application/pdf;base64,{pdf_data}",
                },
            },
            {"type": "text", "text": "Summarize this document."},
        ],
    }],
)

Responses API

An OpenAI Responses API-compatible endpoint for stateless multi-turn conversations, tool calling, and multimodal inputs. Ideal for agents and frameworks that use the OpenAI Python SDK ≥ 1.x with client.responses.create().

POST/api/v1/responses
Note
Accepts the same authentication and model routing as Chat Completions.

Request Body

modelrequired
string
Model ID, e.g. "openai/gpt-4o" or "anthropic/claude-3.5-sonnet"
inputrequired
string | Item[]
User input — a plain string (single message) or an array of input items for multi-turn / multimodal conversations.
instructions
string
System-level instructions, equivalent to a system message. Must be re-sent on every request.
stream
boolean
If true, returns Responses API SSE stream events. Event types: response.created, response.output_text.delta, response.completed.
max_output_tokens
integer
Maximum number of output tokens to generate (includes reasoning tokens for o-series models).
temperature
number
Sampling temperature 0–2. Higher = more random. Default: 1
top_p
number
Nucleus sampling probability mass. Default: 1
tools
Tool[]
Tool (function) definitions — same JSON Schema format as Chat Completions (accepts both the flat Responses shape and the nested shape). OpenAI's own built-in hosted tools (web_search_preview, file_search, computer_use_preview) are not supported; web search is available via plugins: [{id:"web"}] — supported only on some model routes.
tool_choice
string | object
Controls tool use: "auto", "none", or specific tool
parallel_tool_calls
boolean
Enable parallel function calling when tools are provided. Default: true. OpenAI-family models only — see note below.
response_format
object
Force structured JSON output. See Structured Output section
models
string[]
Fallback model list — BazaarLink tries each in order if primary fails
transforms
string[]
Message transforms to apply, e.g. ["middle-out"]. Omit to auto-apply on ≤8k-context models
previous_response_id
string
This endpoint is stateless — passing a non-null value returns 400 (invalid_prompt) immediately, it is never accepted and ignored. Use stateless mode instead: pass the full conversation history in the input array.
provider
object
Advanced routing preferences — most users don't need this.

Request Schema (TypeScript)

type ResponsesRequest = {
  model: string;                    // "provider/model-name"
  input: string | InputItem[];      // string or multi-turn array

  // Optional
  instructions?: string;            // System-level message
  stream?: boolean;                 // Default: false
  max_output_tokens?: number;
  temperature?: number;             // Range: [0, 2], default: 0.7
  top_p?: number;
  tools?: Tool[];
  tool_choice?: "auto" | "none" | "required" | object;
  parallel_tool_calls?: boolean;    // Default: true
  previous_response_id?: string;    // Not supported — use full input array
  provider?: ProviderPreferences;   // Same as Chat Completions
};

type InputItem =
  | { type?: "message"; role: "user" | "assistant" | "system" | "developer"; content: string | ContentBlock[] }
  | { type: "function_call_output"; call_id: string; output: string }   // tool result
  | { type: "function_call"; call_id: string; name: string; arguments: string };

type ContentBlock =
  | { type: "input_text"; text: string }
  | { type: "input_image"; image_url: string; detail?: "auto" | "low" | "high" };

Example Request

curl https://bazaarlink.ai/api/v1/responses \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "instructions": "You are a helpful assistant.",
    "input": "What is the capital of Taiwan?"
  }'

Response Format

// Non-streaming response object
type ResponsesResponse = {
  id: string;             // "resp_..."
  object: "response";
  created_at: number;
  completed_at: number;
  status: "completed" | "failed" | "incomplete";
  model: string;
  output: OutputItem[];
  usage: {
    input_tokens: number;   // equivalent to prompt_tokens
    output_tokens: number;  // equivalent to completion_tokens
    total_tokens: number;
    cost?: number;          // actual cost in credits
  } | null;
  error: null | { code: string; message: string };
};

type OutputItem =
  | {
      type: "message";
      id: string;
      role: "assistant";
      status: "completed";
      content: Array<{ type: "output_text"; text: string; annotations: [] }>;
    }
  | { type: "function_call"; id: string; call_id: string; name: string; arguments: string; status: "completed" };

Migrating from Chat Completions

Replace messages with input (string or array), use instructions instead of a system-role message, and read output[0].content[0].text instead of choices[0].message.content.

# Chat Completions (before)
response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[
        {"role": "system", "content": "You are helpful."},
        {"role": "user",   "content": "Hello"},
    ]
)
text = response.choices[0].message.content

# Responses API (after)
response = client.responses.create(
    model="openai/gpt-4o-mini",
    instructions="You are helpful.",
    input="Hello"
)
text = response.output[0].content[0].text

Limitations

  • previous_response_id or store: true is rejected with 400 (error code invalid_prompt) — not accepted and ignored. Always use stateless mode: pass the full conversation history in the input array.
  • OpenAI's own built-in hosted tools (web_search_preview, file_search, computer_use_preview) are not supported. Web search is available via plugins: [{id:"web"}] — supported only on some model routes.
  • background: true is accepted but ignored — every request runs synchronously to completion.

Messages (Anthropic)

Anthropic-compatible Messages API for Claude SDK. Use exactly as you would with Anthropic's API — just change base URL and auth header.

POST/api/v1/messages
Note
Accepts Bearer token or x-api-key header (Anthropic SDK compatibility). Max body size: 10 MB.

Request Body

modelrequired
string
Model ID, e.g. "openai/gpt-4o" or "anthropic/claude-3.5-sonnet"
max_tokensrequired
integer
Maximum number of tokens to generate (positive integer).
messagesrequired
Message[]
Array of conversation messages (non-empty).
system
string
Optional system prompt.
stream
boolean
If true, returns a Server-Sent Events stream. Default: false
temperature
number
Sampling temperature 0–2. Higher = more random. Default: 1
top_p
number
Nucleus sampling probability mass. Default: 1
top_k
integer
Limit token choices to top-K. 0 = disabled (consider all). Default: 0
stop_sequences
string[]
Custom stop sequence strings.
tools
Tool[]
List of tools (functions) the model may call
tool_choice
string | object
Controls tool use: "auto", "none", or specific tool

Example Request

from anthropic import Anthropic

client = Anthropic(
    base_url="https://bazaarlink.ai/api/v1",
    api_key="sk-bl-YOUR_KEY"
)

response = client.messages.create(
    model="anthropic/claude-opus-4",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}]
)
print(response.content[0].text)

Response

{
  "id": "msg_...",
  "type": "message",
  "role": "assistant",
  "model": "anthropic/claude-opus-4",
  "content": [
    { "type": "text", "text": "Hello! How can I help you today?" }
  ],
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 10,
    "output_tokens": 12,
    "cache_read_input_tokens": 0,
    "cache_creation_input_tokens": 0,
    "bz_cost": 0.00042
  }
}

Errors: 400 (validation), 402 (insufficient credits), 429 (rate limit), 502 (upstream error / missing key), 503 (server restart).

Models

List all available models with pricing and capability information. No authentication required for this endpoint.

GET/api/v1/models
# Text models (default)
curl https://bazaarlink.ai/api/v1/models

# Complete catalog
curl "https://bazaarlink.ai/api/v1/models?output_modalities=all"

Response

{
  "data": [
    {
      "id": "openai/gpt-4.1",
      "name": "GPT 4.1",
      "context_length": 1047576,
      "modality": "text+image+file->text",
      "pricing": {
        "prompt": "2.00",
        "completion": "8.00"
      }
    }
  ]
}
// /v1/models — Response Schema
type ModelsResponse = {
  data: Model[];
};

type Model = {
  id: string;                    // Model ID (e.g. "openai/gpt-4.1")
  name: string;                  // Human-readable name
  context_length: number | null; // Max context window in tokens
  modality: string | null;       // e.g. "text->text", "text+image->text"
  architecture?: {
    input_modalities?: string[];
    output_modalities?: Array<
      "text" | "image" | "embeddings" | "audio" |
      "video" | "rerank" | "speech" | "transcription"
    >;
  };
  pricing: {
    prompt: string;              // Input price per 1M tokens (USD)
    completion: string;          // Output price per 1M tokens (USD)
  };
  description?: string | null;   // Model description
  top_provider?: {
    max_completion_tokens?: number;
  };
  supported_parameters?: string[]; // e.g. ["tools", "response_format", "reasoning"]
  pricing_tiers?: {               // Present only for models with input-length tiers
    above_prompt_tokens: number;  // Ascending; strict "greater than" threshold
    prompt: string;                // USD per token, override tier
    completion: string;            // USD per token, override tier
  }[];
};

Input-Length Tiered Pricing

Some models switch to a different price table once the prompt exceeds a token threshold — the whole table changes, not just the tokens above the threshold. Thresholds are strict: a prompt with exactly N tokens still bills at the tier below N; the higher tier applies only when input tokens are greater than N.

pricing_tiers is a sibling of pricing, present only when a model has override tiers beyond its base price. Entries are sorted by above_prompt_tokens ascending; prompt/completion are USD per token (same unit as pricing.prompt/pricing.completion). pricing.prompt and pricing.completion always remain the base (lowest) tier.

Most models have no tiers — for those, the pricing_tiers key is simply absent from the response.

{
  "id": "openai/gpt-4.1",
  "name": "GPT 4.1",
  "pricing": {
    "prompt": "2.00",
    "completion": "8.00"
  },
  "pricing_tiers": [
    {
      "above_prompt_tokens": 128000,
      "prompt": "4.00",
      "completion": "16.00"
    }
  ]
}

Available Models (254)

These are the models currently available on BazaarLink, loaded dynamically from our database:

OpenAI
openai/gpt-5.3-codex400K ctx · $1.75/$14.00text+image+file->text
openai/gpt-5.4-nano400K ctx · $0.20/$1.25text+image+file->text
openai/gpt-3.5-turbo-instruct4K ctx · $1.50/$2.00text->text
openai/text-embedding-ada-0028K ctx · $0.10/$0.00text->embeddings
openai/gpt-5.1400K ctx · $1.25/$10.00text+image+file->text
openai/gpt-5.6-luna-pro1050K ctx · $0.20/$1.20text+image+file->text
openai/gpt-4.11048K ctx · $2.00/$8.00text+image+file->text
openai/gpt-5.2-chat128K ctx · $1.75/$14.00text+image+file->text
openai/gpt-5.6-terra-pro1050K ctx · $2.00/$12.00text+image+file->text
openai/gpt-4o128K ctx · $2.50/$10.00text+image+file->text
openai/gpt-5.2-codex400K ctx · $1.75/$14.00text+image->text
openai/gpt-5.51050K ctx · $5.00/$30.00text+image+file->text
openai/gpt-3.5-turbo-06134K ctx · $1.00/$2.00text->text
openai/text-embedding-3-small8K ctx · $0.02/$0.00text->embeddings
openai/gpt-5.6-terra1050K ctx · $2.00/$12.00text+image+file->text
openai/gpt-5.1-codex400K ctx · $1.25/$10.00text+image->text
openai/gpt-oss-20b131K ctx · $0.03/$0.13text->text
openai/gpt-oss-safeguard-20b131K ctx · $0.07/$0.30text->text
openai/gpt-4-turbo-preview128K ctx · $10.00/$30.00text->text
openai/gpt-5.2400K ctx · $1.75/$14.00text+image+file->text
openai/gpt-5.1-chat128K ctx · $1.25/$10.00text+image+file->text
openai/gpt-4.1-nano1048K ctx · $0.10/$0.40text+image+file->text
openai/o3200K ctx · $2.00/$8.00text+image+file->text
openai/gpt-5.4-mini400K ctx · $0.75/$4.50text+image+file->text
openai/gpt-4.1-mini1048K ctx · $0.40/$1.60text+image+file->text
openai/gpt-5.2-pro400K ctx · $21.00/$168.00text+image+file->text
openai/o4-mini-high200K ctx · $1.10/$4.40text+image+file->text
openai/gpt-5-codex400K ctx · $1.25/$10.00text+image->text
openai/gpt-3.5-turbo-16k16K ctx · $3.00/$4.00text->text
openai/gpt-4o-mini128K ctx · $0.15/$0.60text+image+file->text
openai/gpt-5.3-chat128K ctx · $1.75/$14.00text+image+file->text
openai/gpt-4o-2024-05-13128K ctx · $5.00/$15.00text+image+file->text
openai/gpt-oss-120b131K ctx · $0.15/$0.60text->text
openai/gpt-4-turbo128K ctx · $10.00/$30.00text+image->text
openai/o3-mini200K ctx · $1.10/$4.40text+file->text
openai/gpt-5.4-pro1050K ctx · $30.00/$180.00text+image+file->text
openai/text-embedding-3-large8K ctx · $0.13/$0.00text->embeddings
openai/gpt-5.41050K ctx · $2.50/$15.00text+image+file->text
openai/gpt-5-nano400K ctx · $0.05/$0.40text+image+file->text
openai/gpt-5.1-codex-max400K ctx · $1.25/$10.00text+image->text
openai/o1200K ctx · $15.00/$60.00text+image+file->text
openai/gpt-5.1-codex-mini400K ctx · $0.25/$2.00text+image->text
openai/gpt-4o-2024-08-06128K ctx · $2.50/$10.00text+image+file->text
openai/gpt-4o-mini-2024-07-18128K ctx · $0.15/$0.60text+image+file->text
openai/gpt-5400K ctx · $1.25/$10.00text+image+file->text
openai/gpt-5.6-sol-pro1050K ctx · $5.00/$30.00text+image+file->text
openai/o3-pro200K ctx · $20.00/$80.00text+image+file->text
openai/gpt-3.5-turbo16K ctx · $0.50/$1.50text->text
openai/gpt-4o-2024-11-20128K ctx · $2.50/$10.00text+image+file->text
openai/o3-mini-high200K ctx · $1.10/$4.40text+file->text
openai/gpt-5-pro400K ctx · $15.00/$120.00text+image+file->text
openai/sora-2-pro · $0.00/$0.00text+image->video
openai/gpt-48K ctx · $30.00/$60.00text->text
openai/o4-mini200K ctx · $1.10/$4.40text+image+file->text
openai/gpt-5.6-luna1050K ctx · $0.20/$1.20text+image+file->text
openai/gpt-5.6-sol1050K ctx · $5.00/$30.00text+image+file->text
openai/gpt-5.4-image-2272K ctx · $8.00/$15.00text+image+file->text+image
openai/gpt-5-mini400K ctx · $0.25/$2.00text+image+file->text
openai/o1-pro200K ctx · $150.00/$600.00text+image+file->text
openai/gpt-image-1400K ctx · $10.00/$10.00text+image->image
openai/gpt-image-2400K ctx · $8.00/$8.00text+image->image
openai/gpt-image-1-mini400K ctx · $2.50/$2.50text+image->image
Qwen
qwen/qwen3.7-plus1000K ctx · $0.32/$1.28text+image->text
qwen/qwen3.7-max1000K ctx · $1.48/$4.42text->text
qwen/qwen3.5-plus-02-151000K ctx · $0.26/$1.56text+image+video->text
qwen/qwen3-coder-flash1000K ctx · $0.20/$0.97text->text
qwen/qwen-2.5-coder-32b-instruct33K ctx · $0.66/$1.00text->text
qwen/qwen-plus1000K ctx · $0.26/$0.78text->text
qwen/qwen3-coder-plus1000K ctx · $0.65/$3.25text->text
qwen/qwen-2.5-72b-instruct33K ctx · $0.36/$0.40text->text
qwen/qwen3.6-27b262K ctx · $0.29/$2.40text+image+video->text
qwen/qwen3.6-35b-a3b262K ctx · $0.14/$1.00text+image+video->text
qwen/qwen3-vl-30b-a3b-instruct262K ctx · $0.15/$0.60text+image->text
qwen/qwen3-30b-a3b-thinking-250782K ctx · $0.20/$2.40text->text
qwen/qwen3-32b131K ctx · $0.08/$0.28text->text
qwen/qwen3-vl-8b-thinking131K ctx · $0.18/$2.10text+image->text
qwen/qwen3.5-flash-02-231000K ctx · $0.07/$0.26text+image+video->text
qwen/qwen3-vl-235b-a22b-instruct262K ctx · $0.21/$1.90text+image->text
qwen/qwen3.5-27b262K ctx · $0.20/$1.56text+image+video->text
qwen/qwen3-235b-a22b131K ctx · $0.46/$1.82text->text
qwen/qwen3.5-9b262K ctx · $0.10/$0.15text+image+video->text
qwen/qwen3-30b-a3b131K ctx · $0.13/$0.52text->text
qwen/qwen3-8b131K ctx · $0.12/$0.46text->text
qwen/qwen3-vl-8b-instruct262K ctx · $0.12/$0.46text+image->text
qwen/qwen3-max-thinking262K ctx · $0.78/$3.90text->text
qwen/qwen3.5-122b-a10b262K ctx · $0.26/$2.08text+image+video->text
qwen/qwen3-vl-32b-instruct131K ctx · $0.10/$0.42text+image->text
qwen/qwen3-vl-30b-a3b-thinking262K ctx · $0.20/$2.40text+image->text
qwen/qwen2.5-vl-72b-instruct128K ctx · $0.80/$1.00text+image->text
qwen/qwen3-235b-a22b-thinking-2507262K ctx · $0.23/$2.30text->text
qwen/qwen3-coder262K ctx · $0.30/$1.00text->text
qwen/qwen3.5-35b-a3b262K ctx · $0.14/$1.00text+image+video->text
qwen/qwen3-coder-next262K ctx · $0.12/$0.80text->text
qwen/qwen3-max262K ctx · $0.78/$3.90text->text
qwen/qwen-plus-2025-07-281000K ctx · $0.26/$0.78text->text
qwen/qwen3-next-80b-a3b-thinking262K ctx · $0.15/$1.20text->text
qwen/qwen3-14b131K ctx · $0.23/$0.91text->text
qwen/qwen-plus-2025-07-28:thinking1000K ctx · $0.40/$1.20text->text
qwen/qwen3.6-plus1000K ctx · $0.33/$1.95text+image+video->text
qwen/qwen3.5-397b-a17b262K ctx · $0.39/$2.34text+image+video->text
qwen/qwen3-coder-30b-a3b-instruct262K ctx · $0.07/$0.27text->text
qwen/qwen3-embedding-8b33K ctx · $0.01/$0.00text->embeddings
qwen/qwen3-235b-a22b-2507262K ctx · $0.09/$0.55text->text
qwen/qwen3.5-plus-202604201000K ctx · $0.30/$1.80text+image+video->text
qwen/qwen-2.5-7b-instruct33K ctx · $0.10/$0.20text->text
qwen/qwen3-30b-a3b-instruct-2507262K ctx · $0.05/$0.19text->text
qwen/qwen3-vl-235b-a22b-thinking131K ctx · $0.40/$4.00text+image->text
qwen/qwen3-embedding-4b33K ctx · $0.02/$0.00text->embeddings
qwen/qwen3-next-80b-a3b-instruct262K ctx · $0.10/$1.10text->text
qwen/qwen-image-edit-maxtext+image->image
qwen/qwen-image-edit-plustext+image->image
qwen/qwen-image-plustext->image
qwen/qwen-image-maxtext->image
qwen/qwen-image-edittext+image->image
qwen/qwen-image-2.0text->image
qwen/qwen-image-2.0-protext->image
qwen/qwen-imagetext->image
Alibaba
alibaba/wan2.6-r2v-flash · $0.00/$0.00text+image+video->video
alibaba/wan2.5-i2i-previewtext+image->image
alibaba/z-image-turbotext->image
alibaba/wan2.1-t2i-plustext->image
alibaba/wan2.1-t2i-turbotext->image
alibaba/wan2.2-t2i-plustext->image
alibaba/wan2.6-imagetext->image
alibaba/wan2.5-i2v-preview · $0.00/$0.00text+image->video
alibaba/wan2.7-i2v · $0.00/$0.00text+image+video->video
alibaba/wan2.6-t2v · $0.00/$0.00text->video
alibaba/wan2.5-t2v-preview · $0.00/$0.00text->video
alibaba/wan2.2-t2v-plus · $0.00/$0.00text->video
alibaba/wan2.7-r2v · $0.00/$0.00text+image+video->video
alibaba/wan2.7-t2v · $0.00/$0.00text->video
alibaba/happyhorse-1.0 · $0.00/$0.00text+image->video
alibaba/happyhorse-1.1 · $0.00/$0.00text->video
alibaba/wan2.2-i2v-plus · $0.00/$0.00text+image->video
alibaba/wan2.1-t2v-plus · $0.00/$0.00text->video
alibaba/wan2.5-t2i-previewtext->image
alibaba/wan2.2-t2i-flashtext->image
alibaba/wan2.2-i2v-flash · $0.00/$0.00text+image->video
alibaba/wan2.6-r2v · $0.00/$0.00text+image+video->video
alibaba/wan2.7-videoedit · $0.00/$0.00text+image+video->video
alibaba/wan2.1-t2v-turbo · $0.00/$0.00text->video
alibaba/wan2.6-i2v-flash · $0.00/$0.00text+image->video
alibaba/wan2.6-i2v · $0.00/$0.00text+image->video
alibaba/wan2.6-t2itext->image
alibaba/wan2.7-imagetext->image
alibaba/wan2.7-image-protext->image
Google
google/gemini-2.5-flash-lite1049K ctx · $0.10/$0.40text+image+file+audio+video->text
google/gemini-3.1-pro-preview1049K ctx · $2.00/$12.00text+image+file+audio+video->text
google/gemini-3.1-flash-lite-preview1049K ctx · $0.25/$1.50text+image+file+audio+video->text
google/gemini-embedding-2-preview8K ctx · $0.20/$0.00text+image+file+audio+video->embeddings
google/gemma-3-4b-it131K ctx · $0.05/$0.10text+image->text
google/gemini-2.5-pro-preview1049K ctx · $1.25/$10.00text+image+file+audio->text
google/gemma-3n-e4b-it33K ctx · $0.06/$0.12text->text
google/gemini-3.1-flash-image-preview66K ctx · $0.50/$3.00text+image->text+image
google/gemma-3-12b-it131K ctx · $0.05/$0.15text+image->text
google/gemini-3.1-flash-image131K ctx · $0.50/$3.00text+image->text+image
google/gemini-3-flash-preview1049K ctx · $0.50/$3.00text+image+file+audio+video->text
google/gemini-2.5-flash1049K ctx · $0.30/$2.50text+image+file+audio+video->text
google/gemma-2-27b-it8K ctx · $0.65/$0.65text->text
google/gemini-2.5-pro1049K ctx · $1.25/$10.00text+image+file+audio+video->text
google/gemma-4-31b-it262K ctx · $0.10/$0.34text+image+video->text
google/gemini-embedding-00120K ctx · $0.15/$0.00text->embeddings
google/gemini-2.5-pro-preview-05-061049K ctx · $1.25/$10.00text+image+file+audio+video->text
google/gemini-3.5-flash-lite1049K ctx · $0.30/$2.50text+image+file+audio+video->text
google/gemini-2.5-flash-image33K ctx · $0.30/$2.50text+image->text+image
google/gemma-3-27b-it262K ctx · $0.08/$0.45text+image->text
google/veo-3.1 · $0.00/$0.00text+image->video
google/gemini-3-pro-image131K ctx · $2.00/$12.00text+image->text+image
google/gemini-3.1-pro-preview-customtools1049K ctx · $2.00/$12.00text+image+file+audio+video->text
google/gemma-4-26b-a4b-it262K ctx · $0.07/$0.34text+image+video->text
google/gemini-3.6-flash1049K ctx · $1.50/$7.50text+image+file+audio+video->text
google/gemini-3.5-flash1049K ctx · $1.50/$9.00text+image+file+audio+video->text
Anthropic
anthropic/claude-opus-4.61000K ctx · $5.00/$25.00text+image+file->text
anthropic/claude-sonnet-4.61000K ctx · $3.00/$15.00text+image+file->text
anthropic/claude-sonnet-41000K ctx · $3.00/$15.00text+image+file->text
anthropic/claude-sonnet-51000K ctx · $2.00/$10.00text+image+file->text
anthropic/claude-haiku-4.5200K ctx · $1.00/$5.00text+image+file->text
anthropic/claude-sonnet-4.51000K ctx · $3.00/$15.00text+image+file->text
anthropic/claude-opus-4.71000K ctx · $5.00/$25.00text+image+file->text
anthropic/claude-fable-51000K ctx · $10.00/$50.00text+image+file->text
anthropic/claude-opus-4.81000K ctx · $5.00/$25.00text+image+file->text
anthropic/claude-3-haiku200K ctx · $0.25/$1.25text+image->text
anthropic/claude-opus-4.5200K ctx · $5.00/$25.00text+image+file->text
anthropic/claude-opus-4200K ctx · $15.00/$75.00text+image+file->text
anthropic/claude-opus-4.1200K ctx · $15.00/$75.00text+image+file->text
anthropic/claude-opus-51000K ctx · $5.00/$25.00text+image+file->text
Zhipu AI
z-ai/glm-5205K ctx · $1.00/$3.20text->text
z-ai/glm-5.1205K ctx · $1.40/$4.40text->text
z-ai/glm-5v-turbo203K ctx · $1.20/$4.00text+image+video->text
z-ai/glm-4.7205K ctx · $0.40/$1.75text->text
z-ai/glm-5.21049K ctx · $1.40/$4.40text->text
z-ai/glm-5-turbo203K ctx · $1.20/$4.00text->text
z-ai/glm-4.5v66K ctx · $0.60/$1.80text+image->text
z-ai/glm-4.6v131K ctx · $0.30/$0.90text+image+video->text
z-ai/glm-4.6205K ctx · $0.50/$2.00text->text
z-ai/glm-4.7-flash203K ctx · $0.06/$0.40text->text
z-ai/glm-4.5-air131K ctx · $0.13/$0.85text->text
z-ai/glm-4.5131K ctx · $0.60/$2.20text->text
DeepSeek
deepseek/deepseek-v3.2164K ctx · $0.28/$0.42text->text
deepseek/deepseek-v4-pro1049K ctx · $2.40/$4.80text->text
deepseek/deepseek-v4-flash1049K ctx · $0.20/$0.40text->text
deepseek/deepseek-chat-v3-0324164K ctx · $0.27/$1.12text->text
deepseek/deepseek-r1164K ctx · $0.70/$2.50text->text
deepseek/deepseek-v3.1-terminus164K ctx · $0.27/$1.00text->text
deepseek/deepseek-r1-0528164K ctx · $0.50/$2.15text->text
deepseek/deepseek-r1-distill-llama-70b8K ctx · $0.80/$0.80text->text
deepseek/deepseek-chat-v3.1164K ctx · $0.25/$0.95text->text
deepseek/deepseek-chat164K ctx · $0.40/$1.30text->text
deepseek/deepseek-v3.2-exp164K ctx · $0.27/$0.41text->text
Moonshot AI
moonshotai/kimi-k31049K ctx · $3.00/$15.00text+image->text
moonshotai/kimi-k2.5262K ctx · $0.60/$3.00text+image->text
moonshotai/kimi-k2.7-code262K ctx · $0.95/$4.00text+image->text
moonshotai/kimi-k2.6262K ctx · $0.95/$4.00text+image->text
moonshotai/kimi-k2131K ctx · $0.57/$2.30text->text
moonshotai/kimi-k2-0905262K ctx · $0.60/$2.50text->text
moonshotai/kimi-k2-thinking262K ctx · $0.60/$2.50text->text
Perplexity
perplexity/sonar-pro200K ctx · $3.00/$15.00text+image->text
perplexity/sonar-pro-search200K ctx · $3.00/$15.00text+image->text
perplexity/sonar127K ctx · $1.00/$1.00text+image->text
perplexity/sonar-reasoning-pro128K ctx · $2.00/$8.00text+image->text
perplexity/sonar-deep-research128K ctx · $2.00/$8.00text->text
xAI
x-ai/grok-4.31000K ctx · $1.25/$2.50text+image+file->text
x-ai/grok-build-0.1256K ctx · $1.00/$2.00text+image+file->text
x-ai/grok-4.202000K ctx · $1.25/$2.50text+image+file->text
x-ai/grok-4.20-multi-agent2000K ctx · $1.25/$2.50text+image+file->text
x-ai/grok-4.5500K ctx · $2.00/$6.00text+image+file->text
MiniMax
minimax/minimax-m2.5205K ctx · $0.30/$1.20text->text
minimax/minimax-m31049K ctx · $0.30/$1.20text+image+video->text
minimax/minimax-m2.7205K ctx · $0.30/$1.20text->text
minimax/minimax-m2.1205K ctx · $0.30/$1.20text->text
Tencent
tencent/kinfra-text-embedding-4b · $0.08/$0.00
tencent/hy3 · $0.13/$0.53
tencent/hy-mt2-plus · $0.10/$0.40
tencent/kinfra-text-embedding-0.6b · $0.07/$0.00
bytedance-seed
bytedance-seed/seed-1.6262K ctx · $0.25/$2.00text+image+video->text
bytedance-seed/seed-2.0-mini262K ctx · $0.10/$0.40text+image+video->text
bytedance-seed/seed-2.0-lite262K ctx · $0.25/$2.00text+image+video->text
bytedance-seed/seed-1.6-flash262K ctx · $0.07/$0.30text+image+video->text
Nous
nousresearch/hermes-3-llama-3.1-70b131K ctx · $0.70/$0.70text->text
nousresearch/hermes-4-70b131K ctx · $0.13/$0.40text->text
nousresearch/hermes-4-405b131K ctx · $1.00/$3.00text->text
nousresearch/hermes-3-llama-3.1-405b131K ctx · $1.00/$1.00text->text
ByteDance
bytedance/seedance-2.0 · $0.00/$0.00text+image+audio+video->video
bytedance/seedance-2.0-fast · $0.00/$0.00text+image+audio+video->video
bytedance/seedance-1-5-pro · $0.00/$0.00text+image->video
Mistral
mistralai/mistral-large128K ctx · $2.00/$6.00text+file->text
mistralai/mixtral-8x22b-instruct66K ctx · $2.00/$6.00text+file->text
xiaomi
xiaomi/mimo-v2.51050K ctx · $0.14/$0.28text+image+audio+video->text
xiaomi/mimo-v2.5-pro1050K ctx · $0.43/$0.87text->text
NVIDIA
nvidia/nemotron-3-nano-30b-a3b262K ctx · $0.05/$0.20text->text
nvidia/nemotron-3-super-120b-a12b1000K ctx · $0.30/$0.90text->text
ibm-granite
ibm-granite/granite-4.0-h-micro131K ctx · $0.02/$0.11text->text
Meta
meta-llama/llama-3.2-1b-instruct60K ctx · $0.03/$0.20text->text
Tongyi-MAI
Tongyi-MAI/Z-Image-Turbotext->image

Browse all models on the Models page.

Streaming

Set stream: true to receive a Server-Sent Events (SSE) stream. Each event contains a chunk of the response.

from openai import OpenAI

client = OpenAI(
    base_url="https://bazaarlink.ai/api/v1",
    api_key="sk-bl-YOUR_API_KEY",
)

stream = client.chat.completions.create(
    model="anthropic/claude-sonnet-4.6",
    messages=[{"role": "user", "content": "Count to 10 slowly."}],
    stream=True,
)

for chunk in stream:
    content = chunk.choices[0].delta.content
    if content:
        print(content, end="", flush=True)

SSE Format

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Hello"},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":" world"},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{},"finish_reason":"stop","index":0}],"usage":{"prompt_tokens":10,"completion_tokens":4,"total_tokens":14}}

data: [DONE]
Usage in streaming
When streaming, usage data is returned in the final chunk before the [DONE] message, alongside a choices array with an empty delta and finish_reason: "stop".

Keep-alive & final chunk

Streams may contain SSE comment lines (starting with a colon) or heartbeat events as keep-alives — skip non-data: lines instead of JSON.parsing the raw stream. The final data chunk carries usage (token counts and cost) before data: [DONE]. Successful responses include an X-Request-Id header — include it when reporting issues.

: keepalive          <- SSE comment line — ignore, do NOT JSON.parse

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Hi"},"index":0}]}

data: {"id":"chatcmpl-abc","choices":[{"delta":{},"finish_reason":"stop","index":0}],"usage":{...}}

data: [DONE]

Stream Cancellation

Streaming requests can be cancelled by closing the client connection — e.g. calling AbortController.abort() or closing the stream object. BazaarLink stops relaying further chunks and cancels the outbound provider request as soon as the cancellation is received.

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://bazaarlink.ai/api/v1",
  apiKey: "sk-bl-YOUR_API_KEY",
});

const controller = new AbortController();

const stream = await client.chat.completions.create(
  {
    model: "anthropic/claude-sonnet-4.6",
    messages: [{ role: "user", content: "Write a long story." }],
    stream: true,
  },
  { signal: controller.signal }
);

for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content;
  if (content) process.stdout.write(content);
}

// e.g. on a "Stop" button click:
controller.abort();
No charge for an interrupted stream
If a stream ends before the final usage chunk arrives — including a client-side cancellation — there is no token-count ground truth for that request, so BazaarLink refunds the full reservation. You are not billed for content already delivered to your client before the cancellation.
Not guaranteed to stop the provider instantly
Closing the connection stops BazaarLink from relaying and paying for further tokens right away, but whether the upstream provider halts generation on its own servers the instant the connection drops depends on that provider — some may keep computing briefly after disconnect.

Mid-Stream Errors

No choices field on error frames
If a failure happens after streaming has already started (e.g. the upstream connection drops), you get an SSE data frame shaped {error:{message,type,code}} instead of the usual {choices:[...]} — with no HTTP status change, since headers were already sent. Check for an error key before reading choices[0].delta, and bill only for tokens already streamed (partial billing applies).
data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"The capital of "},"index":0}]}

data: {"error":{"message":"Upstream connection lost.","type":"upstream_error","code":502}}

data: [DONE]

Embeddings

Embeddings are numerical representations of text that capture semantic meaning — they convert text into vectors (arrays of numbers) usable for a range of machine learning tasks. BazaarLink provides a unified, OpenAI Embeddings API-compatible endpoint so you can call embedding models from multiple providers through one interface.

What are Embeddings?

Embeddings transform text into high-dimensional vectors where semantically similar texts sit closer together in vector space — for example, "cat" and "kitten" would have similar embeddings, while "cat" and "airplane" would be far apart. These vector representations let machines understand relationships between pieces of text, making them foundational to many AI applications.

Common Use Cases

Use Case
Description
RAG (Retrieval-Augmented Generation)Build systems that retrieve relevant context from a knowledge base before generating an answer — embeddings find the most relevant documents to include in the LLM's context.
Semantic SearchConvert documents and queries into embeddings, then find the most relevant documents by vector similarity — this understands meaning rather than just matching keywords, giving better results than keyword search alone.
Recommendation SystemsGenerate embeddings for items (products, articles, videos) and user preferences to recommend similar items — vector comparison surfaces semantically related items even without shared keywords.
Clustering & ClassificationGroup similar documents or classify text by analyzing embedding patterns — documents with similar embeddings usually belong to the same topic or category.
Duplicate DetectionFind duplicate or near-duplicate content by comparing embedding similarity — this works even when the content has been paraphrased or reworded.
Anomaly DetectionSpot unusual or outlier content by identifying embeddings that deviate significantly from the dataset's typical pattern.
POST/api/v1/embeddings
Note
Not all upstream providers support embeddings. If your configured provider does not support the requested model, BazaarLink will automatically failover to the next available provider.

Parameters

modelrequired
string
The embedding model to use, e.g. "openai/text-embedding-3-small".
inputrequired
string | string[] | ContentItem[]
Text to embed — a single string, an array of strings for one batch call, or (for models that support it) an array of {content:[...]} items mixing text and image_url parts.
dimensions
integer
Requested output vector size. Only honored by models that support variable dimensions (e.g. the OpenAI text-embedding-3 family); forwarded to the upstream provider as-is and ignored by models that don't support it.
encoding_format
string
Requested embedding encoding, e.g. "float" or "base64". Forwarded to the upstream provider as-is — support depends on the model.
provider
object
Provider routing preferences — order, allow_fallbacks, data_collection, and the other fields described in Provider Selection.

Basic Request

from openai import OpenAI

client = OpenAI(
    base_url="https://bazaarlink.ai/api/v1",
    api_key="sk-bl-YOUR_API_KEY",
)

response = client.embeddings.create(
    model="openai/text-embedding-3-small",
    input="The quick brown fox jumps over the lazy dog",
)

print(response.data[0].embedding)  # 1536-dimensional vector

Batch Processing

Send an array of strings to embed multiple texts in a single request — cheaper and faster than one call per text.

response = client.embeddings.create(
    model="openai/text-embedding-3-small",
    input=[
        "Machine learning is a subset of artificial intelligence",
        "Deep learning uses neural networks with multiple layers",
        "Natural language processing enables computers to understand text",
    ],
)

for i, item in enumerate(response.data):
    print(f"Embedding {i}: {len(item.embedding)} dimensions")

Multimodal Input (Image + Text)

Models with image input support (output_modalities includes "embeddings" and inputModalities includes "image") accept input items shaped as {content:[{type:"text",...}, {type:"image_url",...}]}, letting you embed an image alone or jointly with text.

Model-dependent
Only some embedding models accept image input — check a model's supported modalities on the Models page before sending image_url content. Text-only models will reject this shape.
import requests

response = requests.post(
    "https://bazaarlink.ai/api/v1/embeddings",
    headers={
        "Authorization": "Bearer sk-bl-YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "google/gemini-embedding-2-preview",
        "input": [{
            "content": [
                {"type": "text", "text": "A scenic boardwalk through a green meadow"},
                {"type": "image_url", "image_url": {"url": "https://example.com/boardwalk.jpg"}},
            ]
        }],
        "encoding_format": "float",
    },
)

embedding = response.json()["data"][0]["embedding"]
print(f"Embedding dimension: {len(embedding)}")

Provider Routing

Control which upstream serves an embedding request the same way as chat completions — see Provider Selection for the full field reference.

{
  "model": "openai/text-embedding-3-small",
  "input": "Your text here",
  "provider": {
    "order": ["openai"],
    "allow_fallbacks": true,
    "data_collection": "deny"
  }
}

Finding Embedding Models

There's no dedicated embeddings model-listing endpoint — call GET /api/v1/models and filter client-side for entries whose output_modalities includes "embeddings", or browse the Models page.

Limitations

  • No streaming — embeddings are always returned as a complete response, unlike chat completions.
  • Each model has a maximum input length; text beyond that limit is truncated or rejected upstream.
  • Embeddings for identical input are deterministic — no temperature or randomness involved.

Best Practices

  • Choose a model for your speed/quality/cost tradeoff — smaller models (e.g. qwen/qwen3-embedding-4b) are cheaper and faster; larger ones (e.g. openai/text-embedding-3-large) generally embed with higher fidelity.
  • Batch multiple texts into one request instead of one call per text — fewer round trips, lower overhead.
  • Cache results — embeddings for the same input never change, so store them rather than regenerating.
  • Compare with cosine similarity, not Euclidean distance — it's scale-invariant and works better for high-dimensional vectors.
  • Watch each model's context length — long documents may need chunking before embedding.

Parameters

Sampling parameters shape the token generation process. BazaarLink passes supported parameters to the upstream provider; unsupported parameters are silently ignored.

Sampling Parameters

Pure passthrough — no local defaults
These are forwarded to the upstream provider exactly as sent — BazaarLink never injects or enforces a default. "Default" below describes the provider's own behavior when a field is omitted, not a guarantee from BazaarLink.
temperature
number
Sampling temperature 0–2. Higher = more random. Default: 1
top_p
number
Nucleus sampling probability mass. Default: 1
top_k
integer
Limit token choices to top-K. 0 = disabled (consider all). Default: 0
frequency_penalty
number
Penalize repeated tokens. Range: [-2, 2]. Default: 0
presence_penalty
number
Penalize tokens based on presence. Range: [-2, 2]. Default: 0
repetition_penalty
number
Reduce token repetition from input. Range: (0, 2]. Default: 1
min_p
number
Minimum probability relative to the top token. Range: [0, 1]. Default: 0
top_a
number
Dynamic top-P based on highest-probability token. Range: [0, 1]. Default: 0
seed
integer
Integer seed for deterministic sampling. Not guaranteed for all models
max_tokens
integer
Maximum number of tokens to generate
n
integer
Number of completions to generate. Default: 1
logit_bias
object
Map token IDs to bias values [-100, 100] added before sampling. OpenAI-family models only — see note below.
logprobs
boolean
Return log probabilities of each output token. OpenAI-family models only — see note below.
top_logprobs
integer
Number of most-likely tokens to return per position (requires logprobs: true). Range: 0–20. OpenAI-family models only — see note below.
response_format
object
Force structured JSON output. See Structured Output section
structured_outputs
boolean
Request strict JSON-schema-conformant output on providers that support it. Passed through as-is
reasoning
object
Provider-specific reasoning/thinking configuration. Passed through as-is
reasoning_effort
string
OpenAI o-series style reasoning effort: "low", "medium", or "high". Passed through as-is
stop
string | string[]
Stop sequences — generation halts when encountered
tools
Tool[]
List of tools (functions) the model may call
tool_choice
string | object
Controls tool use: "auto", "none", or specific tool
parallel_tool_calls
boolean
Enable parallel function calling when tools are provided. Default: true. OpenAI-family models only — see note below.

BazaarLink-only Parameters

transforms
string[]
Message transforms to apply, e.g. ["middle-out"]. Omit to auto-apply on ≤8k-context models
models
string[]
Fallback model list — BazaarLink tries each in order if primary fails
route
string
Advanced routing compatibility field — most users don't need this. Use "models" for fallback.
provider
object
Advanced routing preferences — most users don't need this.

Credits

Query current credit balance and lifetime API usage.

GET/api/v1/credits
Auth
Requires Bearer token (standard API key sk-bl-...).

Example Request

curl https://bazaarlink.ai/api/v1/credits \
  -H "Authorization: Bearer sk-bl-YOUR_KEY"

Response

{
  "data": {
    "total_credits": 100.00,
    "total_usage": 12.34
  }
}

Errors: 401 (missing/invalid key), 403 (suspended user).

Generation Details

Retrieve detailed statistics for a single completion by generation ID (from chat/completions response id or streaming x-bz-gen-id header).

GET/api/v1/generation?id=<generation-id>
Auth
Requires Bearer token (standard API key). Required query param: id.

Example Request

curl "https://bazaarlink.ai/api/v1/generation?id=gen_abc123" \
  -H "Authorization: Bearer sk-bl-YOUR_KEY"

Response

{
  "data": {
    "id": "gen_xyz...",
    "model": "openai/gpt-4.1",
    "provider": "openai",
    "created_at": "2026-04-20T10:00:00.000Z",
    "app_name": "MyApp",
    "finish_reason": "stop",
    "status": 200,
    "duration_ms": 1234,
    "first_token_ms": 234,
    "throughput": 45.6,
    "usage": {
      "prompt_tokens": 100,
      "completion_tokens": 200,
      "total_tokens": 300,
      "prompt_tokens_details": { "cached_tokens": 50 },
      "completion_tokens_details": { "reasoning_tokens": 30 },
      "cost": 0.00123
    },
    "cost_breakdown": {
      "subtotal": 0.00123,
      "cache_discount": 0.00015,
      "total": 0.00108
    }
  }
}

Errors: 400 (missing id), 401 (auth), 404 (generation not found).

API Key Info

Query current API key's rate limit tier and aggregated usage counters (response format follows common industry key-info API conventions).

GET/api/v1/key
Auth
Requires Bearer token (standard API key).

Response

{
  "data": {
    "label": "Production Key",
    "limit": null,
    "limit_remaining": 100.00,
    "limit_reset": null,
    "expires_at": null,
    "is_free_tier": false,
    "is_management_key": false,
    "is_provisioning_key": false,
    "usage": 12.34,
    "usage_daily": 0.12,
    "usage_weekly": 0.45,
    "usage_monthly": 1.23,
    "requests": 1234,
    "requests_daily": 10,
    "requests_weekly": 50,
    "requests_monthly": 200,
    "rate_limit": { "requests": 600, "interval": "1m", "note": "Paid-tier rate limit." }
  }
}
Note
is_free_tier = true when credit balance < $10. Windows are in UTC: daily = current day, weekly = Mon–Sun, monthly = 1st–EOM. When the key has a per-key spend limit set (via the limit param on key creation/update), limit / limit_remaining / limit_reset reflect that limit and the matching period's usage; otherwise limit is null and limit_remaining falls back to your account credit balance. expires_at is the key's expiration time (null if none). is_management_key and is_provisioning_key are aliases for the same concept — both true for a management key.
BYOK
BazaarLink does not offer a bring-your-own-key (BYOK) program, so this endpoint does not return any byok_usage fields.

Errors: 401 (auth), 404 (user missing — rare).

Agent Registration

Self-service registration for AI agents (bots, autonomous systems). Returns an API key with trial credits and a claim token for account upgrade.

POST/api/v1/agents/register
Rate Limit
No authentication required, but IP-limited to 1 registration per 24 hours.

Request Body

namerequired
string
Agent name (non-empty, trimmed, max 100 chars).
description
string
Optional agent description.
referral_code
string
Optional referral code.

Example Request

curl -X POST https://bazaarlink.ai/api/v1/agents/register \
  -H "content-type: application/json" \
  -d '{
    "name": "My Agent",
    "description": "Autonomous research bot"
  }'

Response

{
  "api_key": "sk-bl-xxxxx...",
  "credits": 0.10,
  "credits_usd": "$0.1000",
  "claim_token": "abc...xyz",
  "claim_expires": "2026-04-27T10:00:00.000Z",
  "upgrade_url": "https://bazaarlink.ai/claim?token=...",
  "referral_code": "aBcDeFgH",
  "free_model": "auto:free",
  "message": "Welcome to BazaarLink!...",
  "referral_message": "Share referral link:...",
  "base_url": "https://bazaarlink.ai/api/v1",
  "docs": "https://bazaarlink.ai/llms.txt"
}

Errors: 400 (invalid body / missing name), 429 (rate limit — 1/IP/24h), 500 (internal).

Error Codes

Error response format

Model inference endpoints return an OpenAI-compatible error envelope. The type field may vary or be omitted on specialized endpoints; use the HTTP status and error.code for program logic instead of parsing the message.

{
  "error": {
    "message": "Insufficient credits. Please top up to continue.",
    "type": "invalid_request_error",
    "code": "insufficient_credits"
  }
}

HTTP status and error.code

Before streaming starts, the HTTP status identifies the broad failure class. error.code is either that numeric status or a stable string for failures that require a specific remedy. Prefer a string code when present, fall back to the HTTP status, and treat error.message as human-readable text.

Code
Name
Description
400Bad RequestMalformed request, empty messages array, or missing required fields
401UnauthorizedAPI key is missing, invalid, or disabled
402Payment RequiredInsufficient account credits, per-key spend limit reached, or monthly/weekly budget cap exceeded
403ForbiddenAccount is suspended or does not have permission
404Not FoundThe requested model, generation, key, or other resource does not exist
409ConflictThe resource is not in the required state, such as a video job that is not complete
410GoneThe requested model has been retired and must be replaced
413Payload Too LargeRequest body exceeds 10 MB; reduce content size or split the request
416Range Not SatisfiableThe requested byte range is invalid for generated video content
429Too Many RequestsRate limit exceeded; check Retry-After header before retrying
500Server ErrorInternal BazaarLink error
502Bad GatewayAll upstream providers failed; failover was attempted
503Service UnavailableNo upstream provider is configured for this model; contact admin
504Gateway TimeoutThe upstream connection or stream stalled and timed out

Machine-readable billing codes

A 402 response can represent different controls. These stable codes let clients show the correct next action.

Code
Description
budget_cap_reachedA weekly or monthly advisory budget cap was reached; raise or reset the cap.
credit_limit_exceededA monthly-billing organization's hard credit line was exhausted; contact billing.
insufficient_creditsA prepaid user or organization cannot reserve enough balance; add credits.
spend_limit_exceededThe API key reached its configured daily, weekly, or monthly spend limit.

Detailed error codes

When an API request fails, error.code tells you the specific reason. Two errors can both use HTTP 400 but require different fixes: unknown_model means the model name is wrong, while image_too_large means the image must be reduced. Use the table below to find the cause and next action.

Model and endpoint
Model lookup, lifecycle, pricing, modality, and endpoint compatibility errors.
Code
HTTP status
unknown_model400
invalid_model_id400
model_not_found404
model_retired410
model_endpoint_mismatch400
embedding_on_chat_endpoint400
model_not_priced400
invalid_modality_for_model400
Request and safety
Invalid parameters, context, tools, schemas, and content-safety refusals.
Code
HTTP status
missing_required_field400
unsupported_param400
max_tokens_invalid400
context_too_long400
tool_use_unsupported400
malformed_tool_messages400
invalid_response_format_schema400
invalid_tools_definition400
content_moderation403
content_filter403
unknown_4xx400
Image generation and editing
Image input, multipart editing, output, and image-pipeline errors.
Code
HTTP status
invalid_image_url400
input_images_not_supported400
invalid_content_type400
mask_not_supported400
unsupported_response_format400
missing_prompt400
missing_image400
too_many_images400
invalid_image_type400
image_too_large400
invalid_n400
pipeline_error502
no_images502
Upstream routing
Sanitized provider connectivity, authentication, throttling, and availability errors.
Code
HTTP status
upstream_unreachable502
upstream_auth_failed502
upstream_rate_limited429
upstream_unavailable502/503

Rate limits, budgets, and emergency brakes

These controls can reject an otherwise valid request. They are separate from provider failures and require different recovery actions.

Control
HTTP status
How to identify it
Request rate limit429Numeric code 429; use Retry-After and X-RateLimit-* headers.
Rate-limit penalty block429Numeric code 429 and a temporary restriction message; use Retry-After.
Global spend emergency brake503Numeric code 503, global spend-limit message, and Retry-After of 30 or 300 seconds.
Org/team/member/user spend brake429Numeric code 429 and a spend circuit-breaker message naming the affected scope.
Billing and budget controls402Use the stable billing string codes listed above.

Compatibility note: rate-limit and emergency-brake paths currently emit numeric error.code values. Do not assume undocumented string codes. Use HTTP status, Retry-After, and the documented response message until a stable string code is introduced.

Video and media resource state

Video validation commonly returns numeric code 400. A missing job returns 404, a retired model returns 410, unfinished video content returns 409, and an invalid video byte range returns 416. Poll until completion or correct the Range header before retrying.

Retry policy

Retry only failures that may recover without changing the request. When Retry-After is present, wait that long; otherwise use exponential backoff with jitter. Limit attempts and avoid layering manual retries on top of SDK automatic retries.

Retry with backoff
429, 502, 503, and 504. Respect Retry-After when provided. For generation requests, do not create a second job after an ambiguous network failure until you have checked the original job.
Fix before retrying
400, 401, 402, 403, 404, 409, 410, 413, and 416. Change the request, credentials, balance, permissions, resource state, or Range header first.

Handling Errors

import random
import time
from openai import OpenAI, APIStatusError

client = OpenAI(
    base_url="https://bazaarlink.ai/api/v1",
    api_key="sk-bl-YOUR_API_KEY",
    max_retries=0,  # Avoid double retries; this example handles them.
)

RETRYABLE = {429, 502, 503, 504}

for attempt in range(5):
    try:
        response = client.chat.completions.create(
            model="openai/gpt-4.1",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        break
    except APIStatusError as error:
        if error.status_code not in RETRYABLE or attempt == 4:
            raise
        retry_after = error.response.headers.get("Retry-After")
        delay = (
            float(retry_after)
            if retry_after
            else min(8, 0.5 * (2 ** attempt)) + random.uniform(0, 0.25)
        )
        time.sleep(delay)

Streaming Error Formats

Errors that occur before any tokens are streamed return a standard HTTP error response with a JSON body.

After a stream has started, the HTTP response is already 200. Parse every SSE data frame and treat a top-level error or choices[0].finish_reason === "error" as a failed, incomplete response.

If the stream fails mid-flight, BazaarLink emits a final SSE event with a top-level error object followed by data: [DONE]. Chunks relayed verbatim from some upstreams may instead carry the error on the choice (choices[0].finish_reason === "error") — handle both.

// If the stream fails mid-flight, BazaarLink emits a final SSE event
// with a top-level "error" object, followed by data: [DONE]
data: {"error":{"message":"Upstream stream interrupted. The response is incomplete.","type":"upstream_error","code":502}}

data: [DONE]

// Chunks relayed verbatim from some upstreams may instead carry the error
// inline on the choice: choices[0].finish_reason === "error" with an
// "error" object ({ code, message }) on the choice — handle both shapes.
// Branch on error.code; error.type can vary by failure path.

Versioning

BazaarLink exposes a single stable API path, /api/v1 — there are no date-pinned versions or version headers to manage. The API evolves continuously rather than through numbered releases.

Non-Breaking Changes

These ship without prior notice:

  • New endpoints
  • New models added to the catalog
  • New optional request parameters
  • New response fields
  • New schemas with optional properties
  • Additional response status/error codes
Write clients defensively
Ignore response fields you don't recognize, and don't fail on unknown values in enum-like fields — new ones are added as the catalog and feature set grow.

Breaking Changes

These are rare, and cover:

  • Removing or renaming an endpoint, parameter, or response field
  • Changing a field's type
  • Making an optional parameter required

When they do happen, a breaking change applies to a specific endpoint rather than the whole /api/v1 surface — there's no single version bump that could break every integration at once. We don't yet publish a formal changelog with a Breaking-change tag (see Staying Current below); for anything integration-critical, reach out via Support before you rely on undocumented behavior.

Deprecation Policy

The one routine "breaking" event you should expect: individual models get retired as upstream providers deprecate them. Query a model's current status via GET /api/v1/models.

GET https://bazaarlink.ai/api/v1/models
Authorization: Bearer sk-bl-YOUR_API_KEY

# A model within 30 days of its deprecation date shows in the catalog
# with an "EOL" badge on the Models page. After the effective date it's
# dropped from the catalog and calls return:
# 410 { "error": { "type": "model_not_available", "code": "model_retired" } }

Staying Current

We don't yet publish a dedicated API changelog or RSS feed. For now, check this page directly, watch a model's status via GET /api/v1/models, or contact Support if you need advance notice for a critical integration.

Support
Support
Hi! How can we help you?
Send a message and we'll get back to you soon.
API Reference | Chat, Embeddings & Model Routing