Platform API Client
Note
New in 4.x — TrustwiseClient is the recommended way to interact
with the Trustwise platform. It replaces TrustwiseSDK and provides a
superset of functionality.
The TrustwiseClient provides an
ergonomic Python interface to the full Trustwise Platform API (v1alpha),
including agents, guardrails, policies, evaluations, risk classification,
red-team generation, all v4 metrics, events, and subscriptions.
Note
Breaking change in 4.5 — Agents are now project-scoped. All
client.agents methods require a project_id as the first argument.
Quickstart
import os
from trustwise.sdk.config import TrustwiseConfig
from trustwise.sdk.platform import TrustwiseClient
config = TrustwiseConfig(api_key=os.environ["TW_API_KEY"])
client = TrustwiseClient(config)
# List agents within a project
agents = client.agents.list("my-project-id", limit=5)
# Evaluate faithfulness
result = client.metrics.faithfulness(
query="What is the capital of France?",
response="The capital of France is Paris.",
context=[{"chunk_text": "Paris is the capital.", "chunk_id": "1"}],
)
Raw Envelope Access
By default, methods return the parsed data directly. Pass raw=True to
get the full API envelope (with success, metadata, warnings):
# Parsed — returns the data model directly
agent = client.agents.get("project-id", "agent-id")
# Raw — returns the full API envelope
resp = client.agents.get("project-id", "agent-id", raw=True)
print(resp["success"], resp["metadata"])
Available Resources
Attribute |
Description |
|---|---|
|
Project-scoped CRUD, query, risk-classify, add policies, gateway deploy/undeploy/regenerate-key, status, assign/unassign assessment, export/import; organization-scoped |
|
Assessment lifecycle (CRUD, answers, submit, validate, classify, re-assess) and vendor workflow (decide, send/revoke to vendor, magic links, magic-link details/resolve, clarifications) |
|
List AI Gateway models, guardrails, and MCP servers |
|
CRUD, evaluate, list evaluations (global + per-guardrail), get evaluation by ID, providers, provider guardrails and regions, export/import |
|
CRUD, evaluate, evaluate_batch, recommend, export/import |
|
Project-scoped CRUD, classification, audit logs |
|
List available evaluators (read-only) |
|
CRUD for organizations, logo upload/manage |
|
CRUD, members (list/add/remove), assignable roles and users |
|
List/get templates, classify, scaffold, tags, validate, list versions, assessment evidence (list/upload/download/delete) |
|
Red-team prompt generation (12 endpoints) |
|
All v4 metrics (18 endpoints) |
|
List, get, dismiss event notifications |
|
CRUD for event subscriptions (webhook, email, Slack, Teams) |
|
List runtime providers and auth schemas |
|
Project-scoped CRUD, test connection, gateway deploy/undeploy, export/import; organization-scoped |
|
Project-scoped CRUD, test connection, gateway deploy, list/get model providers, export/import; organization-scoped |
|
List and get background jobs (poll asynchronous operations) |
|
Cross-resource export/import bundles, plus restore-export/restore-import |
|
List the AI components (agents, models, MCP servers) assigned to a project |
|
Generate, poll, refresh and download reports; browse the template, component and datasource catalogue |
|
List the organization’s users (read-only) |
|
Read RBAC metadata (read-only) |
Agents
Agents are project-scoped — every method requires a project_id.
project_id = "my-project-id"
# List
agents = client.agents.list(project_id, search="my-bot", limit=10)
# Create
agent = client.agents.create(
project_id,
name="My Agent",
description="A helpful assistant",
runtime_provider_config={
"type": "http",
"url": "https://my-agent.example.com/query",
},
)
# Get, update, delete
agent = client.agents.get(project_id, agent["id"])
client.agents.update(project_id, agent["id"], description="Updated")
client.agents.delete(project_id, agent["id"])
# Query the agent
response = client.agents.query(project_id, agent["id"], prompt="Hello!")
# Risk classify
result = client.agents.risk_classify(project_id, agent["id"])
# Deploy to AI Gateway
deploy = client.agents.deploy_gateway(project_id, agent["id"], models=["gpt-4.1-nano"])
# Rotate the gateway API key, then remove the deployment
rotated = client.agents.regenerate_gateway_key(project_id, agent["id"])
client.agents.undeploy_gateway(project_id, agent["id"])
# Status history
history = client.agents.status_history(project_id, agent["id"])
Organization-Scoped Components
Agents, models, and MCP servers are AI components. Alongside the
project-scoped methods above, each one also exists as an organization-wide
record addressed by its ID alone. Those methods are prefixed org_, and the
same set is available on client.agents, client.models and
client.mcp_servers.
An organization-scoped component is made available to a project by assigning it, rather than by being created inside one:
# The organization-wide catalogue — no project_id
agents = client.agents.org_list(limit=10, assigned=False)
agent = client.agents.org_create(
name="Shared Agent",
runtime_provider_config={
"type": "http",
"base_url": "https://my-agent.example.com",
},
)
agent = client.agents.org_get(agent.id)
client.agents.org_update(agent.id, description="Updated")
# Make it available to a project, then take it back out
client.agents.assign("my-project-id", agent.id)
client.agents.unassign("my-project-id", agent.id)
client.agents.org_delete(agent.id)
Components can be linked to one another to record what an agent uses. An
association names a target component, its type (agent, model,
mcp_server, rest_api or message_queue) and the relationship
(uses or depends_on):
client.agents.org_add_association(
agent_id,
target_component_id=model_id,
target_component_type="model",
association_type="uses",
)
for edge in client.agents.org_associations(agent_id):
print(edge.target_component_type, edge.association_type)
client.agents.org_remove_association(
agent_id,
target_component_id=model_id,
target_component_type="model",
association_type="uses",
)
The same three calls exist scoped to a single project — associations,
add_association and remove_association — taking a project_id first:
client.models.add_association(
"my-project-id",
model_id,
target_component_id=mcp_server_id,
target_component_type="mcp_server",
association_type="depends_on",
)
Agents additionally expose their organization-scoped query, status and assessment routes:
reply = client.agents.org_query(agent_id, prompt="Hello!")
print(reply.agent_response)
history = client.agents.org_status_history(agent_id, limit=20)
client.agents.org_update_status(agent_id, status="active", reason="Verified")
client.agents.org_assign_assessment(agent_id, assessment_id="assessment-id")
client.agents.org_unassign_assessment(agent_id)
To see every component assigned to a project, whatever its type, use
client.components:
for component in client.components.list("my-project-id", component_type="model"):
print(component.id, component.component_type)
Guardrails
# List guardrails
guardrails = client.guardrails.list()
# Evaluate content against a guardrail
result = client.guardrails.evaluate(
guardrail_id, input="user message", output="assistant reply"
)
# List past evaluations for a single guardrail
evals = client.guardrails.list_evaluations_for_guardrail(guardrail_id, limit=20)
# Fetch one evaluation by its ID alone
evaluation = client.guardrails.get_evaluation_by_id("evaluation-id")
# Browse providers
providers = client.guardrails.providers()
# List guardrails available from a provider (e.g. AWS Bedrock)
result = client.guardrails.provider_guardrails("aws_bedrock", region="us-east-1")
# List regions supported by a provider
regions = client.guardrails.provider_regions("aws_bedrock")
Policies
# List policies
policies = client.policies.list()
# Evaluate content against a policy
result = client.policies.evaluate(policy_id, input="test input")
# Evaluate against multiple policies in one call
results = client.policies.evaluate_batch(
policy_ids=["policy-1", "policy-2"],
input={"text": "test input"},
)
# Get policy recommendations based on tags
recs = client.policies.recommend(tags=["safety", "pii"])
Evaluations
Evaluations are scoped to a project:
# List evaluations in a project
evals = client.evaluations.list("my-project-id", limit=10)
# Get audit logs
logs = client.evaluations.audit_logs("my-project-id")
Risk Engine
# List available templates, or fetch one by ID
templates = client.risk_engine.list_templates()
template = client.risk_engine.get_template("arc-v3")
# Get the questionnaire scaffold
scaffold = client.risk_engine.scaffold("arc-v3")
# Classify risk (returns the raw result dict)
result = client.risk_engine.classify("arc-v3", answers={...})
# Assessment evidence — attach supporting files to an assessment
files = client.risk_engine.list_evidence("assessment-id")
upload = client.risk_engine.initiate_evidence_upload(
"assessment-id", file_name="soc2.pdf", content_type="application/pdf"
)
client.risk_engine.download_evidence("assessment-id", "file-id")
client.risk_engine.delete_evidence("assessment-id", "file-id")
Assessments
Assessments drive the risk-assessment lifecycle and vendor workflow. Create an assessment, save answers, validate, submit for review, and record a decision — or send it to an external vendor via a magic link.
# Create and list
assessment = client.assessments.create(name="Vendor X review", workflow="arc_buy")
assessments = client.assessments.list(status="in_progress", limit=10)
# Get, update, delete
a = client.assessments.get(assessment.id)
client.assessments.update(assessment.id, name="Vendor X — 2026")
client.assessments.delete(assessment.id)
# Fill in answers, validate, then submit
client.assessments.save_answers(assessment.id, answers=[{"question_id": "q1", "value": "yes"}])
client.assessments.validate(assessment.id)
client.assessments.submit(assessment.id)
# Run a classification and read the result
client.assessments.classify(assessment.id)
classifications = client.assessments.list_classifications(assessment.id)
# Review workflow
client.assessments.decide(assessment.id, decision="approve")
client.assessments.request_clarification(assessment.id, message="Please clarify Q3")
client.assessments.reopen(assessment.id)
# Re-run the workflow after changes
client.assessments.re_assess(assessment.id)
# Vendor workflow
link = client.assessments.create_magic_link(assessment.id, expires_in=3600)
client.assessments.send_to_vendor(assessment.id, vendor_email="vendor@example.com")
client.assessments.revoke_from_vendor(assessment.id)
# Inspect the active magic link — returns a masked token, never the full one
details = client.assessments.get_magic_link(assessment.id)
print(details.holder_email, details.masked_token, details.is_expired)
# Resolve a magic-link token back to its assessment
resolved = client.assessments.resolve_magic_link(token="magic-link-token")
# Assign an assessment to an agent
client.agents.assign_assessment("project-id", "agent-id", assessment_id=assessment.id)
client.agents.unassign_assessment("project-id", "agent-id")
Generation (Red-Team)
# Generate red-team prompts
prompts = client.generation.red_prompts(
system_prompt="You are a helpful assistant.",
num_prompts=5,
)
# Generate adversarial tool inputs
tool_inputs = client.generation.red_tool_input(
tool_name="search", tool_schema={...}
)
Events
Event notifications are created automatically when evaluations, guardrail triggers, or policy violations occur.
# List recent events
events = client.events.list(severity="warning", limit=20)
# Get a specific event
event = client.events.get("event-id")
# Dismiss an event
client.events.dismiss("event-id")
# Check events subsystem health
client.events.health()
Subscriptions
Subscriptions forward event notifications to external destinations.
# Create a webhook subscription
sub = client.subscriptions.create(
name="My Webhook",
event_type_filter=["evaluation.completed", "evaluation.failed"],
severity_filter=["critical", "warning"],
handler_type="webhook",
handler_config={"url": "https://my-service.example.com/events"},
)
# List, update, delete
subs = client.subscriptions.list()
client.subscriptions.update(sub.id, enabled=False)
client.subscriptions.delete(sub.id)
Runtime Providers
Runtime providers describe the connector types available for agent deployment (HTTP, A2A, Google ADK, etc.).
# List all runtime providers
providers = client.runtime_providers.list()
# Get a specific provider's config schema
provider = client.runtime_providers.get("http")
# List supported auth schemas
schemas = client.runtime_providers.auth_schemas()
MCP Servers
MCP servers are project-scoped. They can be registered, connection-tested, and deployed to the AI Gateway.
project_id = "my-project-id"
# List MCP servers in a project
servers = client.mcp_servers.list(project_id, limit=10)
# Test connectivity before registering
check = client.mcp_servers.test_connection(
transport_type="http", url="https://my-mcp.example.com"
)
# Create, get, update, delete
server = client.mcp_servers.create(
project_id, name="My MCP Server", transport_type="http",
url="https://my-mcp.example.com",
)
server = client.mcp_servers.get(project_id, server.id)
client.mcp_servers.update(project_id, server.id, description="Updated")
client.mcp_servers.delete(project_id, server.id)
# Deploy / undeploy to the AI Gateway
client.mcp_servers.deploy_gateway(project_id, server.id)
client.mcp_servers.undeploy_gateway(project_id, server.id)
# MCP servers available in the gateway
available = client.gateway.list_mcp_servers()
Models
Models are a project-scoped registry of LLM endpoints (provider + credentials) that can be connection-tested and deployed to the AI Gateway.
project_id = "my-project-id"
# List models in a project
models = client.models.list(project_id, provider="openai", limit=10)
# Test connectivity to a provider
check = client.models.test_connection(
provider="openai", litellm_model_id="gpt-4.1-nano"
)
# Register, get, update, delete
model = client.models.create(
project_id, name="My GPT-4", provider="openai",
litellm_model_id="gpt-4.1-nano",
)
model = client.models.get(project_id, model.id)
client.models.update(project_id, model.id, description="Updated")
client.models.delete(project_id, model.id)
# Deploy to the AI Gateway
client.models.deploy_gateway(project_id, model.id)
# Browse supported model providers (not project-scoped)
providers = client.models.list_providers()
openai_cfg = client.models.get_provider("openai")
Export and Import
Agents, guardrails, models, MCP servers, and policies each expose
export and import_ for moving definitions between organizations or
projects. import_ uploads a bundle as multipart/form-data.
export is a file download: the API answers with
Content-Disposition: attachment and the body is the exported file itself,
not the usual {success, data, ...} envelope. By default the records are
parsed for you, but as_file=True hands back the bytes together with the
server-suggested filename, ready to write to disk or feed straight to
import_.
Project-scoped resources (agents, models, MCP servers) take a
project_id; organization-scoped ones (guardrails, policies) do not.
# Export every agent, or just a few by slug
records = client.agents.export() # list[dict]
subset = client.agents.export(slugs=["support-bot"])
as_yaml = client.agents.export(format="yaml") # bytes
# The file itself — bytes plus the name the server suggested
bundle = client.agents.export(as_file=True)
bundle.name # 'agents.json' (or 'agents.yaml' with format="yaml")
bundle.content # bytes, exactly as sent
Path(bundle.name).write_bytes(bundle.content)
# Import into a project, choosing how to handle name collisions
client.agents.import_(
"project-id",
open("agents.json", "rb"),
conflict_strategy="rename",
)
# Round-trip without touching the filesystem
bundle = client.agents.export(as_file=True)
client.agents.import_("project-id", bundle.content, file_name=bundle.name)
# Organization-scoped — no project_id
client.guardrails.import_(open("guardrails.json", "rb"))
Artifact Bundles
client.artifacts moves several artifact types at once as a single zip
archive. export and restore_export return raw bytes; the
restore_* pair preserves record identifiers so a bundle can be restored
onto the same organization rather than copied to a new one.
Imports are asynchronous — they return a job you can poll via
client.jobs.
# Export a multi-type bundle as a zip
zip_bytes = client.artifacts.export(
artifact_types=["guardrails", "policies", "agents"],
slugs={"agents": ["support-bot"]},
)
# Import it elsewhere
job = client.artifacts.import_(
zip_bytes,
conflict_strategy="skip",
target_project="project-id",
)
# Backup / restore onto the same org (keeps IDs)
backup = client.artifacts.restore_export()
client.artifacts.restore_import(backup)
Background Jobs
Asynchronous operations such as artifact imports return a job id. Use
client.jobs to poll for completion — status is one of INITIALIZED,
RUNNING, SUCCESS, or ERROR.
job = client.jobs.get("job-id")
print(job.status, job.job_result)
# Only the jobs that failed
failed = client.jobs.list(status="ERROR", limit=20)
Project Members
Project membership grants a user a role on one project. add_member returns
an assignment, and it is that assignment’s id — not the user’s — that
remove_member takes.
project_id = "my-project-id"
# Who can be added, and as what
roles = client.projects.list_assignable_roles(project_id)
candidates = client.projects.list_assignable_users(project_id, search="bob")
assignment = client.projects.add_member(
project_id,
user_id=candidates[0].id,
role_id=roles[0].id,
reason="Joining the review team",
)
for member in client.projects.list_members(project_id):
print(member.email, member.role_id)
client.projects.remove_member(project_id, assignment.id)
Report Engine
Report generation is asynchronous: generate returns a report id, status
polls it, and the finished artifact is fetched as HTML, raw bytes, or a PDF.
# What can be built
templates = client.reports.catalogue_templates()
datasources = client.reports.catalogue_datasources()
job = client.reports.generate(template_id=templates[0]["name"])
report_id = job.report_id.root
# Poll until it finishes
state = client.reports.status(report_id)
print(state.status.root) # queued | in_progress | completed | failed
# Fetch the result
html = client.reports.view(report_id)
pdf_bytes = client.reports.pdf(report_id)
# ...or keep the server-suggested filename
downloaded = client.reports.pdf(report_id, as_file=True)
with open(downloaded.name, "wb") as fh:
fh.write(downloaded.content)
# Re-render against current data
client.reports.refresh(report_id)
for report in client.reports.list():
print(report.report_id.root, report.status.root)
Note
The catalogue_* methods return their payload directly rather than the
usual {success, data, ...} envelope, so they take no raw argument.
Users and RBAC
Both resources are read-only. The SDK exposes RBAC metadata for discovery but does not wrap the role, permission, mapping or assignment management routes.
for user in client.users.list(status="active", limit=50):
print(user.id, user.email)
meta = client.rbac.meta() # returned as a plain dict
Metrics
All v4 metrics are available through client.metrics:
# Faithfulness
result = client.metrics.faithfulness(
query="What is Paris?",
response="Paris is the capital of France.",
context=[{"chunk_text": "Paris is the capital of France.", "chunk_id": "1"}],
)
# Toxicity
result = client.metrics.toxicity(text="some text to check")
# Input type — detect encoded segments (binary, hex, base64, ...)
result = client.metrics.input_type(text="the payload is 1101")
# Batch evaluation
result = client.metrics.evaluate(
evaluators=["faithfulness", "toxicity"],
query="...", response="...", context=[...],
)
See V4 Metrics for details on each metric’s parameters and response types.
Full API Reference
For complete method signatures and return types, see the Platform Client section in the API Reference.