Last verified: July 20, 2026
A Python backend can call GPT, Claude, and Gemini through one OpenAI-compatible LumeAPI client. The base URL, API key, and USD wallet remain the same; the application selects an exact model ID for each request. This removes duplicate provider clients and billing integrations while keeping model choice explicit and auditable.
The same LumeAPI account also covers listed image and video models. Those modalities can require different parameters or asynchronous job flows, so 'one platform' should not be mistaken for one identical request schema across every modality.
Current example models and rates
The following model IDs and USD rates were listed by LumeAPI on July 20, 2026, per 1 million input/output tokens:
| Family | Model ID | LumeAPI input / output | Page reference input / output | Displayed difference |
|---|---|---|---|---|
| GPT | gpt-5.4-mini | $0.225 / $1.35 | $0.75 / $4.50 | 70% lower |
| Claude | claude-sonnet-4-6 | $1.80 / $9.00 | $3.00 / $15.00 | 40% lower |
| Gemini | gemini-3.5-flash | $0.90 / $5.40 | $1.50 / $9.00 | 40% lower |
These examples show why 'discounts up to 70%' must be stated carefully. The GPT example reaches 70% against its displayed reference; the Claude and Gemini examples show 40%. Always verify the current model catalog and AI API pricing.
Install and configure one client
python -m pip install --upgrade openaiSet one LumeAPI key:
export LUMEAPI_KEY='your-lumeapi-key'Create multi_model.py:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ['LUMEAPI_KEY'],
base_url='https://api.lumeapi.site/v1',
timeout=30.0,
max_retries=2,
)
MODELS = {
'gpt': 'gpt-5.4-mini',
'claude': 'claude-sonnet-4-6',
'gemini': 'gemini-3.5-flash',
}
def generate(prompt: str, family: str) -> str:
try:
model = MODELS[family]
except KeyError as exc:
raise ValueError(f'Unsupported model family: {family}') from exc
response = client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': prompt}],
)
return response.choices[0].message.content or ''
print(generate('Give me three names for an API monitoring service.', 'gpt'))Changing family changes the model, not the client, key, base URL, or response access path.
Call all three model families
A simple evaluation loop can send the same task to each model:
import time
prompt = 'Classify this support ticket as billing, technical, or account: card charged twice.'
for family, model in MODELS.items():
started = time.perf_counter()
response = client.chat.completions.create(
model=model,
messages=[
{'role': 'system', 'content': 'Return one category only.'},
{'role': 'user', 'content': prompt},
],
)
latency_ms = round((time.perf_counter() - started) * 1000)
print({
'family': family,
'model': model,
'latency_ms': latency_ms,
'input_tokens': response.usage.prompt_tokens if response.usage else None,
'output_tokens': response.usage.completion_tokens if response.usage else None,
'text': response.choices[0].message.content,
})This is an integration test, not enough evidence to name a winner. Use a representative dataset and score task success, format validity, latency, errors, and cost. LumeAPI call logs can then be used to review the gateway-side model, tokens, cost, and latency for each request.
Centralize model policy
Do not let every feature choose arbitrary model strings. Define a model allowlist and map product tasks to internal aliases:
TASK_MODELS = {
'short_reply': 'gpt-5.4-mini',
'careful_review': 'claude-sonnet-4-6',
'fast_interactive': 'gemini-3.5-flash',
}
def generate_for_task(task: str, prompt: str) -> str:
try:
model = TASK_MODELS[task]
except KeyError as exc:
raise ValueError(f'Unknown task: {task}') from exc
response = client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': prompt}],
)
return response.choices[0].message.content or ''The mapping is an application policy, not a universal claim that one family is always best for that task. Update it only after evaluating your own data. A server-side allowlist also prevents user input from selecting an unapproved or unexpectedly expensive model.
Estimate cost before sending traffic
Store dated rates next to their verification date:
RATES = {
'gpt-5.4-mini': {'input': 0.225, 'output': 1.35},
'claude-sonnet-4-6': {'input': 1.80, 'output': 9.00},
'gemini-3.5-flash': {'input': 0.90, 'output': 5.40},
}
def estimate_cost(model: str, input_tokens: int, output_tokens: int) -> float:
rates = RATES[model]
return (
input_tokens / 1_000_000 * rates['input']
+ output_tokens / 1_000_000 * rates['output']
)
for model in MODELS.values():
print(model, f'${estimate_cost(model, 2000, 500):.6f}')With 2,000 input and 500 output tokens, this table produces estimates of $0.001125 for GPT-5.4 mini, $0.008100 for Claude Sonnet 4.6, and $0.004500 for Gemini 3.5 Flash. That is not a quality ranking. The cheapest failed task is still wasted spend, and a more expensive model may reduce retries or escalation.
Rates change. Keep the verification date, update the table from the live catalog, and use actual wallet/call-log data for billing reconciliation.
Add application logs without exposing prompts
Record operational metadata, not secrets or sensitive content:
import json
import time
def generate_with_log(task: str, prompt: str) -> str:
model = TASK_MODELS[task]
started = time.perf_counter()
response = client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': prompt}],
)
latency_ms = round((time.perf_counter() - started) * 1000)
record = {
'task': task,
'model': model,
'latency_ms': latency_ms,
'input_tokens': response.usage.prompt_tokens if response.usage else None,
'output_tokens': response.usage.completion_tokens if response.usage else None,
'request_id': getattr(response, '_request_id', None),
}
print(json.dumps(record))
return response.choices[0].message.content or ''Use these application logs together with LumeAPI's per-call logs. Avoid logging API keys, authorization headers, full prompts, model output, or user data unless a documented policy permits it.
Implement a bounded fallback
Fallback should be explicit and limited. Retry only failures that another model can reasonably recover from, and never repeat an external side effect without idempotency.
import openai
FALLBACKS = {
'gpt-5.4-mini': 'gemini-3.5-flash',
'gemini-3.5-flash': 'gpt-5.4-mini',
}
def generate_with_fallback(prompt: str, primary: str) -> str:
models = [primary]
if primary in FALLBACKS:
models.append(FALLBACKS[primary])
last_error = None
for model in models:
try:
response = client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': prompt}],
)
return response.choices[0].message.content or ''
except (openai.RateLimitError, openai.APITimeoutError) as exc:
last_error = exc
raise RuntimeError('Primary and fallback models failed.') from last_errorThis example shows application-controlled fallback for a read-only generation task. It does not claim that LumeAPI automatically chooses the best model. For a fuller policy, read routing GPT, Claude, and Gemini and the LLM API gateway page.
When one API shape is not enough
A shared Chat Completions shape reduces integration work, but models still differ in behavior and supported features. Test:
- prompt and system-instruction behavior;
- streaming event handling;
- tool-call schemas and loop termination;
- structured output validation;
- context and output limits;
- error bodies and retry rules;
- latency and cost under realistic concurrency.
Image and video models also belong to the LumeAPI account and wallet, but generation parameters, media inputs, output retrieval, and async status polling can differ. Use their model documentation rather than forcing them through a text-only abstraction.
Common multi-model mistakes
One model ID is used for every task
Make the choice explicit in TASK_MODELS and review it with evaluation data.
Model names come from user input
Use a server-side allowlist. Otherwise a caller may select unavailable, untested, or expensive models.
Costs are compared without output length
Input and output rates differ. Include both, plus retries and validation failures.
Fallback repeats a side effect
Use idempotency and durable workflow state for email, payment, order, or write tools. The fallback example above is for read-only text generation.
The team cannot identify which model answered
Log the exact model on every request and review LumeAPI's call logs. A unified endpoint should improve observability, not hide routing decisions.
Why this architecture matches LumeAPI
LumeAPI's strongest fit is operational consolidation: one key, one endpoint for compatible text calls, one USD wallet, and one place to review request model, tokens, cost, and latency across mainstream model families. Supported GPT rates on the site can be up to 70% below their displayed references, while the Claude and Gemini examples above show 40%.
That same account can extend from LLM text calls to listed image and video generation without opening another platform account. Keep modality-specific interfaces and limitations visible, and link every application feature to the relevant model docs.
Sources and verification
- LumeAPI multi-model API, model catalog, and AI API pricing for the shared gateway, current IDs, rates, wallet, and logs.
- GPT-5.4 mini docs, Claude Sonnet 4.6 docs, and Gemini 3.5 Flash docs for model-specific values verified July 20, 2026.
- Official OpenAI Python library for custom client configuration, Chat Completions, usage, errors, and request IDs.
All Python blocks were syntax-checked on July 20, 2026. No customer inference key was used, so this guide does not claim observed model quality, latency, or automatic intelligent routing.