Python SDK

veqen for Python. Wrap OpenAI, Anthropic, Google and any OpenAI-compatible client, for text, embeddings, images and audio; tag calls, set budgets, record any call by hand and price models offline.

pip install veqen

Python 3.10+, no dependencies. Source: github.com/Keyveve/veqen-sdks, MIT licensed.

Configure

import veqen

veqen.init()  # optional: the first wrapped call configures from the environment
Argument Environment variable Default
api_key VEQEN_API_KEY none: price locally, send nothing
endpoint VEQEN_ENDPOINT https://veqen-app.com
environment VEQEN_ENVIRONMENT none (sets the environment tag)
ledger_file VEQEN_LEDGER_FILE none (JSON lines, one per call)
flush_interval 2.0 seconds between background sends
budget_poll 30.0 seconds between cloud budget refreshes

Wrap a client

from anthropic import Anthropic
from google import genai
from openai import AsyncOpenAI, OpenAI

openai_client = veqen.wrap(OpenAI(), feature="search")
async_client = veqen.wrap(AsyncOpenAI())
claude = veqen.wrap(Anthropic(), residency="us")      # US-only processing is priced at 1.1x
gemini = veqen.wrap(genai.Client())

Keyword arguments to wrap() become default tags for every call through that client. The wrapper instruments:

Client Methods
OpenAI, Azure OpenAI and every OpenAI-compatible API chat.completions.create and .stream, responses.create and .stream, embeddings.create, images.generate, images.edit, audio.speech.create, audio.transcriptions.create, audio.translations.create
Anthropic messages.create, messages.stream, beta.messages.create
Google GenAI models.generate_content, models.generate_content_stream, and the aio versions

Image calls are priced per image at the requested size and quality (or by image tokens, when reported), speech by characters, and transcription by seconds of audio or tokens.

An OpenAI client pointed at another provider is priced as that provider, read from its base URL: Together, Fireworks, Groq, DeepInfra, Cerebras, Azure AI Foundry and the rest of the price book's hosts. For your own server, name the provider:

together = veqen.wrap(OpenAI(base_url="https://api.together.xyz/v1", api_key=...), project="research")
local = veqen.wrap(OpenAI(base_url="http://vllm.internal:8000/v1"), provider="self-hosted")

Everything else on the client passes straight through. Streams are priced when they finish; for OpenAI chat streams, the wrapper turns on stream_options.include_usage so the provider reports usage. Calls whose response carries no usage aren't recorded.

Tag calls

with veqen.tags(customer=org.id, user=user.id):
    answer = openai_client.responses.create(model="gpt-5-mini", input=question)

Tags nest, and they follow asyncio tasks and asyncio.to_thread calls started inside the block (they live in a ContextVar). Threads you start yourself don't inherit them: set tags inside the thread. See Tags.

Budgets

veqen.budget(5.00, customer="*")              # every customer: $5 a month, then BudgetExceeded
veqen.budget(200, feature="agent", period="day", mode="warn")
veqen.budget(1_000, project="eval-harness")       # scopes: customer, feature, user, project

try:
    openai_client.responses.create(...)
except veqen.BudgetExceeded as exc:
    print(exc.scope, exc.value, exc.limit_usd)

Local budgets count spend in this process. Budgets created in the dashboard are shared by every process using your key; the SDK refreshes them every 30 seconds and enforces them the same way. See Budgets.

Record a call by hand

For calls the wrapper can't see (batch results, gateways, other languages):

veqen.record(
    "claude-sonnet-4-5",
    provider="anthropic",
    input_tokens=1200, output_tokens=300, cache_read_tokens=8000,
    batch=True,
    customer="acme", feature="nightly-summary",
)

Models billed per unit take units (images, seconds of audio or video, characters, queries or pages) and, for images and video, the variant:

veqen.record("veo-3.1-generate-001", provider="google", units=8, variant="1080p", project="ads")
veqen.record("flux-pro-1.1", provider="bfl", units=4, feature="catalog")
veqen.record("nova-3", provider="deepgram", units=1800, project="call-analytics")   # 30 minutes

Pass cost_usd= for a model the price book doesn't know, or for a call that reports a cost but no usage (fal and Replicate jobs often do); it's kept as reported. Prices for your own models go in custom prices.

Price without recording

veqen.cost("gpt-4o", 1000, 500)                        # 0.0075
veqen.cost("gpt-image-1", units=1, variant="high/1024x1024")
veqen.cost("whisper-1", units=600)                       # ten minutes of audio
veqen.cost("claude-sonnet-4-5", 2000, 400, cache_read_tokens=10_000, residency="us")
price = veqen.lookup("us.anthropic.claude-sonnet-4-5-20250929-v1:0")   # Bedrock ids resolve too
price.rates["standard"], price.retires

Serverless and shutdown

Events are sent every two seconds and at interpreter exit. In AWS Lambda, Cloud Functions or similar, call veqen.flush() before returning: it waits up to five seconds and returns True once everything is sent.

Integrations

LangChain, LiteLLM and the OpenAI Agents SDK: see Framework integrations.