# A2A Protocol
Source: https://docs.useanima.sh/a2a/overview
Agent-to-Agent communication protocol for task delegation, capability negotiation, and structured message exchange between AI agents.
# A2A Protocol
The Anima A2A (Agent-to-Agent) protocol enables structured communication and task delegation between AI agents. Built on top of Agent Cards and DIDs, A2A provides authenticated, capability-aware messaging between agents regardless of their hosting platform.
## How A2A Works
1. **Discovery** -- Agent A resolves Agent B's Agent Card to find its A2A endpoint and capabilities
2. **Authentication** -- Agent A authenticates using DID-based credentials
3. **Task Delegation** -- Agent A sends a structured task request describing what it needs
4. **Execution** -- Agent B processes the task and streams progress updates
5. **Completion** -- Agent B returns the result to Agent A
## Sending a Task
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Delegate a task to another agent
const task = await anima.a2a.sendTask({
fromAgentId: "ag_sender123",
toAgentDid: "did:anima:ag_receiver456",
capability: "purchase-order",
input: {
vendor: "Office Supplies Inc",
items: [
{ name: "Printer paper", quantity: 10, unitPrice: 8.99 },
{ name: "Ink cartridges", quantity: 4, unitPrice: 24.99 },
],
budget: 200,
},
timeout: 300_000, // 5 minutes
});
console.log(`Task ID: ${task.id}`);
console.log(`Status: ${task.status}`); // "pending" | "in_progress" | "completed" | "failed"
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
task = anima.a2a.send_task(
from_agent_id="ag_sender123",
to_agent_did="did:anima:ag_receiver456",
capability="purchase-order",
input={
"vendor": "Office Supplies Inc",
"items": [
{"name": "Printer paper", "quantity": 10, "unitPrice": 8.99},
{"name": "Ink cartridges", "quantity": 4, "unitPrice": 24.99},
],
"budget": 200,
},
timeout=300_000,
)
print(f"Task ID: {task.id}")
print(f"Status: {task.status}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
task, err := client.A2A.SendTask(ctx, &anima.SendTaskParams{
FromAgentID: "ag_sender123",
ToAgentDID: "did:anima:ag_receiver456",
Capability: "purchase-order",
Input: map[string]any{
"vendor": "Office Supplies Inc",
"items": []map[string]any{
{"name": "Printer paper", "quantity": 10, "unitPrice": 8.99},
},
"budget": 200,
},
TimeoutMs: 300000,
})
```
## Receiving Tasks
Register a handler for incoming A2A tasks:
```ts theme={null}
// Register a task handler for a capability
anima.a2a.onTask("ag_receiver456", "purchase-order", async (task) => {
console.log(`Received task from: ${task.fromDid}`);
console.log(`Input: ${JSON.stringify(task.input)}`);
// Update progress
await task.updateStatus("in_progress", { message: "Processing order..." });
// Do the work...
const result = await processOrder(task.input);
// Complete the task
await task.complete({
orderId: result.orderId,
totalCost: result.totalCost,
status: "confirmed",
});
});
```
```python theme={null}
@anima.a2a.on_task("ag_receiver456", "purchase-order")
async def handle_purchase_order(task):
print(f"Received task from: {task.from_did}")
await task.update_status("in_progress", message="Processing order...")
result = await process_order(task.input)
await task.complete({
"orderId": result.order_id,
"totalCost": result.total_cost,
"status": "confirmed",
})
```
## Streaming Task Progress
For long-running tasks, stream progress updates back to the caller:
```ts theme={null}
const task = await anima.a2a.sendTask({
fromAgentId: "ag_sender123",
toAgentDid: "did:anima:ag_receiver456",
capability: "data-analysis",
input: { dataset: "sales-2026-q1" },
stream: true,
});
for await (const update of task.stream()) {
console.log(`[${update.status}] ${update.message}`);
if (update.progress) {
console.log(`Progress: ${update.progress}%`);
}
}
console.log(`Result: ${JSON.stringify(task.result)}`);
```
## Task Lifecycle
| Status | Description |
| ------------- | ---------------------------------------- |
| `pending` | Task submitted, awaiting processing |
| `in_progress` | Handler is actively working on the task |
| `completed` | Task finished successfully with a result |
| `failed` | Task encountered an error |
| `cancelled` | Task was cancelled by the sender |
| `timeout` | Task exceeded the configured timeout |
## API Reference
| Endpoint | Method | Description |
| -------------------------------------------------- | ------ | --------------------------------- |
| `https://api.useanima.sh/api/a2a/tasks` | POST | Send a task to another agent |
| `https://api.useanima.sh/api/a2a/tasks/:id` | GET | Get task status and result |
| `https://api.useanima.sh/api/a2a/tasks/:id/cancel` | POST | Cancel a pending/in-progress task |
| `https://api.useanima.sh/api/a2a/tasks` | GET | List tasks (sent and received) |
| `https://api.useanima.sh/api/a2a/handlers` | POST | Register a task handler |
| `https://api.useanima.sh/api/a2a/handlers` | GET | List registered handlers |
## Configuration
| Variable | Default | Description |
| ---------------------------- | -------- | ------------------------------------ |
| `ANIMA_A2A_DEFAULT_TIMEOUT` | `300000` | Default task timeout in ms (5 min) |
| `ANIMA_A2A_MAX_PAYLOAD_KB` | `1024` | Maximum task input/output size |
| `ANIMA_A2A_REQUIRE_DID_AUTH` | `true` | Require DID authentication for tasks |
| `ANIMA_A2A_STREAM_ENABLED` | `true` | Enable streaming task updates |
## Next Steps
* [Agent Cards](/identity/agent-cards) -- Publish capabilities for discovery
* [Agent Registry](/registry/overview) -- Find agents to delegate tasks to
* [Agent Wallet](/wallet/overview) -- Attach payments to task delegations
# For AI Agents
Source: https://docs.useanima.sh/ai-agents
Anima is built to be operated by AI agents. Point your agent at the skill manifest, connect the docs MCP server, and read the docs as machine-readable markdown.
# For AI Agents
Anima is designed to be set up and operated by an AI agent, not just a human clicking through a dashboard. If you are a coding agent — or you are handing this page to one — everything below is meant to be consumed directly.
## Hand your agent the setup manifest
The fastest path is to let the agent read Anima's skill manifest and follow it. Paste this into Claude Code, Cursor, Claude Desktop, or any MCP-aware agent:
```text theme={null}
Read https://useanima.sh/skill.md and get me set up with Anima.
```
[`https://useanima.sh/skill.md`](https://useanima.sh/skill.md) is an executable, agent-facing manifest. It walks the agent through installing the CLI, authenticating, provisioning an agent identity, wiring Anima as an MCP server, and finishing onboarding — using your existing API key if you already have one.
## Connect the docs MCP server
Anima hosts a Model Context Protocol server for the documentation itself, so your agent can search and retrieve authoritative docs content instead of guessing from stale training data.
| | |
| ------------- | ---------------------------------------------- |
| **Endpoint** | `https://docs.useanima.sh/mcp` |
| **Transport** | Streamable HTTP |
| **Auth** | None — the docs server is public and read-only |
It exposes search and retrieval tools over the published documentation. Add it to any client that supports remote MCP.
```bash Claude Code theme={null}
claude mcp add anima-docs --transport http --url https://docs.useanima.sh/mcp
```
```json Cursor / other HTTP clients theme={null}
{
"mcpServers": {
"anima-docs": {
"url": "https://docs.useanima.sh/mcp"
}
}
}
```
The docs MCP server answers questions about Anima from public documentation. To let an agent actually **do** things — send email, provision a number, place a call, use the vault — connect the product MCP servers described in [Connect your AI client](/integrations).
## Give your agent the product tools
Anima's capabilities are exposed as MCP tools your agent can call. Wire them into your client with the CLI:
```bash theme={null}
anima setup-mcp install --all
```
This configures the Anima MCP servers for every supported client detected on the machine. See [Connect your AI client](/integrations) for per-client configuration, the hosted endpoint, and the full tool list.
## Read the docs as markdown
Every documentation page is available as raw markdown — just append `.md` to the URL. This is the cleanest way for an agent to ingest a page without parsing HTML.
```bash theme={null}
curl https://docs.useanima.sh/getting-started.md
curl https://docs.useanima.sh/webhooks.md
```
For a whole-site view, two indexes follow the [llms.txt](https://llmstxt.org) convention:
| File | Contents |
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| [`https://docs.useanima.sh/llms.txt`](https://docs.useanima.sh/llms.txt) | A compact index of every documentation page, for discovery. |
| [`https://docs.useanima.sh/llms-full.txt`](https://docs.useanima.sh/llms-full.txt) | The full documentation concatenated into one file, for ingestion. |
## Next steps
Wire Anima's tools into Claude Code, Cursor, Claude Desktop, VS Code, and Windsurf.
The CLI-first path: install, onboard, and send from the terminal.
# Delete addresses
Source: https://docs.useanima.sh/api-reference/delete-addresses
/openapi.json delete /addresses/{id}
# Delete agents
Source: https://docs.useanima.sh/api-reference/delete-agents
/openapi.json delete /agents/{id}
# Delete agents email identities
Source: https://docs.useanima.sh/api-reference/delete-agents-email-identities
/openapi.json delete /agents/{agentId}/email-identities/{identityId}
# Delete api keys
Source: https://docs.useanima.sh/api-reference/delete-api-keys
/openapi.json delete /api-keys/{id}
# Delete domains
Source: https://docs.useanima.sh/api-reference/delete-domains
/openapi.json delete /domains/{id}
# Delete emaildrafts
Source: https://docs.useanima.sh/api-reference/delete-emaildrafts
/openapi.json delete /email/drafts/{id}
# Delete inboxes
Source: https://docs.useanima.sh/api-reference/delete-inboxes
/openapi.json delete /inboxes/{id}
# Delete orgs
Source: https://docs.useanima.sh/api-reference/delete-orgs
/openapi.json delete /orgs/{id}
# Delete orgs agents quarantine
Source: https://docs.useanima.sh/api-reference/delete-orgs-agents-quarantine
/openapi.json delete /orgs/{orgId}/agents/{agentId}/quarantine
# Delete orgs anomaly rules
Source: https://docs.useanima.sh/api-reference/delete-orgs-anomaly-rules
/openapi.json delete /orgs/{orgId}/anomaly-rules/{ruleId}
# Delete orgs compliancereports
Source: https://docs.useanima.sh/api-reference/delete-orgs-compliancereports
/openapi.json delete /orgs/{orgId}/compliance/reports/{reportId}
# Delete pods
Source: https://docs.useanima.sh/api-reference/delete-pods
/openapi.json delete /pods/{id}
# Delete registryagents
Source: https://docs.useanima.sh/api-reference/delete-registryagents
/openapi.json delete /registry/agents/{did}
# Delete vaultcredentials
Source: https://docs.useanima.sh/api-reference/delete-vaultcredentials
/openapi.json delete /vault/credentials/{id}
# Delete vaultoauthaccounts
Source: https://docs.useanima.sh/api-reference/delete-vaultoauthaccounts
/openapi.json delete /vault/oauth/accounts/{accountId}
# Delete vaultoauthapps custom
Source: https://docs.useanima.sh/api-reference/delete-vaultoauthapps-custom
/openapi.json delete /vault/oauth/apps/{appSlug}/custom/{id}
# Delete webhooks
Source: https://docs.useanima.sh/api-reference/delete-webhooks
/openapi.json delete /webhooks/{id}
# Get addresses
Source: https://docs.useanima.sh/api-reference/get-addresses
/openapi.json get /addresses
# Get addresses 1
Source: https://docs.useanima.sh/api-reference/get-addresses-1
/openapi.json get /addresses/{id}
# Get agents
Source: https://docs.useanima.sh/api-reference/get-agents
/openapi.json get /agents
# Get agents 1
Source: https://docs.useanima.sh/api-reference/get-agents-1
/openapi.json get /agents/{id}
# Get agents a2atasks
Source: https://docs.useanima.sh/api-reference/get-agents-a2atasks
/openapi.json get /agents/{agentId}/a2a/tasks
# Get agents a2atasks 1
Source: https://docs.useanima.sh/api-reference/get-agents-a2atasks-1
/openapi.json get /agents/{agentId}/a2a/tasks/{taskId}
# Get agents card
Source: https://docs.useanima.sh/api-reference/get-agents-card
/openapi.json get /agents/{agentId}/card
# Get agents credentials
Source: https://docs.useanima.sh/api-reference/get-agents-credentials
/openapi.json get /agents/{agentId}/credentials
# Get agents did
Source: https://docs.useanima.sh/api-reference/get-agents-did
/openapi.json get /agents/{agentId}/did
# Get agents email identities
Source: https://docs.useanima.sh/api-reference/get-agents-email-identities
/openapi.json get /agents/{agentId}/email-identities
# Get agents policy
Source: https://docs.useanima.sh/api-reference/get-agents-policy
/openapi.json get /agents/{agentId}/policy
# Get agentstatus
Source: https://docs.useanima.sh/api-reference/get-agentstatus
/openapi.json get /agent/status
# Get api keys
Source: https://docs.useanima.sh/api-reference/get-api-keys
/openapi.json get /api-keys
# Get api keysscopes
Source: https://docs.useanima.sh/api-reference/get-api-keysscopes
/openapi.json get /api-keys/scopes
# Get attachments download
Source: https://docs.useanima.sh/api-reference/get-attachments-download
/openapi.json get /attachments/{id}/download
# Get billingfeatures
Source: https://docs.useanima.sh/api-reference/get-billingfeatures
/openapi.json get /billing/features/{feature}
# Get billinghard cap
Source: https://docs.useanima.sh/api-reference/get-billinghard-cap
/openapi.json get /billing/hard-cap
# Get billinginvoices
Source: https://docs.useanima.sh/api-reference/get-billinginvoices
/openapi.json get /billing/invoices
# Get billingtier
Source: https://docs.useanima.sh/api-reference/get-billingtier
/openapi.json get /billing/tier
# Get billingusage
Source: https://docs.useanima.sh/api-reference/get-billingusage
/openapi.json get /billing/usage
# Get domains
Source: https://docs.useanima.sh/api-reference/get-domains
/openapi.json get /domains
# Get domains 1
Source: https://docs.useanima.sh/api-reference/get-domains-1
/openapi.json get /domains/{id}
# Get domains deliverability
Source: https://docs.useanima.sh/api-reference/get-domains-deliverability
/openapi.json get /domains/{id}/deliverability
# Get domains dns records
Source: https://docs.useanima.sh/api-reference/get-domains-dns-records
/openapi.json get /domains/{id}/dns-records
# Get domains zone file
Source: https://docs.useanima.sh/api-reference/get-domains-zone-file
/openapi.json get /domains/{id}/zone-file
# Get email
Source: https://docs.useanima.sh/api-reference/get-email
/openapi.json get /email/{id}
# Get email 1
Source: https://docs.useanima.sh/api-reference/get-email-1
/openapi.json get /email
# Get emaildrafts
Source: https://docs.useanima.sh/api-reference/get-emaildrafts
/openapi.json get /email/drafts
# Get emaildrafts 1
Source: https://docs.useanima.sh/api-reference/get-emaildrafts-1
/openapi.json get /email/drafts/{id}
# Get extensionsettings
Source: https://docs.useanima.sh/api-reference/get-extensionsettings
/openapi.json get /extension/settings
# Get feedback
Source: https://docs.useanima.sh/api-reference/get-feedback
/openapi.json get /feedback
# Get inboxes
Source: https://docs.useanima.sh/api-reference/get-inboxes
/openapi.json get /inboxes
# Get invoices
Source: https://docs.useanima.sh/api-reference/get-invoices
/openapi.json get /invoices/{invoiceId}
# Get invoices 1
Source: https://docs.useanima.sh/api-reference/get-invoices-1
/openapi.json get /invoices
# Get invoicesexport
Source: https://docs.useanima.sh/api-reference/get-invoicesexport
/openapi.json get /invoices/export
# Get invoicesreconciliation summary
Source: https://docs.useanima.sh/api-reference/get-invoicesreconciliation-summary
/openapi.json get /invoices/reconciliation-summary
# Get meagents
Source: https://docs.useanima.sh/api-reference/get-meagents
/openapi.json get /me/agents
# Get meorgs
Source: https://docs.useanima.sh/api-reference/get-meorgs
/openapi.json get /me/orgs
# Get messages
Source: https://docs.useanima.sh/api-reference/get-messages
/openapi.json get /messages/{id}
# Get messages 1
Source: https://docs.useanima.sh/api-reference/get-messages-1
/openapi.json get /messages
# Get oauthapps
Source: https://docs.useanima.sh/api-reference/get-oauthapps
/openapi.json get /oauth/apps/{clientId}
# Get oauthuserinfo
Source: https://docs.useanima.sh/api-reference/get-oauthuserinfo
/openapi.json get /oauth/userinfo
# Get openclawagents
Source: https://docs.useanima.sh/api-reference/get-openclawagents
/openapi.json get /openclaw/agents
# Get openclawauthorize
Source: https://docs.useanima.sh/api-reference/get-openclawauthorize
/openapi.json get /openclaw/authorize
# Get openclawcallback
Source: https://docs.useanima.sh/api-reference/get-openclawcallback
/openapi.json get /openclaw/callback
# Get orgs
Source: https://docs.useanima.sh/api-reference/get-orgs
/openapi.json get /orgs
# Get orgs 1
Source: https://docs.useanima.sh/api-reference/get-orgs-1
/openapi.json get /orgs/{id}
# Get orgs access reviews
Source: https://docs.useanima.sh/api-reference/get-orgs-access-reviews
/openapi.json get /orgs/{orgId}/access-reviews
# Get orgs agents baselines
Source: https://docs.useanima.sh/api-reference/get-orgs-agents-baselines
/openapi.json get /orgs/{orgId}/agents/{agentId}/baselines
# Get orgs agents quarantine
Source: https://docs.useanima.sh/api-reference/get-orgs-agents-quarantine
/openapi.json get /orgs/{orgId}/agents/{agentId}/quarantine
# Get orgs agents security policy
Source: https://docs.useanima.sh/api-reference/get-orgs-agents-security-policy
/openapi.json get /orgs/{orgId}/agents/{agentId}/security-policy
# Get orgs anomaly alerts
Source: https://docs.useanima.sh/api-reference/get-orgs-anomaly-alerts
/openapi.json get /orgs/{orgId}/anomaly-alerts
# Get orgs anomaly alerts 1
Source: https://docs.useanima.sh/api-reference/get-orgs-anomaly-alerts-1
/openapi.json get /orgs/{orgId}/anomaly-alerts/{alertId}
# Get orgs anomaly rules
Source: https://docs.useanima.sh/api-reference/get-orgs-anomaly-rules
/openapi.json get /orgs/{orgId}/anomaly-rules
# Get orgs audit logs
Source: https://docs.useanima.sh/api-reference/get-orgs-audit-logs
/openapi.json get /orgs/{orgId}/audit-logs
# Get orgs audit logs 1
Source: https://docs.useanima.sh/api-reference/get-orgs-audit-logs-1
/openapi.json get /orgs/{orgId}/audit-logs/{logId}
# Get orgs compliancecontrols
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancecontrols
/openapi.json get /orgs/{orgId}/compliance/controls
# Get orgs compliancecontrols 1
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancecontrols-1
/openapi.json get /orgs/{orgId}/compliance/controls/{controlId}
# Get orgs compliancecontrols evidence
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancecontrols-evidence
/openapi.json get /orgs/{orgId}/compliance/controls/{controlId}/evidence
# Get orgs compliancedashboard
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancedashboard
/openapi.json get /orgs/{orgId}/compliance/dashboard
# Get orgs compliancedsars
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancedsars
/openapi.json get /orgs/{orgId}/compliance/dsars
# Get orgs compliancedsars 1
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancedsars-1
/openapi.json get /orgs/{orgId}/compliance/dsars/{dsarId}
# Get orgs compliancereports
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancereports
/openapi.json get /orgs/{orgId}/compliance/reports
# Get orgs compliancereports 1
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancereports-1
/openapi.json get /orgs/{orgId}/compliance/reports/{reportId}
# Get orgs compliancesummary
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancesummary
/openapi.json get /orgs/{orgId}/compliance/summary
# Get orgs compliancetemplates
Source: https://docs.useanima.sh/api-reference/get-orgs-compliancetemplates
/openapi.json get /orgs/{orgId}/compliance/templates
# Get orgs members
Source: https://docs.useanima.sh/api-reference/get-orgs-members
/openapi.json get /orgs/{id}/members
# Get orgs securityevents
Source: https://docs.useanima.sh/api-reference/get-orgs-securityevents
/openapi.json get /orgs/{orgId}/security/events
# Get orgs securityscanner status
Source: https://docs.useanima.sh/api-reference/get-orgs-securityscanner-status
/openapi.json get /orgs/{orgId}/security/scanner-status
# Get orgsme
Source: https://docs.useanima.sh/api-reference/get-orgsme
/openapi.json get /orgs/me
# Get orgsmeusage
Source: https://docs.useanima.sh/api-reference/get-orgsmeusage
/openapi.json get /orgs/me/usage
# Get orgsmeworkspace health
Source: https://docs.useanima.sh/api-reference/get-orgsmeworkspace-health
/openapi.json get /orgs/me/workspace-health
# Get phonenumbers
Source: https://docs.useanima.sh/api-reference/get-phonenumbers
/openapi.json get /phone/numbers
# Get phonesearch
Source: https://docs.useanima.sh/api-reference/get-phonesearch
/openapi.json get /phone/search
# Get pods
Source: https://docs.useanima.sh/api-reference/get-pods
/openapi.json get /pods
# Get pods 1
Source: https://docs.useanima.sh/api-reference/get-pods-1
/openapi.json get /pods/{id}
# Get pods usage
Source: https://docs.useanima.sh/api-reference/get-pods-usage
/openapi.json get /pods/{id}/usage
# Get registryagents
Source: https://docs.useanima.sh/api-reference/get-registryagents
/openapi.json get /registry/agents/{did}
# Get registryagentssearch
Source: https://docs.useanima.sh/api-reference/get-registryagentssearch
/openapi.json get /registry/agents/search
# Get scoped tokens
Source: https://docs.useanima.sh/api-reference/get-scoped-tokens
/openapi.json get /scoped-tokens
# Get vaultaudit
Source: https://docs.useanima.sh/api-reference/get-vaultaudit
/openapi.json get /vault/audit
# Get vaultcredentials
Source: https://docs.useanima.sh/api-reference/get-vaultcredentials
/openapi.json get /vault/credentials
# Get vaultcredentials 1
Source: https://docs.useanima.sh/api-reference/get-vaultcredentials-1
/openapi.json get /vault/credentials/{id}
# Get vaultidentities
Source: https://docs.useanima.sh/api-reference/get-vaultidentities
/openapi.json get /vault/identities
# Get vaultoauthaccounts
Source: https://docs.useanima.sh/api-reference/get-vaultoauthaccounts
/openapi.json get /vault/oauth/accounts
# Get vaultoauthapps
Source: https://docs.useanima.sh/api-reference/get-vaultoauthapps
/openapi.json get /vault/oauth/apps
# Get vaultoauthapps 1
Source: https://docs.useanima.sh/api-reference/get-vaultoauthapps-1
/openapi.json get /vault/oauth/apps/{slug}
# Get vaultoauthlink
Source: https://docs.useanima.sh/api-reference/get-vaultoauthlink
/openapi.json get /vault/oauth/link/{token}
# Get vaultsearch
Source: https://docs.useanima.sh/api-reference/get-vaultsearch
/openapi.json get /vault/search
# Get vaultshares
Source: https://docs.useanima.sh/api-reference/get-vaultshares
/openapi.json get /vault/shares
# Get vaultstatus
Source: https://docs.useanima.sh/api-reference/get-vaultstatus
/openapi.json get /vault/status
# Get vaulttotp
Source: https://docs.useanima.sh/api-reference/get-vaulttotp
/openapi.json get /vault/totp/{id}
# Get voiceanalytics
Source: https://docs.useanima.sh/api-reference/get-voiceanalytics
/openapi.json get /voice/analytics
# Get voicecalls
Source: https://docs.useanima.sh/api-reference/get-voicecalls
/openapi.json get /voice/calls
# Get voicecalls 1
Source: https://docs.useanima.sh/api-reference/get-voicecalls-1
/openapi.json get /voice/calls/{callId}
# Get voicecalls recording
Source: https://docs.useanima.sh/api-reference/get-voicecalls-recording
/openapi.json get /voice/calls/{callId}/recording
# Get voicecalls score
Source: https://docs.useanima.sh/api-reference/get-voicecalls-score
/openapi.json get /voice/calls/{callId}/score
# Get voicecalls security
Source: https://docs.useanima.sh/api-reference/get-voicecalls-security
/openapi.json get /voice/calls/{callId}/security
# Get voicecalls summary
Source: https://docs.useanima.sh/api-reference/get-voicecalls-summary
/openapi.json get /voice/calls/{callId}/summary
# Get voicecalls transcript
Source: https://docs.useanima.sh/api-reference/get-voicecalls-transcript
/openapi.json get /voice/calls/{callId}/transcript
# Get voicecatalog
Source: https://docs.useanima.sh/api-reference/get-voicecatalog
/openapi.json get /voice/catalog
# Get webhooks
Source: https://docs.useanima.sh/api-reference/get-webhooks
/openapi.json get /webhooks
# Get webhooks 1
Source: https://docs.useanima.sh/api-reference/get-webhooks-1
/openapi.json get /webhooks/{id}
# Get webhooks dead letters
Source: https://docs.useanima.sh/api-reference/get-webhooks-dead-letters
/openapi.json get /webhooks/{webhookId}/dead-letters
# Get webhooks deliveries
Source: https://docs.useanima.sh/api-reference/get-webhooks-deliveries
/openapi.json get /webhooks/{webhookId}/deliveries
# Get webhooks stats
Source: https://docs.useanima.sh/api-reference/get-webhooks-stats
/openapi.json get /webhooks/{id}/stats
# Get webhooksevent types
Source: https://docs.useanima.sh/api-reference/get-webhooksevent-types
/openapi.json get /webhooks/event-types
# Patch agents
Source: https://docs.useanima.sh/api-reference/patch-agents
/openapi.json patch /agents/{id}
# Patch api keys
Source: https://docs.useanima.sh/api-reference/patch-api-keys
/openapi.json patch /api-keys/{id}
# Patch domains
Source: https://docs.useanima.sh/api-reference/patch-domains
/openapi.json patch /domains/{id}
# Patch extensionsettings
Source: https://docs.useanima.sh/api-reference/patch-extensionsettings
/openapi.json patch /extension/settings
# Patch extensiontoken
Source: https://docs.useanima.sh/api-reference/patch-extensiontoken
/openapi.json patch /extension/token/{id}
# Patch inboxes
Source: https://docs.useanima.sh/api-reference/patch-inboxes
/openapi.json patch /inboxes/{id}
# Patch invoices
Source: https://docs.useanima.sh/api-reference/patch-invoices
/openapi.json patch /invoices/{invoiceId}
# Patch oauthapps
Source: https://docs.useanima.sh/api-reference/patch-oauthapps
/openapi.json patch /oauth/apps/{clientId}
# Patch orgs
Source: https://docs.useanima.sh/api-reference/patch-orgs
/openapi.json patch /orgs/{id}
# Patch orgs anomaly rules
Source: https://docs.useanima.sh/api-reference/patch-orgs-anomaly-rules
/openapi.json patch /orgs/{orgId}/anomaly-rules/{ruleId}
# Patch orgs compliancecontrols
Source: https://docs.useanima.sh/api-reference/patch-orgs-compliancecontrols
/openapi.json patch /orgs/{orgId}/compliance/controls/{controlId}
# Patch orgs compliancedsars
Source: https://docs.useanima.sh/api-reference/patch-orgs-compliancedsars
/openapi.json patch /orgs/{orgId}/compliance/dsars/{dsarId}
# Post addresses
Source: https://docs.useanima.sh/api-reference/post-addresses
/openapi.json post /addresses
# Post addresses validate
Source: https://docs.useanima.sh/api-reference/post-addresses-validate
/openapi.json post /addresses/{id}/validate
# Post agents
Source: https://docs.useanima.sh/api-reference/post-agents
/openapi.json post /agents
# Post agents a2atasks
Source: https://docs.useanima.sh/api-reference/post-agents-a2atasks
/openapi.json post /agents/{agentId}/a2a/tasks
# Post agents a2atasks cancel
Source: https://docs.useanima.sh/api-reference/post-agents-a2atasks-cancel
/openapi.json post /agents/{agentId}/a2a/tasks/{taskId}/cancel
# Post agents credentials revoke
Source: https://docs.useanima.sh/api-reference/post-agents-credentials-revoke
/openapi.json post /agents/{agentId}/credentials/{vcId}/revoke
# Post agents didrotate
Source: https://docs.useanima.sh/api-reference/post-agents-didrotate
/openapi.json post /agents/{agentId}/did/rotate
# Post agents email identities
Source: https://docs.useanima.sh/api-reference/post-agents-email-identities
/openapi.json post /agents/{agentId}/email-identities
# Post agents email identities set primary
Source: https://docs.useanima.sh/api-reference/post-agents-email-identities-set-primary
/openapi.json post /agents/{agentId}/email-identities/{identityId}/set-primary
# Post agents email identities verify
Source: https://docs.useanima.sh/api-reference/post-agents-email-identities-verify
/openapi.json post /agents/{agentId}/email-identities/{identityId}/verify
# Post agents rotate key
Source: https://docs.useanima.sh/api-reference/post-agents-rotate-key
/openapi.json post /agents/{id}/rotate-key
# Post agentsign up
Source: https://docs.useanima.sh/api-reference/post-agentsign-up
/openapi.json post /agent/sign-up
# Post agentverify
Source: https://docs.useanima.sh/api-reference/post-agentverify
/openapi.json post /agent/verify
# Post api keys
Source: https://docs.useanima.sh/api-reference/post-api-keys
/openapi.json post /api-keys
# Post api keys rotate
Source: https://docs.useanima.sh/api-reference/post-api-keys-rotate
/openapi.json post /api-keys/{id}/rotate
# Post billingchange plan
Source: https://docs.useanima.sh/api-reference/post-billingchange-plan
/openapi.json post /billing/change-plan
# Post billingcheckout
Source: https://docs.useanima.sh/api-reference/post-billingcheckout
/openapi.json post /billing/checkout
# Post billingcontact enterprise
Source: https://docs.useanima.sh/api-reference/post-billingcontact-enterprise
/openapi.json post /billing/contact-enterprise
# Post billingportal
Source: https://docs.useanima.sh/api-reference/post-billingportal
/openapi.json post /billing/portal
# Post domains
Source: https://docs.useanima.sh/api-reference/post-domains
/openapi.json post /domains
# Post domains verify
Source: https://docs.useanima.sh/api-reference/post-domains-verify
/openapi.json post /domains/{id}/verify
# Post emaildrafts
Source: https://docs.useanima.sh/api-reference/post-emaildrafts
/openapi.json post /email/drafts
# Post emaildrafts send
Source: https://docs.useanima.sh/api-reference/post-emaildrafts-send
/openapi.json post /email/drafts/{id}/send
# Post emailsend
Source: https://docs.useanima.sh/api-reference/post-emailsend
/openapi.json post /email/send
# Post extensionexchange
Source: https://docs.useanima.sh/api-reference/post-extensionexchange
/openapi.json post /extension/exchange
# Post extensionrevoke
Source: https://docs.useanima.sh/api-reference/post-extensionrevoke
/openapi.json post /extension/revoke
# Post extensiontoken
Source: https://docs.useanima.sh/api-reference/post-extensiontoken
/openapi.json post /extension/token
# Post feedback
Source: https://docs.useanima.sh/api-reference/post-feedback
/openapi.json post /feedback
# Post identities
Source: https://docs.useanima.sh/api-reference/post-identities
/openapi.json post /identities
# Post identityverify
Source: https://docs.useanima.sh/api-reference/post-identityverify
/openapi.json post /identity/verify
# Post inboxes
Source: https://docs.useanima.sh/api-reference/post-inboxes
/openapi.json post /inboxes
# Post invoicesmatch receipts
Source: https://docs.useanima.sh/api-reference/post-invoicesmatch-receipts
/openapi.json post /invoices/match-receipts
# Post mcp authsessions
Source: https://docs.useanima.sh/api-reference/post-mcp-authsessions
/openapi.json post /mcp-auth/sessions
# Post mcp authsessions complete
Source: https://docs.useanima.sh/api-reference/post-mcp-authsessions-complete
/openapi.json post /mcp-auth/sessions/{sessionId}/complete
# Post mcp authsessions deny
Source: https://docs.useanima.sh/api-reference/post-mcp-authsessions-deny
/openapi.json post /mcp-auth/sessions/{sessionId}/deny
# Post mcp authsessionspoll
Source: https://docs.useanima.sh/api-reference/post-mcp-authsessionspoll
/openapi.json post /mcp-auth/sessions/poll
# Post messages attachments
Source: https://docs.useanima.sh/api-reference/post-messages-attachments
/openapi.json post /messages/{messageId}/attachments
# Post messagesemail
Source: https://docs.useanima.sh/api-reference/post-messagesemail
/openapi.json post /messages/email
# Post messagessearch
Source: https://docs.useanima.sh/api-reference/post-messagessearch
/openapi.json post /messages/search
# Post messagessearchsemantic
Source: https://docs.useanima.sh/api-reference/post-messagessearchsemantic
/openapi.json post /messages/search/semantic
# Post messagessms
Source: https://docs.useanima.sh/api-reference/post-messagessms
/openapi.json post /messages/sms
# Post oauthapps
Source: https://docs.useanima.sh/api-reference/post-oauthapps
/openapi.json post /oauth/apps
# Post oauthauth codesmint
Source: https://docs.useanima.sh/api-reference/post-oauthauth-codesmint
/openapi.json post /oauth/auth-codes/mint
# Post oauthregister
Source: https://docs.useanima.sh/api-reference/post-oauthregister
/openapi.json post /oauth/register
# Post oauthrevoke
Source: https://docs.useanima.sh/api-reference/post-oauthrevoke
/openapi.json post /oauth/revoke
# Post oauthtoken
Source: https://docs.useanima.sh/api-reference/post-oauthtoken
/openapi.json post /oauth/token
# Post openclawsignup
Source: https://docs.useanima.sh/api-reference/post-openclawsignup
/openapi.json post /openclaw/signup
# Post orgs
Source: https://docs.useanima.sh/api-reference/post-orgs
/openapi.json post /orgs
# Post orgs access reviews
Source: https://docs.useanima.sh/api-reference/post-orgs-access-reviews
/openapi.json post /orgs/{orgId}/access-reviews
# Post orgs access reviews complete
Source: https://docs.useanima.sh/api-reference/post-orgs-access-reviews-complete
/openapi.json post /orgs/{orgId}/access-reviews/{reviewId}/complete
# Post orgs agents quarantine
Source: https://docs.useanima.sh/api-reference/post-orgs-agents-quarantine
/openapi.json post /orgs/{orgId}/agents/{agentId}/quarantine
# Post orgs anomaly alerts acknowledge
Source: https://docs.useanima.sh/api-reference/post-orgs-anomaly-alerts-acknowledge
/openapi.json post /orgs/{orgId}/anomaly-alerts/{alertId}/acknowledge
# Post orgs anomaly alerts false positive
Source: https://docs.useanima.sh/api-reference/post-orgs-anomaly-alerts-false-positive
/openapi.json post /orgs/{orgId}/anomaly-alerts/{alertId}/false-positive
# Post orgs anomaly alerts resolve
Source: https://docs.useanima.sh/api-reference/post-orgs-anomaly-alerts-resolve
/openapi.json post /orgs/{orgId}/anomaly-alerts/{alertId}/resolve
# Post orgs anomaly rules
Source: https://docs.useanima.sh/api-reference/post-orgs-anomaly-rules
/openapi.json post /orgs/{orgId}/anomaly-rules
# Post orgs audit logsexport
Source: https://docs.useanima.sh/api-reference/post-orgs-audit-logsexport
/openapi.json post /orgs/{orgId}/audit-logs/export
# Post orgs compliancecontrols collect
Source: https://docs.useanima.sh/api-reference/post-orgs-compliancecontrols-collect
/openapi.json post /orgs/{orgId}/compliance/controls/{controlId}/collect
# Post orgs compliancecontrols evidence
Source: https://docs.useanima.sh/api-reference/post-orgs-compliancecontrols-evidence
/openapi.json post /orgs/{orgId}/compliance/controls/{controlId}/evidence
# Post orgs compliancedsars
Source: https://docs.useanima.sh/api-reference/post-orgs-compliancedsars
/openapi.json post /orgs/{orgId}/compliance/dsars
# Post orgs compliancereports
Source: https://docs.useanima.sh/api-reference/post-orgs-compliancereports
/openapi.json post /orgs/{orgId}/compliance/reports
# Post orgs compliancereports export
Source: https://docs.useanima.sh/api-reference/post-orgs-compliancereports-export
/openapi.json post /orgs/{orgId}/compliance/reports/{reportId}/export
# Post orgs complianceseed
Source: https://docs.useanima.sh/api-reference/post-orgs-complianceseed
/openapi.json post /orgs/{orgId}/compliance/seed
# Post orgs messages approve
Source: https://docs.useanima.sh/api-reference/post-orgs-messages-approve
/openapi.json post /orgs/{orgId}/messages/{messageId}/approve
# Post orgs rotate key
Source: https://docs.useanima.sh/api-reference/post-orgs-rotate-key
/openapi.json post /orgs/{id}/rotate-key
# Post orgsfeature interest
Source: https://docs.useanima.sh/api-reference/post-orgsfeature-interest
/openapi.json post /orgs/feature-interest
# Post phoneprovision
Source: https://docs.useanima.sh/api-reference/post-phoneprovision
/openapi.json post /phone/provision
# Post phonerelease
Source: https://docs.useanima.sh/api-reference/post-phonerelease
/openapi.json post /phone/release
# Post phonesend sms
Source: https://docs.useanima.sh/api-reference/post-phonesend-sms
/openapi.json post /phone/send-sms
# Post pods
Source: https://docs.useanima.sh/api-reference/post-pods
/openapi.json post /pods
# Post registryagents
Source: https://docs.useanima.sh/api-reference/post-registryagents
/openapi.json post /registry/agents
# Post scoped tokens
Source: https://docs.useanima.sh/api-reference/post-scoped-tokens
/openapi.json post /scoped-tokens
# Post scoped tokensrevoke
Source: https://docs.useanima.sh/api-reference/post-scoped-tokensrevoke
/openapi.json post /scoped-tokens/revoke
# Post vaultcredentials
Source: https://docs.useanima.sh/api-reference/post-vaultcredentials
/openapi.json post /vault/credentials
# Post vaultdeprovision
Source: https://docs.useanima.sh/api-reference/post-vaultdeprovision
/openapi.json post /vault/deprovision
# Post vaultgenerate password
Source: https://docs.useanima.sh/api-reference/post-vaultgenerate-password
/openapi.json post /vault/generate-password
# Post vaultoauthapps custom
Source: https://docs.useanima.sh/api-reference/post-vaultoauthapps-custom
/openapi.json post /vault/oauth/apps/{appSlug}/custom
# Post vaultoauthlink
Source: https://docs.useanima.sh/api-reference/post-vaultoauthlink
/openapi.json post /vault/oauth/link
# Post vaultoauthrequire auth
Source: https://docs.useanima.sh/api-reference/post-vaultoauthrequire-auth
/openapi.json post /vault/oauth/require-auth
# Post vaultprovision
Source: https://docs.useanima.sh/api-reference/post-vaultprovision
/openapi.json post /vault/provision
# Post vaultshare
Source: https://docs.useanima.sh/api-reference/post-vaultshare
/openapi.json post /vault/share
# Post vaultsharerevoke
Source: https://docs.useanima.sh/api-reference/post-vaultsharerevoke
/openapi.json post /vault/share/revoke
# Post vaultsync
Source: https://docs.useanima.sh/api-reference/post-vaultsync
/openapi.json post /vault/sync
# Post vaulttoken
Source: https://docs.useanima.sh/api-reference/post-vaulttoken
/openapi.json post /vault/token
# Post vaulttokenexchange
Source: https://docs.useanima.sh/api-reference/post-vaulttokenexchange
/openapi.json post /vault/token/exchange
# Post vaulttokenrevoke
Source: https://docs.useanima.sh/api-reference/post-vaulttokenrevoke
/openapi.json post /vault/token/revoke
# Post voicecalls
Source: https://docs.useanima.sh/api-reference/post-voicecalls
/openapi.json post /voice/calls
# Post voicesearch
Source: https://docs.useanima.sh/api-reference/post-voicesearch
/openapi.json post /voice/search
# Post voicesearchcross channel
Source: https://docs.useanima.sh/api-reference/post-voicesearchcross-channel
/openapi.json post /voice/search/cross-channel
# Post webhooks
Source: https://docs.useanima.sh/api-reference/post-webhooks
/openapi.json post /webhooks
# Post webhooks reenable
Source: https://docs.useanima.sh/api-reference/post-webhooks-reenable
/openapi.json post /webhooks/{id}/reenable
# Post webhooks rotate secret
Source: https://docs.useanima.sh/api-reference/post-webhooks-rotate-secret
/openapi.json post /webhooks/{id}/rotate-secret
# Post webhooks test
Source: https://docs.useanima.sh/api-reference/post-webhooks-test
/openapi.json post /webhooks/{id}/test
# Post webhooksdeliveries replay
Source: https://docs.useanima.sh/api-reference/post-webhooksdeliveries-replay
/openapi.json post /webhooks/deliveries/{deliveryId}/replay
# Put addresses
Source: https://docs.useanima.sh/api-reference/put-addresses
/openapi.json put /addresses/{id}
# Put agents policy
Source: https://docs.useanima.sh/api-reference/put-agents-policy
/openapi.json put /agents/{agentId}/policy
# Put billinghard cap
Source: https://docs.useanima.sh/api-reference/put-billinghard-cap
/openapi.json put /billing/hard-cap
# Put orgs agents security policy
Source: https://docs.useanima.sh/api-reference/put-orgs-agents-security-policy
/openapi.json put /orgs/{orgId}/agents/{agentId}/security-policy
# Put pods
Source: https://docs.useanima.sh/api-reference/put-pods
/openapi.json put /pods/{id}
# Put registryagents
Source: https://docs.useanima.sh/api-reference/put-registryagents
/openapi.json put /registry/agents/{did}
# Put vaultcredentials
Source: https://docs.useanima.sh/api-reference/put-vaultcredentials
/openapi.json put /vault/credentials/{id}
# Put webhooks
Source: https://docs.useanima.sh/api-reference/put-webhooks
/openapi.json put /webhooks/{id}
# How We Built Cryptographic Identity for AI Agents with DIDs
Source: https://docs.useanima.sh/blog/agent-identity-did
A technical deep dive into the did:anima method — how Anima uses W3C Decentralized Identifiers and Verifiable Credentials to give AI agents provable, trustworthy identity.
# How We Built Cryptographic Identity for AI Agents with DIDs
When an AI agent sends an email, makes a purchase, or calls an API, the receiving party has a reasonable question: **who is this, and should I trust it?**
Today, most agents authenticate with API keys or OAuth tokens. These prove authorization, not identity. They say "this request is allowed" but not "this is agent X, operated by company Y, with these specific capabilities and constraints." That distinction matters as agents start interacting with each other, with vendors, and with compliance systems.
We built the `did:anima` method to solve this.
## Why Agents Need Verifiable Identity
There are three forces pushing agents toward cryptographic identity:
### 1. Agent-to-Agent Trust
When agent A contacts agent B to negotiate a contract or request a service, B needs to verify that A is who it claims to be. API keys do not help here — they authenticate a request to a specific service, not an identity across services. DIDs provide a portable, verifiable identity that works across any protocol.
### 2. Compliance and Accountability
Regulators are catching up to agentic systems. SOC 2 auditors want to know which agent performed which action and under whose authority. AML rules require knowing the identity behind financial transactions. A DID ties every action to a verifiable identity with a clear chain of custody.
### 3. Discovery and Interoperability
As the agent ecosystem grows, services need to discover agent capabilities and verify their legitimacy. The combination of DIDs and Agent Cards gives every agent a machine-readable, cryptographically verifiable profile that other systems can query.
## The `did:anima` Method
Every agent created on Anima is automatically assigned a DID following the W3C Decentralized Identifiers specification:
```
did:anima:ag_8f3k2m9x1n4p7q6r
```
The DID resolves to a DID Document that contains the agent's public keys, authentication methods, and service endpoints:
```json theme={null}
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "did:anima:ag_8f3k2m9x1n4p7q6r",
"authentication": [
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:anima:ag_8f3k2m9x1n4p7q6r",
"publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
}
],
"service": [
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#email",
"type": "AgentEmail",
"serviceEndpoint": "mailto:agent@acme.useanima.sh"
},
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#a2a",
"type": "AgentToAgent",
"serviceEndpoint": "https://acme.useanima.sh/.well-known/agent.json"
}
]
}
```
### Key Design Decisions
**Ed25519 keys**: We use Ed25519 for signing because it is fast, produces compact signatures, and is widely supported across platforms. Each agent gets a dedicated key pair at creation time.
**Service endpoints**: The DID Document lists every communication channel the agent supports — email, A2A protocol, webhook URLs. Another agent or service can resolve the DID and know exactly how to reach this agent.
**Automatic provisioning**: You do not need to manage keys or DID documents manually. Creating an agent automatically provisions the DID, generates keys, and publishes the document.
## Resolving and Verifying DIDs
Any system can resolve an Anima DID to get the agent's public identity:
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Resolve any agent's DID document
const doc = await anima.identity.resolveDid("did:anima:ag_8f3k2m9x1n4p7q6r");
console.log(doc.authentication); // Public keys
console.log(doc.service); // Communication endpoints
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
doc = anima.identity.resolve_did("did:anima:ag_8f3k2m9x1n4p7q6r")
print(doc.authentication) # Public keys
print(doc.service) # Communication endpoints
```
Resolution is also available via HTTP for systems that do not use the SDK:
```bash theme={null}
curl https://api.useanima.sh/v1/identity/did/did:anima:ag_8f3k2m9x1n4p7q6r
```
## W3C Verifiable Credentials
DIDs establish identity. Verifiable Credentials (VCs) establish **attributes** of that identity. Anima issues VCs that attest to specific facts about an agent:
```json theme={null}
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://useanima.sh/credentials/v1"
],
"type": ["VerifiableCredential", "AgentCapabilityCredential"],
"issuer": "did:anima:platform",
"credentialSubject": {
"id": "did:anima:ag_8f3k2m9x1n4p7q6r",
"organizationId": "org_acme_corp",
"capabilities": ["email", "phone", "vault"],
"complianceStatus": "verified"
},
"proof": {
"type": "Ed25519Signature2020",
"verificationMethod": "did:anima:platform#key-1",
"proofValue": "z58DAdFfa9SkqZMVPxAQp..."
}
}
```
These credentials are cryptographically signed by Anima and can be independently verified by any party. A vendor receiving a request from an agent can verify:
1. The agent's identity (via DID resolution)
2. That the agent belongs to a specific organization
3. What capabilities the agent has
All without calling Anima's API — the proof is in the credential itself.
## Agent Cards: Discovery via `.well-known`
The final piece is discoverability. Every Anima agent can publish an Agent Card at a well-known URL:
```
https://purchasing.acme.com/.well-known/agent.json
```
```json theme={null}
{
"name": "Acme Purchasing Agent",
"description": "Handles procurement for Acme Corp",
"url": "https://purchasing.acme.com",
"did": "did:anima:ag_8f3k2m9x1n4p7q6r",
"version": "1.0.0",
"capabilities": [
{
"name": "purchase-order",
"description": "Create and manage purchase orders",
"inputSchema": {
"type": "object",
"properties": {
"vendor": { "type": "string" },
"items": { "type": "array" },
"budget": { "type": "number" }
}
}
}
],
"authentication": {
"schemes": ["did-auth", "x402"]
}
}
```
Agent Cards serve the same role for agents that OpenAPI specs serve for APIs: a machine-readable description of what this agent can do and how to interact with it.
## Agent Registry
For agents that want to be discoverable beyond their own domain, Anima runs an Agent Registry. Think of it as DNS for agents — register your agent, and other agents can find it by capability, organization, or DID:
```ts theme={null}
// Register an agent in the registry
await anima.registry.register({
agentId: agent.id,
capabilities: ["procurement", "invoice-processing"],
public: true,
});
// Discover agents by capability
const agents = await anima.registry.search({
capability: "invoice-processing",
});
```
## Putting It All Together
Here is the flow when Agent A wants to interact with Agent B:
```mermaid theme={null}
sequenceDiagram
participant A as Agent A
participant Registry as Anima Registry
participant B as Agent B
A->>Registry: Search for invoice-processing agents
Registry-->>A: Agent B (did:anima:ag_xyz)
A->>B: Fetch /.well-known/agent.json
B-->>A: Agent Card (capabilities, DID, auth)
A->>A: Resolve did:anima:ag_xyz, verify credentials
A->>B: Authenticated request (DID-Auth)
B->>B: Verify A's DID and credentials
B-->>A: Response
```
Every step is verifiable. Every identity is cryptographic. No shared secrets. No API key exchange. Just DIDs, credentials, and open protocols.
## What This Enables
* **Zero-trust agent networks**: Agents verify each other's identity before every interaction
* **Compliance reporting**: Every action is tied to a verifiable identity with a clear audit trail
* **Cross-platform portability**: A `did:anima` identifier works everywhere, not just on Anima
* **Selective disclosure**: Agents can present specific credentials without revealing their full identity
* **Revocation**: If an agent is compromised, its DID and credentials can be revoked instantly
## Start Building
Agent identity is not optional anymore. As agents handle real money, real data, and real decisions, verifiable identity becomes infrastructure.
```ts theme={null}
const agent = await anima.agents.create({ name: "My Agent" });
const did = `did:anima:${agent.id}`;
// That's it. Your agent has a cryptographic identity.
```
[Read the DID method specification](/identity/did-method) | [Explore Verifiable Credentials](/identity/verifiable-credentials) | [Set up Agent Cards](/identity/agent-cards)
# Anima vs AgentMail: Why You Need More Than Just Email
Source: https://docs.useanima.sh/blog/anima-vs-agentmail
AgentMail provides email for AI agents. Anima provides email plus phone, vault, and cryptographic identity. Here is when to use each.
# Anima vs AgentMail: Why You Need More Than Just Email
AgentMail does one thing and does it well: email for AI agents. If all your agent needs is to send and receive email, AgentMail is a solid choice. But most production agents need more than an inbox.
## The Problem with Email-Only
Consider a customer support agent. It receives a complaint via email, looks up the order, sends an SMS confirmation, and logs into the merchant portal to update the ticket. That workflow touches:
* **Email** (receive complaint, send resolution)
* **Phone** (send SMS confirmation)
* **Vault** (store merchant portal credentials)
* **Identity** (prove to the merchant portal that it is an authorized agent)
With AgentMail, you get step one. The rest requires separate integrations with separate vendors, separate SDKs, and separate failure modes.
## Feature Comparison
| Capability | AgentMail | Anima |
| ------------------------------------- | ------------ | ----------------------- |
| Agent email inboxes | Yes | Yes |
| Custom domains | Yes | Yes |
| Inbound webhooks | Yes | Yes |
| Content scanning | Basic | Dual-layer (regex + AI) |
| Phone numbers (SMS/voice) | No | Yes |
| Encrypted credential vault | No | Yes (Bitwarden-backed) |
| DID-based identity | No | Yes (did:anima) |
| Verifiable Credentials | No | Yes (W3C VC) |
| Agent Cards (/.well-known/agent.json) | No | Yes |
| Agent Registry & discovery | No | Yes |
| x402 payments | No | Yes |
| A2A protocol support | No | Yes |
| Policy engine | No | Yes |
| MCP server (53 tools) | No | Yes |
| SOC 2 controls | Partial | Yes |
| SDKs | Node, Python | Node, Python, Go, CLI |
## When to Use AgentMail
AgentMail is a reasonable choice if:
* Your agent only sends and receives email
* You do not need phone or identity capabilities
* You are building a prototype and email is the only channel
* You prefer a narrowly scoped vendor for email specifically
## When to Use Anima
Anima is the right choice when:
* Your agent operates across multiple channels (email + phone)
* You need cryptographic identity for agent-to-agent trust
* Your compliance requirements demand audit trails across all agent actions
* You want a single SDK instead of integrating multiple separate services
* You need vault storage or policy enforcement
## Code Comparison
### AgentMail: Send an email
```ts theme={null}
// AgentMail — email only
import { AgentMail } from "agentmail";
const client = new AgentMail({ apiKey: "am_..." });
await client.send({
from: "agent@myco.com",
to: "user@example.com",
subject: "Your order update",
body: "Your order has shipped.",
});
```
### Anima: Full agent workflow
```ts theme={null}
// Anima — email + SMS + vault in one SDK
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const agent = await anima.agents.create({ name: "Support Agent" });
// Send email
await anima.messages.send_email({
agentId: agent.id,
to: "user@example.com",
subject: "Your refund has been processed",
body: "We've issued a $45.00 refund to your original payment method.",
});
// Send SMS confirmation
await anima.messages.sendSms({
agentId: agent.id,
to: "+15551234567",
body: "Refund of $45.00 processed. Check your email for details.",
});
// Store the case credentials for follow-up
await anima.vault.createCredential({
agentId: agent.id,
type: "secure_note",
name: "Case #4821 — Refund details",
notes: JSON.stringify({
orderId: "ORD-9921",
refundAmount: 4500,
}),
});
```
Same agent. Same API key. No glue code between vendors.
## The Unified Identity Advantage
The deeper issue with using AgentMail alongside other point solutions is identity fragmentation. Your agent has one identity in AgentMail, another in your phone service. There is no single source of truth for "who is this agent and what is it authorized to do?"
With Anima, every agent gets a `did:anima` identifier that spans all capabilities. The policy engine enforces rules across email and phone from a single configuration. Audit logs capture every action across every channel in one place.
This matters for compliance. When an auditor asks "what did agent X do last month?", you query one system — not five.
## Migration Path
If you are already on AgentMail and want to move to Anima, the process is straightforward:
1. Install the Anima SDK alongside AgentMail
2. Create agents in Anima and set up custom domains
3. Migrate email sending calls from AgentMail's API to `anima.messages.send_email()`
4. Add phone and vault capabilities as needed
5. Remove the AgentMail dependency
The Anima email API is designed to be familiar. If you have used AgentMail, you will find the patterns similar — the main difference is that Anima uses `agentId` to scope everything to a unified agent identity.
## Bottom Line
AgentMail is fine for email. But production agents do not just send email — they call, authenticate, and prove their identity. Anima provides the full stack so you can build agents that operate in the real world without stitching together multiple different services.
[Get started with Anima](/getting-started) | [See the full SDK reference](/sdks)
# Give Your AI Agent a Phone Number in 5 Minutes
Source: https://docs.useanima.sh/blog/give-agent-phone-number
Step-by-step tutorial: provision a US phone number for your AI agent, send SMS, place a first voice call, and handle inbound events.
# Give Your AI Agent a Phone Number in 5 Minutes
Your AI agent can send email, but some workflows need a phone path too: urgent updates, appointment reminders, SMS replies, voice confirmation, and verification flows. This tutorial provisions a number, sends a real SMS, places a first voice call, and wires inbound events to a webhook.
## Prerequisites
* An Anima API key from [console.useanima.sh](https://console.useanima.sh)
* Python 3.10+ or Node.js 18+
* An existing `agent_id`
* Phone access for SMS
* Voice access if you want to place the call step
* Consent to contact the destination number
Use your own phone number for the first run.
## 1. Install the SDK
```bash theme={null}
npm install @anima-labs/sdk
```
```bash theme={null}
pip install anima-labs
```
## 2. Search for available numbers
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const agentId = "AGENT_ID";
const numbers = await anima.phones.search({
countryCode: "US",
areaCode: "415",
capabilities: ["sms", "voice"],
limit: 3,
});
for (const number of numbers.items) {
console.log(number.phoneNumber, number.region);
}
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
agent_id = "AGENT_ID"
numbers = anima.phones.search(
country_code="US",
area_code="415",
capabilities=["sms", "voice"],
limit=3,
)
for number in numbers["items"]:
print(number["phoneNumber"], number.get("region"))
```
## 3. Provision the number
```ts theme={null}
const phone = await anima.phones.provision({
agentId,
countryCode: "US",
areaCode: "415",
capabilities: ["sms", "voice"],
});
console.log(`Provisioned: ${phone.phoneNumber}`);
```
```python theme={null}
phone = anima.phones.provision(
agent_id=agent_id,
country_code="US",
area_code="415",
capabilities=["sms", "voice"],
)
print(f"Provisioned: {phone.phone_number}")
```
The number is linked to the agent's unified identity: the same `agent_id` used for email, vault, DID, audit logs, and webhooks.
## 4. Text yourself
```ts theme={null}
const sms = await anima.messages.sendSms({
agentId,
to: "+15551234567",
body: "Hi - this is my Anima agent texting from its own number.",
});
console.log(`SMS sent: ${sms.id} (${sms.status})`);
```
```python theme={null}
sms = anima.messages.send_sms(
agent_id=agent_id,
to="+15551234567",
body="Hi - this is my Anima agent texting from its own number.",
)
print(f"SMS sent: {sms.id} ({sms.status})")
```
## 5. Call yourself
Outbound voice calls run through the voice gate before dialing. Only call recipients where you have the required consent.
```ts theme={null}
const call = await anima.calls.create({
agentId,
to: "+15551234567",
tier: "basic",
greeting: "Hi, this is my Anima agent. I am calling from my own phone number.",
});
console.log(`Call started: ${call.callId}, state: ${call.state}`);
```
```python theme={null}
call = anima.calls.create(
agent_id=agent_id,
to="+15551234567",
tier="basic",
greeting="Hi, this is my Anima agent. I am calling from my own phone number.",
)
print(f"Call started: {call.call_id}, state: {call.state}")
```
After the call ends, fetch the transcript:
```ts theme={null}
const transcript = await anima.calls.getTranscript(call.callId);
for (const segment of transcript.segments) {
console.log(`${segment.speaker}: ${segment.text}`);
}
```
```python theme={null}
transcript = anima.calls.get_transcript(call.call_id)
for segment in transcript.segments:
print(f"{segment.speaker}: {segment.text}")
```
## 6. Handle inbound events
Inbound SMS arrives as `message.received`; inspect the message channel/payload to distinguish SMS from email. Call lifecycle events use the `call.*` namespace.
```bash theme={null}
curl -X POST https://api.useanima.sh/v1/webhooks \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/anima",
"events": ["message.received", "phone.provisioned", "call.ended"]
}'
```
Example handler:
```ts theme={null}
app.post("/webhooks/anima", (req, res) => {
const event = req.body;
if (event.type === "message.received") {
console.log("Inbound message:", event.data);
}
if (event.type === "call.ended") {
console.log("Call ended:", event.data.callId);
}
res.status(200).send("ok");
});
```
## 10DLC and voice compliance
For US SMS, 10DLC registration may be required depending on your use case and volume. Anima tracks phone identity status and carrier capability flags with the provisioned number.
For US outbound voice calls, Anima enforces plan eligibility, TCPA consent posture, Reassigned Numbers Database checks, time-of-day windows, and per-tier call caps server-side. If a gate fails, the call is rejected before the provider dials.
## What makes this different
The phone number is not a disconnected CPaaS resource. It is part of the agent identity:
* Same `agent_id` across email, SMS, voice, vault, and DID
* Same policy and audit surface across channels
* Same webhook system for inbound and lifecycle events
* Same vault-backed credential boundary when the agent needs to act after the conversation
[Read the Phone docs](/phone) | [Set up webhooks](/webhooks) | [Get started](/getting-started)
# Introducing Anima: The Unified Identity Platform for AI Agents
Source: https://docs.useanima.sh/blog/introducing-anima
Anima gives AI agents real-world identity — email, phone, encrypted vault, and cryptographic identity — in a single API.
# Introducing Anima: The Unified Identity Platform for AI Agents
AI agents are crossing from demos into production. They book travel, manage procurement, handle customer support, and negotiate with vendors. But to do any of that in the real world, an agent needs more than an LLM and a prompt. It needs **identity**.
## The Identity Gap
Think about what a human employee gets on day one: a work email, a phone extension, access credentials, and an ID badge. An AI agent doing the same job needs the same things — and until now, you had to stitch them together yourself.
The current landscape looks like this:
* **Email**: One vendor gives you agent inboxes
* **Phone**: Another gives you programmable numbers
* **Credentials**: You roll your own secrets management
* **Identity**: You hope nobody asks "which agent did that?"
Each integration has its own SDK, its own auth model, its own billing, and its own failure modes. You end up building an identity layer from scratch every time you deploy an agent.
## One Platform. One API. One Identity.
Anima collapses the entire stack into a single platform. Every agent gets a unified identity that spans:
* **Email** — Real inboxes on custom domains with inbound/outbound, content scanning, and webhooks
* **Phone** — US phone numbers with SMS and voice, backed by Telnyx with 10DLC compliance
* **Vault** — Bitwarden-backed encrypted storage for logins, API keys, and secrets
* **Identity** — W3C DIDs, Verifiable Credentials, and Agent Cards for discovery and trust
All bound to a single `agent_id`. All managed through one SDK.
## What This Looks Like in Code
Here is a complete agent setup — email, phone, vault, and identity — in a single script:
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Create the agent
const agent = await anima.agents.create({ name: "Procurement Agent" });
// Email: send from a real inbox
await anima.messages.send_email({
agentId: agent.id,
to: "vendor@example.com",
subject: "PO #1042 — Confirm delivery date",
body: "Please confirm the expected delivery for PO #1042.",
});
// Phone: provision a number and send SMS
await anima.phones.provision({
agentId: agent.id,
countryCode: "US",
capabilities: ["sms", "voice"],
});
await anima.messages.sendSms({
agentId: agent.id,
to: "+15551234567",
body: "Your order has shipped. Track at https://example.com/track/1042",
});
// Vault: store vendor credentials
await anima.vault.provision({ agentId: agent.id });
await anima.vault.createCredential({
agentId: agent.id,
type: "login",
name: "Vendor Portal",
username: "procurement-bot",
password: "rotated-secret",
uris: ["https://vendor.example.com/login"],
});
// Identity: resolve the agent's DID
const did = await anima.identity.resolveDid(`did:anima:${agent.id}`);
console.log(did);
```
That is one SDK, one API key, one agent ID. No glue code. No multi-vendor orchestration.
## Key Differentiators
### Cryptographic Identity (DIDs)
Every Anima agent gets a `did:anima` decentralized identifier. This is not just a database row — it is a W3C-compliant DID with public keys, service endpoints, and verifiable credentials. Agents can prove who they are to other agents, services, and compliance systems.
### x402 Payments
Agents encounter paywalls and paid APIs constantly. Anima implements the x402 protocol: when a server returns `HTTP 402 Payment Required`, the agent's wallet automatically negotiates and pays — within budget guards you define. No checkout flows.
### Policy Engine
Every action goes through a configurable policy engine. You define rules like "never spend more than \$50 per transaction" or "only send emails to @acme.com domains." Policies are enforced at the platform level, not in your application code.
### SOC 2 Controls
Anima is built for production. Dual-layer content scanning (regex + AI classification), API key scoping (master keys vs. agent keys), encrypted vault storage, and full audit logging.
## SDKs and Tools
Anima ships SDKs for the ecosystems where agents run:
| SDK | Install | Status |
| ---------- | ---------------------------------------------- | ------ |
| Python | `pip install anima-labs` | GA |
| Node.js | `npm install @anima-labs/sdk` | GA |
| Go | `go get github.com/anima-labs-ai/go` | GA |
| CLI | `npm install -g @anima-labs/cli` | GA |
| MCP Server | 53 tools for Claude, GPT, and other LLM agents | GA |
The MCP server is worth highlighting: it exposes every Anima capability as a tool that LLM agents can call directly. Your agent does not need custom integration code — it discovers and uses Anima through the Model Context Protocol.
## Who Is This For?
* **Agent developers** who need production-ready identity primitives without building them from scratch
* **Enterprises** deploying agents that must comply with SOC 2, AML, and audit requirements
* **AI-native startups** building products where agents transact, communicate, and authenticate autonomously
## Get Started
Anima is available today. You can be up and running in under 5 minutes:
1. Sign up at [console.useanima.sh](https://console.useanima.sh)
2. Install the SDK: `pip install anima-labs` or `npm install @anima-labs/sdk`
3. Create your first agent and send an email — see the [Quickstart](/quickstart-email)
We are building the identity layer for the agentic internet. If you are building agents that need to operate in the real world, we would love to hear from you.
[Star us on GitHub](https://github.com/anima-labs) | [Join the Discord](https://discord.gg/anima) | [Read the Docs](/getting-started)
# x402 Payments: How AI Agents Pay for Things on the Internet
Source: https://docs.useanima.sh/blog/x402-payments
The x402 protocol turns HTTP 402 Payment Required into a real payment flow for AI agents. Here is how it works with Anima's Agent Wallet.
# x402 Payments: How AI Agents Pay for Things on the Internet
AI agents need to pay for things. They subscribe to APIs, purchase supplies, pay for compute, and buy services from other agents. But the internet's payment infrastructure was built for humans sitting at checkout forms — not for autonomous software.
Credit card forms require clicking buttons, filling fields, and solving CAPTCHAs. OAuth-based billing requires human approval flows. Neither works when an agent needs to pay for something autonomously, in real time, without human intervention.
The x402 protocol fixes this.
## HTTP 402: The Status Code Nobody Used
HTTP 402 Payment Required has been in the spec since 1997. For nearly 30 years, it was "reserved for future use." Every web developer has seen it in the status code list and wondered what it was for.
Now we know: it is for agent payments.
## How x402 Works
The x402 protocol is straightforward. When an agent makes an HTTP request to a paid resource, the server returns a `402 Payment Required` response with payment terms in the headers:
```
HTTP/1.1 402 Payment Required
X-Payment-Amount: 50
X-Payment-Currency: USD
X-Payment-Address: pay_vendor_abc123
X-Payment-Network: anima
X-Payment-Description: API call — premium data lookup
```
The agent's wallet reads these headers, checks the amount against its budget guards, and if approved, sends a payment and retries the request with a payment receipt:
```
GET /api/premium-data HTTP/1.1
Authorization: Bearer ak_...
X-Payment-Receipt: rcpt_9f8e7d6c5b4a
```
The server validates the receipt and returns the data. The entire flow — request, payment, retry — happens in milliseconds without human involvement.
```mermaid theme={null}
sequenceDiagram
participant Agent
participant Service as Paid API
participant Wallet as Anima Wallet
Agent->>Service: GET /api/premium-data
Service-->>Agent: 402 Payment Required (amount, address)
Agent->>Wallet: Authorize payment ($0.50)
Wallet->>Wallet: Check budget guards
Wallet-->>Agent: Payment receipt
Agent->>Service: GET /api/premium-data + receipt
Service-->>Agent: 200 OK (data)
```
## Setting Up the Agent Wallet
Every Anima agent can have a wallet with configurable budget guards:
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const agent = await anima.agents.create({ name: "Research Agent" });
// Create a wallet with spending limits
const wallet = await anima.wallet.create({
agentId: agent.id,
currency: "usd",
budgetGuards: {
dailyLimitCents: 100_00, // $100/day
monthlyLimitCents: 2000_00, // $2,000/month
perTransactionLimitCents: 10_00, // $10 max per transaction
requireApprovalAboveCents: 5_00, // Human approval above $5
},
});
console.log(`Wallet ${wallet.id} — Balance: $${wallet.balanceCents / 100}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
agent = anima.agents.create(name="Research Agent")
wallet = anima.wallet.create(
agent_id=agent.id,
currency="usd",
budget_guards={
"daily_limit_cents": 10000,
"monthly_limit_cents": 200000,
"per_transaction_limit_cents": 1000,
"require_approval_above_cents": 500,
},
)
print(f"Wallet {wallet.id} — Balance: ${wallet.balance_cents / 100}")
```
## Budget Guards: The Safety Net
Budget guards are the core safety mechanism. They prevent an agent from spending more than you authorize, even if the agent's logic has a bug or encounters an unexpectedly expensive API.
| Guard | Purpose |
| --------------------------- | ------------------------------------------------------------- |
| `dailyLimitCents` | Maximum total spend in a 24-hour rolling window |
| `monthlyLimitCents` | Maximum total spend in a calendar month |
| `perTransactionLimitCents` | Maximum amount for any single payment |
| `requireApprovalAboveCents` | Payments above this amount require human approval via webhook |
When a payment request exceeds any guard, the wallet rejects it and the agent receives an error. No payment is made. The rejection is logged for audit purposes.
### Approval Webhooks
For payments that exceed `requireApprovalAboveCents`, Anima sends a webhook to your application for human review:
```ts theme={null}
// Webhook payload for payment approval
{
"type": "wallet.approval_required",
"data": {
"agentId": "ag_8f3k2m9x1n4p7q6r",
"walletId": "wal_abc123",
"amountCents": 750,
"currency": "usd",
"vendor": "premium-data-api.com",
"description": "API call — premium data lookup",
"approvalUrl": "https://api.useanima.sh/v1/wallet/approve/txn_xyz789"
}
}
```
Your application can approve or deny the payment via the API:
```ts theme={null}
// Approve the payment
await anima.wallet.approveTransaction({ transactionId: "txn_xyz789" });
// Or deny it
await anima.wallet.denyTransaction({
transactionId: "txn_xyz789",
reason: "Exceeded expected cost for this operation",
});
```
## A Complete Payment Flow
Here is a realistic example: a research agent that pays for premium data from multiple sources.
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Create agent with wallet
const agent = await anima.agents.create({ name: "Market Research Agent" });
const wallet = await anima.wallet.create({
agentId: agent.id,
currency: "usd",
budgetGuards: {
dailyLimitCents: 50_00,
monthlyLimitCents: 500_00,
perTransactionLimitCents: 5_00,
requireApprovalAboveCents: 3_00,
},
});
// Fund the wallet
await anima.wallet.deposit({
walletId: wallet.id,
amountCents: 500_00,
source: "org_balance",
});
// The agent can now make x402 payments automatically.
// When it hits a paid API:
//
// 1. Agent sends GET to premium-data-api.com
// 2. Gets 402 with payment terms
// 3. Wallet checks: $2.00 < $5.00 per-txn limit ✓
// 4. Wallet checks: $2.00 < $50.00 daily limit ✓
// 5. Wallet checks: $2.00 < $3.00 approval threshold ✓ (auto-approve)
// 6. Payment sent, receipt returned
// 7. Agent retries request with receipt
// 8. Data returned
// Check spending
const balance = await anima.wallet.balance({ walletId: wallet.id });
console.log(`Remaining: $${balance.remainingCents / 100}`);
console.log(`Spent today: $${balance.spentTodayCents / 100}`);
console.log(`Spent this month: $${balance.spentMonthCents / 100}`);
```
## Security and Monitoring
Payments are the highest-risk action an agent can take. Anima layers multiple controls:
### Policy Engine
Every payment passes through the policy engine before execution. Beyond budget guards, you can define rules like:
* Block payments to specific vendors
* Require approval for first-time vendors
* Limit payments to specific merchant categories
* Set time-of-day restrictions
### Anomaly Detection
Anima's anomaly detection monitors x402 payment patterns. It flags unusual activity:
* Sudden increase in payment frequency
* Payments to new vendors outside the agent's normal pattern
* Spending rate approaching daily or monthly limits
* Payments that are unusually large relative to the agent's history
### Audit Trail
Every payment — approved, denied, or flagged — is logged with:
* Timestamp, amount, currency
* Vendor and payment description
* Which budget guard was checked
* Whether human approval was required
* The agent's DID for identity verification
```ts theme={null}
// Query payment history
const transactions = await anima.wallet.transactions({
walletId: wallet.id,
from: "2026-03-01",
to: "2026-03-28",
});
for (const txn of transactions) {
console.log(`${txn.timestamp} | $${txn.amountCents / 100} | ${txn.vendor} | ${txn.status}`);
}
```
## Why x402 Matters
The x402 protocol is not just a convenience — it is infrastructure for the agent economy. As agents proliferate, they need a way to pay for services without human intermediation. x402 provides:
* **Frictionless micropayments**: Agents can pay \$0.01 for an API call without the overhead of card processing
* **Automatic negotiation**: Payment terms are in HTTP headers — no integration required
* **Composability**: Any HTTP service can become a paid service by returning 402
* **Budget safety**: Wallet guards prevent runaway spending regardless of what the agent's LLM decides to do
The internet already has a status code for this. We just needed wallets smart enough to use it.
## Get Started
Set up an agent wallet in 3 lines:
```ts theme={null}
const agent = await anima.agents.create({ name: "My Agent" });
const wallet = await anima.wallet.create({
agentId: agent.id,
currency: "usd",
budgetGuards: { dailyLimitCents: 100_00, perTransactionLimitCents: 10_00 },
});
// Your agent can now pay for things on the internet.
```
[Read the Wallet docs](/wallet/overview) | [Explore x402 protocol](/protocols/overview) | [Get started](/getting-started)
# Call Intelligence
Source: https://docs.useanima.sh/call-intelligence
Read call records, stream live transcription, fetch transcripts, and use post-call intelligence endpoints.
# Call Intelligence
Anima stores voice call records under the same agent identity as email, SMS, and vault events. Use call intelligence to monitor calls while they run, fetch the finalized transcript after they end, and read post-call artifacts such as summaries, scores, recordings, and security scans when enabled for your account.
## Start a call
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
call = anima.calls.create(
agent_id="AGENT_ID",
to="+15551234567",
tier="basic",
greeting="Hi, this is my Anima agent. I am calling from my own number.",
)
print(call.call_id, call.state)
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const call = await anima.calls.create({
agentId: "AGENT_ID",
to: "+15551234567",
tier: "basic",
greeting: "Hi, this is my Anima agent. I am calling from my own number.",
});
console.log(call.callId, call.state);
```
## Stream live transcription
Use the voice WebSocket for live call events and bidirectional control.
```python theme={null}
conn = anima.calls.connect(agent_id="AGENT_ID")
def on_message(message: dict):
if message.get("type") == "call.transcription":
payload = message.get("data", message)
print(payload.get("text"))
conn.on_message(on_message)
conn.create_call(
"+15551234567",
tier="basic",
greeting="Hi, this is my Anima agent.",
)
```
```ts theme={null}
const conn = anima.calls.connect({ agentId: "AGENT_ID" });
conn.on("message", (message) => {
if (message.type === "call.transcription") {
console.log(message.data?.text);
}
});
conn.createCall("+15551234567", {
tier: "basic",
greeting: "Hi, this is my Anima agent.",
});
```
## Fetch the transcript
After the call ends, fetch the finalized transcript.
```python theme={null}
transcript = anima.calls.get_transcript(call.call_id)
for segment in transcript.segments:
print(f"[{segment.start_time}s] {segment.speaker}: {segment.text}")
```
```ts theme={null}
const transcript = await anima.calls.getTranscript(call.callId);
for (const segment of transcript.segments) {
console.log(`[${segment.startTime}s] ${segment.speaker}: ${segment.text}`);
}
```
## List and inspect calls
```python theme={null}
calls = anima.calls.list(agent_id="AGENT_ID", limit=20)
for item in calls["calls"]:
print(item.id, item.state, item.duration_seconds)
detail = anima.calls.get(call.call_id)
print(detail.state, detail.started_at, detail.ended_at)
```
```ts theme={null}
const calls = await anima.calls.list({ agentId: "AGENT_ID", limit: 20 });
for (const item of calls.calls) {
console.log(item.id, item.state, item.durationSeconds);
}
const detail = await anima.calls.get(call.callId);
console.log(detail.state, detail.startedAt, detail.endedAt);
```
## Post-call intelligence endpoints
Some post-call artifacts are exposed as REST endpoints and MCP tools even when a specific SDK helper is not present yet.
```bash theme={null}
curl https://api.useanima.sh/v1/voice/calls/CALL_ID/transcript \
-H "Authorization: Bearer ak_..."
curl https://api.useanima.sh/v1/voice/calls/CALL_ID/summary \
-H "Authorization: Bearer ak_..."
curl https://api.useanima.sh/v1/voice/calls/CALL_ID/score \
-H "Authorization: Bearer ak_..."
curl https://api.useanima.sh/v1/voice/calls/CALL_ID/recording \
-H "Authorization: Bearer ak_..."
curl https://api.useanima.sh/v1/voice/calls/CALL_ID/security \
-H "Authorization: Bearer ak_..."
```
MCP equivalents include `phone_call_get`, `phone_call_transcript_get`, `phone_call_recording_get`, `voice_get_summary`, `voice_get_score`, and `voice_get_security_scan` depending on the connected MCP server version.
## Guardrails
Outbound calls are gated server-side before dialing. The API enforces plan eligibility, TCPA consent posture, Reassigned Numbers Database checks, time-of-day windows, and per-tier call caps. If one of those checks fails, the call is rejected before reaching the telephony provider.
## Next steps
* [Voice Catalog](/voice-catalog) - List available voice tiers and catalog entries
* [Voice WebSocket Protocol](/protocols/voice-websocket) - Full real-time protocol reference
* [Phone & Voice](/phone) - Provision numbers, send SMS, and place calls
# Compliance Reporting
Source: https://docs.useanima.sh/compliance/reporting
Generate compliance reports, handle DSAR requests, and monitor compliance posture through dashboards and templates.
# Compliance Reporting
Anima provides built-in reporting tools for compliance workflows including SOC 2 audit preparation, DSAR (Data Subject Access Request) fulfillment, and executive compliance dashboards.
## Report Templates
Generate pre-built reports for common compliance needs:
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Generate a SOC 2 audit readiness report
const report = await useanima.shpliance.reports.generate({
template: "soc2-readiness",
period: {
startDate: "2026-01-01",
endDate: "2026-03-31",
},
format: "pdf", // "pdf" | "html" | "json"
includeEvidence: true,
});
console.log(`Report: ${report.id}`);
console.log(`Download: ${report.downloadUrl}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
report = useanima.shpliance.reports.generate(
template="soc2-readiness",
period={
"start_date": "2026-01-01",
"end_date": "2026-03-31",
},
format="pdf",
include_evidence=True,
)
print(f"Report: {report.id}")
print(f"Download: {report.download_url}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
report, err := client.Compliance.Reports.Generate(ctx, &anima.GenerateReportParams{
Template: "soc2-readiness",
Period: anima.ReportPeriod{
StartDate: "2026-01-01",
EndDate: "2026-03-31",
},
Format: "pdf",
IncludeEvidence: true,
})
```
### Available Templates
| Template | Description |
| ------------------ | -------------------------------------------------------------- |
| `soc2-readiness` | SOC 2 Type II audit readiness with control status and evidence |
| `agent-activity` | Summary of agent actions, emails sent, transactions processed |
| `security-posture` | Anomaly detection results, quarantine events, key rotations |
| `access-review` | API key usage, permission changes, pod access |
| `spending-summary` | Wallet spending by agent, pod, and time period |
| `data-inventory` | Inventory of data stored across vault, email, and attachments |
## DSAR (Data Subject Access Requests)
Handle GDPR and CCPA data subject access requests:
```ts theme={null}
// Initiate a DSAR
const dsar = await useanima.shpliance.dsar.create({
subjectEmail: "user@example.com",
requestType: "access", // "access" | "deletion" | "portability"
notes: "GDPR Article 15 request received via support ticket #4521",
});
console.log(`DSAR ID: ${dsar.id}`);
console.log(`Status: ${dsar.status}`); // "processing" | "ready" | "completed"
console.log(`Estimated completion: ${dsar.estimatedCompletionAt}`);
// Check DSAR status and download results
const result = await useanima.shpliance.dsar.get(dsar.id);
if (result.status === "ready") {
console.log(`Download: ${result.downloadUrl}`);
console.log(`Records found: ${result.recordCount}`);
console.log(`Data categories: ${result.categories.join(", ")}`);
}
```
```python theme={null}
dsar = useanima.shpliance.dsar.create(
subject_email="user@example.com",
request_type="access",
notes="GDPR Article 15 request received via support ticket #4521",
)
print(f"DSAR ID: {dsar.id}")
print(f"Status: {dsar.status}")
# Check status and download
result = useanima.shpliance.dsar.get(dsar.id)
if result.status == "ready":
print(f"Download: {result.download_url}")
print(f"Records found: {result.record_count}")
```
### DSAR Data Categories
When a DSAR is processed, data is collected across these categories:
| Category | Data Included |
| ------------------ | ------------------------------------------ |
| `email_messages` | Emails sent to or from the subject |
| `a2a_interactions` | A2A tasks involving the subject's agents |
| `audit_events` | Audit log entries referencing the subject |
| `agent_metadata` | Agent profiles associated with the subject |
## Compliance Dashboard
Get a real-time view of your compliance posture:
```ts theme={null}
const dashboard = await useanima.shpliance.dashboard.get();
console.log("--- Compliance Dashboard ---");
console.log(`SOC 2 Controls: ${dashboard.soc2.passing}/${dashboard.soc2.total} passing`);
console.log(`Readiness Score: ${dashboard.soc2.readinessScore}%`);
console.log(`Open DSARs: ${dashboard.dsar.openCount}`);
console.log(`Avg DSAR Resolution: ${dashboard.dsar.avgResolutionDays} days`);
console.log(`Anomalies (30d): ${dashboard.anomalies.last30Days}`);
console.log(`Quarantined Agents: ${dashboard.anomalies.quarantinedCount}`);
console.log(`Last Audit Report: ${dashboard.lastReport.generatedAt}`);
```
## Scheduled Reports
Automate report generation on a schedule:
```ts theme={null}
await useanima.shpliance.reports.schedule({
template: "security-posture",
frequency: "weekly", // "daily" | "weekly" | "monthly" | "quarterly"
format: "pdf",
recipients: ["compliance@acme.com", "ciso@acme.com"],
dayOfWeek: "monday", // for weekly reports
});
```
## API Reference
| Endpoint | Method | Description |
| --------------------------------------------------------- | ------ | ---------------------------------- |
| `https://api.useanima.sh/api/compliance/reports` | POST | Generate a report |
| `https://api.useanima.sh/api/compliance/reports` | GET | List generated reports |
| `https://api.useanima.sh/api/compliance/reports/:id` | GET | Get report status and download URL |
| `https://api.useanima.sh/api/compliance/reports/schedule` | POST | Schedule recurring reports |
| `https://api.useanima.sh/api/compliance/reports/schedule` | GET | List scheduled reports |
| `https://api.useanima.sh/api/compliance/dsar` | POST | Create a DSAR request |
| `https://api.useanima.sh/api/compliance/dsar` | GET | List DSARs |
| `https://api.useanima.sh/api/compliance/dsar/:id` | GET | Get DSAR status and results |
| `https://api.useanima.sh/api/compliance/dashboard` | GET | Get compliance dashboard |
## Configuration
| Variable | Default | Description |
| ----------------------------------- | ------- | ------------------------------------- |
| `ANIMA_COMPLIANCE_DSAR_SLA_DAYS` | `30` | DSAR completion SLA in days |
| `ANIMA_COMPLIANCE_REPORT_RETENTION` | `730` | Report retention in days (2 years) |
| `ANIMA_COMPLIANCE_REPORT_STORAGE` | `s3` | Storage backend for generated reports |
## Next Steps
* [SOC 2 Controls](/compliance/soc2-controls) -- Detailed control mappings
* [Audit Log](/security/audit-log) -- Underlying data for reports
* [Anomaly Detection](/security/anomaly-detection) -- Security posture data
# SOC 2 Controls
Source: https://docs.useanima.sh/compliance/soc2-controls
SOC 2 Type II compliance framework for AI agent operations. Control mappings, evidence collection, and continuous monitoring.
# SOC 2 Controls
Anima provides built-in SOC 2 Type II controls and automated evidence collection for AI agent operations. The platform maps its security features to Trust Service Criteria, making audit preparation straightforward.
## Trust Service Criteria Mapping
Anima covers controls across all five Trust Service Categories:
### Security (Common Criteria)
| Control ID | Control | Anima Feature |
| ---------- | --------------------------------- | ----------------------------------------- |
| CC6.1 | Logical access security | Pod isolation, API key scoping |
| CC6.2 | Authentication mechanisms | DID-based auth, API key rotation |
| CC6.3 | Authorization and access controls | Role-based permissions, budget guards |
| CC6.6 | System boundary protections | Pod network isolation, MCC controls |
| CC7.1 | Monitoring for anomalies | Anomaly detection, behavioral baselines |
| CC7.2 | Activity monitoring and alerting | Audit log, SIEM integration |
| CC7.3 | Evaluating security events | Quarantine, incident response workflows |
| CC8.1 | Change management | API versioning, configuration audit trail |
### Availability
| Control ID | Control | Anima Feature |
| ---------- | ------------------- | ------------------------------------ |
| A1.1 | Capacity management | Pod resource limits, rate limiting |
| A1.2 | Recovery procedures | Automated backups, disaster recovery |
### Confidentiality
| Control ID | Control | Anima Feature |
| ---------- | ----------------------------------- | ---------------------------------------- |
| C1.1 | Identification of confidential data | Vault encryption, secret classification |
| C1.2 | Disposal of confidential data | Vault secret expiration, secure deletion |
## Viewing Controls Status
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Get SOC 2 controls status
const controls = await useanima.shpliance.soc2.listControls();
for (const control of controls.data) {
console.log(`${control.id}: ${control.name}`);
console.log(` Status: ${control.status}`); // "passing" | "failing" | "not_evaluated"
console.log(` Evidence: ${control.evidenceCount} items`);
console.log(` Last evaluated: ${control.lastEvaluatedAt}`);
}
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
controls = useanima.shpliance.soc2.list_controls()
for control in controls.data:
print(f"{control.id}: {control.name}")
print(f" Status: {control.status}")
print(f" Evidence: {control.evidence_count} items")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
controls, err := client.Compliance.SOC2.ListControls(ctx)
for _, c := range controls.Data {
fmt.Printf("%s: %s -- %s\n", c.ID, c.Name, c.Status)
}
```
## Evidence Collection
Anima automatically collects evidence for each control from audit logs, configurations, and system state:
```ts theme={null}
// Get evidence for a specific control
const evidence = await useanima.shpliance.soc2.getEvidence("CC6.1", {
startDate: "2026-01-01",
endDate: "2026-03-31",
});
for (const item of evidence.data) {
console.log(`[${item.timestamp}] ${item.type}: ${item.description}`);
console.log(` Source: ${item.source}`);
console.log(` Artifact: ${item.artifactUrl}`);
}
```
### Evidence Types
| Type | Description |
| ----------------- | ---------------------------------------------------- |
| `configuration` | System configuration snapshots proving control state |
| `audit_event` | Audit log entries demonstrating control enforcement |
| `policy_document` | Automatically generated policy documentation |
| `test_result` | Results of automated control tests |
| `access_review` | Periodic access review records |
## Continuous Monitoring
Controls are continuously evaluated, not just at audit time:
```ts theme={null}
// Configure continuous monitoring
await useanima.shpliance.soc2.configureMonitoring({
evaluationInterval: "1h", // How often to re-evaluate controls
alertOnFailure: true,
alertChannels: [
{ type: "email", address: "compliance@acme.com" },
{ type: "slack", webhookUrl: "https://hooks.slack.com/..." },
],
});
// Get monitoring dashboard data
const dashboard = await useanima.shpliance.soc2.getDashboard();
console.log(`Controls passing: ${dashboard.passing}/${dashboard.total}`);
console.log(`Last full evaluation: ${dashboard.lastFullEvaluation}`);
console.log(`Audit readiness score: ${dashboard.readinessScore}%`);
```
## API Reference
| Endpoint | Method | Description |
| ------------------------------------------------------------- | ------ | ---------------------------------- |
| `https://api.useanima.sh/api/compliance/soc2/controls` | GET | List all SOC 2 controls and status |
| `https://api.useanima.sh/api/compliance/soc2/controls/:id` | GET | Get a specific control |
| `https://api.useanima.sh/api/compliance/soc2/evidence` | GET | Query evidence by control and date |
| `https://api.useanima.sh/api/compliance/soc2/evidence/export` | POST | Export evidence package |
| `https://api.useanima.sh/api/compliance/soc2/monitoring` | PUT | Configure continuous monitoring |
| `https://api.useanima.sh/api/compliance/soc2/dashboard` | GET | Get compliance dashboard data |
## Configuration
| Variable | Default | Description |
| ------------------------------------ | ------- | ----------------------------------- |
| `ANIMA_SOC2_EVALUATION_INTERVAL` | `1h` | Control evaluation frequency |
| `ANIMA_SOC2_EVIDENCE_RETENTION_DAYS` | `730` | Evidence retention period (2 years) |
| `ANIMA_SOC2_ALERT_ON_FAILURE` | `true` | Alert when a control starts failing |
## Next Steps
* [Compliance Reporting](/compliance/reporting) -- Generate audit-ready reports
* [Audit Log](/security/audit-log) -- Underlying event data for evidence
* [Anomaly Detection](/security/anomaly-detection) -- CC7.x control implementation
# Conversational Calls
Source: https://docs.useanima.sh/conversational-calls
Understand Anima's REST-hosted, realtime, and WebSocket-controlled voice-call modes.
# Conversational Calls
Anima supports three voice-call modes. Pick the mode based on who should drive the live conversation: Anima's hosted loop, the realtime voice pipeline, or your own agent over WebSocket.
## Modes
| Mode | How to start | Who drives the conversation | Best for |
| -------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| REST hosted, Basic/Premium | `POST /v1/voice/calls` with `tier: "basic"` or `tier: "premium"` | Anima attaches a server-side conversation loop after dialing | "Call me now" demos, scripted follow-up calls, quick production calls |
| REST realtime | `POST /v1/voice/calls` with `tier: "realtime"` | The realtime pipeline drives STT, LLM, TTS, tools, and barge-in | Low-latency calls with a custom per-call `systemPrompt` |
| WebSocket BYO agent | Voice WebSocket / SDK connection | Your agent runtime accepts calls, streams events, and sends speech/control messages | Custom agents, complex routing, external memory, custom tool orchestration |
All modes still use the same phone identity, call records, transcripts, guardrails, and plan caps.
## REST hosted calls
Use REST when you want one HTTP request to start a call and let Anima handle the live response loop.
```bash theme={null}
curl -X POST https://api.useanima.sh/v1/voice/calls \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{
"agentId": "agt_...",
"to": "+15551234567",
"tier": "basic",
"greeting": "Hi, this is my Anima agent. I am calling from my own number."
}'
```
For `basic` and `premium`, Anima attaches the hosted conversation loop. The first spoken line comes from `greeting`. Deeper behavior comes from the agent configuration and the hosted voice loop.
## Realtime calls
Use `realtime` when you want the low-latency realtime pipeline. This mode accepts an optional per-call `systemPrompt`.
```bash theme={null}
curl -X POST https://api.useanima.sh/v1/voice/calls \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{
"agentId": "agt_...",
"to": "+15551234567",
"tier": "realtime",
"greeting": "Hi, I can help with your appointment.",
"systemPrompt": "You are a concise scheduling assistant. Confirm the caller identity before discussing appointment details."
}'
```
`systemPrompt` is for the realtime tier. Basic and Premium use the hosted conversation loop and agent configuration instead.
## WebSocket-controlled calls
Use the Voice WebSocket when your own agent runtime needs full control over the call.
```ts theme={null}
const conn = anima.calls.connect({ agentId: "agt_..." });
conn.on("message", (message) => {
if (message.type === "call.transcription") {
console.log(message.data?.text);
}
});
conn.createCall("+15551234567", {
tier: "basic",
greeting: "Hi, this is my Anima agent.",
});
```
The WebSocket path is the right choice when you need custom memory, custom tool routing, multi-agent handoff, or external application state during the live call.
## What Anima handles
* Number ownership and call placement
* Voice pipeline selection
* TCPA, RND, time-of-day, and plan-cap gates
* Call lifecycle records
* Transcripts and post-call artifacts
* Webhooks for call lifecycle events
## What your app still owns
* The lawful basis and consent record for contacting the recipient
* Agent behavior and escalation policy
* Any business-specific data used during the call
* Follow-up workflows after the call ends
## Related docs
* [Quickstart: Voice Calls](/quickstart-voice)
* [Voice WebSocket Protocol](/protocols/voice-websocket)
* [Call Intelligence](/call-intelligence)
* [Pricing & Limits](/pricing-and-limits)
# Custom Domains
Source: https://docs.useanima.sh/custom-domains
Set up branded sending domains in Anima with DNS records, verification guidance, and troubleshooting tips.
# Custom Domains
Use your own domain for branded agent email. Anima generates the required DNS records, shows what still needs to propagate, and lets you verify once your provider publishes the changes.
***
### Why use a custom domain?
Send from your own brand, improve trust with recipients, and separate production sending from shared or testing domains.
### What you need first
A domain you control plus access to its DNS provider — for example Cloudflare, Route 53, Namecheap, GoDaddy, or another registrar.
### How long does it take?
Many DNS changes appear within minutes, but some providers take up to 48 hours to fully propagate.
***
## What Anima sets up for you
Your agents both send and receive mail on a custom domain, so Anima generates a complete set of DNS records covering both directions. You publish them once at your DNS provider; Anima handles delivery, signing, reputation, and inbound routing from there.
| Direction | What the records do |
| ------------ | -------------------------------------------------------------------------------------- |
| **Inbound** | Route incoming mail and replies to your agents' inboxes. |
| **Outbound** | Authenticate outgoing mail (SPF, DKIM, DMARC) so recipient mailbox providers trust it. |
Your only job is DNS. Once the records verify, sending and receiving work with no further configuration.
***
## 1. Create the domain in Anima
Go to **Dashboard → Domains**, click **Add domain**, and enter the root domain you want to send from — for example `example.com`. Once created, Anima opens the DNS setup surface immediately so you can copy the required records without hunting through the table.
## 2. Copy the required DNS records
Anima generates the ownership TXT, the mail-routing MX records, the DKIM CNAME records, the SPF TXT record, and the DMARC TXT record for you. The product shows both the full record name and the shorter host value most DNS providers expect.
| Record | Host example | Why it matters |
| ------ | -------------------- | ----------------------------------------------------------------------------------------------------------- |
| TXT | `@` | Verifies that you control the domain. |
| MX | `mail` | Routes bounce and return-path traffic for outbound mail. |
| TXT | `mail` | Publishes SPF for the dedicated return-path subdomain. |
| CNAME | `token-a._domainkey` | Publishes DKIM keys so mailbox providers trust mail signed for your domain. |
| MX | `@` | Routes inbound agent mail and replies for the domain. |
| TXT | `@` or merge | Authorizes Anima to send on your behalf via SPF. Merge into an existing SPF record if you already have one. |
| TXT | `_dmarc` | Tells inbox providers how to handle failed authentication and where to send aggregate reports. |
## 3. Use the right host format in your DNS provider
This is the most common source of mistakes. Many DNS providers automatically append your root domain, so the safe default is to paste the **Host** column values from Anima instead of manually reconstructing the full record name.
Avoid entering `_dmarc.example.com` into a provider that automatically appends `example.com` — that creates `_dmarc.example.com.example.com`.
### Provider-specific notes
**Cloudflare** — Usually appends the root domain automatically. Paste the Host column, not the full name.
**Route 53** — Supports manual entry and zone imports, but review long TXT values carefully if you paste them manually.
**Namecheap** — Uses Host and Value fields. Prefer `@`, `mail`, and `_dmarc` instead of full FQDNs where possible.
**GoDaddy** — Treat the UI as relative hostnames unless the screen explicitly asks for the full record name.
The `mail` host is reserved for outbound return-path and bounce handling. Leave your apex MX pointed at the inbound record Anima provides so agent mail and replies are delivered.
## 4. Download the zone file if your provider supports imports
The DNS setup surface includes a **Download zone file** action. Use it when your DNS provider accepts BIND-style imports — it's the fastest way to publish all records at once. If your provider does not support imports, copy each record individually from the setup table.
## 5. Verify and troubleshoot
When you click **Verify records**, Anima checks each required DNS record and marks it as **Valid**, **Missing**, or **Invalid**. Fix only the rows that fail — if a record already matches, leave it alone and allow DNS time to propagate.
### Verification statuses
**Missing** — The provider has not published the record yet, or propagation is still in progress.
**Invalid** — A record exists, but the value or host is wrong. Compare the row in Anima against what your provider shows.
**Valid** — That record is correct and does not need changes.
### SPF merge rule
A domain should publish only one SPF TXT record at the root. If you already use SPF elsewhere, keep the existing record and merge Anima's `include:` mechanism into it rather than creating a second SPF TXT record.
## Ready to configure your domain?
Open the Domains page to create a domain, copy records, and verify the setup in one place.
* [Open domains](https://console.useanima.sh/domains)
# Encryption & Security
Source: https://docs.useanima.sh/encryption
Learn how Anima uses AES-256-GCM field-level encryption, envelope encryption, per-agent key derivation, and key rotation to protect sensitive data.
# Encryption & Security
Anima protects sensitive integration secrets with field-level encryption built on AES-256-GCM and envelope key management.
### AES-256-GCM by Default
Field-level encryption uses AES-256-GCM for secure secret storage.
### Envelope Encryption
Org data encryption keys are wrapped and managed through envelope encryption.
## Field-Level Encryption Model
Sensitive values are encrypted at the field level before persistence, keeping secrets protected while preserving application-level access controls.
* **Algorithm:** AES-256-GCM.
* **Scope:** Encrypt sensitive secret fields individually.
* **Integrity:** Authenticated encryption provides tamper detection.
* **Tenant isolation:** Each organization uses isolated encryption context.
## Envelope Encryption (KEK → DEK)
Envelope encryption separates key encryption from data encryption so secrets can be protected with layered key management.
```text theme={null}
1. Create org DEK
2. Wrap DEK with KEK (stored in KMS/HSM boundary)
3. Encrypt secret field with org DEK (AES-256-GCM)
4. Persist ciphertext + iv + authTag + keyVersion
5. On read, unwrap DEK and decrypt if access policy allows
```
## Encrypted Fields
* API keys
* Webhook secrets
* Email provider credentials
## Key Rotation
Key rotation is versioned so encrypted data can move to newer key material over time without breaking existing records.
> **Note:** Rotation is non-breaking: reads support legacy key versions until migration is complete.
## Prisma Encryption Extension Example
This Prisma extension encrypts secrets on write and decrypts them on read.
```ts title="prisma/encryption-extension.ts" theme={null}
import { PrismaClient } from "@prisma/client";
import { encryptField, decryptField } from "@/lib/crypto/field-encryption";
const prisma = new PrismaClient().$extends({
query: {
integrationCredential: {
async create({ args, query }) {
const organizationId = args.data.organizationId;
return query({
...args,
data: {
...args.data,
secretCiphertext: encryptField({
organizationId,
plaintext: args.data.secretPlaintext,
field: "secretPlaintext",
}),
},
});
},
async findUnique({ args, query }) {
const record = await query(args);
if (!record) return null;
return {
...record,
secretPlaintext: decryptField({
organizationId: record.organizationId,
ciphertext: record.secretCiphertext,
field: "secretPlaintext",
}),
};
},
},
},
});
export { prisma };
```
> **Warning:** Never log decrypted secrets, and never render plaintext credentials in client-side UI.
## Vault Per-Agent Encryption
The [Vault](/vault) extends this model with a unique Data Encryption Key (DEK) per agent, derived from the organization DEK with HKDF:
```text theme={null}
HKDF-SHA256(
ikm = orgDek,
salt = SHA256(agentId),
info = "anima-vault-agent-dek"
) → agentDek (32 bytes)
```
This gives three properties:
* **Cross-agent isolation** — Agent A cannot decrypt Agent B's credentials, because each derives a different DEK.
* **No extra key storage** — the derivation is deterministic, so agent DEKs are computed on demand rather than stored.
* **Rotation cascades** — rotating the organization DEK automatically re-derives (and so rotates) every agent DEK.
See the [Vault documentation](/vault) for how these keys protect credential storage, sharing, and injection.
# API Error Reference
Source: https://docs.useanima.sh/errors
Every error code the Anima API emits — RFC 7807 problem types, what they mean, and how to fix them.
# API Errors
The Anima API returns errors as [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) `application/problem+json`. The `type` URI is always `https://docs.useanima.sh/errors/` (the code, lowercased, `_` → `-`) — those URIs are stable forever, and they all resolve to this page. Machine clients should branch on the `code` extension field.
```json theme={null}
{
"type": "https://docs.useanima.sh/errors/rate-limited",
"title": "Too Many Requests",
"status": 429,
"detail": "Too many requests",
"instance": "/v1/email/send",
"code": "RATE_LIMITED",
"details": { "retryAfter": 12 },
"error": { "code": "RATE_LIMITED", "message": "Too many requests" }
}
```
* `code` and `details` are Anima extensions (RFC 7807 permits extensions).
* Many errors include `details.remediation` — a `hint` written for both humans and LLM agents, sometimes with a `docsUrl` or `verificationUrl`. Agents should surface or act on the hint before retrying.
* The legacy `error: { code, message, details }` sibling is preserved through SDK v1.x and will be removed in v2.
* Every response carries `x-request-id` (unique per call) and `x-correlation-id` (stable per workflow) — include both when contacting support.
## Request errors (4xx)
| Code | HTTP | Meaning | What to do |
| ---------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `VALIDATION_ERROR` | 400 | The request body or parameters failed schema validation. | Fix the request shape; `details` carries field-level errors. |
| `BAD_REQUEST` | 400 | The request is well-formed but invalid in the current state (e.g. re-enabling an already-active webhook, replaying a delivery that isn't dead-lettered). | Read `detail` — it names the state that blocked the operation. |
| `INVALID_IDEMPOTENCY_KEY` | 400 | `Idempotency-Key` isn't 1–255 printable ASCII characters. | Send a UUID (or any conforming string). |
| `UNAUTHORIZED` | 401 | Missing or invalid credentials. | Send `Authorization: Bearer ` with a live `ak_`/`mk_` key or OAuth token. |
| `PAYMENT_REQUIRED` | 402 | A plan limit was reached (agents, identities, monthly volume). | Upgrade the tier or wait for the billing period; see [Pricing & Limits](/pricing-and-limits). |
| `VOICE_MONTHLY_CAP_EXCEEDED` | 402 | The tier's monthly outbound-call cap is used up. | Upgrade or wait until the next billing period; `details` carries `current`/`cap`. |
| `FORBIDDEN` | 403 | Authenticated, but not allowed: acting on another agent's resources, or an [agent capability policy](/security#agent-capability-policies) refused the action. | Use the right key for the agent, or have an org admin adjust the agent's policy. |
| `MASTER_KEY_REQUIRED` | 403 | The operation needs org-admin authority (agent creation, billing, policy writes). | Use an `mk_` key, or request the `admin:full` scope in the OAuth flow. |
| `NOT_FOUND` | 404 | The resource doesn't exist — or belongs to another organization (deliberately indistinguishable). | Check the id and which org your key belongs to. |
| `CONFLICT` | 409 | State conflict, e.g. a duplicate slug or an already-existing resource. | Change the conflicting value or reuse the existing resource. |
| `IDEMPOTENCY_BODY_MISMATCH` | 409 | The same `Idempotency-Key` was reused with a different body or path. | Use a fresh key per distinct request; reuse keys only for identical retries. |
| `IDENTITY_NOT_VERIFIED` | 409 | The sending email identity isn't verified in the send region. | Follow `details.remediation` — verify the identity or attach one on a verified domain ([Custom Domains](/custom-domains)). |
| `DOMAIN_NOT_VERIFIED` | 409 | Provision-time gate: the email domain isn't added/verified for this workspace. | Add and verify the domain first — see [Custom Domains](/custom-domains). |
| `RECIPIENT_NOT_VERIFIED` | 409 | The upstream provider (SES sandbox) only delivers to verified recipients. | Verify the recipient at AWS or request SES production access; `details.remediation` explains both. |
| `RECIPIENT_SUPPRESSED` | 409 | The recipient unsubscribed, hard-bounced, or complained — Anima refuses to send to them. | Remove the address from the recipient list; suppressions are inspectable per workspace. |
| `RATE_LIMITED`, `RATE_LIMIT` | 429 | Per-minute/per-hour quota exceeded for the channel. | Honor `Retry-After` and the `X-RateLimit-*` headers; back off and retry. |
| `RATE_LIMIT_PER_SECOND` | 429 | The per-org per-second soft cap was hit. | Smooth the burst; caps scale with tier. |
| `VOICE_RATE_LIMIT_EXCEEDED` | 429 | Outbound dialing exceeded the per-second call cap. | Slow the dialing loop; `details` carries `current`/`cap`. |
| `TCPA_GATE_BLOCKED` | 451 | Outbound calling is blocked until the org completes consent attestation (TCPA/DNC), or this call failed the gate. | Complete the consent attestation in the console; `details.missingFields` lists what's missing. |
## Server errors (5xx)
| Code | HTTP | Meaning | What to do |
| ---------------------------- | ---- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| `INTERNAL_ERROR`, `INTERNAL` | 500 | Unexpected server failure. | Retry with backoff; if it persists, contact support with the `x-request-id`. |
| `BAD_GATEWAY` | 502 | The upstream email provider rejected or failed the request. | Retry; if persistent, the `detail` names the provider error. |
| `PHONE_PROVIDER_ERROR` | 502 | The upstream phone/voice provider failed the operation. | Retry; `detail` names the provider and operation. |
| `SERVICE_UNAVAILABLE` | 503 | The feature is disabled or its infrastructure isn't configured for this environment. | Nothing client-side — the `detail` names the service; contact support if unexpected. |
## Related
* [Webhooks](/webhooks) — delivery signing and retry behavior
* [Security](/security) — key types and agent capability policies
* [Pricing & Limits](/pricing-and-limits) — tier quotas behind 402/429
# Examples
Source: https://docs.useanima.sh/examples
Example agents demonstrating the Anima platform.
# Example Agents
Explore complete, runnable example agents that demonstrate how to use the Anima platform.
## Available Examples
| Example | Services Used | Description |
| --------------------------------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------- |
| [Email Agent](https://github.com/anima-labs-ai/examples/tree/main/email-agent) | Email | AI agent that monitors an inbox and auto-replies using GPT-4 |
| [E-Commerce Agent](https://github.com/anima-labs-ai/examples/tree/main/ecommerce-agent) | Email, Vault | Purchase agent with AI evaluation, vault-backed checkout, and credential storage |
| [Support Agent](https://github.com/anima-labs-ai/examples/tree/main/support-agent) | Email, Vault | Customer support with AI triage, response generation, and escalation |
| [Travel Agent](https://github.com/anima-labs-ai/examples/tree/main/travel-agent) | Email, Vault | Travel booking with AI planning, loyalty credentials, and vault-backed checkout |
| [OpenAI Terminal](https://github.com/anima-labs-ai/examples/tree/main/openai-terminal) | Email | Terminal chat agent using OpenAI Agents SDK |
| [Vercel AI Agent](https://github.com/anima-labs-ai/examples/tree/main/vercel-ai-agent) | Email | Streaming agent using Vercel AI SDK (TypeScript) |
## Getting Started
```bash theme={null}
git clone https://github.com/anima-labs-ai/examples.git
cd examples/
cp .env.example .env
# Add your API keys
pip install -r requirements.txt # or npm install
python main.py # or npx tsx main.ts
```
## Building Your Own Agent
Every Anima agent follows a similar pattern:
1. **Create an agent** — your agent's identity on the platform
2. **Provision capabilities** — email inbox, vault, phone number
3. **Implement logic** — use AI to process inputs and make decisions
4. **Act through Anima** — send emails, store credentials, place calls
5. **Clean up** — deprovision resources when done
See the [quickstart guides](/quickstart-email) to get started with each capability.
# Headless Extension Connect
Source: https://docs.useanima.sh/extension-connect
Connect the Anima browser extension to an agent with no human — mint a connect URL, open it in a headless browser (e.g. a Puppeteer worker), and the extension auto-binds its bridge.
# Headless Extension Connect
The [Anima browser extension](/vault#browser-extension) links an agent to a real browser so it can autofill vault credentials and drive logins without any secret entering the model's context. Normally a person installs the extension and clicks **Connect**.
For automation — a Puppeteer worker, a scheduled scraper, a partner integration — there is no person to click. **Headless connect** closes that gap: mint a one-time connect URL with the API, open it in the headless browser, and the extension binds its bridge to the agent automatically.
The connect response never contains a token or a secret. `connectUrl` itself carries a short-lived, single-use exchange code; the extension redeems it out of band. Nothing sensitive passes through the model.
## The flow
Call `POST /v1/extension/connect`. The API returns a `connectUrl` pointing at the console connect page, carrying a single-use `exc_auto_…` exchange code.
Navigate the automation browser (with the Anima extension loaded) to `connectUrl`. The `exc_auto_` prefix tells the page to relay the code to the extension automatically — no click.
The page exposes `data-connect-status`, which transitions to `connected` once the extension has bound its bridge to the agent. Wait on `[data-connect-status="connected"]`, then run your automation.
## Auth model
Who you authenticate as decides whether you pass `agentId`:
| Credential | `agentId` | Behavior |
| ---------------------- | ------------ | ----------------------------------------------------------------------------------- |
| **Master key** (`mk_`) | **Required** | Selects which agent the extension connects as. |
| **Agent key** (`ak_`) | **Omit** | The server resolves the agent from the key. Passing another agent's id is rejected. |
Two org policies support headless connect: **`session`** and **`pre_approved`**. The **`prompt_owner`** policy is **not supported** — there is no owner to approve an unattended connection, so the API rejects it:
```
Headless connect is not available under the prompt_owner policy — use session or pre_approved.
```
Under `pre_approved`, the target agent must be on the org's pre-approved allowlist (configure it under **Settings → Extension** in the console), or the request is rejected.
### `ttl`
`ttl` is optional and **shorten-only**: `"15m" | "1h" | "session"`. It may only be shorter than — or equal to — the org's configured maximum. A value **longer** than the org policy is rejected rather than silently downgraded, so you learn the org forbids that lifetime instead of quietly getting a shorter one. Omit `ttl` to use the org default. A `"session"` TTL has no wall-clock expiry, so `expiresAt` comes back `null`.
The separate `exchangeExpiresAt` is the deadline for redeeming the connect URL itself (a single-use handoff window, \~60 seconds) — distinct from `expiresAt`, the lifetime of the resulting connection.
## Mint a connect URL
```bash cURL theme={null}
curl -X POST https://api.useanima.sh/v1/extension/connect \
-H "Authorization: Bearer $ANIMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agentId": "agent_123", "ttl": "session"}'
# → {
# "agentId": "agent_123",
# "connectUrl": "https://console.useanima.sh/extension/connect?code=exc_auto_…",
# "expiresAt": null,
# "exchangeExpiresAt": "2026-01-01T00:01:00.000Z",
# "policy": "session"
# }
```
```bash CLI theme={null}
# Master key: pass the agent.
anima extension connect --agent agent_123 --ttl session
# Agent key: omit it — the agent is resolved from the key.
anima extension connect
# Add --json for the full payload instead of the human-readable summary.
anima extension connect --agent agent_123 --json
```
```typescript Node theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: process.env.ANIMA_API_KEY });
const { connectUrl } = await anima.extension.connect({
agentId: "agent_123", // omit when using an agent key
ttl: "session",
});
```
```python Python theme={null}
import os
from anima import Anima
client = Anima(api_key=os.environ["ANIMA_API_KEY"])
result = client.extension.connect(agent_id="agent_123", ttl="session")
connect_url = result.connect_url
# Async: from anima import AsyncAnima
# result = await client.extension.connect(agent_id="agent_123", ttl="session")
```
```go Go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
res, err := client.Extension.Connect(ctx, anima.ConnectExtensionParams{
AgentID: "agent_123", // omit when using an agent key
TTL: "session",
})
if err != nil {
log.Fatal(err)
}
connectURL := res.ConnectURL
```
```json MCP theme={null}
// Tool: extension_connect
{
"agentId": "agent_123",
"ttl": "session"
}
```
### Response
| Field | Type | Description |
| ------------------- | ----------------------------- | ------------------------------------------------------------------------------ |
| `agentId` | `string` | The agent the extension will connect as. |
| `connectUrl` | `string` | URL to open in the headless browser. Carries the single-use `exc_auto_…` code. |
| `expiresAt` | `string \| null` | When the resulting connection expires. `null` for a `session` TTL. |
| `exchangeExpiresAt` | `string` | Deadline to redeem `connectUrl` (single-use handoff window). |
| `policy` | `"session" \| "pre_approved"` | The policy governing the session. |
## Puppeteer worker recipe
End to end: mint the URL, launch Chrome with the automation bundle loaded, open the URL, and wait for the bridge.
```javascript theme={null}
import puppeteer from "puppeteer";
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: process.env.ANIMA_API_KEY });
const { connectUrl } = await anima.extension.connect({ agentId: "agent_123" });
// The automation bundle: the extension built with the Chrome Web Store `key`
// injected, so an unpacked --load-extension resolves to the SAME extension ID
// the connect page targets. Built with `bun run build:automation` → dist-automation/.
const EXT = "/path/to/anima-extension/dist-automation";
const browser = await puppeteer.launch({
headless: "new", // old headless can't load extensions
args: [
`--disable-extensions-except=${EXT}`,
`--load-extension=${EXT}`,
],
});
const page = await browser.newPage();
await page.goto(connectUrl); // exc_auto_ code auto-relays, no click
await page.waitForSelector('[data-connect-status="connected"]');
// The extension bridge is now live for agent_123 — drive your automation here.
```
**Use the automation bundle, not the plain build.** The console connect page only ever messages the *published* Chrome Web Store extension ID — it never trusts a caller-supplied one. An ordinary unpacked build gets a different, per-path ID, so the relay silently never reaches it. The automation bundle (`dist-automation/`) injects the Chrome Web Store `key` into the manifest, pinning the unpacked extension to the production ID the page targets.
A few operational notes:
* **`--headless=new` is required.** Chrome's old headless mode cannot load extensions at all.
* **A fresh browser profile connects with no prompt.** The `exc_auto_` code auto-relays on page load.
* **Re-connecting a profile that already holds a live bridge requires confirmation.** An unattended page must not silently replace an existing connection — the extension asks the owner to approve the re-pair, and denies otherwise. For a clean worker run, start from a fresh profile.
## Related
* [Vault — Browser Extension](/vault#browser-extension) — how the extension performs credential autofill without exposing secrets.
* [Vault](/vault) — per-agent encrypted credential storage and the secret boundary.
* [Security](/security) — key types (`mk_` vs `ak_`) and the master-key model.
# Frequently Asked Questions
Source: https://docs.useanima.sh/faq
Frequently asked questions about Anima.
# Frequently Asked Questions
Answers to common questions about Anima.
### Can I use Anima with Gmail?
Yes. You can configure Anima to relay emails through your Gmail account, or use it as a standalone mail server with your own domain.
### Is it free?
Anima is open-core. The community edition is free to self-host. We also offer a managed cloud version with enterprise features.
### How many agents can I create?
There is no hard limit on the number of agents you can create in the self-hosted version. The cloud version has tiered limits based on your plan.
### Does it support attachments?
Yes, fully supported. You can send and receive attachments. Incoming attachments are parsed and available via the API, and every attachment is scanned for malware and disguised executables in both directions (see [Attachment Scanning](/security#attachment-scanning)).
### What happens if an agent tries to leak my API key?
The Outbound Guard will detect the pattern and block the email immediately. You will receive an alert about the attempt.
### Can agents email each other?
Yes! Agents can communicate with each other using their unique email addresses, just like normal users.
# Getting Started
Source: https://docs.useanima.sh/getting-started
Install the Anima CLI, provision an agent identity, and send its first email from the terminal — then call the same platform from your code.
# Getting Started
Give an AI agent a real, owned identity — an email inbox, and optionally a phone number — and send its first message, all from the terminal. Anima is hosted; there is nothing to run locally and no infrastructure to stand up. This page takes you from zero to a working agent that can send email.
The `anima` CLI is the fastest way to provision and drive an agent.
```bash theme={null}
npm install -g @anima-labs/cli
```
Bun and pnpm work too: `bun add -g @anima-labs/cli` or `pnpm add -g @anima-labs/cli`. Use this on your development machine, and as a dependency of any Node/TypeScript agent project.
For containers, servers, and CI runners, download the signed static binary from [GitHub Releases](https://github.com/anima-labs-ai/cli/releases) (`anima-linux-x64` / `anima-linux-arm64`). Every release is signed with Sigstore keyless signing; verify it before installing:
```bash theme={null}
VERSION="v0.6.5"
ARCH="$(uname -m | sed 's/x86_64/x64/; s/aarch64/arm64/')"
BIN="anima-linux-${ARCH}"
BASE="https://github.com/anima-labs-ai/cli/releases/download/${VERSION}"
curl -fsSL -O "${BASE}/${BIN}"
curl -fsSL -O "${BASE}/${BIN}.sigstore.bundle"
cosign verify-blob \
--bundle "${BIN}.sigstore.bundle" \
--certificate-identity-regexp 'https://github.com/anima-labs-ai/cli/\.github/workflows/release\.yml@refs/tags/v.+' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"${BIN}"
install -m 0755 "${BIN}" /usr/local/bin/anima
```
macOS and Windows binaries are not shipped — on those platforms use the npm package. See [Install the Anima CLI](/install) for the full verification chain, the `curl | sh` installer, and Dockerfile examples.
Confirm it's on your PATH:
```bash theme={null}
anima --version
```
The primary binary is `anima`; `am` is a shorter alias for the same tool.
Run the guided onboarding:
```bash theme={null}
anima onboard
```
If you're not signed in yet, `anima onboard` starts setup for you. Choosing **Create a fresh agent identity** provisions an organization, an agent, and an email inbox in a single flow, and saves your credentials locally. You'll be asked for two things:
* **The agent owner's email** — the human who owns this agent. A 6-digit verification code is sent here.
* **A username for the agent** — this becomes the agent's address, `@agents.useanima.sh`.
Onboarding then shows your identity and plan tier, offers a couple of optional test-mode demos (no real email is sent), and offers to wire Anima into your AI client over MCP. When it finishes you have a working agent identity with an inbox, its credentials stored in `~/.anima`, and the commands to do everything else.
Already have an Anima organization and API key? Choose **Configure with an existing API key** instead, or run `anima init --non-interactive --api-key ak_...`.
A brand-new agent starts **unverified**, and an unverified agent may only email its own owner. To unlock sending to anyone, get the 6-digit code from the owner's inbox and submit it:
```bash theme={null}
anima verify
```
On success, the agent is verified and can send to any recipient. You can confirm your identity and tier at any time:
```bash theme={null}
anima auth whoami
```
Send an email from your agent. Until the agent is verified, send it to the owner's address — that always works and proves the inbox is live end to end. You'll need the agent's ID, which onboarding printed and stored; `anima auth whoami` shows your identity.
```bash theme={null}
anima email send \
--agent \
--to you@example.com \
--subject "Hello from my Anima agent" \
--body "This email was sent by an AI agent."
```
The command prints the sent message's ID. To watch messages arrive and other events in real time, open the live event stream:
```bash theme={null}
anima tail
```
On a Starter tier or above, give the same agent a phone number for SMS and voice:
```bash theme={null}
anima phone provision --agent --country US --capabilities sms,voice
```
Then text a number you control:
```bash theme={null}
anima phone send-sms --agent --to +15551234567 --body "Texting from my Anima agent."
```
See [Phone & Voice](/phone) for the full SMS-then-call walkthrough.
## Use it from code
The same platform is available from the official SDKs. Once onboarding has provisioned an agent, use its ID to send from your application. Set `ANIMA_API_KEY` in your environment (the CLI stored your key under `~/.anima`), or pass the key to the client directly.
```bash theme={null}
npm install @anima-labs/sdk
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: process.env.ANIMA_API_KEY });
const message = await anima.messages.sendEmail({
agentId: "agent_...",
to: ["you@example.com"],
subject: "Hello from my Anima agent",
body: "This email was sent by an AI agent.",
});
console.log(message.id, message.status);
```
```bash theme={null}
pip install anima-labs
```
```python theme={null}
import os
from anima import Anima
anima = Anima(api_key=os.environ["ANIMA_API_KEY"])
message = anima.messages.send_email(
agent_id="agent_...",
to=["you@example.com"],
subject="Hello from my Anima agent",
body="This email was sent by an AI agent.",
)
print(message.id, message.status)
```
```bash theme={null}
go get github.com/anima-labs-ai/go
```
```go theme={null}
package main
import (
"context"
"fmt"
"log"
"os"
anima "github.com/anima-labs-ai/go"
)
func main() {
client := anima.NewClient(os.Getenv("ANIMA_API_KEY"))
msg, err := client.Messages.SendEmail(context.Background(), anima.SendEmailParams{
AgentID: "agent_...",
To: []string{"you@example.com"},
Subject: "Hello from my Anima agent",
Body: "This email was sent by an AI agent.",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.ID, msg.Status)
}
```
The REST API lives at `https://api.useanima.sh/v1` and accepts your key as either a `Bearer` token or an `X-API-Key` header.
## Next steps
Let your agent set itself up from `skill.md`, and connect the docs and product MCP servers.
Wire Anima's tools into Claude Code, Cursor, Claude Desktop, VS Code, and Windsurf.
Store credentials your agent can use without exposing raw secrets to the model.
Typed clients for Node.js, Python, and Go.
# Agent Cards
Source: https://docs.useanima.sh/identity/agent-cards
Publish machine-readable Agent Cards at .well-known/agent.json for agent discovery, capability declaration, and interoperability.
# Agent Cards
Agent Cards are machine-readable JSON documents that describe an agent's identity, capabilities, and communication endpoints. Published at a well-known URL, they enable other agents and services to discover and interact with your agents.
## Agent Card Format
An Agent Card follows the Agent Card specification and is served at:
```
https:///.well-known/agent.json
```
### Example Agent Card
```json theme={null}
{
"name": "Acme Purchasing Agent",
"description": "Handles procurement and vendor payments for Acme Corp.",
"url": "https://purchasing.acme.com",
"did": "did:anima:ag_8f3k2m9x1n4p7q6r",
"version": "1.0.0",
"capabilities": [
{
"name": "purchase-order",
"description": "Create and manage purchase orders",
"inputSchema": {
"type": "object",
"properties": {
"vendor": { "type": "string" },
"items": { "type": "array" },
"budget": { "type": "number" }
}
}
},
{
"name": "invoice-processing",
"description": "Process and approve vendor invoices"
}
],
"endpoints": {
"a2a": "https://api.useanima.sh/a2a/ag_8f3k2m9x1n4p7q6r",
"email": "purchasing@acme.com"
},
"authentication": {
"schemes": ["did-auth", "bearer"]
},
"provider": {
"organization": "Acme Corp",
"url": "https://acme.com"
}
}
```
## Publishing Agent Cards
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Generate and publish an Agent Card
const card = await anima.identity.agentCards.publish({
agentId: "ag_8f3k2m9x1n4p7q6r",
domain: "purchasing.acme.com",
capabilities: [
{
name: "purchase-order",
description: "Create and manage purchase orders",
inputSchema: {
type: "object",
properties: {
vendor: { type: "string" },
items: { type: "array" },
budget: { type: "number" },
},
},
},
],
});
console.log(`Published at: ${card.url}`);
// => https://purchasing.acme.com/.well-known/agent.json
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
card = anima.identity.agent_cards.publish(
agent_id="ag_8f3k2m9x1n4p7q6r",
domain="purchasing.acme.com",
capabilities=[
{
"name": "purchase-order",
"description": "Create and manage purchase orders",
"inputSchema": {
"type": "object",
"properties": {
"vendor": {"type": "string"},
"items": {"type": "array"},
"budget": {"type": "number"},
},
},
},
],
)
print(f"Published at: {card.url}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
card, err := client.Identity.AgentCards.Publish(ctx, &anima.PublishAgentCardParams{
AgentID: "ag_8f3k2m9x1n4p7q6r",
Domain: "purchasing.acme.com",
Capabilities: []anima.Capability{
{
Name: "purchase-order",
Description: "Create and manage purchase orders",
},
},
})
```
## Resolving Agent Cards
Fetch another agent's card to discover its capabilities before initiating communication:
```ts theme={null}
const card = await anima.identity.agentCards.resolve("purchasing.acme.com");
console.log(card.name); // "Acme Purchasing Agent"
console.log(card.capabilities); // [{ name: "purchase-order", ... }]
console.log(card.endpoints.a2a); // A2A endpoint URL
```
```python theme={null}
card = anima.identity.agent_cards.resolve("purchasing.acme.com")
print(card.name)
print(card.capabilities)
print(card.endpoints["a2a"])
```
## API Reference
| Endpoint | Method | Description |
| ----------------------------------------------------------- | ------ | ------------------------ |
| `https://api.useanima.sh/api/identity/agent-cards` | POST | Publish an Agent Card |
| `https://api.useanima.sh/api/identity/agent-cards/:agentId` | GET | Get an agent's card |
| `https://api.useanima.sh/api/identity/agent-cards/:agentId` | PUT | Update an Agent Card |
| `https://api.useanima.sh/api/identity/agent-cards/:agentId` | DELETE | Unpublish an Agent Card |
| `https://api.useanima.sh/api/identity/agent-cards/resolve` | GET | Resolve a card by domain |
## Configuration
| Variable | Default | Description |
| ------------------------------- | ------- | --------------------------------------- |
| `ANIMA_AGENT_CARD_AUTO_PUBLISH` | `true` | Auto-publish cards on agent creation |
| `ANIMA_AGENT_CARD_CACHE_TTL` | `600` | Cache TTL for resolved cards in seconds |
## Next Steps
* [DID Method](/identity/did-method) -- Understand agent DIDs
* [Agent Registry](/registry/overview) -- Register for public discovery
* [A2A Protocol](/a2a/overview) -- Communicate between agents
# DID Method (did:anima)
Source: https://docs.useanima.sh/identity/did-method
Decentralized identifiers for AI agents using the did:anima method. Document structure, resolution, and lifecycle management.
# DID Method (did:anima)
Anima assigns every agent a globally unique decentralized identifier (DID) using the `did:anima` method. DIDs provide a self-sovereign identity foundation that agents can use across protocols and platforms.
## DID Format
Every agent DID follows the W3C DID specification:
```
did:anima:
```
For example: `did:anima:ag_8f3k2m9x1n4p7q6r`
## DID Document Structure
Each DID resolves to a DID Document containing the agent's public keys, service endpoints, and authentication methods.
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Resolve a DID document
const doc = await anima.identity.resolveDid("did:anima:ag_8f3k2m9x1n4p7q6r");
console.log(doc);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
doc = anima.identity.resolve_did("did:anima:ag_8f3k2m9x1n4p7q6r")
print(doc)
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
doc, err := client.Identity.ResolveDID(ctx, "did:anima:ag_8f3k2m9x1n4p7q6r")
```
### Example DID Document
```json theme={null}
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:anima:ag_8f3k2m9x1n4p7q6r",
"verificationMethod": [
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:anima:ag_8f3k2m9x1n4p7q6r",
"publicKeyMultibase": "z6Mkf5rG..."
}
],
"authentication": ["did:anima:ag_8f3k2m9x1n4p7q6r#key-1"],
"service": [
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#email",
"type": "AgentEmail",
"serviceEndpoint": "mailto:agent@useanima.sh"
},
{
"id": "did:anima:ag_8f3k2m9x1n4p7q6r#a2a",
"type": "AgentToAgent",
"serviceEndpoint": "https://api.useanima.sh/a2a/ag_8f3k2m9x1n4p7q6r"
}
]
}
```
## API Reference
### Resolve DID
```
GET https://api.useanima.sh/api/identity/did/:did
```
Resolves a `did:anima` identifier to its DID Document.
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------- |
| `did` | string | The full DID, e.g. `did:anima:...` |
### Create DID
DIDs are created automatically when an agent is provisioned. To explicitly create or rotate keys:
```
POST https://api.useanima.sh/api/identity/did
```
```json theme={null}
{
"agentId": "ag_8f3k2m9x1n4p7q6r",
"keyType": "Ed25519"
}
```
### Rotate Keys
```
POST https://api.useanima.sh/api/identity/did/:did/rotate
```
Rotates the agent's verification key. The previous key is added to the document's `keyAgreement` section for a configurable grace period.
## Configuration
| Variable | Default | Description |
| -------------------------- | --------- | ----------------------------------- |
| `ANIMA_DID_KEY_TYPE` | `Ed25519` | Default key type for new DIDs |
| `ANIMA_DID_ROTATION_GRACE` | `72h` | Grace period before old keys expire |
| `ANIMA_DID_CACHE_TTL` | `300` | DID document cache TTL in seconds |
## Next Steps
* [Verifiable Credentials](/identity/verifiable-credentials) -- Issue and verify credentials for your agents
* [Agent Cards](/identity/agent-cards) -- Publish discoverable agent metadata
* [A2A Protocol](/a2a/overview) -- Agent-to-agent communication using DIDs
# Verifiable Credentials
Source: https://docs.useanima.sh/identity/verifiable-credentials
Issue, verify, and revoke W3C Verifiable Credentials for AI agents. Credential types, presentation, and revocation lists.
# Verifiable Credentials
Anima supports W3C Verifiable Credentials (VCs) so agents can prove capabilities, authorizations, and affiliations to other agents or services without exposing underlying secrets.
## Credential Lifecycle
1. **Issuance** -- An issuer (your organization) creates a signed credential for an agent
2. **Holding** -- The agent stores the credential in its identity wallet
3. **Presentation** -- The agent presents the credential to a verifier
4. **Verification** -- The verifier checks the signature, issuer, and revocation status
5. **Revocation** -- The issuer can revoke a credential at any time
## Credential Types
| Type | Description |
| --------------------- | ------------------------------------------------------ |
| `AgentAuthorization` | Grants the agent permission to act on behalf of an org |
| `SpendingLimit` | Attests to the agent's approved spending budget |
| `ServiceAccess` | Grants access to a specific external service |
| `DomainVerification` | Proves the agent is authorized for an email domain |
| `ComplianceClearance` | Attests the agent has passed compliance checks |
## Issuing Credentials
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const credential = await anima.identity.credentials.issue({
agentId: "ag_8f3k2m9x1n4p7q6r",
type: "AgentAuthorization",
claims: {
organization: "Acme Corp",
role: "purchasing-agent",
maxSpendUsd: 10000,
},
expiresAt: "2027-01-01T00:00:00Z",
});
console.log(credential.id); // "vc_3n7k..."
console.log(credential.proof); // Ed25519 signature
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
credential = anima.identity.credentials.issue(
agent_id="ag_8f3k2m9x1n4p7q6r",
type="AgentAuthorization",
claims={
"organization": "Acme Corp",
"role": "purchasing-agent",
"maxSpendUsd": 10000,
},
expires_at="2027-01-01T00:00:00Z",
)
print(credential.id)
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
cred, err := client.Identity.Credentials.Issue(ctx, &anima.IssueCredentialParams{
AgentID: "ag_8f3k2m9x1n4p7q6r",
Type: "AgentAuthorization",
Claims: map[string]any{
"organization": "Acme Corp",
"role": "purchasing-agent",
"maxSpendUsd": 10000,
},
ExpiresAt: "2027-01-01T00:00:00Z",
})
```
## Verifying Credentials
```
POST https://api.useanima.sh/api/identity/credentials/verify
```
```json theme={null}
{
"credential": "",
"checkRevocation": true
}
```
```ts theme={null}
const result = await anima.identity.credentials.verify({
credential: credentialJwt,
checkRevocation: true,
});
if (result.valid) {
console.log("Credential is valid, issued by:", result.issuer);
} else {
console.log("Invalid:", result.errors);
}
```
```python theme={null}
result = anima.identity.credentials.verify(
credential=credential_jwt,
check_revocation=True,
)
if result.valid:
print(f"Valid, issued by: {result.issuer}")
else:
print(f"Invalid: {result.errors}")
```
## Revoking Credentials
```
POST https://api.useanima.sh/api/identity/credentials/:credentialId/revoke
```
```ts theme={null}
await anima.identity.credentials.revoke("vc_3n7k...", {
reason: "Agent decommissioned",
});
```
```python theme={null}
anima.identity.credentials.revoke("vc_3n7k...", reason="Agent decommissioned")
```
Revoked credentials are added to a StatusList2021 revocation list. Verifiers automatically check this list when `checkRevocation` is enabled.
## API Reference
| Endpoint | Method | Description |
| ------------------------------------------------------------------ | ------ | ----------------------- |
| `https://api.useanima.sh/api/identity/credentials` | POST | Issue a new credential |
| `https://api.useanima.sh/api/identity/credentials/:id` | GET | Retrieve a credential |
| `https://api.useanima.sh/api/identity/credentials/verify` | POST | Verify a credential |
| `https://api.useanima.sh/api/identity/credentials/:id/revoke` | POST | Revoke a credential |
| `https://api.useanima.sh/api/identity/credentials/revocation-list` | GET | Get the revocation list |
## Configuration
| Variable | Default | Description |
| --------------------------- | ------- | ----------------------------------- |
| `ANIMA_VC_ISSUER_DID` | auto | DID used to sign issued credentials |
| `ANIMA_VC_DEFAULT_EXPIRY` | `365d` | Default credential expiration |
| `ANIMA_VC_REVOCATION_CHECK` | `true` | Check revocation on verification |
## Next Steps
* [DID Method](/identity/did-method) -- Understand the underlying DID infrastructure
* [Agent Cards](/identity/agent-cards) -- Publish agent capabilities for discovery
* [Agent Registry](/registry/overview) -- Register agents for public discovery
# Install the Anima CLI
Source: https://docs.useanima.sh/install
Install anima in an agent runtime — npm for Node/TS agents, signed Linux binary for containers and CI. Every path verifies signatures end-to-end.
# Install the Anima CLI
The `anima` CLI is built for **agents**, not for human click-through installs. That shapes every decision on this page:
* **No macOS or Windows binaries.** Agent workloads run on Linux — in containers, VMs, and CI runners. A developer on a Mac should use the npm package; their agent, when it actually executes, runs on Linux.
* **No Homebrew or Winget.** Those exist to make installs ergonomic for humans; agents read release manifests directly.
* **Sigstore everywhere.** One uniform trust anchor for both install paths, verifiable offline from any pipeline.
## Pick your channel
```bash theme={null}
# npm
npm install -g @anima-labs/cli
# Bun
bun install -g @anima-labs/cli
# pnpm
pnpm add -g @anima-labs/cli
```
The package is published with [npm provenance](https://docs.npmjs.com/generating-provenance-statements), linking the tarball to the exact commit and GitHub Actions workflow that built it.
Verify the attestation:
```bash theme={null}
npm view @anima-labs/cli --json | jq .dist.attestations
```
Or enforce verification at install time (npm ≥ 9.5):
```bash theme={null}
npm install @anima-labs/cli
npm audit signatures
```
Use this path when `anima` is a runtime dependency of a Node/TS agent project.
```bash theme={null}
curl -fsSL https://get.useanima.sh | sh
```
The installer:
1. Detects architecture (x64 / arm64) — aborts on non-Linux.
2. Downloads [cosign](https://docs.sigstore.dev/cosign/system_config/installation/) if not already present (hash-pinned to a known-good build).
3. Fetches the signed `SHA256SUMS` manifest from the GitHub release.
4. Verifies the manifest's Sigstore signature against our pinned release-workflow identity.
5. Downloads the platform binary and checks it against the now-trusted hash.
6. Installs to `/usr/local/bin` if writable, otherwise `~/.local/bin`.
If *any* verification step fails, the install aborts — there is no silent fallback. A failed install is visible; a degraded one isn't.
Pin a specific version (recommended for reproducible container builds):
```bash theme={null}
curl -fsSL https://get.useanima.sh | sh -s -- --version v0.5.0
```
Install into a custom prefix:
```bash theme={null}
curl -fsSL https://get.useanima.sh | sh -s -- --prefix /opt/anima/bin
```
## Inside a Dockerfile
For a reproducible agent container, pin the version and verify explicitly:
```dockerfile theme={null}
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
# Pin the version. Bumping this is a deliberate, reviewable change.
ARG ANIMA_VERSION=v0.5.0
RUN curl -fsSL https://get.useanima.sh | sh -s -- --version "$ANIMA_VERSION" \
&& anima --version
```
The installer does the signature verification inline. If the release is ever tampered with or the pinned workflow identity changes, the `RUN` step fails and the image build stops.
## Verify the install
```bash theme={null}
anima --version
anima vault --help
```
## Configuration
Every setting resolves in priority order — a flag wins, then an environment
variable, then the active profile, then your saved defaults:
1. **CLI flag** (e.g. `--org`, `--api-key`, `--api-url`)
2. **Environment variable** (`ANIMA_API_KEY`, `ANIMA_API_URL`, `ANIMA_DEFAULT_ORG`, `ANIMA_DEFAULT_IDENTITY`, `ANIMA_OUTPUT_FORMAT`)
3. **Active profile** (`anima config profile use `)
4. **Saved defaults** (`anima config set ` or `anima init`)
This keeps the CLI ergonomic in CI and containers — export your key and default
org once, then drop the flags:
```bash theme={null}
export ANIMA_API_KEY="ak_..."
export ANIMA_DEFAULT_ORG="org_..."
anima security scan # resolves the org from the environment
```
## Verify a binary manually
Every release asset has a matching Sigstore bundle. To verify end-to-end without trusting the installer (e.g. in an air-gapped pipeline):
```bash theme={null}
VERSION="v0.5.0"
ARCH="$(uname -m | sed 's/x86_64/x64/; s/aarch64/arm64/')"
BIN="anima-linux-${ARCH}"
BASE="https://github.com/anima-labs-ai/cli/releases/download/${VERSION}"
curl -fsSL -O "${BASE}/${BIN}"
curl -fsSL -O "${BASE}/${BIN}.sigstore.bundle"
cosign verify-blob \
--bundle "${BIN}.sigstore.bundle" \
--certificate-identity-regexp 'https://github.com/anima-labs-ai/cli/\.github/workflows/release\.yml@refs/tags/v.+' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
"${BIN}"
```
A successful verification means:
1. The binary was signed by *our* release workflow, at a release tag — not a different repo's and not a non-tagged build.
2. The signing event is recorded in the public [Rekor transparency log](https://rekor.sigstore.dev) — anyone can audit it.
3. The binary bytes haven't been modified since signing.
## GPG (optional, for distro pipelines)
Releases ship a GPG-signed `SHA256SUMS.asc` when the publisher key is provisioned. This is redundant with Sigstore and exists only for downstream packagers that prefer a traditional PGP trust chain. Verify with:
```bash theme={null}
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
```
Our publisher key fingerprint is published at [useanima.sh/.well-known/gpg-key.asc](https://useanima.sh/.well-known/gpg-key.asc).
## Troubleshooting
**`Unsupported OS`** — You ran the `curl | sh` installer on macOS or Windows. The CLI ships Linux-only binaries; on a developer machine, use `npm install -g @anima-labs/cli` instead.
**Signature verification failed** — Do not proceed. Report at [github.com/anima-labs-ai/cli/issues](https://github.com/anima-labs-ai/cli/issues) and include the full installer output. A failed verification is either a transient CDN issue (retry) or a genuine tampering attempt (we want to hear about it immediately).
**`~/.local/bin not in PATH`** — The installer prints the exact line to add to your shell rc:
```bash theme={null}
export PATH="$HOME/.local/bin:$PATH"
```
## See also
* [Security](/security) — full signing chain and threat model
* [Quickstart: Vault](/quickstart-vault) — your first `anima vault` command
* [SDKs](/sdks) — Python & TypeScript client libraries
# Connect your AI client
Source: https://docs.useanima.sh/integrations
Wire Anima's tools into Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, and other MCP clients — automatically with the CLI, or by hand.
# Connect your AI client
Anima's capabilities are exposed as [Model Context Protocol](https://modelcontextprotocol.io) tools, so any MCP-aware client can send email, provision numbers, place calls, and use the vault on your behalf.
The tools are split into focused domain servers, so you install only what you need:
| Server | Package | Covers |
| -------- | -------------------------- | ----------------------------------------------- |
| Agent | `@anima-labs/mcp-agent` | Agents, organizations, identity, registry, A2A |
| Email | `@anima-labs/mcp-email` | Email, messages, domains, addresses |
| Phone | `@anima-labs/mcp-phone` | Phone numbers, SMS, voice calls |
| Vault | `@anima-labs/mcp-vault` | Encrypted credential storage, security policies |
| Platform | `@anima-labs/mcp-platform` | Webhooks, pods, utilities |
## Fastest path: let the CLI configure it
The [Anima CLI](/install) detects your installed MCP clients and writes the right config for each one:
```bash theme={null}
# Configure every detected client
anima setup-mcp install --all
# Or target a single client and a subset of servers
anima setup-mcp install --client cursor --server email,phone
```
`setup-mcp install` auto-configures **Claude Code, Claude Desktop, Cursor, VS Code, and Windsurf**. It backs up any existing config before writing, and stores your API key in the client's config. Check and confirm what it did:
```bash theme={null}
anima setup-mcp status # what's configured, where, and in which mode
anima setup-mcp verify # validate the config (add --ping to test connectivity)
```
To connect a client the CLI doesn't configure automatically (such as Codex or Zed), add the configuration by hand using the tabs below.
## Per-client setup
Each tab shows the CLI command where it applies, plus the manual configuration in that client's native format. Every server takes your Anima API key (`ak_...`) as `ANIMA_API_KEY`.
```bash theme={null}
anima setup-mcp install --client claude-code
```
Or add a server manually:
```bash theme={null}
claude mcp add anima-email -- npx -y @anima-labs/mcp-email
claude mcp add anima-phone -- npx -y @anima-labs/mcp-phone
claude mcp add anima-vault -- npx -y @anima-labs/mcp-vault
```
Claude Code stores MCP servers in `~/.claude.json`.
```bash theme={null}
anima setup-mcp install --client claude-desktop
```
Or edit the config file directly:
* **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
* **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
* **Linux:** `~/.config/Claude/claude_desktop_config.json`
```json theme={null}
{
"mcpServers": {
"anima-email": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-email"],
"env": { "ANIMA_API_KEY": "ak_..." }
},
"anima-phone": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-phone"],
"env": { "ANIMA_API_KEY": "ak_..." }
}
}
}
```
```bash theme={null}
anima setup-mcp install --client cursor
```
Or edit `~/.cursor/mcp.json`:
```json theme={null}
{
"mcpServers": {
"anima-email": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-email"],
"env": { "ANIMA_API_KEY": "ak_..." }
}
}
}
```
```bash theme={null}
anima setup-mcp install --client vscode
```
Or edit your user `mcp.json` (Command Palette → **MCP: Open User Configuration**):
```json theme={null}
{
"servers": {
"anima-email": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-email"],
"env": { "ANIMA_API_KEY": "ak_..." }
}
}
}
```
```bash theme={null}
anima setup-mcp install --client windsurf
```
Or edit `~/.codeium/windsurf/mcp_config.json`:
```json theme={null}
{
"mcpServers": {
"anima-email": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-email"],
"env": { "ANIMA_API_KEY": "ak_..." }
}
}
}
```
The CLI does not configure these clients automatically — add the servers using each client's MCP configuration. Both support stdio servers launched with `npx`:
```
command: npx
args: ["-y", "@anima-labs/mcp-email"]
env: ANIMA_API_KEY=ak_...
```
Repeat for each domain server you want (`@anima-labs/mcp-agent`, `-phone`, `-vault`, `-platform`), following your client's native config format.
## Hosted (remote) server
If you'd rather not run the servers locally, Anima hosts them at a single endpoint. Point any client with native remote-MCP support at it and send your API key as a bearer token:
| | |
| ------------- | ------------------------------ |
| **Endpoint** | `https://mcp.useanima.sh/mcp` |
| **Transport** | Streamable HTTP |
| **Auth** | `Authorization: Bearer ak_...` |
```json theme={null}
{
"mcpServers": {
"anima": {
"url": "https://mcp.useanima.sh/mcp",
"headers": { "Authorization": "Bearer ak_..." }
}
}
}
```
Treat your API key like a password. Prefer your client's secret-input mechanism over hardcoding the key in a file that might be committed.
## Try it
Once connected, ask your assistant in natural language:
* "Send an email from my agent to [user@example.com](mailto:user@example.com)."
* "Text me now from my agent's number."
* "Store my CRM login in the vault — don't print the password."
* "Make a voice call to +1-555-0123 after confirming consent."
## Related
The skill manifest, the docs MCP server, and machine-readable docs.
Provision a number, text a human, and place a call.
# Data Processing Agreement
Source: https://docs.useanima.sh/legal/data-processing-agreement
Data Processing Agreement for Anima platform customers — GDPR-compliant data processing terms.
# Data Processing Agreement
**Effective Date:** March 28, 2026
**Last Updated:** March 28, 2026
This Data Processing Agreement ("DPA") forms part of the Terms of Service (the "Agreement") between the entity identified as the customer in the Agreement ("Controller" or "Customer") and Anima Labs Ltd, including its affiliates ("Processor" or "Anima"), and supplements the Agreement with respect to Anima's processing of Personal Data on behalf of the Customer.
This DPA applies where and only to the extent that Anima processes Personal Data on behalf of the Customer in the course of providing the Service, and such Personal Data is subject to the European General Data Protection Regulation (EU 2016/679) ("GDPR"), the UK General Data Protection Regulation ("UK GDPR"), the Swiss Federal Act on Data Protection ("FADP"), or other applicable data protection laws.
***
## 1. Definitions
In this DPA, the following terms have the meanings set out below. Capitalized terms not defined in this DPA have the meanings given to them in the Agreement.
**"Applicable Data Protection Law"** means all data protection and privacy laws applicable to the processing of Personal Data under this DPA, including the GDPR, UK GDPR, FADP, and the California Consumer Privacy Act ("CCPA").
**"Controller"** means the entity that determines the purposes and means of the processing of Personal Data, as defined in Applicable Data Protection Law.
**"Data Subject"** means the identified or identifiable natural person to whom the Personal Data relates.
**"EEA"** means the European Economic Area.
**"Personal Data"** means any information relating to a Data Subject that is processed by Anima on behalf of the Customer in connection with the Service, as defined in Applicable Data Protection Law.
**"Personal Data Breach"** means a breach of security leading to the accidental or unlawful destruction, loss, alteration, unauthorized disclosure of, or access to Personal Data transmitted, stored, or otherwise processed.
**"Processing"** means any operation or set of operations performed on Personal Data, whether or not by automated means, including collection, recording, organization, structuring, storage, adaptation, alteration, retrieval, consultation, use, disclosure by transmission, dissemination, alignment, combination, restriction, erasure, or destruction.
**"Processor"** means the entity that processes Personal Data on behalf of the Controller, as defined in Applicable Data Protection Law.
**"Standard Contractual Clauses" or "SCCs"** means the standard contractual clauses for the transfer of personal data to processors established in third countries, as adopted by the European Commission Decision 2021/914 of 4 June 2021, and as may be amended or replaced from time to time.
**"Sub-processor"** means any third party appointed by Anima to process Personal Data on behalf of the Customer.
***
## 2. Scope and Purpose of Processing
### 2.1 Scope
This DPA applies to the processing of Personal Data as described in Annex I (Details of Processing) attached hereto. The categories of Data Subjects, types of Personal Data, and purposes of processing are specified in Annex I.
### 2.2 Customer Instructions
Anima shall process Personal Data only on documented instructions from the Customer, including with respect to transfers of Personal Data to a third country or international organization, unless required to do so by applicable law. In such a case, Anima shall inform the Customer of that legal requirement before processing, unless that law prohibits such notification on important grounds of public interest.
### 2.3 Purpose Limitation
Anima shall process Personal Data solely for the purpose of providing the Service in accordance with the Agreement and this DPA, and shall not process Personal Data for any other purpose unless instructed by the Customer in writing or required by applicable law.
***
## 3. Obligations of the Processor
Anima shall:
### 3.1 Compliance
Process Personal Data in compliance with Applicable Data Protection Law and the terms of this DPA.
### 3.2 Confidentiality
Ensure that all persons authorized to process Personal Data have committed themselves to confidentiality or are under an appropriate statutory obligation of confidentiality.
### 3.3 Security
Implement and maintain appropriate technical and organizational measures to ensure a level of security appropriate to the risk, as described in Annex II (Security Measures) attached hereto. These measures include, at a minimum:
* Encryption of Personal Data at rest (AES-256) and in transit (TLS 1.2+).
* Measures to ensure the ongoing confidentiality, integrity, availability, and resilience of processing systems and services.
* The ability to restore the availability and access to Personal Data in a timely manner in the event of a physical or technical incident.
* A process for regularly testing, assessing, and evaluating the effectiveness of technical and organizational measures.
### 3.4 Assistance
Taking into account the nature of processing, assist the Customer by appropriate technical and organizational measures, insofar as this is possible, for the fulfillment of the Customer's obligation to respond to requests for exercising Data Subject rights under Applicable Data Protection Law.
### 3.5 Deletion and Return
At the choice of the Customer, delete or return all Personal Data to the Customer after the end of the provision of the Service, and delete existing copies unless applicable law requires storage of the Personal Data. Anima will provide the Customer with a 30-day period following termination to export or request return of Personal Data.
***
## 4. Sub-processors
### 4.1 Authorization
The Customer provides general written authorization for Anima to engage Sub-processors for the processing of Personal Data under this DPA. The current list of approved Sub-processors is set forth in Annex III and is available at [https://useanima.sh/subprocessors](https://useanima.sh/subprocessors).
### 4.2 Notification of Changes
Anima shall notify the Customer at least 30 days in advance of any intended addition or replacement of a Sub-processor, providing the Customer with an opportunity to object to the change.
### 4.3 Objection Right
If the Customer reasonably objects to a new Sub-processor within 15 days of receiving notice, Anima shall use commercially reasonable efforts to: (a) make available to the Customer a change in the Service that avoids the use of the objected-to Sub-processor; or (b) recommend a commercially reasonable alternative. If Anima is unable to provide an alternative within 30 days, either party may terminate the affected portion of the Service without penalty.
### 4.4 Sub-processor Obligations
Anima shall: (a) impose data protection obligations on each Sub-processor that are no less protective than those in this DPA; (b) remain fully liable to the Customer for the performance of each Sub-processor's obligations; and (c) ensure that each Sub-processor agreement provides for termination and data deletion/return provisions consistent with this DPA.
***
## 5. Data Subject Rights
### 5.1 Assistance
Anima shall, taking into account the nature of the processing, assist the Customer by appropriate technical and organizational measures for the fulfillment of the Customer's obligation to respond to Data Subject requests under Applicable Data Protection Law, including requests for access, rectification, erasure, restriction, data portability, and objection.
### 5.2 Notification
If Anima receives a request from a Data Subject regarding Personal Data processed on behalf of the Customer, Anima shall promptly notify the Customer and shall not respond to the request directly unless instructed by the Customer or required by applicable law.
### 5.3 Cost
Anima shall provide reasonable assistance at no additional charge. If a Data Subject request requires significant effort beyond routine assistance, Anima may charge a reasonable fee based on the administrative cost of responding, provided Anima notifies the Customer of the fee in advance.
***
## 6. Security Measures
### 6.1 Technical Measures
Anima implements and maintains the technical security measures described in Annex II, including:
* **Encryption:** AES-256 encryption at rest for all Personal Data; TLS 1.2+ encryption in transit.
* **Access Controls:** Role-based access control (RBAC), multi-factor authentication (MFA) for all administrative access, principle of least privilege.
* **Network Security:** Network segmentation, firewalls, intrusion detection and prevention systems, DDoS protection.
* **Audit Logging:** Comprehensive logging of all access to Personal Data, with tamper-evident log storage.
* **Vulnerability Management:** Regular vulnerability scanning, annual penetration testing by qualified third parties, and a responsible disclosure program.
### 6.2 Organizational Measures
* **Personnel Security:** Background checks for employees with access to Personal Data, mandatory security awareness training, and binding confidentiality obligations.
* **Incident Response:** Documented incident response plan with defined roles, escalation procedures, and post-incident review processes.
* **Business Continuity:** Redundant infrastructure, automated backups, and documented disaster recovery procedures with defined recovery time objectives (RTO) and recovery point objectives (RPO).
* **Vendor Management:** Due diligence and ongoing monitoring of Sub-processors' security practices.
***
## 7. Personal Data Breach Notification
### 7.1 Notification to Customer
Anima shall notify the Customer without undue delay, and in any event within 72 hours, after becoming aware of a Personal Data Breach affecting Personal Data processed on behalf of the Customer.
### 7.2 Content of Notification
The notification shall include, to the extent available:
* A description of the nature of the Personal Data Breach, including the categories and approximate number of Data Subjects and Personal Data records concerned.
* The name and contact details of Anima's point of contact for further information.
* A description of the likely consequences of the Personal Data Breach.
* A description of the measures taken or proposed to be taken to address the Personal Data Breach, including measures to mitigate its possible adverse effects.
### 7.3 Ongoing Cooperation
Anima shall cooperate with the Customer and take reasonable commercial steps to assist in the investigation, mitigation, and remediation of the Personal Data Breach. Anima shall provide the Customer with timely updates as additional information becomes available.
### 7.4 Documentation
Anima shall document all Personal Data Breaches, including the facts relating to the breach, its effects, and the remedial action taken.
***
## 8. Audit Rights
### 8.1 Information and Audit
Anima shall make available to the Customer all information necessary to demonstrate compliance with this DPA and shall allow for and contribute to audits, including inspections, conducted by the Customer or an auditor mandated by the Customer.
### 8.2 Audit Procedure
Audits shall be conducted subject to the following conditions:
* The Customer shall provide at least 30 days' written notice of an audit request.
* Audits shall be conducted during normal business hours and shall not unreasonably disrupt Anima's operations.
* The Customer and its auditors shall comply with Anima's reasonable security and confidentiality requirements.
* Audits shall be limited to once per year unless a Personal Data Breach has occurred or a supervisory authority requires an additional audit.
### 8.3 Third-Party Certifications
Anima may satisfy audit requests by providing: (a) relevant third-party audit reports or certifications (e.g., SOC 2 Type II); (b) responses to reasonable written questions; or (c) facilitating an on-site audit if the foregoing are insufficient to demonstrate compliance.
### 8.4 Cost
Each party shall bear its own costs in connection with audits, except that if an audit reveals a material breach of this DPA by Anima, Anima shall bear the reasonable costs of the audit.
***
## 9. Data Deletion and Return
### 9.1 Upon Termination
Upon termination or expiration of the Agreement, Anima shall, at the Customer's election:
* Return all Personal Data to the Customer in a structured, commonly used, and machine-readable format; or
* Delete all Personal Data and certify such deletion in writing.
### 9.2 Retention Period
Anima will provide the Customer with a 30-day period following termination to export or request return of Personal Data. After this period, Anima shall delete all remaining Personal Data within 30 additional days, unless applicable law requires continued storage.
### 9.3 Sub-processor Data
Anima shall ensure that all Sub-processors delete or return Personal Data in accordance with the timelines set forth in this Section 9.
***
## 10. International Data Transfers
### 10.1 Transfer Mechanism
To the extent that the performance of the Service involves the transfer of Personal Data from the EEA, the United Kingdom, or Switzerland to a country that has not been recognized as providing an adequate level of data protection, the parties agree that such transfers shall be governed by the Standard Contractual Clauses, which are incorporated into this DPA by reference.
### 10.2 Module Application
The SCCs shall apply as follows:
* **Module Two (Controller to Processor):** Where the Customer is a Controller and Anima processes Personal Data as a Processor.
* **Module Three (Processor to Processor):** Where the Customer is a Processor acting on behalf of its own controller, and Anima processes Personal Data as a Sub-processor.
### 10.3 UK International Data Transfer Addendum
For transfers of Personal Data subject to the UK GDPR, the UK International Data Transfer Addendum to the EU SCCs (as issued by the UK Information Commissioner under Section 119A of the Data Protection Act 2018) shall apply and is incorporated into this DPA by reference.
### 10.4 Swiss Addendum
For transfers of Personal Data subject to the Swiss FADP, the SCCs shall apply with the modifications necessary to comply with the FADP, including treating the Swiss Federal Data Protection and Information Commissioner (FDPIC) as the competent supervisory authority.
### 10.5 Supplementary Measures
In addition to the SCCs, Anima implements the following supplementary measures to protect transferred Personal Data:
* Encryption at rest and in transit as described in Annex II.
* Strict access controls limiting access to Personal Data to authorized personnel.
* Policies and procedures to handle government access requests in accordance with applicable law, including transparency reporting where permitted.
***
## 11. Duration and Termination
### 11.1 Term
This DPA shall remain in effect for the duration of the Agreement and shall automatically terminate upon termination or expiration of the Agreement, subject to Section 9 (Data Deletion and Return).
### 11.2 Survival
The obligations of Anima under this DPA with respect to the processing of Personal Data shall continue for as long as Anima retains Personal Data processed on behalf of the Customer.
***
## 12. Liability
The liability of each party under this DPA is subject to the limitations of liability set forth in the Agreement. For the avoidance of doubt, the aggregate liability of Anima under the Agreement and this DPA combined shall not exceed the limitations set forth in the Agreement.
***
## 13. Governing Law
This DPA shall be governed by and construed in accordance with the governing law provisions of the Agreement, except that: (a) where the SCCs apply, the governing law of the SCCs shall be as specified therein; and (b) where required by Applicable Data Protection Law, the relevant data protection law shall govern.
***
## 14. Contact
For questions regarding this DPA, please contact:
**Anima Labs Ltd**
Data Protection Officer
Email: [legal@useanima.sh](mailto:legal@useanima.sh)
Website: [https://useanima.sh](https://useanima.sh)
***
## Annex I: Details of Processing
### A. List of Parties
**Data Exporter (Controller):** The Customer, as identified in the Agreement.
**Data Importer (Processor):** Anima Labs Ltd, registered in England and Wales, and its affiliates.
### B. Description of Processing
| Element | Description |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Categories of Data Subjects** | Customer's employees, contractors, end users, and the natural persons whose data is processed by Customer's Agents (e.g., email recipients, phone call participants). |
| **Categories of Personal Data** | Account data (name, email, company); email data (addresses, content, metadata); phone/SMS data (numbers, content, metadata); vault entries (encrypted credentials); identity data (DIDs, verifiable credential metadata); usage data (API logs, dashboard activity); technical data (IP addresses, device information). |
| **Sensitive Data** | None intentionally processed. If Customer submits sensitive data to the Service, Customer is responsible for ensuring a lawful basis and appropriate safeguards. |
| **Frequency of Transfer** | Continuous, for the duration of the Service. |
| **Nature and Purpose of Processing** | Processing is necessary to provide the Service, including: email routing and delivery; phone/SMS communication services; encrypted credential storage; cryptographic identity management; API request handling; usage metering and billing. |
| **Retention Period** | As specified in Anima's Privacy Policy (Section 5) and subject to Customer configuration, except as required by applicable law. |
### C. Competent Supervisory Authority
The competent supervisory authority shall be determined in accordance with Clause 13 of the SCCs. For UK-based Data Exporters, the competent supervisory authority is the UK Information Commissioner's Office (ICO).
***
## Annex II: Security Measures
Anima implements and maintains the following technical and organizational security measures:
### Technical Measures
| Measure | Description |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Encryption at Rest** | AES-256 encryption for all stored Personal Data, including database fields, vault entries, and backups. |
| **Encryption in Transit** | TLS 1.2 or higher for all data in transit. Certificate pinning for critical internal services. |
| **Access Control** | Role-based access control (RBAC) with principle of least privilege. Multi-factor authentication (MFA) required for all administrative access. |
| **Network Security** | Virtual private cloud (VPC) isolation, network segmentation, Web Application Firewall (WAF), DDoS protection, and intrusion detection/prevention systems (IDS/IPS). |
| **Audit Logging** | Immutable, tamper-evident audit logs for all access to Personal Data and administrative actions. Logs retained for a minimum of 2 years. |
| **Vulnerability Management** | Automated vulnerability scanning (weekly), annual third-party penetration testing, and a responsible disclosure/bug bounty program. |
| **Data Isolation** | Logical separation of Customer data through tenant isolation at the application and database layers. |
| **Backup and Recovery** | Automated daily backups with encryption, geo-redundant storage, and tested disaster recovery procedures. RTO: 4 hours. RPO: 1 hour. |
### Organizational Measures
| Measure | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Personnel Security** | Background checks for all employees with access to Personal Data. Mandatory security awareness training upon onboarding and annually thereafter. |
| **Confidentiality** | All employees and contractors bound by written confidentiality agreements. |
| **Incident Response** | Documented incident response plan with 24/7 on-call rotation, defined escalation procedures, and mandatory post-incident reviews. |
| **Vendor Management** | Security assessment and due diligence for all Sub-processors prior to engagement. Ongoing monitoring of Sub-processor compliance. |
| **Physical Security** | Infrastructure hosted on SOC 2 Type II and ISO 27001 certified Google Cloud Platform data centers with physical access controls, surveillance, and environmental protections. |
| **Change Management** | Formal change management process with peer review, testing, and approval requirements for all changes to production systems. |
***
## Annex III: List of Sub-processors
| Sub-processor | Processing Activity | Location | Data Processed |
| ------------------------- | -------------------------------- | ----------------- | ------------------------------ |
| **Google Cloud Platform** | Cloud infrastructure and hosting | United States, EU | All categories (encrypted) |
| **Stripe** | Payment processing | United States | Billing data, payment methods |
| **Telnyx** | Telephony and SMS services | United States, EU | Phone numbers, call/SMS data |
| **Clerk** | Authentication and identity | United States | Account data, auth events |
| **Resend** | Email delivery | United States | Email addresses, email content |
This list is current as of the Effective Date. Updated lists are maintained at [https://useanima.sh/subprocessors](https://useanima.sh/subprocessors).
# Privacy Policy
Source: https://docs.useanima.sh/legal/privacy-policy
Privacy Policy for the Anima platform — how we collect, use, and protect your data.
# Privacy Policy
**Effective Date:** March 28, 2026
**Last Updated:** March 28, 2026
Anima Labs Ltd ("Anima," "we," "us," or "our") is committed to protecting the privacy of our customers and their end users. This Privacy Policy explains how we collect, use, disclose, and safeguard personal data in connection with the Anima platform, APIs, and related services (the "Service") available at [https://useanima.sh](https://useanima.sh).
This Privacy Policy applies to all users of the Service, including developers, administrators, and operators acting on behalf of their organizations.
***
## 1. Data Controller Information
**Anima Labs Ltd** is the data controller for personal data processed in connection with the operation of the Service and your account.
For personal data processed on behalf of our customers (e.g., email content, phone records, and vault entries associated with customer Agents), the customer is the data controller and Anima acts as a data processor. The terms of such processing are governed by our [Data Processing Agreement](/legal/data-processing-agreement).
**Contact:**
Email: [legal@useanima.sh](mailto:legal@useanima.sh)
Website: [https://useanima.sh](https://useanima.sh)
***
## 2. Types of Personal Data Collected
### 2.1 Account Data
When you register for the Service, we collect:
* Full name and job title
* Business email address
* Company or organization name
* Billing address and payment information
* Phone number (optional)
### 2.2 Usage Data
We automatically collect data about how you interact with the Service:
* API call logs (endpoints called, timestamps, response codes, latency)
* Dashboard activity (pages visited, features used)
* Authentication events (login times, IP addresses, authentication methods)
* Error logs and diagnostic data
* Feature usage metrics and patterns
### 2.3 Agent Data
When your Agents use the Service, we process data on your behalf, which may include:
* **Email Data:** Email addresses, message content (headers, body, attachments), delivery status, bounce and complaint data.
* **Phone and SMS Data:** Phone numbers, call metadata (duration, timestamps, call direction), SMS message content, delivery receipts.
* **Vault Entries:** Encrypted credential data, metadata about stored entries (creation date, last accessed, entry type). Anima does not have access to decrypted vault content in customer-managed encryption configurations.
* **Identity Data:** Decentralized Identifiers (DIDs), verifiable credential metadata, Agent Card profiles, A2A protocol interaction logs.
### 2.4 Technical Data
We collect technical information from devices and browsers used to access the Service:
* IP addresses
* Browser type and version
* Operating system and device type
* Referring URLs
* Time zone and language settings
***
## 3. Legal Bases for Processing (GDPR Article 6)
We process personal data under the following legal bases:
### 3.1 Contract Performance (Article 6(1)(b))
Processing necessary for the performance of our contract with you, including:
* Provisioning and maintaining your account
* Providing the Service features you have requested (email, phone, vault, identity)
* Processing billing and payments
* Providing customer support
### 3.2 Legitimate Interest (Article 6(1)(f))
Processing necessary for our legitimate interests, provided these interests are not overridden by your rights and freedoms, including:
* Improving and optimizing the Service
* Detecting and preventing fraud, abuse, and security incidents
* Analyzing usage patterns to develop new features
* Ensuring network and information security
* Enforcing our Terms of Service
### 3.3 Consent (Article 6(1)(a))
Where required by applicable law, we process personal data based on your freely given, specific, informed, and unambiguous consent, including:
* Sending marketing communications and newsletters
* Placing non-essential cookies and tracking technologies
* Processing data for purposes beyond those described in this Privacy Policy
You may withdraw consent at any time by contacting us at [legal@useanima.sh](mailto:legal@useanima.sh) or by using the relevant opt-out mechanism. Withdrawal of consent does not affect the lawfulness of processing carried out before withdrawal.
### 3.4 Legal Obligation (Article 6(1)(c))
Processing necessary for compliance with legal obligations, including tax reporting, responding to lawful government requests, and maintaining records required by financial regulations.
***
## 4. How We Use Your Data
We use the personal data we collect to:
* **Provide the Service:** Operate, maintain, and deliver the features and functionality of the Platform, including email routing, phone/SMS services, vault storage, and identity management.
* **Process Transactions:** Process payments, generate invoices, and manage your billing account.
* **Communicate with You:** Send transactional communications (account notifications, security alerts, service updates), and, where you have opted in, marketing communications.
* **Ensure Security:** Monitor for and protect against fraud, abuse, unauthorized access, and other security threats.
* **Improve the Service:** Analyze usage data to understand how the Service is used, identify areas for improvement, and develop new features.
* **Comply with Law:** Fulfill our legal and regulatory obligations, including tax reporting, anti-money laundering requirements, and responding to lawful requests from authorities.
* **Enforce Our Terms:** Investigate and enforce compliance with our Terms of Service and Acceptable Use Policy.
***
## 5. Data Retention
We retain personal data only for as long as necessary to fulfill the purposes for which it was collected, unless a longer retention period is required by law.
| Data Category | Retention Period |
| --------------------- | ---------------------------------------------------------------------- |
| Account Data | Duration of the account plus 3 years after termination |
| Usage Data (API logs) | 90 days in detailed form; 2 years in aggregated form |
| Email Content | 30 days after delivery, unless configured otherwise by the customer |
| Phone/SMS Records | 90 days, or as required by telecommunications regulations |
| Vault Entries | Duration of the account; deleted within 30 days of account termination |
| Identity Data (DIDs) | Duration of the account plus 1 year after termination |
| Technical Data | 90 days |
| Billing Records | 7 years, as required by tax and accounting regulations |
Customers may request earlier deletion of their data subject to applicable legal retention requirements. See Section 8 (Data Subject Rights) for details.
***
## 6. Data Sharing and Subprocessors
### 6.1 No Sale of Personal Data
Anima does not sell personal data to third parties. We do not share personal data for third-party advertising purposes.
### 6.2 Subprocessors
We share personal data with the following categories of subprocessors, who process data on our behalf and under our instructions:
| Subprocessor | Purpose | Data Processed |
| ------------------------------- | ---------------------------------- | -------------------------------------------- |
| **Google Cloud Platform (GCP)** | Cloud infrastructure and hosting | All categories (encrypted at rest) |
| **Stripe** | Payment processing and billing | Billing data, payment methods |
| **Telnyx** | Phone and SMS services | Phone numbers, call/SMS metadata and content |
| **Clerk** | Authentication and user management | Account data, authentication events |
| **Resend** | Transactional email delivery | Email addresses, email content |
### 6.3 Other Disclosures
We may disclose personal data:
* **To comply with law:** In response to a subpoena, court order, or other lawful request from a government authority.
* **To protect rights:** When we believe in good faith that disclosure is necessary to protect our rights, your safety, or the safety of others, investigate fraud, or respond to a government request.
* **In a business transfer:** In connection with a merger, acquisition, bankruptcy, or sale of assets, in which case you will be notified of any change in data controller.
* **With your consent:** Where you have provided explicit consent to the disclosure.
### 6.4 Subprocessor Updates
We maintain an up-to-date list of subprocessors at [https://useanima.sh/subprocessors](https://useanima.sh/subprocessors). Customers who have entered into a Data Processing Agreement will receive 30 days' prior notice of any new subprocessor additions.
***
## 7. International Data Transfers
### 7.1 Transfer Mechanisms
Anima Labs Ltd is based in the United Kingdom. Personal data may be transferred to and processed in the United States and other countries where our subprocessors operate.
For transfers of personal data from the European Economic Area (EEA), the United Kingdom, or Switzerland to countries that have not received an adequacy decision, we rely on:
* **Standard Contractual Clauses (SCCs):** As adopted by the European Commission (Decision 2021/914) and, where applicable, the UK International Data Transfer Addendum.
* **Supplementary Measures:** Including encryption in transit and at rest, access controls, and contractual commitments from subprocessors.
### 7.2 EU-U.S. Data Privacy Framework
Where applicable, we rely on relevant data privacy framework certifications maintained by our subprocessors.
***
## 8. Data Subject Rights (GDPR)
If you are located in the EEA or the United Kingdom, you have the following rights under the GDPR and UK GDPR:
### 8.1 Right of Access (Article 15)
You have the right to obtain confirmation of whether we process your personal data and, if so, to request a copy of that data along with information about the purposes and categories of processing.
### 8.2 Right to Rectification (Article 16)
You have the right to request correction of inaccurate personal data and completion of incomplete personal data.
### 8.3 Right to Erasure (Article 17)
You have the right to request deletion of your personal data where: the data is no longer necessary for the purposes for which it was collected; you withdraw consent and there is no other legal basis; you object to processing and there are no overriding legitimate grounds; or the data has been unlawfully processed.
### 8.4 Right to Restriction of Processing (Article 18)
You have the right to request restriction of processing where: the accuracy of the data is contested; the processing is unlawful and you prefer restriction to erasure; Anima no longer needs the data but you require it for legal claims; or you have objected to processing pending verification.
### 8.5 Right to Data Portability (Article 20)
You have the right to receive your personal data in a structured, commonly used, and machine-readable format, and to transmit that data to another controller, where processing is based on consent or contract and is carried out by automated means.
### 8.6 Right to Object (Article 21)
You have the right to object to processing based on legitimate interests. We will cease processing unless we demonstrate compelling legitimate grounds that override your interests, rights, and freedoms, or where processing is necessary for the establishment, exercise, or defense of legal claims.
### 8.7 Right Related to Automated Decision-Making (Article 22)
Anima does not currently make decisions based solely on automated processing that produce legal effects or similarly significant effects concerning you. If this changes, we will provide meaningful information about the logic involved and the significance and envisaged consequences of such processing, and provide a mechanism to request human review.
### 8.8 Exercising Your Rights
To exercise any of these rights, contact us at [legal@useanima.sh](mailto:legal@useanima.sh). We will respond to your request within 30 days. We may request verification of your identity before fulfilling your request. If we are acting as a data processor on behalf of a customer, we will direct your request to the appropriate data controller.
***
## 9. CCPA Rights (California Residents)
If you are a California resident, you have the following rights under the California Consumer Privacy Act (CCPA), as amended by the California Privacy Rights Act (CPRA):
### 9.1 Right to Know
You have the right to request that we disclose the categories and specific pieces of personal information we have collected about you, the categories of sources, the business or commercial purpose for collecting the information, and the categories of third parties with whom we share it.
### 9.2 Right to Delete
You have the right to request deletion of personal information we have collected from you, subject to certain exceptions (e.g., legal obligations, completing a transaction, security purposes).
### 9.3 Right to Opt-Out of Sale or Sharing
Anima does not sell personal information and does not share personal information for cross-context behavioral advertising purposes as defined by the CCPA/CPRA.
### 9.4 Right to Correct
You have the right to request that we correct inaccurate personal information that we maintain about you.
### 9.5 Non-Discrimination
We will not discriminate against you for exercising any of your CCPA rights. We will not deny you the Service, charge you different prices, or provide a different level of quality based on your exercise of privacy rights.
### 9.6 Exercising Your Rights
To exercise your CCPA rights, contact us at [legal@useanima.sh](mailto:legal@useanima.sh). We will verify your identity before fulfilling your request and respond within 45 days.
***
## 10. Cookies and Tracking Technologies
### 10.1 Types of Cookies
We use the following categories of cookies on our website and dashboard:
* **Strictly Necessary Cookies:** Required for the operation of the Service (authentication, session management, security). These cookies cannot be disabled.
* **Analytics Cookies:** Used to understand how visitors interact with the Service, measure performance, and identify areas for improvement. Deployed only with your consent where required by law.
* **Preference Cookies:** Used to remember your settings and preferences (language, theme, display options).
### 10.2 Managing Cookies
You can manage your cookie preferences through: (a) the cookie consent banner displayed on first visit; (b) your browser settings; or (c) contacting us at [legal@useanima.sh](mailto:legal@useanima.sh).
### 10.3 Do Not Track
The Service currently does not respond to "Do Not Track" browser signals. However, you can opt out of analytics cookies as described above.
***
## 11. Children's Privacy
The Service is not directed to individuals under the age of 18. We do not knowingly collect personal data from children under 18. If we become aware that we have collected personal data from a child under 18, we will take steps to delete that information promptly. If you believe that a child under 18 has provided us with personal data, please contact us at [legal@useanima.sh](mailto:legal@useanima.sh).
***
## 12. Security Measures
We implement appropriate technical and organizational measures to protect personal data against unauthorized access, alteration, disclosure, or destruction. These measures include:
* **Encryption:** Data is encrypted at rest (AES-256) and in transit (TLS 1.2+).
* **Access Controls:** Role-based access control, multi-factor authentication for administrative access, and principle of least privilege.
* **Infrastructure Security:** Hosted on SOC 2 Type II certified infrastructure (Google Cloud Platform) with network segmentation, intrusion detection, and DDoS protection.
* **Audit Logging:** Comprehensive audit logs of administrative actions and data access events.
* **Employee Security:** Background checks, security training, and confidentiality agreements for all employees with access to personal data.
* **Vulnerability Management:** Regular security assessments, penetration testing, and a responsible disclosure program.
***
## 13. Data Breach Notification
### 13.1 Supervisory Authorities
In the event of a personal data breach that is likely to result in a risk to the rights and freedoms of natural persons, Anima will notify the relevant supervisory authority within 72 hours of becoming aware of the breach, in accordance with GDPR Article 33.
### 13.2 Affected Individuals
Where a personal data breach is likely to result in a high risk to the rights and freedoms of natural persons, Anima will communicate the breach to the affected individuals without undue delay, in accordance with GDPR Article 34.
### 13.3 Customer Notification
For data breaches affecting Customer Data where Anima acts as a data processor, Anima will notify the affected customer without undue delay and in any event within 72 hours of becoming aware of the breach, providing sufficient information for the customer to fulfill its own notification obligations.
***
## 14. Changes to This Privacy Policy
We may update this Privacy Policy from time to time to reflect changes in our practices, technology, legal requirements, or other factors. We will notify you of material changes by:
* Posting the updated Privacy Policy on our website with a revised "Last Updated" date.
* Sending an email notification to the address associated with your account at least 30 days before the changes take effect.
Your continued use of the Service after the effective date of any changes constitutes your acceptance of the updated Privacy Policy.
***
## 15. Contact Us
If you have questions, concerns, or requests regarding this Privacy Policy or our data practices, please contact our Data Protection team:
**Anima Labs Ltd**
Data Protection Officer
Email: [legal@useanima.sh](mailto:legal@useanima.sh)
Website: [https://useanima.sh](https://useanima.sh)
If you are located in the EEA or UK and are unsatisfied with our response to a privacy concern, you have the right to lodge a complaint with your local supervisory authority. For UK residents, this is the Information Commissioner's Office (ICO) at [https://ico.org.uk](https://ico.org.uk).
# Terms of Service
Source: https://docs.useanima.sh/legal/terms-of-service
Terms of Service for the Anima platform — the unified agent identity infrastructure for AI agents.
# Terms of Service
**Effective Date:** March 28, 2026
**Last Updated:** March 28, 2026
These Terms of Service ("Terms") constitute a legally binding agreement between you ("Customer," "you," or "your") and Anima Labs Ltd, a company incorporated in England and Wales, and its affiliates including Anima Labs Inc. (collectively, "Anima," "we," "us," or "our"). These Terms govern your access to and use of the Anima platform, APIs, SDKs, documentation, and related services (collectively, the "Service") available at [https://useanima.sh](https://useanima.sh).
By accessing or using the Service, you agree to be bound by these Terms. If you are entering into these Terms on behalf of an organization, you represent and warrant that you have the authority to bind that organization to these Terms, and references to "you" or "Customer" shall refer to that organization.
***
## 1. Definitions
**"Agent"** means an autonomous or semi-autonomous artificial intelligence software program that accesses or uses the Service on behalf of a Customer or Organization.
**"Agent Identity"** means the set of credentials, identifiers, and capabilities provisioned to an Agent through the Service, including but not limited to email addresses, phone numbers, cryptographic identifiers (DIDs), and vault entries.
**"API"** means the application programming interfaces provided by Anima for programmatic access to the Service.
**"API Key"** means the unique authentication credential issued to a Customer for accessing the API.
**"Organization"** means a legal entity that has entered into these Terms and under which one or more Users and Agents operate.
**"Platform"** means the Anima infrastructure, including email services, phone/SMS services, credential vault, cryptographic identity (DIDs), verifiable credentials, and the Agent-to-Agent (A2A) protocol.
**"Service"** means the Anima platform, APIs, SDKs, documentation, dashboard, and all related services.
**"User"** means any individual who accesses the Service on behalf of an Organization, including developers, administrators, and operators.
**"Vault"** means the encrypted credential storage system provided as part of the Service.
***
## 2. Account Registration and API Keys
### 2.1 Account Creation
To use the Service, you must create an account by providing accurate, complete, and current information. You must maintain the accuracy of this information throughout the term of your use.
### 2.2 API Keys
Upon registration, you will be issued API Keys for programmatic access to the Service. You are responsible for:
* Maintaining the confidentiality and security of all API Keys.
* All activity that occurs under your API Keys, whether authorized or unauthorized.
* Immediately notifying Anima at [legal@useanima.sh](mailto:legal@useanima.sh) if you become aware of any unauthorized use or compromise of your API Keys.
### 2.3 Account Security
You shall implement reasonable security measures to protect your account credentials and API Keys. Anima reserves the right to suspend access if we reasonably believe your credentials have been compromised.
***
## 3. Acceptable Use Policy
### 3.1 General Requirements
You agree to use the Service only for lawful purposes and in accordance with these Terms. You shall ensure that all Agents operating under your account comply with this Acceptable Use Policy.
### 3.2 Prohibited Activities
You shall not, and shall not permit any Agent to:
* **Fraud and Deception:** Engage in fraudulent, deceptive, or misleading activities, including impersonating humans or other entities without proper disclosure, or using Agent Identities to deceive third parties.
* **Spam and Unsolicited Communications:** Send unsolicited bulk email, SMS, or other communications; engage in email harvesting; or distribute malware or phishing content.
* **Illegal Activity:** Use the Service in violation of any applicable law, regulation, or third-party right, including laws governing telecommunications and data protection.
* **System Interference:** Interfere with or disrupt the integrity or performance of the Service, attempt to gain unauthorized access to other accounts or systems, or circumvent rate limits or security measures.
* **Harmful Content:** Use the Service to generate, store, or transmit content that is unlawful, defamatory, threatening, or that infringes intellectual property rights.
* **Reverse Engineering:** Reverse engineer, decompile, disassemble, or otherwise attempt to derive the source code of the Service.
* **Unauthorized Resale:** Resell, sublicense, or redistribute the Service without Anima's prior written consent.
### 3.3 Agent Conduct Requirements
Customers are solely responsible for the conduct of their Agents. All Agents must:
* Clearly identify themselves as AI agents when interacting with third parties, unless otherwise permitted by applicable law.
* Operate within the scope of permissions and capabilities granted by the Customer.
* Comply with all applicable laws and regulations in the jurisdictions in which they operate.
* Respect rate limits, usage quotas, and fair usage policies.
### 3.4 Enforcement
Anima reserves the right to investigate and take appropriate action against violations of this Acceptable Use Policy, including suspension or termination of access, removal of content, and reporting to law enforcement authorities.
***
## 4. Service Level Commitments
### 4.1 Uptime Target
Anima targets 99.9% monthly uptime for the core Service, measured as the percentage of total minutes in a calendar month during which the Service is available. Scheduled maintenance windows, which will be communicated at least 48 hours in advance, are excluded from uptime calculations.
### 4.2 Service Credits
If the Service falls below the 99.9% uptime target in any calendar month, eligible Customers on paid plans may request service credits in accordance with the Service Level Agreement published at [https://useanima.sh/sla](https://useanima.sh/sla).
### 4.3 Exclusions
Uptime commitments do not apply to: (a) features identified as alpha, beta, or preview; (b) downtime caused by factors outside Anima's reasonable control, including force majeure events; (c) downtime resulting from Customer's equipment, software, or network connections; or (d) downtime caused by Customer's breach of these Terms.
***
## 5. Rate Limiting and Fair Usage
### 5.1 Rate Limits
The Service enforces rate limits on API calls, email sending, SMS sending, and other operations. Current rate limits are published in the API documentation and may vary by plan tier.
### 5.2 Fair Usage
Even within published rate limits, Anima reserves the right to throttle or restrict access if usage patterns are inconsistent with normal business operations, place disproportionate load on the infrastructure, or negatively impact other customers.
### 5.3 Notification
Anima will make reasonable efforts to notify you before imposing restrictions under this section, except where immediate action is necessary to protect the Service or other customers.
***
## 6. Email Sending Policies
### 6.1 Anti-Spam Compliance
All email sent through the Service must comply with applicable anti-spam legislation, including but not limited to:
* **CAN-SPAM Act (United States):** All commercial email must include a valid physical postal address, a clear and conspicuous unsubscribe mechanism, and accurate header information. Unsubscribe requests must be honored within 10 business days.
* **GDPR (European Union):** Email communications to EU residents must comply with the General Data Protection Regulation, including obtaining valid consent where required under Article 6 and Article 7.
* **PECR (United Kingdom):** Email to UK recipients must comply with the Privacy and Electronic Communications Regulations.
* **CASL (Canada):** Email to Canadian recipients must comply with Canada's Anti-Spam Legislation, including obtaining express or implied consent.
### 6.2 Agent Email Requirements
Agents sending email through the Service must:
* Use only email addresses provisioned through the Platform or verified custom domains.
* Include clear identification that the sender is an AI agent, where required by law or recipient policy.
* Not forge, spoof, or misrepresent email headers or sender identity.
* Maintain bounce rates below 5% and spam complaint rates below 0.1%.
### 6.3 Email Suspension
Anima reserves the right to immediately suspend email sending capabilities if: (a) bounce rates or spam complaint rates exceed acceptable thresholds; (b) the Customer's sending practices violate applicable law; or (c) the Customer's email activity negatively impacts the Platform's sending reputation.
***
## 7. Phone and SMS Usage Policies
### 7.1 Regulatory Compliance
All phone and SMS usage through the Service must comply with applicable telecommunications regulations, including:
* **TCPA (United States):** You must obtain prior express consent (or prior express written consent for marketing messages) before sending SMS or making automated calls to US numbers. You must honor opt-out requests immediately.
* **10DLC Registration:** Customers sending SMS to US numbers must complete 10DLC (10-Digit Long Code) registration through the Platform before sending application-to-person (A2P) messages.
* **GDPR and ePrivacy:** SMS to EU recipients must comply with applicable EU data protection and electronic communications laws.
### 7.2 Prohibited SMS Content
The following content is prohibited in SMS messages sent through the Service: SHAFT content (sex, hate, alcohol, firearms, tobacco), illegal substances, deceptive or misleading offers, phishing or social engineering, and content that violates carrier acceptable use policies.
### 7.3 Call Recording and Monitoring
If you use the Service to record or monitor phone calls, you are solely responsible for complying with all applicable consent and notification requirements under federal and state law.
***
## 8. Vault and Credential Storage
### 9.1 Encryption
All data stored in the Vault is encrypted at rest using AES-256 encryption and in transit using TLS 1.2 or higher. Anima employs industry-standard key management practices.
### 9.2 Customer Responsibility
You are solely responsible for:
* The content stored in your Vault, including ensuring you have all necessary rights to store such content.
* Managing access controls and permissions for Vault entries.
* Maintaining backup copies of critical credentials and secrets, as Anima's liability for data loss is limited as set forth in Section 14.
### 9.3 Prohibited Vault Content
You shall not store in the Vault: content that violates applicable law, malware or malicious code, or content that infringes third-party intellectual property rights.
***
## 9. Data Processing and Privacy
### 10.1 Privacy Policy
Our collection and use of personal data in connection with the Service is described in our [Privacy Policy](/legal/privacy-policy). The Privacy Policy is incorporated into these Terms by reference.
### 10.2 Data Processing Agreement
For Customers who require a Data Processing Agreement under GDPR or other applicable data protection laws, our standard [Data Processing Agreement](/legal/data-processing-agreement) is available and is incorporated into these Terms where applicable.
### 10.3 Customer Data
As between you and Anima, you retain all rights in and to the data you submit to the Service ("Customer Data"). You grant Anima a limited, non-exclusive license to process Customer Data solely as necessary to provide and improve the Service.
***
## 10. Intellectual Property
### 11.1 Anima IP
The Service, including all software, APIs, documentation, designs, trademarks, and other intellectual property, is and remains the exclusive property of Anima. Nothing in these Terms grants you any right, title, or interest in the Service except the limited right to use the Service in accordance with these Terms.
### 11.2 Customer IP
As between you and Anima, you retain all intellectual property rights in your Customer Data, Agent configurations, and any software you develop using the Service. These Terms do not transfer any Customer intellectual property to Anima.
### 11.3 Feedback
If you provide Anima with feedback, suggestions, or ideas regarding the Service ("Feedback"), you grant Anima a perpetual, irrevocable, worldwide, royalty-free license to use, modify, and incorporate such Feedback into the Service without obligation to you.
***
## 11. API Terms
### 12.1 API Access
Access to the API is granted subject to these Terms and the API documentation. You shall use the API only in accordance with the published documentation.
### 12.2 Versioning
Anima uses semantic versioning for the API. Major version changes that include breaking changes will be communicated at least 90 days in advance.
### 12.3 Deprecation Policy
When an API version or feature is deprecated:
* Anima will provide at least 90 days' notice before removing a major API version.
* Deprecated features will be clearly marked in the API documentation and response headers.
* Anima will provide migration guides for significant version changes.
### 12.4 Backward Compatibility
Within a major API version, Anima will maintain backward compatibility. Additive changes (new endpoints, new optional fields) are not considered breaking changes.
***
## 12. Billing and Payments
### 13.1 Pricing
The Service is offered on a usage-based pricing model. Current pricing is published at [https://useanima.sh/pricing](https://useanima.sh/pricing) and may be updated from time to time with 30 days' prior notice.
### 13.2 Usage-Based Billing
You will be billed based on your actual usage of the Service, including but not limited to: API calls, emails sent and received, SMS messages, phone minutes, virtual card transactions, vault storage, and agent identities provisioned.
### 13.3 Invoicing
Invoices are generated monthly and are due within 30 days of the invoice date unless otherwise agreed in a separate order form. All fees are stated in US Dollars unless otherwise specified.
### 13.4 Taxes
All fees are exclusive of applicable taxes, duties, and levies. You are responsible for all taxes associated with your use of the Service, except for taxes based on Anima's net income.
### 13.5 Late Payments
Late payments accrue interest at the lesser of 1.5% per month or the maximum rate permitted by applicable law. Anima reserves the right to suspend the Service for accounts with payments overdue by more than 30 days.
***
## 13. Disclaimer of Warranties
THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. ANIMA DOES NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE, OR SECURE, OR THAT ANY DEFECTS WILL BE CORRECTED.
***
## 14. Limitation of Liability
### 15.1 Exclusion of Consequential Damages
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL ANIMA BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS, REVENUE, DATA, OR BUSINESS OPPORTUNITY ARISING OUT OF OR RELATED TO THESE TERMS OR THE SERVICE, REGARDLESS OF THE THEORY OF LIABILITY.
### 15.2 Cap on Liability
ANIMA'S TOTAL AGGREGATE LIABILITY ARISING OUT OF OR RELATED TO THESE TERMS OR THE SERVICE SHALL NOT EXCEED THE GREATER OF (A) THE AMOUNTS PAID BY YOU TO ANIMA IN THE TWELVE (12) MONTHS PRECEDING THE EVENT GIVING RISE TO THE CLAIM, OR (B) ONE HUNDRED US DOLLARS (\$100).
### 15.3 Exceptions
The limitations in this Section 14 do not apply to: (a) either party's indemnification obligations; (b) either party's breach of confidentiality obligations; (c) your breach of Section 3 (Acceptable Use Policy); or (d) liability that cannot be limited under applicable law.
***
## 15. Indemnification
### 16.1 Customer Indemnification
You agree to indemnify, defend, and hold harmless Anima and its officers, directors, employees, and agents from and against any claims, damages, losses, liabilities, costs, and expenses (including reasonable attorneys' fees) arising out of or related to:
* Your use of the Service or any Agent's use of the Service under your account.
* Your breach of these Terms or any applicable law or regulation.
* Your Agent's interactions with third parties, including any claims arising from email, phone, SMS, or card transactions initiated by your Agents.
* Any content or data you submit to or transmit through the Service.
### 16.2 Anima Indemnification
Anima agrees to indemnify, defend, and hold harmless Customer from and against any third-party claims that the Service, as provided by Anima, infringes such third party's intellectual property rights, provided that Customer promptly notifies Anima of the claim, gives Anima sole control of the defense, and cooperates with Anima's defense.
***
## 16. Termination and Suspension
### 17.1 Termination by Customer
You may terminate your account at any time by providing written notice to Anima. Termination does not relieve you of any obligation to pay fees incurred prior to termination.
### 17.2 Termination by Anima
Anima may terminate or suspend your access to the Service immediately, without prior notice, if:
* You breach any material provision of these Terms.
* You fail to pay any fees when due after a 15-day cure period.
* Your use of the Service poses a security risk to the Service or other customers.
* Required by applicable law, regulation, or court order.
### 17.3 Suspension
Anima may suspend your access to all or part of the Service if we reasonably believe suspension is necessary to prevent harm to the Service, other customers, or third parties. We will provide notice of the suspension and the reasons therefor as soon as practicable.
### 17.4 Effect of Termination
Upon termination: (a) all rights granted to you under these Terms will immediately cease; (b) you must cease all use of the Service and delete all API Keys; (c) Anima will make your Customer Data available for export for 30 days following termination, after which Anima may delete it; and (d) provisions that by their nature should survive termination will survive, including Sections 11, 14, 15, 16, and 19.
***
## 17. Dispute Resolution
### 18.1 Informal Resolution
Before filing any formal dispute, the parties agree to attempt to resolve any dispute informally by sending written notice to the other party describing the dispute and proposed resolution. The parties shall negotiate in good faith for at least 30 days before initiating formal proceedings.
### 18.2 Arbitration
Any dispute arising out of or relating to these Terms that cannot be resolved informally shall be settled by binding arbitration administered by the American Arbitration Association (AAA) under its Commercial Arbitration Rules. The arbitration shall take place in Wilmington, Delaware, and be conducted in English.
### 18.3 Exceptions
Either party may seek injunctive or equitable relief in any court of competent jurisdiction to protect its intellectual property rights or confidential information without first engaging in the dispute resolution procedures above.
### 18.4 Class Action Waiver
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, YOU AND ANIMA EACH WAIVE THE RIGHT TO PARTICIPATE IN A CLASS ACTION, COLLECTIVE ACTION, OR REPRESENTATIVE ACTION WITH RESPECT TO ANY DISPUTE ARISING UNDER THESE TERMS.
***
## 18. Governing Law
These Terms are governed by and construed in accordance with the laws of the State of Delaware, United States of America, without regard to its conflict of laws principles. The parties consent to the exclusive jurisdiction of the state and federal courts located in Delaware for any dispute not subject to arbitration.
***
## 19. Changes to These Terms
Anima may modify these Terms from time to time. We will provide at least 30 days' prior written notice of material changes by email to the address associated with your account and by posting the updated Terms on our website. Your continued use of the Service after the effective date of any modification constitutes your acceptance of the modified Terms. If you do not agree with any modification, you must cease using the Service before the modification takes effect.
***
## 20. General Provisions
### 21.1 Entire Agreement
These Terms, together with the Privacy Policy, Data Processing Agreement (where applicable), and any applicable order forms, constitute the entire agreement between you and Anima regarding the Service and supersede all prior agreements and understandings.
### 21.2 Severability
If any provision of these Terms is held to be invalid or unenforceable, the remaining provisions will continue in full force and effect.
### 21.3 Waiver
The failure of either party to enforce any right or provision of these Terms shall not constitute a waiver of such right or provision.
### 21.4 Assignment
You may not assign or transfer these Terms, or any rights or obligations hereunder, without Anima's prior written consent. Anima may assign these Terms in connection with a merger, acquisition, or sale of all or substantially all of its assets.
### 21.5 Force Majeure
Neither party shall be liable for any failure or delay in performance due to circumstances beyond its reasonable control, including acts of God, natural disasters, pandemics, war, terrorism, government actions, or failures of third-party infrastructure providers.
### 21.6 Notices
All notices under these Terms shall be in writing and sent to: (a) Anima: [legal@useanima.sh](mailto:legal@useanima.sh); (b) Customer: the email address associated with your account.
***
## 22. Contact Information
If you have questions about these Terms, please contact us at:
**Anima Labs Ltd**
Email: [legal@useanima.sh](mailto:legal@useanima.sh)
Website: [https://useanima.sh](https://useanima.sh)
# MCP Servers
Source: https://docs.useanima.sh/mcp-servers
Connect Anima to Claude Desktop, Cursor, VS Code, and other MCP clients via Model Context Protocol.
# MCP Servers
Anima exposes 53 specialized tools via the [Model Context Protocol](https://modelcontextprotocol.io) (MCP), giving AI assistants direct access to agent email, vault, phone, voice calls, identity cards, and more.
Tools are organized into domain servers, so you can install only what you need:
| Server | Package | Description |
| ------------ | -------------------------- | ------------------------------------------------------- |
| **Agent** | `@anima-labs/mcp-agent` | Agent lifecycle, organizations, identity, registry, A2A |
| **Email** | `@anima-labs/mcp-email` | Email, messages, domains, addresses |
| **Phone** | `@anima-labs/mcp-phone` | Phone numbers, SMS, voice calls |
| **Cards** | `@anima-labs/mcp-cards` | Agent cards and identity metadata |
| **Vault** | `@anima-labs/mcp-vault` | Encrypted credential storage, security policies |
| **Platform** | `@anima-labs/mcp-platform` | Webhooks, pods, utilities |
## Quick Start
### Option A: Local (stdio)
Run one or more servers locally via `npx`:
```bash theme={null}
npx @anima-labs/mcp-phone --api-key=ak_...
```
### Option B: Hosted (remote)
Connect to Anima's hosted MCP endpoint — no local install needed:
```
https://mcp.useanima.sh/mcp
```
Authenticate with your API key as a Bearer token (`Authorization: Bearer ak_...`). The hosted
endpoint exposes the full tool surface, so there is nothing to install or keep updated.
## Configuration
### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
**Local (stdio):**
```json theme={null}
{
"mcpServers": {
"anima-phone": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-phone"],
"env": {
"ANIMA_API_KEY": "ak_..."
}
},
"anima-email": {
"command": "npx",
"args": ["-y", "@anima-labs/mcp-email"],
"env": {
"ANIMA_API_KEY": "ak_..."
}
}
}
}
```
**Hosted (remote via mcp-remote bridge):**
```json theme={null}
{
"mcpServers": {
"anima-phone": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp.useanima.sh/mcp",
"--header", "Authorization:${ANIMA_TOKEN}"
],
"env": {
"ANIMA_TOKEN": "Bearer ak_..."
}
}
}
}
```
### Cursor
**Hosted (remote — native HTTP support):**
```json theme={null}
{
"mcpServers": {
"anima-phone": {
"url": "https://mcp.useanima.sh/mcp",
"headers": {
"Authorization": "Bearer ak_..."
}
}
}
}
```
### Claude Code
```bash theme={null}
# Local
claude mcp add anima-phone -- npx -y @anima-labs/mcp-phone
# Hosted
claude mcp add anima-phone --transport http \
--url https://mcp.useanima.sh/mcp \
--header "Authorization: Bearer ak_..."
```
### VS Code
Add to `.vscode/settings.json`:
```json theme={null}
{
"mcp": {
"servers": {
"anima-phone": {
"type": "http",
"url": "https://mcp.useanima.sh/mcp",
"headers": {
"Authorization": "Bearer ${input:anima-key}"
}
}
},
"inputs": [
{
"id": "anima-key",
"type": "promptString",
"description": "Anima API Key",
"password": true
}
]
}
}
```
### CLI Setup (all clients)
The Anima CLI can auto-configure all detected MCP clients:
```bash theme={null}
# Install for all detected clients (local mode)
anima setup-mcp install --all
# Install specific server for a specific client (remote mode)
anima setup-mcp install --client cursor --mode remote --server phone
# Install all servers
anima setup-mcp install --all --server all
```
## Environment Variables
| Variable | Description |
| --------------- | ------------------------------ |
| `ANIMA_API_KEY` | Your Anima API key (required) |
| `ANIMA_API_URL` | Custom API base URL (optional) |
## Available Tools by Server
### mcp-agent
| Category | Tools | Description |
| ---------------- | --------------------------------------- | -------------------------- |
| **Agent** | create, list, get, delete, rotate-key | Manage AI agent identities |
| **Organization** | get, update, create, delete, rotate-key | Organization settings |
| **Identity** | create, list, get, verify | Agent identity management |
| **Registry** | register, search, get, list | Agent registry / discovery |
| **A2A** | send, receive, list | Agent-to-agent messaging |
### mcp-email
| Category | Tools | Description |
| ----------- | ---------------------------- | ------------------------------ |
| **Email** | send, reply, search, list | Send and manage email |
| **Message** | send, list, get | Inbox messaging operations |
| **Domain** | create, verify, list, delete | Custom email domain management |
| **Address** | create, list, get | Email address management |
### mcp-phone
| Category | Tools | Description |
| --------- | --------------------------------------------------------------- | -------------------------------------- |
| **Phone** | search, provision, list, release, send-sms | Phone number and SMS management |
| **Voice** | catalog, call, list-calls, get-call, transcript, summary, score | Voice call operations and intelligence |
### mcp-cards
| Category | Tools | Description |
| --------- | -------------------- | -------------------------------- |
| **Cards** | get, publish, verify | Agent card and identity metadata |
### mcp-vault
| Category | Tools | Description |
| ------------ | -------------------------------------------- | ----------------------------- |
| **Vault** | provision, create, get, search, list, delete | Encrypted credential storage |
| **Security** | policies, audit, update | Security policy configuration |
### mcp-platform
| Category | Tools | Description |
| ----------- | ------------------------------------- | ----------------------------------------------------------------------- |
| **Webhook** | set (upsert), get, list, delete, test | Real-time event subscriptions, with endpoint auth and delivery throttle |
| **Pod** | create, list, get | Pod management |
| **Utility** | search, status, health | Utility and status tools |
## Legacy Monolith Server
The original monolith `@anima-labs/mcp` package is still supported but deprecated. Migrate to the split servers for better performance and selective loading.
## Example Usage
Once connected, ask your AI assistant natural language questions:
* "Send an email from my agent to [user@example.com](mailto:user@example.com)" → **mcp-email**
* "Store my CRM login credentials in the vault" → **mcp-vault**
* "Text me now from my agent's number" → **mcp-phone**
* "Make a voice call to +1-555-0123" → **mcp-phone**
* "Register my agent in the public registry" → **mcp-agent**
For editor-specific setup, see [Connect your AI client](/integrations).
# Phone & Voice
Source: https://docs.useanima.sh/phone
Provision phone numbers, send SMS, receive replies, and place voice calls from an AI agent identity.
# Phone & Voice
Give your AI agents real phone numbers for SMS and voice. The phone number belongs to the same agent identity as its email inbox, vault, addresses, and DID, so cross-channel workflows stay tied to one actor and one audit trail.
## Overview
Anima Phone lets you:
* Search for available US numbers by area code and capability
* Provision a dedicated number for an agent
* Send a real "text me now" SMS from that agent
* Receive inbound SMS through webhooks
* Place outbound voice calls with server-side TCPA, RND, and time-of-day gates
* Read call records and transcripts from the same identity surface
Use this page when you already have an `agent_id`. If you are starting from zero, create an agent first in the console or through the agent API, then come back here with the agent ID.
## 1. Search for a number
Find available numbers by area code and requested capability:
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
numbers = anima.phones.search(
country_code="US",
area_code="415",
capabilities=["sms", "voice"],
limit=3,
)
for number in numbers["items"]:
print(number["phoneNumber"], number.get("region"))
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const numbers = await anima.phones.search({
countryCode: "US",
areaCode: "415",
capabilities: ["sms", "voice"],
limit: 3,
});
for (const number of numbers.items) {
console.log(number.phoneNumber, number.region);
}
```
## 2. Provision a phone identity
Provisioning assigns one number to one agent. Request both `sms` and `voice` when you want the number to support the full demo path.
```python theme={null}
agent_id = "AGENT_ID"
phone = anima.phones.provision(
agent_id=agent_id,
country_code="US",
area_code="415",
capabilities=["sms", "voice"],
)
print(f"Provisioned: {phone.phone_number}")
```
```ts theme={null}
const agentId = "AGENT_ID";
const phone = await anima.phones.provision({
agentId,
countryCode: "US",
areaCode: "415",
capabilities: ["sms", "voice"],
});
console.log(`Provisioned: ${phone.phoneNumber}`);
```
## 3. Text your human now
Send the first SMS to a number you control. This is the fastest way to prove the agent has a real, reachable phone path.
```python theme={null}
message = anima.messages.send_sms(
agent_id=agent_id,
to="+15551234567", # your phone number
body="Hi - this is my Anima agent texting from its own number.",
)
print(f"SMS sent: {message.id} ({message.status})")
```
```ts theme={null}
const message = await anima.messages.sendSms({
agentId,
to: "+15551234567", // your phone number
body: "Hi - this is my Anima agent texting from its own number.",
});
console.log(`SMS sent: ${message.id} (${message.status})`);
```
## 4. Receive replies
Inbound SMS is delivered as a message event. Subscribe to `message.received`, then inspect the message channel/payload to distinguish SMS from email.
```bash theme={null}
curl -X POST https://api.useanima.sh/v1/webhooks \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/anima",
"events": ["message.received", "phone.provisioned", "call.ended"]
}'
```
See [Webhooks](/webhooks) for signature verification and delivery retries.
## 5. Call your human now
Outbound voice calls run through the voice gate before dialing. Use a number you control for the first call, and only call recipients where you have the required consent.
```python theme={null}
call = anima.calls.create(
agent_id=agent_id,
to="+15551234567", # your phone number
tier="basic",
greeting="Hi, this is my Anima agent. I am calling from my own phone number.",
)
print(f"Call started: {call.call_id} ({call.state})")
```
```ts theme={null}
const call = await anima.calls.create({
agentId,
to: "+15551234567", // your phone number
tier: "basic",
greeting: "Hi, this is my Anima agent. I am calling from my own phone number.",
});
console.log(`Call started: ${call.callId} (${call.state})`);
```
Voice behavior comes from the configured agent and selected tier. Use `greeting` for the first spoken line; use the agent configuration and voice pipeline for deeper call behavior.
## 6. Read the transcript
After the call ends, fetch the transcript:
```python theme={null}
transcript = anima.calls.get_transcript(call.call_id)
for segment in transcript.segments:
print(f"{segment.speaker}: {segment.text}")
```
```ts theme={null}
const transcript = await anima.calls.getTranscript(call.callId);
for (const segment of transcript.segments) {
console.log(`${segment.speaker}: ${segment.text}`);
}
```
For live call events and bidirectional voice control, see the [Voice WebSocket Protocol](/protocols/voice-websocket).
## Phone, mail, and vault together
The useful Anima pattern is not "a phone API in isolation." It is one agent identity using the right channel at each step:
1. Email the human or customer with context.
2. Text them if the workflow needs an immediate response.
3. Place a voice call when the situation needs synchronous confirmation.
4. Store credentials and tokens in the vault so the agent can act without exposing secrets to the LLM.
5. Tie the full workflow together in audit logs and webhooks through the same agent ID.
## Compliance guardrails
For US outbound calls, Anima enforces guardrails server-side before the dial reaches the telephony provider. These include TCPA consent attestation, Reassigned Numbers Database checks, time-of-day windows, and per-tier call caps. The platform can reject a call before dialing when those requirements are not satisfied.
For SMS, keep the same standard: do not send spam, honor opt-outs, and only contact recipients where you have a lawful basis to do so.
## List or release numbers
List numbers assigned to an agent:
```python theme={null}
numbers = anima.phones.list(agent_id=agent_id)
for phone in numbers:
print(phone.phone_number, phone.ten_dlc_status)
```
```ts theme={null}
const numbers = await anima.phones.list({ agentId });
for (const phone of numbers.items) {
console.log(phone.phoneNumber, phone.tenDlcStatus);
}
```
Release a number when the agent no longer needs it:
```python theme={null}
anima.phones.release(
agent_id=agent_id,
phone_number="+14155551234",
)
```
```ts theme={null}
await anima.phones.release({
agentId,
phoneNumber: "+14155551234",
});
```
## Next steps
* [Quickstart: Voice Calls](/quickstart-voice) - Run the SMS-then-call demo end to end
* [Conversational Calls](/conversational-calls) - Choose REST hosted, realtime, or WebSocket-controlled calls
* [Voice Catalog](/voice-catalog) - Browse voice tiers and options
* [Call Intelligence](/call-intelligence) - Summaries, scoring, transcripts, and recordings
* [Pricing & Limits](/pricing-and-limits) - Check included phone, SMS, and voice quotas
* [Vault](/vault) - Store credentials without exposing raw secrets to the model
# Multi-Tenancy Pods
Source: https://docs.useanima.sh/pods/overview
Isolate agent environments with pods. API key scoping, resource isolation, and cross-pod policies.
# Multi-Tenancy Pods
Pods provide logical isolation for groups of agents within your Anima organization. Each pod has its own agents, API keys, budgets, and security policies, enabling multi-tenant architectures and environment separation.
## Core Concepts
* **Pod** -- An isolated namespace containing agents, keys, and resources
* **API Key Scoping** -- Keys are scoped to a specific pod and cannot access resources in other pods
* **Resource Isolation** -- Agents in one pod cannot interact with agents in another unless explicitly allowed
* **Cross-Pod Policies** -- Configure controlled communication between pods when needed
## Creating Pods
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." }); // org-level key
// Create a pod for a specific tenant or environment
const pod = await anima.pods.create({
name: "production",
description: "Production agent environment",
settings: {
maxAgents: 50,
maxApiKeys: 10,
allowCrossPodCommunication: false,
},
});
console.log(`Pod: ${pod.id}, Name: ${pod.name}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
pod = anima.pods.create(
name="production",
description="Production agent environment",
settings={
"max_agents": 50,
"max_api_keys": 10,
"allow_cross_pod_communication": False,
},
)
print(f"Pod: {pod.id}, Name: {pod.name}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
pod, err := client.Pods.Create(ctx, &anima.CreatePodParams{
Name: "production",
Description: "Production agent environment",
Settings: &anima.PodSettings{
MaxAgents: 50,
MaxAPIKeys: 10,
AllowCrossPodCommunication: false,
},
})
```
## API Key Scoping
API keys are scoped to a single pod. An agent created with a pod-scoped key automatically belongs to that pod.
```ts theme={null}
// Create a pod-scoped API key
const key = await anima.pods.createApiKey(pod.id, {
name: "prod-backend",
permissions: ["agents:read", "agents:write", "messages:send"],
expiresAt: "2027-01-01T00:00:00Z",
});
console.log(`Key: ${key.apiKey}`); // ak_pod_...
// Use the pod-scoped key -- all operations are isolated to the pod
const podClient = new Anima({ apiKey: key.apiKey });
const agent = await podClient.agents.create({ name: "Pod Agent" });
// This agent is automatically scoped to the pod
```
## Resource Isolation
Each pod maintains isolation for:
| Resource | Isolation Behavior |
| ------------- | ------------------------------------------------ |
| Agents | Agents only exist within their pod |
| API Keys | Keys only access resources in their pod |
| Email Domains | Domains are assigned per pod |
| Vault Secrets | Secrets are encrypted per-pod with separate keys |
| Cards | Card programs are scoped to pods |
| Webhooks | Webhook subscriptions are per-pod |
| Audit Logs | Logs are tagged with pod ID for filtering |
## Cross-Pod Communication
When you need agents in different pods to communicate:
```ts theme={null}
// Enable cross-pod communication between two pods
await anima.pods.createBridge({
sourcePodId: "pod_prod",
targetPodId: "pod_analytics",
permissions: ["a2a:send", "a2a:receive"],
allowedCapabilities: ["data-export"],
});
```
## Listing and Managing Pods
```ts theme={null}
// List all pods
const pods = await anima.pods.list();
// Get pod usage statistics
const stats = await anima.pods.getStats("pod_prod");
console.log(`Agents: ${stats.agentCount}, API Keys: ${stats.apiKeyCount}`);
console.log(`Monthly spend: $${(stats.monthlySpendCents / 100).toFixed(2)}`);
// Delete a pod (must be empty)
await anima.pods.delete("pod_staging");
```
## API Reference
| Endpoint | Method | Description |
| ----------------------------------------------- | ------ | --------------------------- |
| `https://api.useanima.sh/api/pods` | POST | Create a pod |
| `https://api.useanima.sh/api/pods` | GET | List all pods |
| `https://api.useanima.sh/api/pods/:id` | GET | Get pod details |
| `https://api.useanima.sh/api/pods/:id` | PUT | Update pod settings |
| `https://api.useanima.sh/api/pods/:id` | DELETE | Delete a pod |
| `https://api.useanima.sh/api/pods/:id/api-keys` | POST | Create a pod-scoped API key |
| `https://api.useanima.sh/api/pods/:id/api-keys` | GET | List pod API keys |
| `https://api.useanima.sh/api/pods/:id/stats` | GET | Get pod usage statistics |
| `https://api.useanima.sh/api/pods/bridges` | POST | Create a cross-pod bridge |
## Configuration
| Variable | Default | Description |
| ------------------------------- | ------- | ---------------------------------------- |
| `ANIMA_PODS_MAX_PER_ORG` | `20` | Maximum pods per organization |
| `ANIMA_PODS_DEFAULT_MAX_AGENTS` | `100` | Default max agents per pod |
| `ANIMA_PODS_CROSS_POD_DEFAULT` | `false` | Allow cross-pod communication by default |
## Next Steps
* [Security](/security) -- Pod-level security policies
* [Audit Log](/security/audit-log) -- Filter audit events by pod
* [Agent Registry](/registry/overview) -- Register agents with pod context
# Pricing & Limits
Source: https://docs.useanima.sh/pricing-and-limits
Plan limits, phone/SMS/voice rates, MCP pricing, and call caps for Anima.
# Pricing & Limits
The canonical pricing page is [useanima.sh/pricing](https://useanima.sh/pricing). Use this page as the docs summary for plan limits and phone/voice meters.
## Plans
| Plan | Price | Agent identities | Phone numbers | SMS | Voice minutes | Outbound calls | Vault |
| ---------- | ---------------------- | ---------------- | ----------------------------- | --------------------- | ----------------------------- | ------------------- | ------------------ |
| Free | `$0/forever` | 3 | 1 local number | 10 out + 10 in / mo | 10 Basic min | 20 / mo hard cap | 20 credentials |
| Starter | `$29/mo` | 25 | 1 included, then `$2/mo` each | 500 out + 500 in / mo | 100 Basic + 10 Premium min | 250 / mo | 500 credentials |
| Growth | `$99/mo` | 100 | 3 included | 5K out + 5K in / mo | 500 Basic + 100 Premium min | 1,000 / mo | 5,000 credentials |
| Scale | `$249/mo` | 500 | 10 included | 25K out + 25K in / mo | 1,500 Basic + 300 Premium min | 4,000 / mo | 25,000 credentials |
| Enterprise | From `$999/mo + usage` | Unlimited | Pooled numbers | Negotiated | Negotiated | 20,000 / mo default | Negotiated |
Free is hard-capped. Paid tiers use the unit rates below when usage exceeds the included quota.
## Usage rate card
| Meter | Rate | Notes |
| -------------------------- | ----------------------------- | -------------------------------------------------------------------- |
| Email sent | `$0.50 / 1,000` | Inbound email is included. |
| SMS sent, US 10DLC | `$0.015 / message` | Carrier and registration handling included in the published US rate. |
| SMS received, US 10DLC | `$0.010 / message` | Applies to inbound replies. |
| SMS sent, US toll-free | `$0.020 / message` | Toll-free numbers have separate carrier treatment. |
| Voice, Basic | `$0.07 / min` | Promo through 2026-09-30. Steady-state `$0.08/min`. |
| Voice, Premium | `$0.15 / min` | Promo through 2026-09-30. Steady-state `$0.18/min`. |
| Phone number, US local | `$2 / mo each` | Above included quota. |
| Phone number, US toll-free | `$3 / mo each` | Above included quota. |
| Outbound voice calls | `$0.03 / call above included` | Includes the RND check cost. |
| Vault stored credentials | `$0.001 / credential / mo` | Above tier cap. |
| MCP tool calls | Included | No per-tool-call charge. |
| Webhook deliveries | Included | Includes retry budget. |
## Voice call caps
Outbound voice calls are limited by both minutes and call count. The count cap exists because short-call loops can burn compliance checks before minute caps catch them.
| Plan | Monthly outbound-call cap |
| ---------- | ------------------------- |
| Free | 20 |
| Starter | 250 |
| Growth | 1,000 |
| Scale | 4,000 |
| Enterprise | 20,000 default |
Anima also enforces a per-second outbound-call rate limit to stop runaway loops.
## Compliance gates
Outbound calls run through server-side gates before dialing:
* TCPA consent attestation
* Reassigned Numbers Database checks
* Time-of-day windows
* Plan and monthly call caps
If a gate blocks the call, the API rejects it before the telephony provider dials.
## MCP pricing
MCP access is included. You do not pay per MCP tool call. The underlying action can still consume a metered resource, such as SMS, voice minutes, a phone number, or stored vault credentials.
## Related docs
* [Phone & Voice](/phone)
* [Conversational Calls](/conversational-calls)
* [MCP Servers](/mcp-servers)
# Google AP2
Source: https://docs.useanima.sh/protocols/ap2
Implement Google AP2 mandates, delegation chains, and capability narrowing for agent-driven checkout and payments.
# Google AP2
AP2 defines structured mandates and delegation chains so agents can execute commerce actions with explicit, narrow authority.
## Mandate-First Model
## Narrowing by Hop
## VDC Mandate Types
* Cart
* Intent
* Payment
## Scopes
* `checkout`
* `payment`
* `browse`
* `compare`
* `negotiate`
## Capabilities
| Capability | Description |
| -------------------- | --------------------------------------------- |
| select\_item | Choose candidate products/services. |
| add\_to\_cart | Modify cart composition and quantities. |
| checkout | Submit checkout details up to payment step. |
| pay | Execute authorized payment transaction. |
| confirm\_order | Confirm and persist final order receipt. |
| manage\_subscription | Create/update/cancel recurring service plans. |
## Multi-Hop Delegation Chains
Delegation chains narrow authority at each hop so every child mandate is a strict subset of its parent.
> **Note:** Delegation invariant: child scopes ⊆ parent scopes and child capabilities ⊆ parent capabilities.
## Mandate Parsing Example
```ts title="ap2-parse-mandate.ts" theme={null}
type Scope = "checkout" | "payment" | "browse" | "compare" | "negotiate";
type Capability =
| "select_item"
| "add_to_cart"
| "checkout"
| "pay"
| "confirm_order"
| "manage_subscription";
interface MandatePayload {
type: "Cart" | "Intent" | "Payment";
scopes: Scope[];
capabilities: Capability[];
delegations: Array<{
delegate: string;
scopes: Scope[];
capabilities: Capability[];
}>;
}
const mandate = JSON.parse(payload) as MandatePayload;
const hasPaymentScope = mandate.scopes.includes("payment");
const canPay = mandate.capabilities.includes("pay");
if (!hasPaymentScope || !canPay) {
throw new Error("Mandate does not authorize payment execution");
}
```
> **Tip:** Persist parsed mandate snapshots and subset-validation results for every delegation hop.
> **Note:** Route all AP2 verification outcomes through `ProtocolRouter.verify()` for consistent fallback and metrics tagging.
# Mastercard VI
Source: https://docs.useanima.sh/protocols/mastercard-vi
Validate Mastercard Verifiable Intelligence credential chains using SD-JWT, ES256 signatures, and constraint-aware delegation rules.
# Mastercard VI
Mastercard VI uses SD-JWT credential chains to delegate payment authority from issuers to agents with explicit time and policy constraints.
## Layered Credentials
## Strong Signatures
## Credential Chain Model
* L1
* L2 Immediate
* L2 Autonomous
* L3a/L3b
## Algorithm Requirements
* JWS: ES256
* Curve: P-256
* Hash: SHA-256
## Constraint Types
| Constraint | Intent |
| ----------------- | ---------------------------------------------------------- |
| allowed\_merchant | Permit transactions only for specific merchant identities. |
| line\_items | Constrain purchasable SKUs/items and quantities. |
| allowed\_payee | Restrict destination beneficiary/payee account. |
| amount | Set max/min transaction amount boundaries. |
| budget | Enforce cumulative spending ceiling over period. |
| recurrence | Define schedule rules for recurring charges. |
| agent\_recurrence | Limit autonomous repeated actions by agent identity. |
| reference | Require transaction metadata/reference matching policy. |
## Credential Chain Validation Example
```ts title="mastercard-vi-validate.ts" theme={null}
const result = await verifyViChain({
algorithm: "ES256",
credentials: {
l1,
l2,
l3,
},
now: Date.now(),
});
if (!result.signaturesValid) throw new Error("Invalid signature chain");
if (!result.hashLinksValid) throw new Error("sd_hash mismatch");
if (!result.timeWindowsValid)
throw new Error("Credential expired or not yet valid");
const policyDecision = evaluateConstraints({
constraints: result.constraints,
paymentRequest,
});
if (!policyDecision.allowed) {
throw new Error("Constraint violation:" + policyDecision.reason);
}
```
> **Warning:** Never skip L3 terminal validation even when L1/L2 are valid. L3 binds the delegated chain to the immediate transaction context.
> **Tip:** Cache verified L1 trust anchors, but always recompute L2/L3 validity and constraint checks per authorization request.
> **Note:** Feed normalized constraint results into your shared decision engine to keep Mastercard VI aligned with Visa TAP and AP2 policy outputs.
# Payment Protocols
Source: https://docs.useanima.sh/protocols/overview
Understand agent payment protocols, how ProtocolRouter unifies verification, and when to use Visa TAP, Google AP2, or Mastercard VI.
# Payment Protocols
Agent payment protocols let autonomous systems prove intent, permissions, and constraints before money moves.
## Why Protocols Matter
## Supported Standards
## Supported Protocols
* Visa TAP with RFC 9421
* Google AP2 mandates
* Mastercard VI SD-JWT
## ProtocolRouter
ProtocolRouter gives you a unified entry point for payment verification so each protocol can be normalized behind one decision surface.
```ts title="protocol-router.ts" theme={null}
const verification = await protocolRouter.verify({
protocol: request.protocol,
headers: request.headers,
body: request.body,
featureFlags: {
visaTap: true,
googleAp2: true,
mastercardVi: true,
},
fallback: "deny",
});
```
## Quick Comparison
| Protocol | Primary Primitive | Best Fit | Delegation Model |
| ------------- | ------------------------ | ------------------------------ | ----------------------------- |
| Visa TAP | HTTP signatures + nonces | Real-time API authorization | Key-based agent identity |
| Google AP2 | Mandates + capabilities | Checkout and shopping tasks | Multi-hop narrowing chain |
| Mastercard VI | SD-JWT credentials | Constrained delegated payments | L1 → L2 → L3 credential chain |
> **Note:** Recommendation: normalize all protocol outputs into one internal policy schema so fraud and limit engines stay protocol-agnostic.
## Explore by Protocol
* visa-tap
* ap2
* mastercard-vi
# Visa TAP
Source: https://docs.useanima.sh/protocols/visa-tap
Implement Visa TAP with RFC 9421 HTTP Message Signatures, agent registry key management, and nonce-based replay protection.
# Visa TAP
Visa TAP secures agent-initiated payment requests with HTTP Message Signatures and registry-verifiable agent keys.
## RFC 9421 Signatures
## Registry-Based Trust
## Agent Registry API
* `GET https://api.useanima.sh/api/agents/:id`
* `POST https://api.useanima.sh/api/agents/:id/keys`
* `POST https://api.useanima.sh/api/agents/:id/revoke`
## Replay Protection (Nonce + Freshness)
Replay protection relies on a unique nonce, a tight freshness window, and a short-lived nonce cache to reject captured requests before they can be reused.
| Field | Requirement | Purpose |
| ---------------- | -------------------- | ---------------------------------------------- |
| Nonce | 64-byte base64 value | Prevent duplicate request replay. |
| Freshness window | 8 minutes max skew | Reject stale captured requests. |
| Nonce cache | TTL ≥ 8 minutes | Guarantee one-time use within validity window. |
## Supported Algorithms
* Ed25519
* rsa-pss-sha256
## Signing Example
```ts title="visa-tap-sign.ts" theme={null}
import { createHash, randomBytes, sign } from "crypto";
const body = JSON.stringify({ amount: 1250, currency: "USD" });
const nonce = randomBytes(64).toString("base64");
const created = Math.floor(Date.now() / 1000);
const digest = createHash("sha-256").update(body).digest("base64");
const signatureBase = [
'"@method": post',
'"@path": /payments/authorize',
'"x-agent-nonce": ' + nonce,
'"x-agent-created": ' + created,
'"digest": sha-256=:' + digest + ":",
].join("\n");
const signature = sign(null, Buffer.from(signatureBase), privateKey).toString(
"base64",
);
const signatureInput =
'sig1=("@method" "@path" "@x-agent-nonce" "@x-agent-created" "digest");alg="ed25519"';
```
> **Note:** Persist nonce + signature input hashes for short-term forensic replay analysis.
> **Tip:** Validate signature, timestamp, nonce uniqueness, and key status in a single atomic verification transaction.
# Voice WebSocket Protocol
Source: https://docs.useanima.sh/protocols/voice-websocket
Full protocol reference for real-time voice call events over WebSocket, including message types, schemas, authentication, and error handling.
# Voice WebSocket Protocol
Stream real-time voice call events over a persistent WebSocket connection. Use this protocol for live dashboards, call monitoring, real-time transcription displays, and custom call control interfaces.
## Connection Setup
### Endpoint
```
wss://api.useanima.sh/v1/events/ws
```
### Authentication
Include your API key as a query parameter or in the first message after connection:
```
wss://api.useanima.sh/v1/events/ws?apiKey=ak_...
```
Or authenticate with an `auth` message after connecting:
```json theme={null}
{
"type": "auth",
"apiKey": "ak_..."
}
```
The server responds with an `auth.success` or `auth.error` message:
```json theme={null}
{
"type": "auth.success",
"connectionId": "conn_abc123",
"serverTime": "2025-01-15T10:30:00.000Z"
}
```
### SDK Connection
The SDKs handle connection, authentication, and reconnection automatically.
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
stream = anima.events.connect()
for event in stream:
print(f"{event['type']}: {event['data']}")
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const stream = anima.events.connect();
stream.on("event", (event) => {
console.log(`${event.type}:`, event.data);
});
stream.on("error", (err) => {
console.error("Stream error:", err);
});
```
## Message Format
All messages follow a consistent envelope format:
```json theme={null}
{
"type": "string",
"timestamp": "ISO 8601 string",
"data": { }
}
```
| Field | Type | Description |
| ----------- | ------ | ------------------------------- |
| `type` | string | Message type identifier |
| `timestamp` | string | ISO 8601 timestamp of the event |
| `data` | object | Event-specific payload |
## Message Types
### call.started
Emitted when an outbound or inbound call is connected.
```json theme={null}
{
"type": "call.started",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"callId": "call_abc123",
"agentId": "ag_xyz789",
"direction": "outbound",
"from": "+14155551234",
"to": "+14155555678",
"voiceId": "voice_aria",
"recordingEnabled": true
}
}
```
| Field | Type | Description |
| ------------------ | ------- | ----------------------------- |
| `callId` | string | Unique call identifier |
| `agentId` | string | Agent handling the call |
| `direction` | string | `"outbound"` or `"inbound"` |
| `from` | string | Caller phone number (E.164) |
| `to` | string | Callee phone number (E.164) |
| `voiceId` | string | Voice model used for the call |
| `recordingEnabled` | boolean | Whether recording is active |
### call.ringing
Emitted when the outbound call is ringing on the recipient's end.
```json theme={null}
{
"type": "call.ringing",
"timestamp": "2025-01-15T10:30:01.000Z",
"data": {
"callId": "call_abc123"
}
}
```
### call.answered
Emitted when the recipient picks up.
```json theme={null}
{
"type": "call.answered",
"timestamp": "2025-01-15T10:30:05.000Z",
"data": {
"callId": "call_abc123",
"answeredAt": "2025-01-15T10:30:05.000Z"
}
}
```
### call.transcription
Emitted in real-time as speech is transcribed. Segments may be partial (streaming) or final.
```json theme={null}
{
"type": "call.transcription",
"timestamp": "2025-01-15T10:30:10.000Z",
"data": {
"callId": "call_abc123",
"segmentId": "seg_001",
"speaker": "caller",
"text": "Hi, I'd like to schedule an appointment.",
"isFinal": true,
"confidence": 0.97,
"startTime": 5.2,
"endTime": 8.1,
"language": "en"
}
}
```
| Field | Type | Description |
| ------------ | ------- | ----------------------------------------- |
| `segmentId` | string | Unique segment identifier |
| `speaker` | string | `"agent"` or `"caller"` |
| `text` | string | Transcribed text |
| `isFinal` | boolean | `false` for partial, `true` for finalized |
| `confidence` | number | Transcription confidence (0.0 - 1.0) |
| `startTime` | number | Seconds from call start |
| `endTime` | number | Seconds from call start |
| `language` | string | Detected language code |
### call.agent\_response
Emitted when the agent generates a response that will be spoken.
```json theme={null}
{
"type": "call.agent_response",
"timestamp": "2025-01-15T10:30:11.000Z",
"data": {
"callId": "call_abc123",
"text": "Of course! I can help you with that. What day works best for you?",
"tokensUsed": 42,
"latencyMs": 320
}
}
```
### call.dtmf
Emitted when the caller presses a key on their phone keypad (DTMF tone).
```json theme={null}
{
"type": "call.dtmf",
"timestamp": "2025-01-15T10:31:00.000Z",
"data": {
"callId": "call_abc123",
"digit": "1",
"durationMs": 120
}
}
```
| Field | Type | Description |
| ------------ | ------ | ---------------------------------------- |
| `digit` | string | Key pressed: `"0"`-`"9"`, `"*"`, `"#"` |
| `durationMs` | number | How long the key was held (milliseconds) |
### call.hold
Emitted when the call is placed on or taken off hold.
```json theme={null}
{
"type": "call.hold",
"timestamp": "2025-01-15T10:32:00.000Z",
"data": {
"callId": "call_abc123",
"status": "on_hold"
}
}
```
| Field | Type | Description |
| -------- | ------ | -------------------------- |
| `status` | string | `"on_hold"` or `"resumed"` |
### call.transfer
Emitted when the call is transferred to another number or agent.
```json theme={null}
{
"type": "call.transfer",
"timestamp": "2025-01-15T10:33:00.000Z",
"data": {
"callId": "call_abc123",
"transferTo": "+14155559999",
"reason": "Customer requested human agent"
}
}
```
### call.sentiment
Emitted periodically with rolling sentiment analysis.
```json theme={null}
{
"type": "call.sentiment",
"timestamp": "2025-01-15T10:33:30.000Z",
"data": {
"callId": "call_abc123",
"current": "positive",
"score": 0.72,
"trend": "improving"
}
}
```
| Field | Type | Description |
| --------- | ------ | ------------------------------------------- |
| `current` | string | `"positive"`, `"neutral"`, or `"negative"` |
| `score` | number | Sentiment score (-1.0 to 1.0) |
| `trend` | string | `"improving"`, `"stable"`, or `"declining"` |
### call.ended
Emitted when the call terminates for any reason.
```json theme={null}
{
"type": "call.ended",
"timestamp": "2025-01-15T10:35:00.000Z",
"data": {
"callId": "call_abc123",
"reason": "completed",
"durationSeconds": 300,
"recordingUrl": "https://recordings.useanima.sh/call_abc123.wav",
"transcriptAvailable": true,
"summary": "Caller scheduled an appointment for January 20th at 2 PM."
}
}
```
| Field | Type | Description |
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------- |
| `reason` | string | `"completed"`, `"caller_hangup"`, `"agent_hangup"`, `"no_answer"`, `"busy"`, `"failed"`, `"timeout"` |
| `durationSeconds` | number | Total call duration in seconds |
| `recordingUrl` | string | Signed URL to the recording (if enabled) |
| `transcriptAvailable` | boolean | Whether the full transcript is ready |
| `summary` | string | AI-generated call summary |
### call.error
Emitted when an error occurs during the call.
```json theme={null}
{
"type": "call.error",
"timestamp": "2025-01-15T10:35:01.000Z",
"data": {
"callId": "call_abc123",
"code": "voice_synthesis_timeout",
"message": "Voice synthesis did not respond within 5 seconds",
"recoverable": true
}
}
```
## Subscribing to Specific Calls
Filter events to a specific call or agent by sending a `subscribe` message:
```json theme={null}
{
"type": "subscribe",
"filters": {
"callId": "call_abc123"
}
}
```
```json theme={null}
{
"type": "subscribe",
"filters": {
"agentId": "ag_xyz789",
"eventTypes": ["call.transcription", "call.ended"]
}
}
```
The server confirms with:
```json theme={null}
{
"type": "subscribe.success",
"subscriptionId": "sub_abc123",
"filters": {
"agentId": "ag_xyz789",
"eventTypes": ["call.transcription", "call.ended"]
}
}
```
## Heartbeat / Ping-Pong
The server sends a `ping` message every 30 seconds. The client must respond with a `pong` within 10 seconds or the connection will be closed.
```json theme={null}
// Server sends
{
"type": "ping",
"timestamp": "2025-01-15T10:30:30.000Z"
}
// Client responds
{
"type": "pong"
}
```
The SDKs handle ping-pong automatically. If you are implementing a raw WebSocket client, ensure you respond to every `ping`.
## Error Handling
### Connection Errors
| Code | Reason | Action |
| ------ | ------------------------ | ------------------------------------------------- |
| `4001` | Invalid API key | Check your API key and reconnect |
| `4002` | Rate limit exceeded | Back off and retry after the `Retry-After` header |
| `4003` | Connection limit reached | Close unused connections before opening new ones |
| `4008` | Ping timeout | Client did not respond to ping in time; reconnect |
| `4500` | Internal server error | Retry with exponential backoff |
### Reconnection Strategy
Use exponential backoff with jitter for automatic reconnection:
1. First retry: 1 second
2. Second retry: 2 seconds
3. Third retry: 4 seconds
4. Max backoff: 30 seconds
5. Add random jitter of 0-1 seconds to each delay
```ts theme={null}
// The SDK handles reconnection automatically
const stream = anima.events.connect({
reconnect: true, // default: true
maxReconnectAttempts: 10, // default: 10
maxReconnectDelay: 30000, // default: 30s
});
stream.on("reconnecting", (attempt) => {
console.log(`Reconnecting (attempt ${attempt})...`);
});
stream.on("reconnected", () => {
console.log("Reconnected successfully");
});
```
```python theme={null}
stream = anima.events.connect(
reconnect=True,
max_reconnect_attempts=10,
max_reconnect_delay=30000,
)
```
## Next Steps
* [Quickstart: Voice Calls](/quickstart-voice) -- Make your first AI-powered phone call
* [Voice Catalog](/voice-catalog) -- Browse available voice models
* [Call Intelligence](/call-intelligence) -- Recording, transcription, and scoring
* [Webhooks](/webhooks) -- HTTP-based event delivery as an alternative to WebSocket
# Quickstart: Email
Source: https://docs.useanima.sh/quickstart-email
Send your first email from an AI agent in under 5 minutes.
# Quickstart: Email
Give your AI agent a real email address and send its first message.
## Prerequisites
* Your org's **master key** (`mk_...`) from [console.useanima.sh](https://console.useanima.sh) — creating agents is a master-key operation
* Your organization ID (`org_...`), shown in the console
* Python 3.10+ or Node.js 18+
## Python
```bash theme={null}
pip install anima-labs
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="mk_...") # master key — agent creation is admin-gated
# Create an agent with an email inbox
agent = anima.agents.create(
org_id="org_...", # your organization ID, from the console
name="My First Agent",
slug="my-first-agent",
)
print(f"Agent: {agent.id}")
# Send an email
anima.messages.send_email(
agent_id=agent.id,
to=["recipient@example.com"],
subject="Hello from my AI agent",
body="This email was sent by an AI agent powered by Anima.",
)
print("Email sent!")
```
## Node.js / TypeScript
```bash theme={null}
npm install @anima-labs/sdk
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "mk_..." }); // master key — agent creation is admin-gated
// Create an agent with an email inbox
const agent = await anima.agents.create({
orgId: "org_...", // your organization ID, from the console
name: "My First Agent",
slug: "my-first-agent",
});
console.log(`Agent: ${agent.id}`);
// Send an email
await anima.messages.sendEmail({
agentId: agent.id,
to: ["recipient@example.com"],
subject: "Hello from my AI agent",
body: "This email was sent by an AI agent powered by Anima.",
});
console.log("Email sent!");
```
## What's Next
* [Quickstart: Vault](/quickstart-vault) — Store credentials securely
* [Webhooks](/webhooks) — Get notified when emails arrive
* [Custom Domains](/custom-domains) — Use your own domain
# Quickstart: Vault
Source: https://docs.useanima.sh/quickstart-vault
Store and retrieve encrypted credentials for your AI agent.
# Quickstart: Vault
Give your AI agent secure access to credentials — logins, API keys, and secrets.
## Prerequisites
* An Anima API key from [console.useanima.sh](https://console.useanima.sh)
* Python 3.10+ or Node.js 18+
## Python
```bash theme={null}
pip install anima-labs
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="mk_...") # master key — agent creation is admin-gated
# Create an agent
agent = anima.agents.create(
org_id="org_...", # your organization ID, from the console
name="Web Agent",
slug="web-agent",
)
# Provision a vault for the agent
anima.vault.provision(agent_id=agent.id)
# Store a login credential
credential = anima.vault.create_credential(
agent_id=agent.id,
type="login",
name="CRM Login",
login={
"username": "bot@company.com",
"password": "s3cur3-p4ssw0rd",
"uris": [{"uri": "https://crm.company.com"}],
},
)
print(f"Stored: {credential.name}")
# Or let the vault generate the password server-side — it is stored with
# the credential and never returned; you get back only the credential ref.
generated = anima.vault.create_credential(
agent_id=agent.id,
type="login",
name="Acme Portal",
login={"username": "bot@company.com"},
generate_password={}, # defaults: 24 chars, all character classes
)
print(f"Credential ref: {generated.id}")
# Retrieve it later
creds = anima.vault.get_credential(
agent_id=agent.id,
credential_id=credential.id,
)
print(f"Username: {creds.username}")
# Clean up
anima.vault.delete_credential(
agent_id=agent.id,
credential_id=credential.id,
)
anima.vault.deprovision(agent_id=agent.id)
```
## Node.js / TypeScript
```bash theme={null}
npm install @anima-labs/sdk
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "mk_..." }); // master key — agent creation is admin-gated
// Create an agent
const agent = await anima.agents.create({
orgId: "org_...", // your organization ID, from the console
name: "Web Agent",
slug: "web-agent",
});
// Provision a vault
await anima.vault.provision({ agentId: agent.id });
// Store a login credential
const credential = await anima.vault.createCredential({
agentId: agent.id,
type: "login",
name: "CRM Login",
login: {
username: "bot@company.com",
password: "s3cur3-p4ssw0rd",
uris: [{ uri: "https://crm.company.com" }],
},
});
console.log(`Stored: ${credential.name}`);
// Or let the vault generate the password server-side — it is stored with
// the credential and never returned; you get back only the credential ref.
const generated = await anima.vault.createCredential({
agentId: agent.id,
type: "login",
name: "Acme Portal",
login: { username: "bot@company.com" },
generatePassword: {}, // defaults: 24 chars, all character classes
});
console.log(`Credential ref: ${generated.id}`);
// Retrieve it later
const creds = await anima.vault.getCredential({
agentId: agent.id,
credentialId: credential.id,
});
console.log(`Username: ${creds.username}`);
```
## Credential Types
The vault supports four credential types:
| Type | Use Case |
| ------------- | ------------------------------------------- |
| `login` | Website logins (username + password + URIs) |
| `secure_note` | Free-form encrypted text (API keys, tokens) |
| `card` | Payment card details |
| `identity` | Personal/business identity information |
## What's Next
* [Quickstart: Email](/quickstart-email) — Send emails from agents
* [Security](/security) — Understand Anima's security model
* [Encryption](/encryption) — How vault data is encrypted
# Quickstart: Voice Calls
Source: https://docs.useanima.sh/quickstart-voice
Text yourself, then place your first AI-powered phone call from an Anima agent.
# Quickstart: Voice Calls
Give your AI agent a real phone number, send yourself an SMS, then place the first voice call to a number you control.
## Prerequisites
* An Anima API key from [console.useanima.sh](https://console.useanima.sh)
* Python 3.10+ or Node.js 18+
* An existing `agent_id`
* Phone access for SMS
* Voice access for outbound calls
* Consent to contact the destination number
If you are testing for the first time, use your own phone number as the destination.
## Python
```bash theme={null}
pip install anima-labs
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
agent_id = "AGENT_ID"
your_phone = "+15551234567"
# 1. Provision a phone number for SMS and voice.
phone = anima.phones.provision(
agent_id=agent_id,
country_code="US",
capabilities=["voice", "sms"],
)
print(f"Phone: {phone.phone_number}")
# 2. Text yourself first. This proves the number is real and reachable.
sms = anima.messages.send_sms(
agent_id=agent_id,
to=your_phone,
body="Hi - this is my Anima agent texting before it calls.",
)
print(f"SMS sent: {sms.id} ({sms.status})")
# 3. Confirm the voice catalog is available for your tier.
voices = anima.voices.list(tier="basic")
print(f"Available basic voices: {len(voices['voices'])}")
# 4. Place the first outbound call.
call = anima.calls.create(
agent_id=agent_id,
to=your_phone,
tier="basic",
greeting="Hi, this is my Anima agent. I am calling from my own phone number.",
)
print(f"Call started: {call.call_id}, state: {call.state}")
# 5. After the call ends, fetch the transcript.
transcript = anima.calls.get_transcript(call.call_id)
for segment in transcript.segments:
print(f"{segment.speaker}: {segment.text}")
```
## Node.js / TypeScript
```bash theme={null}
npm install @anima-labs/sdk
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const agentId = "AGENT_ID";
const yourPhone = "+15551234567";
// 1. Provision a phone number for SMS and voice.
const phone = await anima.phones.provision({
agentId,
countryCode: "US",
capabilities: ["voice", "sms"],
});
console.log(`Phone: ${phone.phoneNumber}`);
// 2. Text yourself first. This proves the number is real and reachable.
const sms = await anima.messages.sendSms({
agentId,
to: yourPhone,
body: "Hi - this is my Anima agent texting before it calls.",
});
console.log(`SMS sent: ${sms.id} (${sms.status})`);
// 3. Confirm the voice catalog is available for your tier.
const voices = await anima.voices.list({ tier: "basic" });
console.log(`Available basic voices: ${voices.voices.length}`);
// 4. Place the first outbound call.
const call = await anima.calls.create({
agentId,
to: yourPhone,
tier: "basic",
greeting: "Hi, this is my Anima agent. I am calling from my own phone number.",
});
console.log(`Call started: ${call.callId}, state: ${call.state}`);
// 5. After the call ends, fetch the transcript.
const transcript = await anima.calls.getTranscript(call.callId);
for (const segment of transcript.segments) {
console.log(`${segment.speaker}: ${segment.text}`);
}
```
## Environment Variables
You can also configure via environment variables instead of passing options directly:
```bash theme={null}
export ANIMA_API_KEY="ak_..."
export ANIMA_API_URL="https://api.useanima.sh" # optional, defaults to production
export ANIMA_LOG="debug" # optional, enables debug logging
```
```python theme={null}
# No need to pass api_key when ANIMA_API_KEY is set
from anima import Anima
anima = Anima()
```
```ts theme={null}
// No need to pass apiKey when ANIMA_API_KEY is set
const anima = new Anima();
```
## Handle Inbound Calls
To react after calls complete, set up a webhook endpoint and subscribe to `call.ended`. Inbound real-time call control happens over the voice WebSocket.
```python theme={null}
from anima import Anima, fastapi_webhook_dependency
from fastapi import FastAPI, Depends
app = FastAPI()
webhook_dep = fastapi_webhook_dependency("whsec_...")
@app.post("/webhooks")
async def handle(event=Depends(webhook_dep)):
if event.type == "call.ended":
print(f"Call ended: {event.data['callId']}")
```
```ts theme={null}
import express from "express";
import { Anima, webhookMiddleware } from "@anima-labs/sdk";
const app = express();
app.use(express.json());
app.post("/webhooks", webhookMiddleware("whsec_..."), (req, res) => {
const event = req.webhookEvent;
if (event.type === "call.ended") {
console.log(`Call ended: ${event.data.callId}`);
}
res.sendStatus(200);
});
```
## Real-Time Call Events (WebSocket)
Monitor and control calls in real time over the voice WebSocket:
```ts theme={null}
const anima = new Anima({ apiKey: "ak_..." });
const conn = anima.calls.connect({ agentId });
conn.on("message", (message) => {
switch (message.type) {
case "call.started":
console.log("Call started:", message.data?.callId);
break;
case "call.transcription":
console.log(`[${message.data?.speaker}]: ${message.data?.text}`);
break;
case "call.ended":
console.log("Call ended:", message.data?.callId);
break;
}
});
conn.createCall(yourPhone);
```
## What's Next?
* [Voice Catalog](/voice-catalog) — Browse all available voices with audio samples
* [Call Intelligence](/call-intelligence) — Recording, transcription, RAG, and scoring
* [Conversational Calls](/conversational-calls) — REST hosted, realtime, and WebSocket call modes
* [Voice WebSocket Protocol](/protocols/voice-websocket) — Full protocol reference for real-time events
* [MCP Setup](/mcp-servers) — Use voice calls from Claude Desktop and other AI tools
# Agent Registry
Source: https://docs.useanima.sh/registry/overview
Discover, search, and register AI agents in the Anima Agent Registry. Public and private registry modes.
# Agent Registry
The Anima Agent Registry is a searchable directory of agents and their capabilities. It enables agent discovery, facilitates A2A communication, and provides a trust layer through verified identity records.
## How It Works
1. **Register** -- Agents publish their identity, capabilities, and endpoints to the registry
2. **Discover** -- Other agents or services search the registry by capability, domain, or name
3. **Verify** -- Registry entries are linked to DIDs and Agent Cards for cryptographic verification
4. **Connect** -- Use discovered endpoints to initiate A2A communication
## Registering an Agent
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const entry = await anima.registry.register({
agentId: "ag_8f3k2m9x1n4p7q6r",
visibility: "public",
tags: ["procurement", "invoicing", "payments"],
description: "Handles procurement workflows for Acme Corp",
});
console.log(`Registered: ${entry.id}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
entry = anima.registry.register(
agent_id="ag_8f3k2m9x1n4p7q6r",
visibility="public",
tags=["procurement", "invoicing", "payments"],
description="Handles procurement workflows for Acme Corp",
)
print(f"Registered: {entry.id}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
entry, err := client.Registry.Register(ctx, &anima.RegisterAgentParams{
AgentID: "ag_8f3k2m9x1n4p7q6r",
Visibility: "public",
Tags: []string{"procurement", "invoicing", "payments"},
Description: "Handles procurement workflows for Acme Corp",
})
```
## Searching the Registry
```ts theme={null}
// Search by capability
const results = await anima.registry.search({
query: "invoice processing",
tags: ["payments"],
limit: 10,
});
for (const agent of results.data) {
console.log(`${agent.name} -- ${agent.did}`);
console.log(` Capabilities: ${agent.capabilities.map(c => c.name).join(", ")}`);
console.log(` Endpoint: ${agent.endpoints.a2a}`);
}
```
```python theme={null}
results = anima.registry.search(
query="invoice processing",
tags=["payments"],
limit=10,
)
for agent in results.data:
print(f"{agent.name} -- {agent.did}")
print(f" Capabilities: {', '.join(c.name for c in agent.capabilities)}")
```
## Visibility Modes
| Mode | Description |
| ---------- | ---------------------------------------------------------- |
| `public` | Visible to all registry users. Searchable by anyone. |
| `private` | Only visible within your organization's pod. |
| `unlisted` | Not searchable, but accessible via direct DID or agent ID. |
## API Reference
| Endpoint | Method | Description |
| ------------------------------------------------- | ------ | ----------------------- |
| `https://api.useanima.sh/api/registry/agents` | POST | Register an agent |
| `https://api.useanima.sh/api/registry/agents/:id` | GET | Get a registry entry |
| `https://api.useanima.sh/api/registry/agents/:id` | PUT | Update a registry entry |
| `https://api.useanima.sh/api/registry/agents/:id` | DELETE | Deregister an agent |
| `https://api.useanima.sh/api/registry/search` | GET | Search the registry |
### Search Parameters
| Parameter | Type | Description |
| ------------ | --------- | -------------------------------------------- |
| `query` | string | Free-text search across name and description |
| `tags` | string\[] | Filter by capability tags |
| `visibility` | string | Filter by visibility mode |
| `limit` | number | Max results (default 20, max 100) |
| `cursor` | string | Pagination cursor |
## Configuration
| Variable | Default | Description |
| ----------------------------- | --------- | ---------------------------------------- |
| `ANIMA_REGISTRY_DEFAULT_VIS` | `private` | Default visibility for new registrations |
| `ANIMA_REGISTRY_SEARCH_LIMIT` | `20` | Default search result limit |
## Next Steps
* [Agent Cards](/identity/agent-cards) -- Publish detailed agent metadata
* [A2A Protocol](/a2a/overview) -- Communicate with discovered agents
* [Verifiable Credentials](/identity/verifiable-credentials) -- Prove agent capabilities
# Official SDKs
Source: https://docs.useanima.sh/sdks
Official TypeScript and Python SDKs for Anima.
# Official SDKs
Seamlessly integrate Anima into your Python and TypeScript applications. Both SDKs provide access to the full unified platform: agents, email, vault, phone, and webhooks. Using Go? See the [Go SDK reference](/sdks/go).
## TypeScript / Node.js
The TypeScript SDK provides full type safety and works with Node.js, Bun, and Deno.
### Installation
```bash theme={null}
npm install @anima-labs/sdk
```
### Usage
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "mk_..." }); // agent creation needs the master key
// Create an agent
const agent = await anima.agents.create({
orgId: "org_...",
name: "Researcher",
slug: "researcher",
});
// Send email
await anima.messages.sendEmail({
agentId: agent.id,
to: ["user@example.com"],
subject: "Hello",
body: "Sent by an AI agent",
});
```
## Python
The Python SDK is fully typed and supports both sync and async operations.
### Installation
```bash theme={null}
pip install anima-labs
```
### Usage
```python theme={null}
from anima import Anima
anima = Anima(api_key="mk_...") # agent creation needs the master key
# Create an agent
agent = anima.agents.create(
org_id="org_...",
name="Researcher",
slug="researcher",
)
# Send email
anima.messages.send_email(
agent_id=agent.id,
to=["user@example.com"],
subject="Hello",
body="Sent by an AI agent",
)
```
### Async Usage
```python theme={null}
from anima import AsyncAnima
anima = AsyncAnima(api_key="mk_...")
agent = await anima.agents.create(
org_id="org_...",
name="Async Agent",
slug="async-agent",
)
```
## Available Resources
Both SDKs expose the same set of resources:
| Resource | Description |
| --------------- | ------------------------------------------- |
| `agents` | Create and manage AI agents |
| `organizations` | Organization settings and profile |
| `messages` | Send email and SMS as an agent |
| `emails` | List an agent's mail and handle attachments |
| `vault` | Store and retrieve encrypted credentials |
| `phones` | Provision and manage phone numbers |
| `calls` | Place and manage voice calls |
| `webhooks` | Subscribe to real-time events |
| `domains` | Configure custom email domains |
| `security` | Content scanning and security events |
…plus `identity`, `registry`, `wallet`, `pods`, `a2a`, `audit`, `compliance`, `anomaly`, `voices`, `events`, and `addresses` — the same names in both SDKs (snake\_case arguments in Python, camelCase in TypeScript).
# Go SDK
Source: https://docs.useanima.sh/sdks/go
Quickstart and reference for the Anima Go SDK. Manage agents, email, vault, identity, and A2A from Go applications.
# Go SDK
The official Anima Go SDK provides idiomatic Go access to the full Anima platform: agents, email, vault, identity, registry, and A2A.
## Installation
```bash theme={null}
go get github.com/anima-labs-ai/go
```
Requires Go 1.21 or later.
## Quickstart
```go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/anima-labs-ai/go"
)
func main() {
ctx := context.Background()
client := anima.NewClient("ak_...")
// Create an agent
agent, err := client.Agents.Create(ctx, &anima.CreateAgentParams{
Name: "Go Agent",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Agent: %s\n", agent.ID)
// Send an email
_, err = client.Messages.SendEmail(ctx, &anima.SendEmailParams{
AgentID: agent.ID,
To: "user@example.com",
Subject: "Hello from Go",
Body: "This email was sent by an AI agent using the Go SDK.",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Email sent!")
}
```
## Client Configuration
```go theme={null}
// Basic client
client := anima.NewClient("ak_...")
// Client with options
client := anima.NewClient("ak_...",
anima.WithBaseURL("https://api.useanima.sh"),
anima.WithTimeout(30 * time.Second),
anima.WithRetries(3),
anima.WithPodID("pod_prod"),
)
```
### Configuration Options
| Option | Default | Description |
| ---------------- | ------------------------- | ----------------------------- |
| `WithBaseURL` | `https://api.useanima.sh` | API base URL |
| `WithTimeout` | `30s` | HTTP request timeout |
| `WithRetries` | `2` | Max retry attempts on failure |
| `WithPodID` | none | Scope all requests to a pod |
| `WithHTTPClient` | `http.DefaultClient` | Custom HTTP client |
| `WithUserAgent` | `anima-go/` | Custom User-Agent header |
## Resource Reference
### Agents
```go theme={null}
// Create
agent, err := client.Agents.Create(ctx, &anima.CreateAgentParams{
Name: "Research Bot",
})
// Get
agent, err := client.Agents.Get(ctx, "ag_abc123")
// List
agents, err := client.Agents.List(ctx, &anima.ListAgentsParams{
Limit: 20,
})
// Update
agent, err := client.Agents.Update(ctx, "ag_abc123", &anima.UpdateAgentParams{
Name: "Updated Bot",
})
// Delete
err := client.Agents.Delete(ctx, "ag_abc123")
```
### Email
```go theme={null}
// Send email
msg, err := client.Messages.SendEmail(ctx, &anima.SendEmailParams{
AgentID: "ag_abc123",
To: "user@example.com",
Subject: "Hello",
Body: "Sent from Go",
})
// List messages
messages, err := client.Messages.List(ctx, &anima.ListMessagesParams{
AgentID: "ag_abc123",
Limit: 50,
})
// Get a message
msg, err := client.Messages.Get(ctx, "msg_xyz789")
```
### Vault
```go theme={null}
// Store a secret
secret, err := client.Vault.Store(ctx, &anima.StoreSecretParams{
AgentID: "ag_abc123",
Key: "openai_key",
Value: "sk-...",
Tags: []string{"llm", "production"},
})
// Retrieve a secret
secret, err := client.Vault.Get(ctx, "ag_abc123", "openai_key")
fmt.Println(secret.Value)
// List secrets (metadata only)
secrets, err := client.Vault.List(ctx, &anima.ListSecretsParams{
AgentID: "ag_abc123",
})
```
### Identity
```go theme={null}
// Resolve DID
doc, err := client.Identity.ResolveDID(ctx, "did:anima:ag_abc123")
// Issue a credential
cred, err := client.Identity.Credentials.Issue(ctx, &anima.IssueCredentialParams{
AgentID: "ag_abc123",
Type: "AgentAuthorization",
Claims: map[string]any{"role": "purchasing-agent"},
})
// Publish Agent Card
card, err := client.Identity.AgentCards.Publish(ctx, &anima.PublishAgentCardParams{
AgentID: "ag_abc123",
Domain: "agent.acme.com",
})
```
### A2A
```go theme={null}
// Send a task
task, err := client.A2A.SendTask(ctx, &anima.SendTaskParams{
FromAgentID: "ag_sender",
ToAgentDID: "did:anima:ag_receiver",
Capability: "data-analysis",
Input: map[string]any{"dataset": "q1-sales"},
TimeoutMs: 300000,
})
// Get task result
task, err := client.A2A.GetTask(ctx, task.ID)
fmt.Printf("Status: %s, Result: %v\n", task.Status, task.Result)
```
### Wallet
```go theme={null}
// Create a wallet
wallet, err := client.Wallet.Create(ctx, &anima.CreateWalletParams{
AgentID: "ag_abc123",
Currency: "usd",
BudgetGuards: &anima.BudgetGuards{
DailyLimitCents: 50000,
},
})
// Check balance
balance, err := client.Wallet.GetBalance(ctx, wallet.ID)
fmt.Printf("Available: %d cents\n", balance.AvailableCents)
```
### Webhooks
```go theme={null}
// Create a webhook, with the auth Anima presents to your endpoint
// (on top of the X-Anima-Signature HMAC) plus delivery throttling.
rateLimit, maxAttempts := 120, 5
wh, err := client.Webhooks.Create(ctx, anima.CreateWebhookParams{
URL: "https://example.com/hooks/anima",
Events: []anima.WebhookEventType{anima.WebhookEventMessageReceived},
// Also: NewBasicAuth(user, pass), NewCustomHeaderAuth(name, value), NewNoAuth().
AuthConfig: anima.NewBearerAuth("your-endpoint-token"),
RateLimitPerMinute: &rateLimit, // omit for unlimited
MaxAttempts: &maxAttempts, // 1-10, default 3
})
// The credential is write-only — only the scheme (wh.AuthType) is returned.
fmt.Println(wh.ID, wh.AuthType)
```
## Error Handling
The SDK uses typed errors for common failure cases:
```go theme={null}
agent, err := client.Agents.Get(ctx, "ag_nonexistent")
if err != nil {
var apiErr *anima.APIError
if errors.As(err, &apiErr) {
fmt.Printf("API error: %d %s\n", apiErr.StatusCode, apiErr.Message)
fmt.Printf("Request ID: %s\n", apiErr.RequestID)
}
log.Fatal(err)
}
```
| Error Type | Description |
| ------------------ | ------------------------------------------ |
| `*APIError` | API returned an error response |
| `*AuthError` | Invalid or expired API key |
| `*RateLimitError` | Rate limit exceeded (includes retry-after) |
| `*ValidationError` | Invalid request parameters |
| `*NotFoundError` | Resource not found |
## Pagination
All list endpoints support cursor-based pagination:
```go theme={null}
var allAgents []anima.Agent
cursor := ""
for {
result, err := client.Agents.List(ctx, &anima.ListAgentsParams{
Limit: 100,
Cursor: cursor,
})
if err != nil {
log.Fatal(err)
}
allAgents = append(allAgents, result.Data...)
if !result.HasMore {
break
}
cursor = result.NextCursor
}
```
## Next Steps
* [Official SDKs](/sdks) -- TypeScript and Python SDK documentation
* [Getting Started](/getting-started) -- Platform quickstart guide
* [Examples](/examples) -- Complete runnable examples
# SDK Migration Guide
Source: https://docs.useanima.sh/sdks/migration
Upgrade to the latest Anima SDKs with auto-pagination, env var fallback, debug logging, per-request options, and more.
# SDK Migration Guide
This guide covers the new features in the latest Anima SDKs and how to adopt them. The upgrade is non-breaking -- your existing code will continue to work.
## What's New
| Feature | Description |
| -------------------------------- | --------------------------------------------------- |
| Auto-pagination (`PageIterator`) | Automatically iterate through all pages of results |
| Environment variable fallback | SDK reads `ANIMA_API_KEY` if no key is passed |
| Debug logging | Built-in structured logging with `ANIMA_LOG` |
| Per-request options | Override timeout, headers, and idempotency per call |
| Raw response access | Get the full HTTP response alongside typed data |
| Request/response events | Hook into the request lifecycle for observability |
| Webhook middleware | Framework-native webhook verification |
## Auto-Pagination (PageIterator)
No more manual cursor management. The new `PageIterator` handles pagination automatically.
### Before
```python theme={null}
# Python -- manual pagination
all_agents = []
cursor = None
while True:
result = anima.agents.list(limit=100, cursor=cursor)
all_agents.extend(result["items"])
if not result.get("hasMore"):
break
cursor = result["nextCursor"]
```
```ts theme={null}
// TypeScript -- manual pagination
const allAgents = [];
let cursor: string | undefined;
do {
const result = await anima.agents.list({ limit: 100, cursor });
allAgents.push(...result.items);
cursor = result.hasMore ? result.nextCursor : undefined;
} while (cursor);
```
### After
```python theme={null}
# Python -- auto-pagination
for agent in anima.agents.list_auto_paging(limit=100):
print(agent["name"])
# Or collect all at once
all_agents = list(anima.agents.list_auto_paging())
```
```ts theme={null}
// TypeScript -- auto-pagination
for await (const agent of anima.agents.listAutoPaging({ limit: 100 })) {
console.log(agent.name);
}
// Or collect all at once
const allAgents = await anima.agents.listAutoPaging().toArray();
```
## Environment Variable Fallback
The SDK now reads configuration from environment variables automatically. The `apiKey` parameter is now optional -- if omitted, the SDK looks for `ANIMA_API_KEY`.
### Before
```python theme={null}
# Python -- api_key was required
anima = Anima(api_key="ak_...")
```
```ts theme={null}
// TypeScript -- apiKey was required
const anima = new Anima({ apiKey: "ak_..." });
```
### After
```bash theme={null}
# Set environment variables
export ANIMA_API_KEY="ak_..."
export ANIMA_API_URL="https://api.useanima.sh" # optional
```
```python theme={null}
# Python -- no arguments needed
from anima import Anima
anima = Anima()
# Explicit key still works and takes precedence
anima = Anima(api_key="ak_override")
```
```ts theme={null}
// TypeScript -- no arguments needed
import { Anima } from "@anima-labs/sdk";
const anima = new Anima();
// Explicit key still works and takes precedence
const anima2 = new Anima({ apiKey: "ak_override" });
```
### Supported Environment Variables
| Variable | Description | Default |
| --------------- | -------------------------------------------- | ------------------------- |
| `ANIMA_API_KEY` | API key for authentication | none |
| `ANIMA_API_URL` | Base URL for the API | `https://api.useanima.sh` |
| `ANIMA_LOG` | Log level (`debug`, `info`, `warn`, `error`) | `warn` |
## Debug Logging
Enable structured debug logs to inspect HTTP requests, retries, and timing.
### Before
```python theme={null}
# Python -- no built-in logging
import logging
logging.basicConfig(level=logging.DEBUG)
# ...but SDK didn't emit structured logs
```
### After
```bash theme={null}
export ANIMA_LOG=debug
```
```python theme={null}
# Python -- structured logging built in
anima = Anima(log="debug")
# Output:
# [anima] POST /v1/agents 201 (142ms)
# [anima] GET /v1/agents/ag_abc123 200 (89ms)
# [anima] GET /v1/agents/ag_abc123 429 -- retrying in 1s (attempt 1/3)
```
```ts theme={null}
// TypeScript -- structured logging built in
const anima = new Anima({ log: "debug" });
// Output:
// [anima] POST /v1/agents 201 (142ms)
// [anima] GET /v1/agents/ag_abc123 200 (89ms)
```
## Per-Request Options
Override client-level settings on a per-request basis. Useful for setting custom timeouts, idempotency keys, or extra headers.
### Before
```python theme={null}
# Python -- no per-request overrides
# Had to create separate client instances for different timeouts
anima_fast = Anima(api_key="ak_...", timeout=5)
anima_slow = Anima(api_key="ak_...", timeout=60)
```
### After
```python theme={null}
# Python -- per-request options
from anima import RequestOptions
agent = anima.agents.create(
org_id="org_...",
name="My Agent",
slug="my-agent",
options=RequestOptions(
timeout=60,
idempotency_key="create-agent-abc",
),
)
```
```ts theme={null}
// TypeScript -- per-request options
const agent = await anima.agents.create(
{ orgId: "org_...", name: "My Agent", slug: "my-agent" },
{
timeout: 60_000,
idempotencyKey: "create-agent-abc",
},
);
```
## Raw Response Access
Access the full HTTP response (status, headers) alongside the parsed body.
### Before
```python theme={null}
# Python -- only parsed data was available
agent = anima.agents.get("ag_abc123")
# No access to status code, headers, or request ID
```
### After
```python theme={null}
# Python -- raw response access
response = anima.agents.with_raw_response.get("ag_abc123")
print(f"Status: {response.status_code}")
print(f"Request ID: {response.headers['x-request-id']}")
print(f"Rate limit remaining: {response.headers['x-ratelimit-remaining']}")
agent = response.parsed # typed data, same as before
print(f"Agent: {agent['name']}")
```
```ts theme={null}
// TypeScript -- raw response access
const response = await anima.agents.withRawResponse.get("ag_abc123");
console.log(`Status: ${response.status}`);
console.log(`Request ID: ${response.headers.get("x-request-id")}`);
console.log(`Rate limit remaining: ${response.headers.get("x-ratelimit-remaining")}`);
const agent = response.data; // typed data, same as before
console.log(`Agent: ${agent.name}`);
```
## Request/Response Events
Hook into the SDK's request lifecycle for logging, metrics, or tracing.
### Before
```python theme={null}
# Python -- no event hooks
# Had to wrap the client or monkey-patch methods
```
### After
```python theme={null}
# Python -- request/response events
def on_request(event):
print(f"--> {event['method']} {event['url']}")
def on_response(event):
print(f"<-- {event['status']} ({event['durationMs']}ms)")
anima = Anima(
on_request=on_request,
on_response=on_response,
)
# Every SDK call now emits events:
# --> POST /v1/agents
# <-- 201 (142ms)
```
```ts theme={null}
// TypeScript -- request/response events
const anima = new Anima({
onRequest: (event) => {
console.log(`--> ${event.method} ${event.url}`);
},
onResponse: (event) => {
console.log(`<-- ${event.status} (${event.durationMs}ms)`);
},
});
```
## Webhook Middleware
Framework-native webhook verification replaces manual signature checking.
### Before
```python theme={null}
# Python -- manual verification
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
@app.post("/webhooks")
async def handle(request: Request):
body = await request.body()
sig = request.headers.get("x-anima-signature", "")
if not verify_webhook(body, sig, "whsec_..."):
raise HTTPException(status_code=401)
event = json.loads(body)
# handle event...
```
### After
```python theme={null}
# Python -- FastAPI dependency
from anima import fastapi_webhook_dependency
from fastapi import FastAPI, Depends
app = FastAPI()
webhook_dep = fastapi_webhook_dependency("whsec_...")
@app.post("/webhooks")
async def handle(event=Depends(webhook_dep)):
if event.type == "message.received":
print(f"New email from {event.data['from']}")
```
```ts theme={null}
// TypeScript -- Express middleware
import express from "express";
import { webhookMiddleware } from "@anima-labs/sdk";
const app = express();
app.use(express.json());
app.post("/webhooks", webhookMiddleware("whsec_..."), (req, res) => {
const event = req.webhookEvent;
console.log(`Event: ${event.type}`);
res.sendStatus(200);
});
```
## Breaking Changes
There are **no breaking changes** in this release. All new features are additive:
* `apiKey` / `api_key` is now optional (falls back to `ANIMA_API_KEY`), but passing it explicitly still works
* All existing method signatures remain unchanged
* New methods (`listAutoPaging`, `withRawResponse`) are additions, not replacements
## Upgrade Steps
1. Update your SDK to the latest version:
```bash theme={null}
# Python
pip install --upgrade anima-labs
# Node.js
npm install @anima-labs/sdk@latest
```
2. (Optional) Set `ANIMA_API_KEY` in your environment and remove hardcoded keys
3. (Optional) Replace manual pagination loops with `listAutoPaging`
4. (Optional) Add `ANIMA_LOG=debug` during development for visibility
## Next Steps
* [Official SDKs](/sdks) -- Full SDK reference for TypeScript and Python
* [Go SDK](/sdks/go) -- Go SDK documentation
* [Webhooks](/webhooks) -- Webhook event reference
* [Examples](/examples) -- Complete runnable examples
# SecretRef & anima.json
Source: https://docs.useanima.sh/secret-ref
A declarative spec for pointing at secrets without hardcoding them — used by anima vault exec, anima vault proxy, and the zero-knowledge MCP tools.
# SecretRef & `anima.json`
A **SecretRef** is a declarative pointer to a secret. Instead of writing `API_KEY=sk-...` in a `.env` file and praying it doesn't end up in a commit or an LLM's context window, you write:
```json theme={null}
{ "source": "anima", "credentialId": "cred_abc123", "field": "apiKey.key" }
```
The Anima CLI resolves these refs at execution time — the agent composing the command, and the LLM reviewing its output, never see the actual value.
## The three sources
Every SecretRef has a `source` field that determines where the value comes from. Only these three are supported, and that's deliberate — every additional source is a new place a secret can be misused.
### `anima` — Anima Vault
The default. Points at a credential in your vault.
```json theme={null}
{
"source": "anima",
"credentialId": "cred_01HXYZ...",
"field": "apiKey.key",
"agentId": "agent_optional"
}
```
| Field | Required | Notes |
| -------------- | -------- | ------------------------------------------------------------------ |
| `credentialId` | yes | The `cred_...` id from the Anima console or `anima vault list` |
| `field` | yes | Dot-path into the credential (e.g. `apiKey.key`, `login.password`) |
| `agentId` | no | Explicit agent scope; defaults to the CLI's authenticated agent |
Under the hood the CLI mints a single-use `vtk_` token, exchanges it, and the resolved value never touches disk. Every resolution is written to the audit log with the actor's key type recorded — reveals via a master key (`mk_`) show up distinctly from agent-scoped accesses.
### `env` — Environment variable
Escape hatch for secrets that aren't yet migrated into Anima (rotating dev tokens, one-off sandbox keys).
```json theme={null}
{ "source": "env", "name": "MY_DEV_TOKEN" }
```
| Field | Required | Notes |
| ------ | -------- | -------------------------------------------------- |
| `name` | yes | Must be present in the environment at resolve time |
If the variable is unset, the CLI refuses to run. It does not fall back to an empty string — that pattern causes too many "it worked locally but 401'd in prod" bugs.
### `exec` — Trusted binary
For dynamic secrets that come from a local tool (AWS STS, `op read`, `gcloud auth print-access-token`, short-lived GitHub App tokens).
```json theme={null}
{
"source": "exec",
"command": "aws",
"args": ["sts", "get-session-token", "--output", "text"]
}
```
| Field | Required | Notes |
| --------- | -------- | --------------------------------------------------------------------------------------------------- |
| `command` | yes | Bare binary name or absolute path; shell metacharacters (`;`, `\|`, `` ` ``, `$`, `&`) are rejected |
| `args` | no | String array. Spawned with `shell: false` so each element is a literal argv slot |
| `passEnv` | no | Env var names passed through to the subprocess — everything else is stripped |
| `cwd` | no | Working directory for the subprocess |
Output is captured with a 15-second timeout and a 1 MB buffer cap. If the binary exits non-zero, the CLI refuses to run. The child process starts with a minimal environment: only the variables listed in `passEnv`, plus `PATH` so the binary can be found. Be explicit about what your provider needs — e.g. `"passEnv": ["HOME", "AWS_PROFILE"]` for the AWS CLI.
## `anima.json` — putting it together
Drop an `anima.json` at the root of any project (or any ancestor directory — the CLI walks up from `cwd`). The shape:
```json theme={null}
{
"$schema": "https://docs.useanima.sh/schemas/anima.json",
"secrets": {
"GH_TOKEN": { "source": "anima", "credentialId": "cred_github", "field": "apiKey.key" },
"DATABASE_URL":{ "source": "env", "name": "DATABASE_URL" },
"AWS_KEY": {
"source": "exec",
"command": "aws",
"args": ["sts", "get-session-token", "--output", "text"]
}
}
}
```
The keys (`GH_TOKEN`, `DATABASE_URL`, `AWS_KEY`) are the variable names that will be exposed to whatever command consumes the refs — typically environment variables passed to a child process.
The `$schema` line is optional, but with it any JSON-Schema-aware editor (VS Code out of the box) validates refs and autocompletes fields as you type. The schema is published at [docs.useanima.sh/schemas/anima.json](https://docs.useanima.sh/schemas/anima.json).
### Using it
```bash theme={null}
# Resolve all refs and exec a subprocess with them in-env
anima vault exec -- gh api /user
# Proxy a single ref through an HTTPS injector
anima vault proxy --cred GH_TOKEN --allow-host api.github.com --port 19840
# Quick lookup (plaintext; requires `anima vault unlock` first)
anima vault get GH_TOKEN
```
If the CLI can't resolve a ref (missing env var, failing exec, deleted vault credential) it refuses to run and emits a structured error — no partial execution, no silent fallback.
## Why not just `.env`?
Three reasons:
1. **`.env` files are static.** `exec` sources pull fresh values on every resolve — matters for STS tokens, SSO-minted GitHub App tokens, and anything else with a lifetime under an hour.
2. **`.env` files are untyped.** A SecretRef is a JSON schema — you get IDE completion, and the CLI can refuse to run if the shape is wrong before the subprocess starts.
3. **`.env` files don't participate in the audit log.** Every `anima`-source resolution is attributed to an agent or user and shows up in the console Access Log. Agents that ingest a `.env` file by accident are a common leak vector; an `anima.json` commits only *references* — the values live exclusively in the vault.
## Security rules the resolver enforces
These are non-negotiable — the resolver refuses to run if any are violated:
* `exec.command` may not contain whitespace or `;`, `|`, `&`, `<`, `>`, `$`, `` ` ``, `\`. If you need a pipeline, write a wrapper script and point `command` at it.
* `exec` child processes get a minimal environment: `PATH`, plus only the variables listed in `passEnv`. Everything else is dropped.
* `anima` refs require an active CLI auth context — the resolver prompts for login rather than falling through silently.
* Resolved values never reach disk. They live in process memory for the duration of the child, then are overwritten.
See also: [Vault overview](/vault), [Security](/security).
# Security
Source: https://docs.useanima.sh/security
Learn about Anima security controls, dual-layer scanning, policy engine rules, and operational best practices.
# Security
Built-in safeguards to protect your agents, users, and outbound communications.
### API Keys
Two types: Master Keys (full admin access) and Agent Keys (scoped to a single mailbox).
### Dual-Layer Content Scanning
Scans with both deterministic regex heuristics and AI classification.
## API Key Types
| Type | Prefix | Permissions | Best Practice |
| ---------- | ------ | ------------------------------------------------------ | ------------------------------------------------------------------ |
| Master Key | `mk_` | Full access. Create agents, manage billing, view logs. | Store in server-only environment variables and rotate on schedule. |
| Agent Key | `ak_` | Scoped access. Send/receive for one specific agent. | Issue least-privilege keys per service and revoke unused keys. |
## Content Scanning Overview (Regex + AI)
* **Regex Layer:** Fast checks for known injection markers, secret patterns, and risky payload signatures.
* **AI Layer:** GPT-4o-mini classification into `SAFE`, `SUSPICIOUS`, or `BLOCKED`.
* **Fallback Safety:** If AI credentials are missing, scanning gracefully continues in regex-only mode.
> **Note:** Use `low`, `medium` (default), or `high` sensitivity depending on risk tolerance and expected message variability.
## Content Policy Configuration
The policy engine applies layered rules to outbound content and can combine deterministic and model-based checks.
* **Regex rules:** Match known dangerous patterns.
* **AI rules:** Enforce decisions based on model classification.
* **Domain rules:** Whitelist or blacklist domains in message content.
* **Keyword rules:** Detect finance, attachment, and social engineering signals.
```ts theme={null}
const policies = [
{
id: "block-injection",
name: "Block Injection",
action: "block",
priority: 100,
rules: [
{ type: "regex", value: "ignore\\s+previous\\s+instructions", description: "Prompt injection" },
{ type: "ai", value: ["BLOCKED"], description: "AI high-risk verdict" }
]
}
];
```
## Agent Capability Policies
Separate from content scanning: each agent carries an optional **capability policy** — hard limits an org admin sets on what the agent may do, regardless of message content.
Read it with `GET /v1/agents/{agentId}/policy` (any key in the org). Write it with `PUT /v1/agents/{agentId}/policy` (master key only):
```bash theme={null}
curl -X PUT https://api.useanima.sh/v1/agents/agt_.../policy \
-H "Authorization: Bearer mk_..." \
-H "Content-Type: application/json" \
-d '{
"policy": {
"email": {
"allowedRecipientDomains": ["example.com"],
"blockedRecipientDomains": [],
"maxPerHour": 20
},
"vault": { "readOnly": true, "blocked": false },
"phone": { "allowedCountries": ["US", "DE"], "maxSmsPerHour": 10, "blocked": false }
}
}'
```
| Field | Type | Meaning |
| ------------------------------- | ---------- | ------------------------------------------------------------------------------------- |
| `email.allowedRecipientDomains` | `string[]` | If non-empty, the agent may **only** send to these domains. Empty = no restriction. |
| `email.blockedRecipientDomains` | `string[]` | The agent may **never** send to these domains. |
| `email.maxPerHour` | `number` | Per-agent override of the emails-per-hour rate limit. |
| `vault.readOnly` | `boolean` | Agent can read vault items but not create, update, or delete them. |
| `vault.blocked` | `boolean` | Disable vault access for this agent entirely. |
| `phone.allowedCountries` | `string[]` | ISO 3166-1 alpha-2 codes. If non-empty, the agent may only call/text these countries. |
| `phone.maxSmsPerHour` | `number` | Per-agent override of the SMS-per-hour rate limit. |
| `phone.blocked` | `boolean` | Disable phone/SMS for this agent entirely. |
Every section is optional — omit one to leave that channel unrestricted. Validation is strict: unknown fields are rejected with a `400` rather than silently ignored, so typos can't create a policy that looks stricter than it is.
An email send that violates the policy is refused and logged as a security event, so blocked attempts show up in the audit trail.
> **Note:** Email constraints are enforced on every send today. Vault and phone constraints are validated and stored, but not yet enforced at request time.
## Rate Limiting for AI Scanning
AI scanning is rate limited to 100 req/min, uses an LRU cache with 1000 entries and a 5min TTL, and falls back to regex scanning when needed.
## Attachment Scanning
Email attachments are scanned both when an agent receives them and before an agent sends them, so malicious files are caught in either direction.
* **Magic-byte detection:** the actual leading bytes are inspected, not the declared type or the file extension (both are trivially spoofed). An executable or script disguised as `invoice.pdf` is unmasked and blocked.
* **Content scanning:** text attachments run through the same content scanner as message bodies, catching leaked credentials, PII, and risky file types.
* **Verdict:** each attachment gets a `scanStatus` of `CLEAN`, `FLAGGED`, or `BLOCKED`, surfaced in the message's attachment metadata so an agent can decide before fetching the bytes.
A `BLOCKED` attachment cannot be downloaded — the download endpoint returns `403`. Download URLs are short-lived (15 minutes) and scoped to the requesting agent.
## Webhook Security (HMAC Verification)
Webhook payloads are protected with HMAC verification and freshness checks to prevent tampering and replay attacks.
* Use a dedicated webhook secret.
* Verify the HMAC signature on every request.
* Compare signatures using constant-time comparison.
* Reject requests that fail timestamp freshness checks.
> **Warning:** If content is blocked by policy, the API returns a denial response with a reason code so you can audit and tune policy behavior safely.
## Operational Best Practices
* Rotate keys on a regular schedule.
* Store master keys only in server-side environments.
* Use least-privilege agent keys per service.
* Review blocked events and adjust policies carefully.
# Anomaly Detection
Source: https://docs.useanima.sh/security/anomaly-detection
Behavioral baselines, detection rules, and automated quarantine for AI agent activity. Protect against compromised or misbehaving agents.
# Anomaly Detection
Anima continuously monitors agent behavior and compares it against learned baselines to detect unusual activity. When anomalies are detected, agents can be automatically quarantined to prevent damage while alerts are sent for human review.
## How It Works
1. **Baseline Learning** -- Anima observes agent behavior over a configurable window to establish normal patterns
2. **Real-Time Monitoring** -- Every action is compared against the baseline in real time
3. **Detection Rules** -- Built-in and custom rules flag deviations
4. **Response Actions** -- Anomalies trigger alerts, require approval, or quarantine the agent
## Behavioral Baselines
Baselines are computed per-agent across multiple dimensions:
| Dimension | What It Tracks |
| ---------------------- | -------------------------------------------- |
| **Email volume** | Emails sent/received per hour, day |
| **Recipient patterns** | Typical recipients and new-contact frequency |
| **Spending velocity** | Transaction frequency and amount patterns |
| **API call rate** | Requests per minute by endpoint |
| **Active hours** | Typical hours of activity |
| **Data access** | Vault secret access patterns |
| **A2A communication** | Task delegation frequency and partner agents |
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// View an agent's current behavioral baseline
const baseline = await anima.anomalyDetection.getBaseline("ag_8f3k2m9x1n4p7q6r");
console.log(`Baseline period: ${baseline.windowDays} days`);
console.log(`Avg emails/day: ${baseline.emailVolume.avgPerDay}`);
console.log(`Avg spend/day: $${(baseline.spending.avgDailyCents / 100).toFixed(2)}`);
console.log(`Active hours: ${baseline.activeHours.start}-${baseline.activeHours.end}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
baseline = anima.anomaly_detection.get_baseline("ag_8f3k2m9x1n4p7q6r")
print(f"Baseline period: {baseline.window_days} days")
print(f"Avg emails/day: {baseline.email_volume.avg_per_day}")
print(f"Avg spend/day: ${baseline.spending.avg_daily_cents / 100:.2f}")
```
## Detection Rules
### Built-In Rules
| Rule | Trigger | Default Action |
| --------------------- | ----------------------------------------- | -------------- |
| `email_volume_spike` | Emails sent exceed 3x baseline in 1 hour | Alert |
| `new_recipient_burst` | 10+ new recipients in 1 hour | Alert |
| `spending_spike` | Spend exceeds 5x daily baseline | Quarantine |
| `off_hours_activity` | Activity outside established active hours | Alert |
| `vault_mass_access` | 5+ vault secrets accessed in 1 minute | Quarantine |
| `api_rate_anomaly` | API calls exceed 10x per-minute baseline | Throttle |
| `a2a_unknown_agent` | Task sent to never-before-seen agent | Approval |
### Custom Rules
Define custom detection rules for your specific use case:
```ts theme={null}
await anima.anomalyDetection.rules.create({
name: "high-volume-email-new-recipient",
description: "Flag high email volume to recipients never sent to before",
conditions: [
{ field: "category", operator: "eq", value: "email.send" },
{ field: "metadata.batchSize", operator: "gt", value: 100 },
{ field: "metadata.to", operator: "not_in_baseline", value: true },
],
action: "require_approval",
severity: "high",
enabled: true,
});
```
```python theme={null}
anima.anomaly_detection.rules.create(
name="high-volume-email-new-recipient",
description="Flag high email volume to recipients never sent to before",
conditions=[
{"field": "category", "operator": "eq", "value": "email.send"},
{"field": "metadata.batchSize", "operator": "gt", "value": 100},
{"field": "metadata.to", "operator": "not_in_baseline", "value": True},
],
action="require_approval",
severity="high",
enabled=True,
)
```
## Quarantine
When an agent is quarantined, all its outbound actions are suspended until a human reviews the flagged activity.
```ts theme={null}
// Manually quarantine an agent
await anima.anomalyDetection.quarantine("ag_8f3k2m9x1n4p7q6r", {
reason: "Unusual spending pattern detected",
});
// Release an agent from quarantine
await anima.anomalyDetection.release("ag_8f3k2m9x1n4p7q6r", {
reviewedBy: "admin@acme.com",
notes: "Confirmed legitimate activity -- budget increase approved",
});
// List quarantined agents
const quarantined = await anima.anomalyDetection.listQuarantined();
```
## Anomaly Alerts
Configure how anomaly alerts are delivered:
```ts theme={null}
await anima.anomalyDetection.configureAlerts({
channels: [
{ type: "webhook", url: "https://acme.com/webhooks/anomaly" },
{ type: "email", address: "security@acme.com" },
{ type: "slack", webhookUrl: "https://hooks.slack.com/..." },
],
minSeverity: "medium", // "low" | "medium" | "high" | "critical"
});
```
## API Reference
| Endpoint | Method | Description |
| ------------------------------------------------------------------ | ------ | ----------------------------- |
| `https://api.useanima.sh/api/anomaly-detection/baselines/:agentId` | GET | Get agent behavioral baseline |
| `https://api.useanima.sh/api/anomaly-detection/rules` | POST | Create a detection rule |
| `https://api.useanima.sh/api/anomaly-detection/rules` | GET | List detection rules |
| `https://api.useanima.sh/api/anomaly-detection/rules/:id` | PUT | Update a detection rule |
| `https://api.useanima.sh/api/anomaly-detection/rules/:id` | DELETE | Delete a detection rule |
| `https://api.useanima.sh/api/anomaly-detection/alerts` | GET | List recent anomaly alerts |
| `https://api.useanima.sh/api/anomaly-detection/quarantine` | POST | Quarantine an agent |
| `https://api.useanima.sh/api/anomaly-detection/quarantine` | GET | List quarantined agents |
| `https://api.useanima.sh/api/anomaly-detection/release` | POST | Release from quarantine |
| `https://api.useanima.sh/api/anomaly-detection/alerts/config` | PUT | Configure alert channels |
## Configuration
| Variable | Default | Description |
| ------------------------------------ | -------- | --------------------------------------- |
| `ANIMA_ANOMALY_BASELINE_WINDOW_DAYS` | `14` | Days of data used to compute baselines |
| `ANIMA_ANOMALY_SENSITIVITY` | `medium` | Detection sensitivity (low/medium/high) |
| `ANIMA_ANOMALY_AUTO_QUARANTINE` | `true` | Auto-quarantine on critical anomalies |
| `ANIMA_ANOMALY_COOLDOWN_MINUTES` | `30` | Cooldown between repeated alerts |
## Next Steps
* [Audit Log](/security/audit-log) -- Review the events that triggered anomalies
* [SOC 2 Controls](/compliance/soc2-controls) -- Map anomaly detection to compliance
* [Compliance Reporting](/compliance/reporting) -- Include anomaly metrics in reports
# Audit Log
Source: https://docs.useanima.sh/security/audit-log
Immutable audit log for all agent actions. Query, filter, export, and integrate with SIEM systems.
# Audit Log
Anima maintains an immutable, append-only audit log of every action performed by or on behalf of agents. The audit log is critical for compliance, incident response, and operational visibility.
## What Gets Logged
Every API call, agent action, and system event produces an audit entry:
| Category | Events |
| ------------ | ---------------------------------------------------------- |
| **Agent** | Create, update, delete, suspend |
| **Email** | Send, receive, forward, delete |
| **Cards** | Create, authorize, decline, close |
| **Vault** | Store, retrieve, rotate, delete secrets |
| **Wallet** | Payment, budget change, approval request |
| **Identity** | DID creation, key rotation, credential issuance/revocation |
| **A2A** | Task sent, received, completed, failed |
| **Auth** | API key created, rotated, revoked; login attempts |
| **Pod** | Created, updated, deleted, bridge created |
## Querying the Audit Log
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Query audit events
const events = await anima.auditLog.query({
agentId: "ag_8f3k2m9x1n4p7q6r",
category: "email",
action: "send",
startTime: "2026-03-01T00:00:00Z",
endTime: "2026-03-28T23:59:59Z",
limit: 50,
});
for (const event of events.data) {
console.log(`[${event.timestamp}] ${event.action}`);
console.log(` Actor: ${event.actorId} (${event.actorType})`);
console.log(` Resource: ${event.resourceType}/${event.resourceId}`);
console.log(` Details: ${JSON.stringify(event.metadata)}`);
}
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
events = anima.audit_log.query(
agent_id="ag_8f3k2m9x1n4p7q6r",
category="email",
action="send",
start_time="2026-03-01T00:00:00Z",
end_time="2026-03-28T23:59:59Z",
limit=50,
)
for event in events.data:
print(f"[{event.timestamp}] {event.action}")
print(f" Actor: {event.actor_id} ({event.actor_type})")
print(f" Resource: {event.resource_type}/{event.resource_id}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
events, err := client.AuditLog.Query(ctx, &anima.AuditLogQueryParams{
AgentID: "ag_8f3k2m9x1n4p7q6r",
Category: "email",
Action: "send",
StartTime: "2026-03-01T00:00:00Z",
EndTime: "2026-03-28T23:59:59Z",
Limit: 50,
})
```
## Audit Event Structure
```json theme={null}
{
"id": "evt_9x2m4k7p1n",
"timestamp": "2026-03-15T14:32:01.234Z",
"category": "email",
"action": "send",
"actorId": "ag_8f3k2m9x1n4p7q6r",
"actorType": "agent",
"resourceType": "message",
"resourceId": "msg_abc123",
"podId": "pod_prod",
"metadata": {
"to": "ops@example.com",
"subject": "Deploy complete",
"decision": "delivered",
"ruleEvaluations": [
{ "rule": "per_minute_rate_limit", "result": "pass" },
{ "rule": "daily_send_quota", "result": "pass" },
{ "rule": "domain_allowlist", "result": "pass" }
]
},
"ipAddress": "10.0.1.42",
"userAgent": "anima-sdk-node/1.5.0",
"immutableHash": "sha256:a1b2c3d4..."
}
```
## Exporting Audit Logs
Export logs for compliance review or SIEM integration:
```ts theme={null}
// Export to JSON
const exportJob = await anima.auditLog.export({
format: "json", // "json" | "csv" | "parquet"
startTime: "2026-01-01T00:00:00Z",
endTime: "2026-03-31T23:59:59Z",
destination: "s3://my-bucket/audit-logs/q1-2026.json",
});
console.log(`Export job: ${exportJob.id}, Status: ${exportJob.status}`);
// Stream to a SIEM (Splunk, Datadog, etc.)
await anima.auditLog.configureSiemStream({
provider: "datadog",
apiKey: "dd_...",
site: "datadoghq.com",
tags: ["env:production", "service:anima"],
});
```
```python theme={null}
export_job = anima.audit_log.export(
format="json",
start_time="2026-01-01T00:00:00Z",
end_time="2026-03-31T23:59:59Z",
destination="s3://my-bucket/audit-logs/q1-2026.json",
)
print(f"Export job: {export_job.id}, Status: {export_job.status}")
```
## API Reference
| Endpoint | Description |
| ------------------------------------------------------- | ------------------------ |
| `GET https://api.useanima.sh/api/audit-log/events` | Query audit events |
| `GET https://api.useanima.sh/api/audit-log/events/{id}` | Get a single audit event |
| `POST https://api.useanima.sh/api/audit-log/export` | Start an export job |
| `GET https://api.useanima.sh/api/audit-log/export/{id}` | Check export job status |
| `POST https://api.useanima.sh/api/audit-log/siem` | Configure SIEM streaming |
| `GET https://api.useanima.sh/api/audit-log/siem` | Get SIEM configuration |
### Query Parameters
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------------------------ |
| `agentId` | string | Filter by agent |
| `podId` | string | Filter by pod |
| `category` | string | Filter by category (e.g., `email`, `phone`, `vault`, `auth`) |
| `action` | string | Filter by specific action |
| `startTime` | string | ISO 8601 start time |
| `endTime` | string | ISO 8601 end time |
| `limit` | number | Max results (default 50, max 1000) |
| `cursor` | string | Pagination cursor |
## Configuration
| Variable | Default | Description |
| ----------------------------- | --------- | -------------------------------------- |
| `ANIMA_AUDIT_RETENTION_DAYS` | `365` | How long to retain audit events |
| `ANIMA_AUDIT_HASH_ALGORITHM` | `sha256` | Hash algorithm for immutability proofs |
| `ANIMA_AUDIT_SIEM_BATCH_SIZE` | `100` | Batch size for SIEM streaming |
| `ANIMA_AUDIT_EXPORT_MAX_ROWS` | `1000000` | Maximum rows per export job |
## Next Steps
* [Anomaly Detection](/security/anomaly-detection) -- Detect unusual agent behavior
* [SOC 2 Controls](/compliance/soc2-controls) -- Map audit events to SOC 2 controls
* [Compliance Reporting](/compliance/reporting) -- Generate compliance reports
# Vault
Source: https://docs.useanima.sh/vault
Store, share, and inject encrypted credentials for your AI agents — with a hard guarantee that the LLM never sees raw secrets.
# Vault
The Anima Vault provides encrypted credential storage for AI agents, with a critical security guarantee: **the LLM never sees raw secrets**. Each agent gets its own isolated, per-agent-encrypted vault for logins, API keys, payment cards, and identity data. Agents reference credentials through opaque tokens, and the CLI or browser extension performs the last-mile substitution at execution time.
## Overview
Agents often need to authenticate with external services — CRMs, booking platforms, merchant sites. The vault stores these credentials securely and makes them available to the agent at runtime, without exposing secrets in code, environment variables, or the model's context.
The core idea:
```text theme={null}
Agent (LLM) → composes a command containing a vtk_ token
CLI / extension → detects the token, exchanges it for the credential, substitutes
Execution → the real secret is used in the request
Output → matching secrets are redacted before returning to the LLM
```
## Provisioning
Before an agent can store credentials, its vault must be provisioned:
```python theme={null}
# Python
anima.vault.provision(agent_id=agent.id)
```
```ts theme={null}
// TypeScript
await anima.vault.provision({ agentId: agent.id });
```
From the CLI:
```bash theme={null}
anima vault provision --agent
anima vault status --agent
```
## Credential Types
| Type | Primary secret | Use case |
| ------------- | -------------- | ---------------------------------------------------------------- |
| `login` | password | Website logins, SSH credentials (username, password, URIs, TOTP) |
| `api_key` | key | API keys (e.g. provider keys) |
| `oauth_token` | accessToken | OAuth integrations |
| `certificate` | privateKey | TLS / mTLS certificates |
| `secure_note` | notes | Free-form secret text |
| `card` | number | Payment card details |
| `identity` | — | Personal / business identity data (not auto-injectable) |
## CRUD Operations
### Create a credential
```python theme={null}
# Python
credential = anima.vault.create_credential(
agent_id=agent.id,
type="login",
name="CRM Login",
login={
"username": "bot@company.com",
"password": "s3cur3-p4ssw0rd",
"uris": [{"uri": "https://crm.company.com"}],
},
)
```
```ts theme={null}
// TypeScript
const credential = await anima.vault.createCredential({
agentId: agent.id,
type: "login",
name: "CRM Login",
login: {
username: "bot@company.com",
password: "s3cur3-p4ssw0rd",
uris: [{ uri: "https://crm.company.com" }],
},
});
```
### Create a login with a generated password
For account provisioning, don't supply a password at all — ask the vault to
generate one server-side in the same call. The password is created inside the
vault, stored with the credential, and **never returned**: the response
carries only the credential ref with masked fields. Your code (and, for MCP
agents, the model's context) never sees the secret.
```python theme={null}
# Python
credential = anima.vault.create_credential(
agent_id=agent.id,
type="login",
name="Acme Portal",
login={"username": "bot@company.com", "uris": [{"uri": "https://acme.io/login"}]},
generate_password={}, # server defaults: 24 chars, all character classes
)
print(credential.id) # store this ref
print(credential.login.password) # "****" — the plaintext stays in the vault
```
```ts theme={null}
// TypeScript
const credential = await anima.vault.createCredential({
agentId: agent.id,
type: "login",
name: "Acme Portal",
login: { username: "bot@company.com", uris: [{ uri: "https://acme.io/login" }] },
generatePassword: { length: 32, special: false }, // tune per site policy
});
```
Generation options: `length` (8–128, default 24) and the character-class
toggles `uppercase` / `lowercase` / `number` / `special` (all default `true`).
`generatePassword` is only valid for `login` credentials and is mutually
exclusive with `login.password`.
At fill time — for example when the Anima Chrome extension signs in to
provision an account — the agent mints a single-use, audit-logged vault token
(`POST /vault/token`, scope `autofill`) and exchanges it for the credential
(see [Ephemeral Tokens](#ephemeral-tokens) below). The plaintext is revealed
exactly once, to the component that needs it.
### Retrieve a credential
```python theme={null}
creds = anima.vault.get_credential(
agent_id=agent.id,
credential_id=credential.id,
)
print(creds.username, creds.password)
```
### List and search
```python theme={null}
all_creds = anima.vault.list(agent_id=agent.id)
results = anima.vault.search(agent_id=agent.id, query="crm")
```
### Update and delete
```python theme={null}
anima.vault.update_credential(
agent_id=agent.id,
credential_id=credential.id,
password="new-p4ssw0rd",
)
anima.vault.delete_credential(
agent_id=agent.id,
credential_id=credential.id,
)
```
### REST endpoints
| Method | Path | Description |
| -------- | -------------------------------------- | ------------------------------------------------ |
| `GET` | `/vault/credentials?agentId=` | List all credentials |
| `GET` | `/vault/credentials/{id}?agentId=` | Get a single credential |
| `POST` | `/vault/credentials` | Create a credential |
| `PUT` | `/vault/credentials/{id}` | Update a credential |
| `DELETE` | `/vault/credentials/{id}` | Delete a credential (`agentId` in the JSON body) |
| `GET` | `/vault/search?agentId=&search=&type=` | Search credentials |
| `POST` | `/vault/generate-password` | Generate a random password |
| `GET` | `/vault/totp/{id}?agentId=` | Get the current TOTP code |
| `GET` | `/vault/status?agentId=` | Vault connection status |
| `POST` | `/vault/sync` | Trigger a vault sync |
## TOTP Support
For credentials with TOTP (Time-based One-Time Password) configured:
```python theme={null}
totp = anima.vault.get_totp(
agent_id=agent.id,
credential_id=credential.id,
)
print(totp.code) # Current 6-digit code
```
## Password Generation
For agent flows, prefer the atomic
[create-with-generated-password](#create-a-login-with-a-generated-password)
above — it generates and stores the password in one call and never returns
the plaintext.
The standalone generator remains available for interactive use. Note that it
**returns the generated password to the caller**, so it should not be used in
flows where the secret must stay inside the vault:
```ts theme={null}
// TypeScript
const { password } = await anima.vault.generatePassword({
length: 24,
uppercase: true,
lowercase: true,
number: true,
special: true,
});
```
## Credential Sharing
Share a credential from one agent to another, with a scoped permission and optional expiry. Sharing is one credential to one target agent at a time.
| Method | Path | Description |
| ------ | ----------------------------------- | ------------------------------------- |
| `POST` | `/vault/share` | Share a credential with another agent |
| `GET` | `/vault/shares?agentId=&direction=` | List shares (granted or received) |
| `POST` | `/vault/share/revoke` | Revoke a share |
`POST /vault/share` takes `credentialId`, `sourceAgentId`, `targetAgentId`, a `permission`, and either `expiresAt` or `expiresInSeconds`. Revoke with a `shareId`.
**Permissions:**
| Permission | Grants |
| ---------- | ------------------------------------------------------------------------ |
| `READ` | View credential metadata only |
| `USE` | Auto-fill the credential in the CLI or browser, without seeing its value |
| `MANAGE` | Full read/update/delete access to the shared credential |
## Ephemeral Tokens
An ephemeral token is a short-lived, single-use handle to a credential. The agent puts the token in a command; the CLI or extension exchanges it for the real value at the moment of execution.
| Method | Path | Description |
| ------ | ----------------------- | ----------------------------------- |
| `POST` | `/vault/token` | Create an ephemeral token |
| `POST` | `/vault/token/exchange` | Exchange a token for its credential |
| `POST` | `/vault/token/revoke` | Revoke all tokens for a credential |
`POST /vault/token` takes `credentialId`, a `scope`, and an optional `ttlSeconds` (and `agentId` / `taskId`). The token value (`vtk_`) is returned **only at creation time**.
**Scopes:**
| Scope | Purpose |
| ---------- | ---------------------------------------- |
| `autofill` | CLI and browser-extension auto-fill |
| `proxy` | Delegated access through the local proxy |
| `export` | One-time credential reveal |
**Token security:**
* Tokens use the `vtk_` prefix with 32 bytes of entropy.
* Only the token's hash is stored — the raw token is never persisted.
* Tokens are single-use: consumed on first exchange.
* Configurable TTL (10–3600 seconds).
* Scope-bound: a token scoped to `autofill` cannot be used for `export`.
## Secret Redaction
Output from any command that used injected credentials is scanned and redacted before it returns to the LLM, so a secret that appears in a response body or error message never lands in the model's context.
```bash theme={null}
some-command | anima vault redact --agent
# any value matching a stored credential becomes [REDACTED]
```
`anima vault redact` fetches the agent's credentials, replaces any matching secret value in stdin with `[REDACTED]`, and can take extra literal strings via `--pattern`.
## Template Substitution
For structured references inside a block of text, use the template syntax and let the CLI resolve it at execution time:
```text theme={null}
{{vault:credentialId:login.password}}
{{vault:credentialId:apiKey.key}}
{{vault:credentialId:oauthToken.accessToken}}
```
The CLI detects `{{vault:...}}` templates (and `vtk_` tokens) in input and exchanges them for real credentials before the command runs.
## Zero-Knowledge Execution
Ephemeral tokens, template substitution, and redaction protect against *accidental* plaintext exposure. For a tighter boundary — where the agent authors the call but can never read the secret — the CLI adds a set of execution primitives. All resolve credentials through [SecretRef & `anima.json`](/secret-ref).
### `anima vault exec`
Run a subprocess with resolved secrets injected as environment variables. The agent writes the command; the CLI resolves the `anima.json` references and spawns the child — the model's context never sees the values. Output is scrubbed by the redaction engine.
```bash theme={null}
anima vault exec -- gh api /user
anima vault exec -- psql -c "select count(*) from users"
```
### `anima vault proxy`
A loopback-only HTTPS proxy that injects an `Authorization` header into outbound requests. The agent holds only a short-lived proxy token (`pxt_`); the credential lives in the CLI process and is never reachable from the network. Requests to any host not on `--allow-host` are rejected.
```bash theme={null}
anima vault proxy --cred cred_github --allow-host api.github.com --port 19840 &
# proxy_token=pxt_... port=19840
curl -H "X-Anima-Proxy: pxt_..." \
http://127.0.0.1:19840/https://api.github.com/user
```
### `anima vault agent` (keystroke injection)
A local daemon that binds to a Unix socket (mode `0600`) and — on a user-confirmed hotkey — types a credential into the focused text field. Useful for apps that can't take a proxy, such as desktop SSH clients or native database UIs.
```bash theme={null}
anima vault agent start
anima vault type --cred GH_TOKEN # press the hotkey to confirm; the daemon types the value
```
### `anima vault unlock`
A master-key ceremony that mints a short-lived session for plaintext reveals. Without an active unlock, the CLI refuses any command that would print plaintext to the terminal, even if you hold a master key.
```bash theme={null}
anima vault unlock # prompts for the master key, ~5-minute session
anima vault get cred_github --unmask # prints plaintext
anima vault unlock --lock # end the session early
```
### `anima vault audit`
Scan the filesystem for leaked secrets, cross-referenced against the vault inventory. High-confidence key patterns are flagged by heuristic; literal values that match a stored credential are flagged by exact comparison.
```bash theme={null}
anima vault audit . # scan the current directory
anima vault audit --check # CI mode: exit non-zero on findings
```
MCP vault tools never return plaintext to the model. They hand back a plan that a trusted local process (the CLI, the extension, or the keystroke daemon) executes — the LLM composes intent, and the local process enforces the secret boundary.
## Browser Extension
The Anima browser extension performs vault credential autofill for login forms, so an agent can log in without the password ever entering its context:
1. The agent stores credential data ephemerally.
2. The agent asks the extension to fill the detected login form.
3. The extension detects the username, password, and TOTP fields.
4. Credentials are injected and immediately zeroized from memory.
To bind the extension to an agent from a headless browser — a Puppeteer worker, a scheduled job, no human to click — use [Headless Extension Connect](/extension-connect).
## Access Log
Every credential access — token mints, `exec` invocations, and masked reads — is recorded in the vault audit log.
```bash theme={null}
anima vault audit # (GET /vault/audit) — the vault access stream
```
In the console, the **Vault → Access Log** page filters this stream and highlights plaintext reveals (via a master key) with a warning banner, so compliance teams can confirm they were intentional. Masked accesses from agent keys are the common path and don't need review.
## Deprovision
Remove an agent's vault and all stored credentials:
```python theme={null}
anima.vault.deprovision(agent_id=agent.id)
```
## Security
* All credentials are encrypted at rest with AES-256-GCM.
* Each agent's vault is isolated, with its own per-agent encryption key — agents cannot access each other's credentials.
* Vault access is scoped to the agent's API key.
* Credential reads are masked by default; plaintext access requires a master-key `reveal` (audit-logged) or a single-use vault token exchange.
* Vault-generated passwords never appear in any API response, audit log, or webhook payload — only the credential ref leaves the vault.
* See [Encryption](/encryption) for the per-agent key-derivation model, and [SecretRef & `anima.json`](/secret-ref) for the reference schema used by `exec` and `proxy`.
# Voice Catalog
Source: https://docs.useanima.sh/voice-catalog
List available voice tiers and catalog entries for AI-powered phone calls.
# Voice Catalog
Use the voice catalog to inspect which voices are available for outbound phone calls. The current SDK exposes catalog listing and filtering; call creation uses the selected `tier` plus the agent's configured voice pipeline.
## List voices
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
voices = anima.voices.list(tier="basic")
for voice in voices["voices"]:
print(f"{voice.id}: {voice.name} ({voice.provider}, {voice.language})")
```
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
const voices = await anima.voices.list({ tier: "basic" });
for (const voice of voices.voices) {
console.log(`${voice.id}: ${voice.name} (${voice.provider}, ${voice.language})`);
}
```
## Filters
The catalog supports these optional filters:
| Filter | Values |
| ---------- | ------------------------------------- |
| `tier` | `basic`, `premium` |
| `gender` | `male`, `female`, `neutral` |
| `language` | BCP-47 language code, such as `en-US` |
```python theme={null}
premium_voices = anima.voices.list(tier="premium")
female_voices = anima.voices.list(gender="female")
english_voices = anima.voices.list(language="en-US")
```
```ts theme={null}
const premiumVoices = await anima.voices.list({ tier: "premium" });
const femaleVoices = await anima.voices.list({ gender: "female" });
const englishVoices = await anima.voices.list({ language: "en-US" });
```
## Place a call
The public SDK call creation surface accepts `to`, optional `agentId`, `tier`, `greeting`, and optional `fromNumber`.
```python theme={null}
call = anima.calls.create(
agent_id="AGENT_ID",
to="+15551234567",
tier="basic",
greeting="Hi, this is my Anima agent calling from its own number.",
)
print(call.call_id, call.state)
```
```ts theme={null}
const call = await anima.calls.create({
agentId: "AGENT_ID",
to: "+15551234567",
tier: "basic",
greeting: "Hi, this is my Anima agent calling from its own number.",
});
console.log(call.callId, call.state);
```
Per-call `voiceId`, `voiceSettings`, and custom `systemPrompt` fields are not part of the current public SDK call input. Configure persistent agent behavior in the agent/voice pipeline, and use `greeting` for the opening line.
## REST endpoint
```bash theme={null}
curl "https://api.useanima.sh/v1/voice/catalog?tier=basic" \
-H "Authorization: Bearer ak_..."
```
## Next steps
* [Quickstart: Voice Calls](/quickstart-voice) - Text yourself, then place the first call
* [Call Intelligence](/call-intelligence) - Transcripts, summaries, scores, and recordings
* [Voice WebSocket Protocol](/protocols/voice-websocket) - Real-time call event streaming
# Agent Wallet
Source: https://docs.useanima.sh/wallet/overview
Manage agent budgets, enforce spending guards, and handle x402 payments with the Anima Agent Wallet.
# Agent Wallet
The Anima Agent Wallet provides budget management and payment capabilities for AI agents. It combines spending guardrails with the x402 payment protocol so agents can transact autonomously within defined boundaries.
## Core Concepts
* **Budget Guards** -- Configurable limits that prevent agents from overspending
* **x402 Payments** -- HTTP-native payment protocol for agent-to-agent and agent-to-service payments
* **Balance Tracking** -- Real-time tracking of agent spending across all payment methods
## Setting Up a Wallet
```ts theme={null}
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
// Create a wallet for an agent
const wallet = await anima.wallet.create({
agentId: "ag_8f3k2m9x1n4p7q6r",
currency: "usd",
budgetGuards: {
dailyLimitCents: 500_00,
monthlyLimitCents: 5000_00,
perTransactionLimitCents: 100_00,
requireApprovalAboveCents: 50_00,
},
});
console.log(`Wallet: ${wallet.id}, Balance: ${wallet.balanceCents}`);
```
```python theme={null}
from anima import Anima
anima = Anima(api_key="ak_...")
wallet = anima.wallet.create(
agent_id="ag_8f3k2m9x1n4p7q6r",
currency="usd",
budget_guards={
"daily_limit_cents": 50000,
"monthly_limit_cents": 500000,
"per_transaction_limit_cents": 10000,
"require_approval_above_cents": 5000,
},
)
print(f"Wallet: {wallet.id}, Balance: {wallet.balance_cents}")
```
```go theme={null}
import "github.com/anima-labs-ai/go"
client := anima.NewClient("ak_...")
wallet, err := client.Wallet.Create(ctx, &anima.CreateWalletParams{
AgentID: "ag_8f3k2m9x1n4p7q6r",
Currency: "usd",
BudgetGuards: &anima.BudgetGuards{
DailyLimitCents: 50000,
MonthlyLimitCents: 500000,
PerTransactionLimitCents: 10000,
},
})
```
## Budget Guards
Budget guards enforce spending policies at the wallet level. When a payment request exceeds a guard threshold, it is either declined or routed for human approval.
| Guard | Description |
| --------------------------- | ----------------------------------------------------- |
| `dailyLimitCents` | Maximum total spend per calendar day |
| `monthlyLimitCents` | Maximum total spend per calendar month |
| `perTransactionLimitCents` | Maximum single transaction amount |
| `requireApprovalAboveCents` | Transactions above this amount require human approval |
| `allowedMerchantCategories` | Restrict payments to specific MCC codes |
| `blockedMerchantCategories` | Block payments to specific MCC codes |
### Updating Budget Guards
```ts theme={null}
await anima.wallet.updateBudgetGuards("wlt_abc123", {
dailyLimitCents: 1000_00,
requireApprovalAboveCents: 200_00,
});
```
## x402 Payments
Anima wallets natively support the [x402 payment protocol](https://www.x402.org/), enabling agents to pay for HTTP resources by including payment headers.
```ts theme={null}
// Make an x402 payment to access a paid API
const response = await anima.wallet.payAndFetch({
walletId: "wlt_abc123",
url: "https://data-provider.example/api/report",
maxPaymentCents: 500,
});
console.log(`Paid: ${response.paymentCents} cents`);
console.log(`Data: ${response.body}`);
```
```python theme={null}
response = anima.wallet.pay_and_fetch(
wallet_id="wlt_abc123",
url="https://data-provider.example/api/report",
max_payment_cents=500,
)
print(f"Paid: {response.payment_cents} cents")
print(f"Data: {response.body}")
```
## Checking Balance and History
```ts theme={null}
// Check current balance
const balance = await anima.wallet.getBalance("wlt_abc123");
console.log(`Available: $${(balance.availableCents / 100).toFixed(2)}`);
console.log(`Spent today: $${(balance.spentTodayCents / 100).toFixed(2)}`);
// List transactions
const txns = await anima.wallet.listTransactions("wlt_abc123", {
limit: 20,
startDate: "2026-03-01",
});
```
## API Reference
| Endpoint | Method | Description |
| ------------------------------------------------------ | ------ | ------------------------------ |
| `https://api.useanima.sh/api/wallet` | POST | Create a wallet |
| `https://api.useanima.sh/api/wallet/:id` | GET | Get wallet details and balance |
| `https://api.useanima.sh/api/wallet/:id/budget-guards` | PUT | Update budget guards |
| `https://api.useanima.sh/api/wallet/:id/pay` | POST | Initiate a payment |
| `https://api.useanima.sh/api/wallet/:id/transactions` | GET | List transactions |
| `https://api.useanima.sh/api/wallet/:id/x402` | POST | Make an x402 payment |
## Configuration
| Variable | Default | Description |
| ------------------------------- | ------- | ------------------------------------------ |
| `ANIMA_WALLET_DEFAULT_CURRENCY` | `usd` | Default currency for new wallets |
| `ANIMA_WALLET_X402_ENABLED` | `true` | Enable x402 payment protocol support |
| `ANIMA_WALLET_APPROVAL_WEBHOOK` | -- | Webhook URL for approval-required payments |
## Next Steps
* [A2A Protocol](/a2a/overview) -- Agent-to-agent payments and task delegation
* [Audit Log](/security/audit-log) -- Track all wallet transactions
# Webhooks
Source: https://docs.useanima.sh/webhooks
Configure webhooks to receive real-time updates for email, SMS, and call events — with signed, replay-protected deliveries.
# Webhooks
Subscribe to real-time events like incoming emails, delivery failures, and completed calls.
## Configuration
Configure webhooks in the dashboard, via the API, the CLI, the `webhook_set` MCP tool, or any SDK. Each delivery is a JSON POST to your endpoint:
```json theme={null}
{
"event": "message.received",
"data": {
"id": "msg_12345",
"agent_id": "agent_abc",
"from": "user@example.com",
"subject": "Hello",
"body": "Hi there...",
"timestamp": "2023-10-01T12:00:00Z"
}
}
```
## Event Types
| Event Name | Description |
| ------------------ | ---------------------------------------------------- |
| `message.received` | Triggered when an agent receives a new email or SMS. |
| `message.sent` | Triggered when a message is successfully sent. |
| `message.failed` | Triggered when a message fails to send or bounces. |
| `agent.created` | Triggered when a new agent mailbox is created. |
| `call.ended` | Triggered when a voice call completes. |
The full, current list is available from `GET /webhooks/event-types`.
## Signing secret
When you create a webhook, the API returns a `secret` **once**, in the create response. Store it securely — read endpoints (`GET /webhooks` and `GET /webhooks/{id}`) never return it again. If you lose it, rotate it:
```bash theme={null}
curl -X POST https://api.useanima.sh/v1/webhooks/{id}/rotate-secret \
-H "Authorization: Bearer mk_..."
# → { "id": "wh_...", "secret": "" }
```
Rotating immediately invalidates the previous secret.
## Verifying deliveries
Every delivery carries a signature and a timestamp so you can confirm it came from Anima and reject replays:
| Header | Description |
| --------------------- | ---------------------------------------------------------------------------------- |
| `X-Anima-Signature` | `v1=` — HMAC-SHA256 of `{timestamp}.{rawBody}`, keyed by your signing secret. |
| `X-Anima-Timestamp` | ISO-8601 time the delivery was signed; bound into the signature. |
| `X-Anima-Event` | The event name (e.g. `message.received`). |
| `X-Anima-Delivery-Id` | Stable id for this delivery, unchanged across retries. |
Recompute the HMAC over `{timestamp}.{rawBody}`, compare it in constant time, and reject deliveries whose timestamp falls outside a tolerance window (for example, 5 minutes). The timestamp is part of the signed content specifically so you can stop replays.
```ts theme={null}
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_MS = 5 * 60 * 1000;
export function verifyAnimaWebhook(
rawBody: string,
headers: { "x-anima-signature": string; "x-anima-timestamp": string },
secret: string,
): boolean {
const timestamp = headers["x-anima-timestamp"];
// Reject stale or replayed deliveries.
if (Math.abs(Date.now() - Date.parse(timestamp)) > TOLERANCE_MS) return false;
const provided = headers["x-anima-signature"].replace(/^v1=/, "");
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const a = Buffer.from(provided, "hex");
const b = Buffer.from(expected, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}
```
Verify against the **raw request body**, before any JSON parse or re-serialize — re-encoding can change bytes and break the signature.
## Advanced settings
The `X-Anima-Signature` HMAC already proves a delivery came from Anima. On top of it, you can have Anima present a credential your endpoint checks, and control how fast it delivers.
### Endpoint authentication
Handy when your gateway expects a header rather than a signature. This is in addition to the HMAC.
| Type | What Anima sends |
| --------------- | -------------------------------------------------- |
| `bearer` | `Authorization: Bearer ` |
| `basic` | `Authorization: Basic ` |
| `custom_header` | A header you name, e.g. `X-My-Secret: ` |
The credential is write-only — set on create or update, never returned by a read, encrypted at rest.
### Delivery throttling and retries
* **`rateLimitPerMinute`** — cap deliveries per minute to a single endpoint. Over-limit deliveries defer to the next window rather than dropping.
* **`maxAttempts`** — max delivery attempts before dead-lettering (default 3). Retries use exponential backoff, and an endpoint that keeps failing is auto-disabled.
Set these when you create or update a webhook — via the API, the `webhook_set` MCP tool, the CLI, or any SDK:
```bash theme={null}
# CLI
anima webhook create \
--url https://example.com/hooks/anima \
--events message.received,message.sent \
--auth-config '{"type":"bearer","token":"your-endpoint-token"}' \
--rate-limit-per-minute 120 \
--max-attempts 5
```
```python theme={null}
# Python
from anima import Anima, WebhookAuthBearer
anima = Anima(api_key="ak_...")
anima.webhooks.create(
url="https://example.com/hooks/anima",
events=["message.received", "message.sent"],
auth_config=WebhookAuthBearer(token="your-endpoint-token"),
rate_limit_per_minute=120,
max_attempts=5,
)
```
```ts theme={null}
// TypeScript
import { Anima } from "@anima-labs/sdk";
const anima = new Anima({ apiKey: "ak_..." });
await anima.webhooks.create({
url: "https://example.com/hooks/anima",
events: ["message.received", "message.sent"],
authConfig: { type: "bearer", token: "your-endpoint-token" },
rateLimitPerMinute: 120,
maxAttempts: 5,
});
```
```go theme={null}
// Go
rateLimit, maxAttempts := 120, 5
client.Webhooks.Create(ctx, anima.CreateWebhookParams{
URL: "https://example.com/hooks/anima",
Events: []anima.WebhookEventType{anima.WebhookEventMessageReceived},
AuthConfig: anima.NewBearerAuth("your-endpoint-token"),
RateLimitPerMinute: &rateLimit,
MaxAttempts: &maxAttempts,
})
```
The other schemes work the same way: `basic` (username + password) and `custom_header` (a header name + value) — in the SDKs, `WebhookAuthBasic` / `WebhookAuthCustomHeader` (Python), the matching `{ type: "basic", … }` union member (TypeScript), or `anima.NewBasicAuth` / `anima.NewCustomHeaderAuth` (Go). Pass `{"type":"none"}` on update to remove authentication.