Skip to content

Python SDK

The official VeraID Python SDK provides a client for managing credentials, monitoring AI agent usage, enforcing budgets, and detecting prompt injection attacks. It includes async support, built-in retry logic, and integration wrappers for OpenAI and LangChain.

Installation

Terminal window
pip install veraid

Optional Extras

Install with framework-specific integrations:

Terminal window
pip install veraid[openai] # OpenAI integration
pip install veraid[langchain] # LangChain integration
pip install veraid[all] # All integrations

Quick Start

from veraid import VeraIDClient
client = VeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123",
)
# Fetch a credential
db_url = client.get_credential("production-db-url")
print(f"Connected to: {db_url.value}")

Initialization

Create a client instance with your API key and optional configuration:

from veraid import VeraIDClient
client = VeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123", # Required for AI agent features
base_url="https://app.veraid.io", # Optional, defaults to production
debug=False, # Optional, enables verbose logging
retry_attempts=3, # Optional, default: 3
timeout=30, # Optional, request timeout in seconds
)

Async Client

For async applications, use the AsyncVeraIDClient:

from veraid import AsyncVeraIDClient
client = AsyncVeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123",
)
# All methods are async
credential = await client.get_credential("production-db-url")

Authentication: the agent’s own key

The SDK authenticates as one AI agent, with a credential issued for that agent’s identity (kd_live_...). Issue a long-lived one with POST /api/v1/credentials ({"identityId": "<the agent's id>", "name": "sdk", "type": "API_KEY"}) while signed in; only an organization admin or the agent’s owner can, and the secret is shown once. Generate Credential on the agent’s page under Identities issues a temporary one (kd_jit_...), which works the same way until it expires.

The key acts for its own agent and nothing else:

  • It reads that agent’s budget (get_budget_status, check_budget) and usage (get_stats), and checks text for prompt injection (check_injection).
  • It records that agent’s usage (record_usage), and so its spend, only if an organization admin issued it. Any member can create an agent and issue it a key, and recorded spend also counts toward the organization-wide limits, so a key issued by anyone else gets 403 there. A key rotated automatically (with no one starting it) has no issuer: an admin re-issues it.
  • A call naming another agent is refused with 403, even one in the same organization.
  • Revoking the credential, suspending the agent, or the issuer losing admin rights takes effect within a minute.
  • If the agent has an IP allowlist (addresses or CIDR ranges), calls must come from an allowed address.
  • Scopes on the credential are not checked for these calls.
  • A non-admin owner of the agent can rotate its keys but cannot sync (deliver) a key an admin or another member issued: only an organization admin can.

It lists this agent’s vault secrets (list_credentials), and reads their values (get_credential) only if an organization admin issued it.


Credential Management

Secrets an organization admin stores in this agent’s vault (an OpenAI key, a database password), which the agent reads at run time. See Storing secrets for an agent. Reading a value needs the agent’s key to have been issued by an organization admin; listing does not.

get_credential

Read a secret’s value by name (POST /api/v1/credentials/retrieve). Every read is audited.

openai_key = await client.get_credential("openai-api-key") # the value, a str

Parameters:

ParameterTypeRequiredDescription
namestrYesThe secret’s name in this agent’s vault

Returns: str. Refused with 403 for a key not issued by an admin, 404 for an unknown name, 429 past 300 reads a minute per agent.

list_credentials

List the secrets in this agent’s vault: names and metadata, never values (GET /api/v1/agents/{agentId}/credentials).

for secret in await client.list_credentials():
print(f"{secret.name}: expires {secret.expires_at or 'never'}")

Returns: list[Credential]

class Credential(BaseModel):
id: str
name: str
value: str | None # only from get_credential's route, never here
type: str | None
status: str | None
expires_at: datetime | None
scopes: list[str]
created_at: datetime | None

Budget Management

get_budget_status

Retrieve the current budget status for the AI agent.

budget = client.get_budget_status()
print(f"Budget: ${budget.used:.2f} / ${budget.limit:.2f} ({budget.percent_used:.1f}%)")
print(f"Status: {budget.status}") # 'OK' | 'WARNING' | 'CRITICAL' | 'EXCEEDED'
print(f"Projected: ${budget.projected_spend:.2f}")

Returns: BudgetStatus

@dataclass
class BudgetStatus:
limit: float
used: float
percent_used: float
status: str # 'OK' | 'WARNING' | 'CRITICAL' | 'EXCEEDED'
period: str # 'daily' | 'weekly' | 'monthly'
projected_spend: float
reset_at: str

check_budget

Check if a specific cost can be accommodated within the remaining budget.

result = client.check_budget(2.50)
if result.allowed:
# Proceed with the AI call
response = openai_client.chat.completions.create(...)
else:
print(f"Budget exceeded: {result.reason}")

Parameters:

ParameterTypeRequiredDescription
costfloatYesEstimated cost in USD

Returns: BudgetCheck

@dataclass
class BudgetCheck:
allowed: bool
remaining_budget: float
reason: str | None

Usage Tracking

record_usage

Record token and cost usage for an AI agent request.

client.record_usage(
prompt_tokens=1250,
completion_tokens=847,
total_tokens=2097,
cost=0.063,
model="gpt-4",
latency=2340,
metadata={
"task_type": "ticket-triage",
"ticket_id": "TICKET-4521",
},
)

Parameters:

ParameterTypeRequiredDescription
prompt_tokensintYesNumber of prompt tokens
completion_tokensintYesNumber of completion tokens
total_tokensintYesTotal tokens consumed
costfloatYesEstimated cost in USD
modelstrYesModel identifier
latencyintNoResponse time in milliseconds
tool_callslist[str]NoTools invoked during the request
metadatadictNoAdditional context

Returns: None


Prompt Security

check_injection

Analyze a prompt for potential injection attacks (POST /api/v1/ai-monitoring/check-injection).

result = await client.check_injection(user_prompt)
if result.is_injection:
print(f"Injection detected: {result.summary}")
print(f"Score: {result.score}, confidence: {result.confidence}")
print(f"Patterns: {', '.join(result.patterns)}")

Parameters:

ParameterTypeRequiredDescription
promptstrYesThe prompt to analyze

Returns: InjectionCheckResult

class InjectionDetail(BaseModel):
category: str
pattern: str
risk: Literal["low", "medium", "high", "critical"]
description: str
matched_text: str | None
class InjectionCheckResult(BaseModel):
is_injection: bool
score: float # 0 to 1
confidence: Literal["low", "medium", "high"]
method: Literal["pattern", "ml", "combined"] | None
patterns: list[str] # detected pattern categories
summary: str
details: list[InjectionDetail] | None
high_risk_patterns: list[InjectionDetail] | None
recommendations: list[str] | None # when an injection was detected

guard_prompt

Check for injection and raise an exception if one is detected.

from veraid.exceptions import InjectionDetectedError
try:
safe_prompt = client.guard_prompt(user_prompt)
# safe_prompt is the original prompt, returned only if safe
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": safe_prompt}],
)
except InjectionDetectedError as e:
print(f"Blocked: {e.category} ({e.confidence})")
# Return a safe response to the user

Parameters:

ParameterTypeRequiredDescription
promptstrYesThe prompt to guard

Returns: str (the original prompt if safe)

Raises: InjectionDetectedError if injection is detected


Analytics

get_stats

Retrieve this agent’s usage over a period: the current day, week or month (UTC).

stats = await client.get_stats("week") # "day" (default), "week" or "month"
print(f"Total requests: {stats.total_requests}")
print(f"Total cost: ${stats.total_cost:.2f}")
print(f"Average latency: {stats.avg_latency_ms}ms")
print(f"Injections detected: {stats.injection_detections}")

Returns: AgentStats, from GET /api/v1/ai-monitoring/{agent_id}?period=daily|weekly|monthly

class UsageBreakdown(BaseModel):
requests: int
tokens: int
cost: float
class AgentStats(BaseModel):
period: Literal["daily", "weekly", "monthly"]
period_start: datetime
period_end: datetime
total_requests: int
successful_requests: int
failed_requests: int
total_input_tokens: int
total_output_tokens: int
total_tokens: int
total_cost: float # USD
avg_latency_ms: float
max_latency_ms: float
by_model: dict[str, UsageBreakdown]
by_action: dict[str, UsageBreakdown]
injection_detections: int

OpenAI Integration

The SDK provides a wrapper for the OpenAI client that automatically monitors all API calls.

from openai import OpenAI
from veraid import VeraIDClient
from veraid.integrations.openai import wrap_openai
veraid_client = VeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123",
)
openai_client = wrap_openai(OpenAI(), veraid_client)
# All calls are now automatically monitored
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Summarize this document..."}],
)
# Usage is automatically recorded:
# - Token counts (prompt + completion)
# - Cost estimate based on model pricing
# - Latency
# - Budget check before each call
# - Prompt injection detection on user messages

Async OpenAI

from openai import AsyncOpenAI
from veraid import AsyncVeraIDClient
from veraid.integrations.openai import wrap_openai
veraid_client = AsyncVeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123",
)
openai_client = wrap_openai(AsyncOpenAI(), veraid_client)
response = await openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Summarize this document..."}],
)

Configuration

Customize the wrapper behavior:

openai_client = wrap_openai(OpenAI(), veraid_client,
check_budget=True,
record_usage=True,
detect_injection=False, # Disable for lower latency
)

LangChain Integration

Use the VeraID callback handler to automatically monitor LangChain chains and agents.

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from veraid import VeraIDClient
from veraid.integrations.langchain import VeraIDCallback
veraid_client = VeraIDClient(
api_key="kd_live_your_api_key",
agent_id="id_agent123",
)
callback = VeraIDCallback(veraid_client)
llm = ChatOpenAI(model="gpt-4", callbacks=[callback])
# All LLM calls through this chain are monitored
response = llm.invoke("What is the status of ticket TICKET-4521?")

The callback automatically tracks:

FeatureDescription
Token usageRecords prompt and completion tokens for each LLM call
Cost trackingEstimates cost based on model and token counts
LatencyMeasures response time for each call
Tool callsLogs tool invocations in agent chains
Chain trackingAssociates multiple LLM calls within a single chain execution
Error captureReports LLM errors and timeouts to VeraID

Agent Monitoring

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain.tools import Tool
from veraid.integrations.langchain import VeraIDCallback
callback = VeraIDCallback(veraid_client)
# Define your tools
tools = [
Tool(name="search_kb", func=search_knowledge_base, description="Search the knowledge base"),
Tool(name="get_ticket", func=get_ticket, description="Get ticket details"),
]
llm = ChatOpenAI(model="gpt-4")
agent = create_openai_functions_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, callbacks=[callback])
# The callback monitors the entire agent execution, including tool calls
result = executor.invoke({"input": "Resolve ticket TICKET-4521"})

Error Handling

The SDK provides typed exception classes for different failure modes:

from veraid import VeraIDClient
from veraid.exceptions import (
VeraIDError,
AuthenticationError,
RateLimitError,
BudgetExceededError,
InjectionDetectedError,
NotFoundError,
)
try:
credential = client.get_credential("my-secret")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except BudgetExceededError as e:
print(f"Budget exceeded: {e.limit} / {e.used}")
except InjectionDetectedError as e:
print(f"Injection: {e.category} ({e.confidence})")
except NotFoundError:
print("Credential not found")
except VeraIDError as e:
print(f"VeraID error: {e.message}")

Context Manager

The client supports context manager usage for automatic cleanup:

with VeraIDClient(api_key="kd_live_your_api_key") as client:
credential = client.get_credential("my-secret")
# Client is automatically closed when exiting the block

Async version:

async with AsyncVeraIDClient(api_key="kd_live_your_api_key") as client:
credential = await client.get_credential("my-secret")

Environment Variables

The SDK reads the following environment variables as defaults:

VariableDescriptionRequired
VERAID_API_KEYAPI key for authenticationYes
VERAID_AGENT_IDAgent identity ID (for AI agent features)For agent features
VERAID_BASE_URLBase URL override (default: https://app.veraid.io)No
VERAID_DEBUGEnable debug logging (true / false)No
Terminal window
export VERAID_API_KEY="kd_live_your_api_key"
export VERAID_AGENT_ID="id_agent123"
export VERAID_DEBUG="false"