SDK Usage
BVE Gateway supports multiple official SDKs. Each requires only a baseURL override to point at api.bve.me — no provider-specific API key is needed. The one difference is the Anthropic SDK: use https://api.bve.me (without /v1) because the SDK appends /v1/messages automatically.
| SDK / Provider | Auth header sent | baseURL to set |
|---|---|---|
| OpenAI TypeScript/Python | Authorization: Bearer | https://api.bve.me/v1 |
| Anthropic TypeScript/Python | x-api-key | https://api.bve.me |
| Groq TypeScript/Python | Authorization: Bearer | https://api.bve.me/v1 |
| Cohere models (use OpenAI SDK) | Authorization: Bearer | https://api.bve.me/v1 |
| Gemini models (use OpenAI SDK) | Authorization: Bearer | https://api.bve.me/v1 |
| Mistral / Llama models (use OpenAI SDK) | Authorization: Bearer | https://api.bve.me/v1 |
OpenAI SDK
Section titled “OpenAI SDK”Install:
bun add openai# or: npm install openaipip install openaiChat completions
Section titled “Chat completions”import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'sk-bve-YOUR_KEY', baseURL: 'https://api.bve.me/v1',});
const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'What is 2 + 2?' }, ],});
console.log(response.choices[0].message.content);from openai import OpenAI
client = OpenAI( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me/v1",)
response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is 2 + 2?"}, ],)
print(response.choices[0].message.content)Streaming
Section titled “Streaming”const stream = await client.chat.completions.stream({ model: 'gpt-4o', messages: [{ role: 'user', content: 'Count from 1 to 5.' }],});
for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '');}with client.chat.completions.stream( model="gpt-4o", messages=[{"role": "user", "content": "Count from 1 to 5."}],) as stream: for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)Embeddings
Section titled “Embeddings”const response = await client.embeddings.create({ model: 'text-embedding-3-small', input: 'The quick brown fox',});
console.log(response.data[0].embedding);response = client.embeddings.create( model="text-embedding-3-small", input="The quick brown fox",)
print(response.data[0].embedding[:5])List models
Section titled “List models”const models = await client.models.list();for (const model of models.data) { console.log(model.id);}models = client.models.list()for model in models.data: print(model.id)Error handling
Section titled “Error handling”try { const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: 'Hello' }], });} catch (err) { if (err instanceof OpenAI.APIError) { console.error(err.status, err.message); // err.error?.code for the machine-readable code (e.g. 'rate_limit_exceeded') }}from openai import APIError
try: response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Hello"}], )except APIError as e: print(e.status_code, e.message) # e.code for machine-readable code (e.g. 'rate_limit_exceeded')Function calling (tool use)
Section titled “Function calling (tool use)”Use tools and tool_choice to let the model invoke functions:
const tools: OpenAI.ChatCompletionTool[] = [ { type: 'function', function: { name: 'get_weather', description: 'Get the current weather for a city', parameters: { type: 'object', properties: { city: { type: 'string', description: 'City name' }, }, required: ['city'], }, }, },];
const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: "What's the weather in Tokyo?" }], tools, tool_choice: 'auto',});
const choice = response.choices[0];if (choice.finish_reason === 'tool_calls') { const call = choice.message.tool_calls![0]; const args = JSON.parse(call.function.arguments); console.log('Function to call:', call.function.name, 'Args:', args); // { city: 'Tokyo' }}tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Get the current weather for a city", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "City name"}, }, "required": ["city"], }, }, }]
response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "What's the weather in Tokyo?"}], tools=tools, tool_choice="auto",)
choice = response.choices[0]if choice.finish_reason == "tool_calls": call = choice.message.tool_calls[0] import json args = json.loads(call.function.arguments) print("Function:", call.function.name, "Args:", args) # {'city': 'Tokyo'}Structured output (JSON mode)
Section titled “Structured output (JSON mode)”Force the model to return valid JSON using response_format:
// JSON object modeconst response = await client.chat.completions.create({ model: 'gpt-4o', messages: [ { role: 'user', content: 'Return the capitals of France, Germany, and Japan as JSON.', }, ], response_format: { type: 'json_object' },});
const data = JSON.parse(response.choices[0].message.content!);console.log(data);// { france: 'Paris', germany: 'Berlin', japan: 'Tokyo' }For strict schema validation, use json_schema:
const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [{ role: 'user', content: 'What is 2 + 2? Return as JSON.' }], response_format: { type: 'json_schema', json_schema: { name: 'math_result', strict: true, schema: { type: 'object', properties: { answer: { type: 'integer' } }, required: ['answer'], additionalProperties: false, }, }, },});
const result = JSON.parse(response.choices[0].message.content!);console.log(result.answer); // 4response = client.chat.completions.create( model="gpt-4o", messages=[ { "role": "user", "content": "Return the capitals of France, Germany, and Japan as JSON.", } ], response_format={"type": "json_object"},)
import jsondata = json.loads(response.choices[0].message.content)print(data)Retry with backoff on 429
Section titled “Retry with backoff on 429”When a rate limit is hit, use the Retry-After header to wait before retrying:
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.BVE_API_KEY, baseURL: 'https://api.bve.me/v1', maxRetries: 0, // disable SDK auto-retry; handle manually});
async function chatWithRetry( model: string, messages: OpenAI.ChatCompletionMessageParam[], maxAttempts = 3,) { for (let attempt = 0; attempt < maxAttempts; attempt++) { try { return await client.chat.completions.create({ model, messages }); } catch (err) { if (err instanceof OpenAI.RateLimitError && attempt < maxAttempts - 1) { const retryAfter = Number(err.headers?.['retry-after'] ?? 5); console.warn(`Rate limited. Retrying in ${retryAfter}s…`); await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)); continue; } throw err; } }}import osimport timefrom openai import OpenAI, RateLimitError
client = OpenAI( api_key=os.environ["BVE_API_KEY"], base_url="https://api.bve.me/v1", max_retries=0, # handle retries manually)
def chat_with_retry(model, messages, max_attempts=3): for attempt in range(max_attempts): try: return client.chat.completions.create(model=model, messages=messages) except RateLimitError as e: if attempt < max_attempts - 1: retry_after = int(e.response.headers.get("retry-after", 5)) print(f"Rate limited. Retrying in {retry_after}s…") time.sleep(retry_after) else: raiseEnvironment variable pattern
Section titled “Environment variable pattern”Avoid hardcoding keys. Use environment variables:
const client = new OpenAI({ apiKey: process.env.BVE_API_KEY, baseURL: 'https://api.bve.me/v1',});import os
client = OpenAI( api_key=os.environ["BVE_API_KEY"], base_url="https://api.bve.me/v1",)Anthropic SDK
Section titled “Anthropic SDK”BVE Gateway accepts the x-api-key header that the Anthropic SDK sends by default. Set baseURL to https://api.bve.me — the SDK appends /v1/messages automatically.
Install:
bun add @anthropic-ai/sdk# or: npm install @anthropic-ai/sdkpip install anthropicChat (Messages API)
Section titled “Chat (Messages API)”import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: 'sk-bve-YOUR_KEY', // sent as x-api-key, accepted by BVE Gateway baseURL: 'https://api.bve.me',});
const message = await client.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, messages: [ { role: 'user', content: 'Explain quantum entanglement in one paragraph.' }, ],});
console.log(message.content[0].text);import anthropic
client = anthropic.Anthropic( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me",)
message = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, messages=[ {"role": "user", "content": "Explain quantum entanglement in one paragraph."} ],)
print(message.content[0].text)Streaming
Section titled “Streaming”const stream = await client.messages.stream({ model: 'claude-sonnet-4-6', max_tokens: 512, messages: [{ role: 'user', content: 'Write a haiku about autumn.' }],});
for await (const event of stream) { if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') { process.stdout.write(event.delta.text); }}with client.messages.stream( model="claude-sonnet-4-6", max_tokens=512, messages=[{"role": "user", "content": "Write a haiku about autumn."}],) as stream: for text in stream.text_stream: print(text, end="", flush=True)Groq SDK
Section titled “Groq SDK”The Groq SDK is OpenAI-compatible and sends Authorization: Bearer headers. Set baseURL to https://api.bve.me/v1.
Install:
bun add groq-sdk# or: npm install groq-sdkpip install groqChat completions
Section titled “Chat completions”import Groq from 'groq-sdk';
const client = new Groq({ apiKey: 'sk-bve-YOUR_KEY', baseURL: 'https://api.bve.me/v1',});
const response = await client.chat.completions.create({ model: 'llama-4-maverick-17b-128e', messages: [ { role: 'user', content: 'What is the capital of France?' }, ],});
console.log(response.choices[0].message.content);from groq import Groq
client = Groq( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me/v1",)
response = client.chat.completions.create( model="llama-4-maverick-17b-128e", messages=[ {"role": "user", "content": "What is the capital of France?"} ],)
print(response.choices[0].message.content)Streaming
Section titled “Streaming”const stream = await client.chat.completions.create({ model: 'llama-4-maverick-17b-128e', messages: [{ role: 'user', content: 'List 5 programming languages.' }], stream: true,});
for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '');}stream = client.chat.completions.create( model="llama-4-maverick-17b-128e", messages=[{"role": "user", "content": "List 5 programming languages."}], stream=True,)
for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)Cohere models
Section titled “Cohere models”Cohere’s command-r family is accessible via the OpenAI SDK — just swap in the Cohere model ID. No Cohere SDK or Cohere API key is needed; your BVE Gateway key handles authentication.
Supported Cohere model IDs:
| Model | ID |
|---|---|
| Command A (Mar 2025) | command-a-03-2025 |
| Command R+ | command-r-plus |
| Command R+ (Aug 2024) | command-r-plus-08-2024 |
| Command R | command-r |
| Command R (Aug 2024) | command-r-08-2024 |
| Command R7B (Dec 2024) | command-r7b-12-2024 |
Chat completions
Section titled “Chat completions”import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'sk-bve-YOUR_KEY', baseURL: 'https://api.bve.me/v1',});
const response = await client.chat.completions.create({ model: 'command-r-plus', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Summarize the water cycle in two sentences.' }, ],});
console.log(response.choices[0].message.content);from openai import OpenAI
client = OpenAI( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me/v1",)
response = client.chat.completions.create( model="command-r-plus", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Summarize the water cycle in two sentences."}, ],)
print(response.choices[0].message.content)Streaming
Section titled “Streaming”const stream = await client.chat.completions.stream({ model: 'command-r7b-12-2024', messages: [{ role: 'user', content: 'List 3 fun facts about penguins.' }],});
for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '');}stream = client.chat.completions.create( model="command-r7b-12-2024", messages=[{"role": "user", "content": "List 3 fun facts about penguins."}], stream=True,)
for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)Gemini models
Section titled “Gemini models”Google’s Gemini models are accessible via the OpenAI SDK — use the model ID directly. No Google SDK or Google API key is needed; your BVE Gateway key handles authentication.
Supported Gemini models available via BVE Gateway (select examples — see Models for the full list):
| Model | ID |
|---|---|
| Gemini 2.5 Flash | gemini-2.5-flash |
| Gemini 2.5 Pro | gemini-2.5-pro |
| Gemini 3 Flash | gemini-3-flash |
| Gemini 3.1 Pro | gemini-3.1-pro |
| Gemini 3.5 Flash | gemini-3.5-flash |
Chat completions
Section titled “Chat completions”import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'sk-bve-YOUR_KEY', baseURL: 'https://api.bve.me/v1',});
const response = await client.chat.completions.create({ model: 'gemini-2.5-flash', messages: [ { role: 'user', content: 'Explain the Transformer architecture in one paragraph.' }, ],});
console.log(response.choices[0].message.content);from openai import OpenAI
client = OpenAI( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me/v1",)
response = client.chat.completions.create( model="gemini-2.5-flash", messages=[ {"role": "user", "content": "Explain the Transformer architecture in one paragraph."} ],)
print(response.choices[0].message.content)curl https://api.bve.me/v1/chat/completions \ -H "Authorization: Bearer sk-bve-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-2.5-flash", "messages": [{"role": "user", "content": "Explain the Transformer architecture in one paragraph."}] }'Streaming
Section titled “Streaming”const stream = await client.chat.completions.stream({ model: 'gemini-2.5-flash', messages: [{ role: 'user', content: 'Write a short poem about the moon.' }],});
for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '');}stream = client.chat.completions.create( model="gemini-2.5-flash", messages=[{"role": "user", "content": "Write a short poem about the moon."}], stream=True,)
for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)Mistral and Llama models
Section titled “Mistral and Llama models”Mistral and Meta’s Llama models are accessible via the OpenAI SDK with no additional SDK or provider key. Use their model IDs directly with the same client setup.
| Provider | Model | ID |
|---|---|---|
| Mistral | Mistral Large | mistral-large-24.02 |
| Mistral | Mixtral 8x7B | mixtral-8x7b-32768 |
| Meta (via Groq) | Llama 4 Maverick | llama-4-maverick-17b-128e |
| Meta (via Groq) | Llama 4 Scout | llama-4-scout-17b-16e |
| Meta (via Groq) | Llama 3.3 70B | llama-3.3-70b-versatile |
| Meta (via Groq) | Llama 3.1 70B | llama-3.1-70b-versatile |
Chat completions
Section titled “Chat completions”import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'sk-bve-YOUR_KEY', baseURL: 'https://api.bve.me/v1',});
// Mistralconst mistralResponse = await client.chat.completions.create({ model: 'mistral-large-24.02', messages: [{ role: 'user', content: 'What is mixture-of-experts architecture?' }],});console.log(mistralResponse.choices[0].message.content);
// Llamaconst llamaResponse = await client.chat.completions.create({ model: 'llama-4-maverick-17b-128e', messages: [{ role: 'user', content: 'Describe attention mechanisms in LLMs.' }],});console.log(llamaResponse.choices[0].message.content);from openai import OpenAI
client = OpenAI( api_key="sk-bve-YOUR_KEY", base_url="https://api.bve.me/v1",)
# Mistralresponse = client.chat.completions.create( model="mistral-large-24.02", messages=[{"role": "user", "content": "What is mixture-of-experts architecture?"}],)print(response.choices[0].message.content)
# Llamaresponse = client.chat.completions.create( model="llama-4-maverick-17b-128e", messages=[{"role": "user", "content": "Describe attention mechanisms in LLMs."}],)print(response.choices[0].message.content)# Mistralcurl https://api.bve.me/v1/chat/completions \ -H "Authorization: Bearer sk-bve-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"mistral-large-24.02","messages":[{"role":"user","content":"What is mixture-of-experts?"}]}'
# Llamacurl https://api.bve.me/v1/chat/completions \ -H "Authorization: Bearer sk-bve-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"llama-4-maverick-17b-128e","messages":[{"role":"user","content":"Describe attention mechanisms."}]}'