SDKs
Official TypeScript (upivia on npm) and Python (upivia on PyPI) clients for the Upivia v1 API — typed wrappers over the full surface: governed service requests, agents, orchestration, workflows, streaming chat, triggers, storage, and knowledge. Both are v0.2.0 with matching resources.
Overview
The SDKs are thin, dependency-light wrappers over the same HTTP API. The TypeScript client exposes camelCase resources (client.serviceRequests.createAndWait); the Python client mirrors the exact surface in snake_case (client.service_requests.create_and_wait), with a sync UpiviaClient and an async AsyncUpiviaClient.
Install
npm install @upivia/sdk # TypeScript / Node 18+ pip install upivia # Python 3.10+
Publishing to npm and PyPI is coming soon. Today both SDKs live in the Upivia monorepo (packages/sdk-ts and packages/sdk-py) and are usable in-repo as workspace dependencies. The API surface documented here is the shipped v0.2.0 surface.
The core idea
Agents never call external providers directly. Every SDK call to serviceRequests.create travels the same governed pipeline: policy check → budget check → approval if needed → execution adapter → audit log + usage record. Money is displayed in dollars everywhere; on the wire it is always integer cents. Every request resolves to one of four outcomes — executed, blocked, approval_required, or failed (plus running for asynchronous operations that reconcile later).
Request
The agent POSTs /api/v1/service-requests with its API key, a service.operation, and a JSON payload. The platform resolves identity and the idempotency key — the agent never talks to a provider directly.
Quickstart
Construct a client (options fall back to the UPIVIA_API_KEY, UPIVIA_PAT, and UPIVIA_BASE_URL environment variables), dispatch a service request, and branch on the outcome:
blocked, approval_required, and failed are return values, not exceptions. The SDKs only raise/throw for transport-level problems (network, auth, rate limits — see Retries & errors).
Authentication
| Credential | Client option | Used for |
|---|---|---|
| agent_key_live_… / agent_key_test_… | apiKey / api_key (env UPIVIA_API_KEY) | Agent endpoints: service requests, spawn, delegation, budget check, memory reads. |
| upivia_pat_live_… | pat (env UPIVIA_PAT) | Workspace endpoints: balance, usage, audit logs, teams, chat sessions, health. Mint at /settings/tokens. |
| Cookie session | custom fetch / transport | Cookie-session-only endpoints (marked in each method's docs): agent update/delete, workflows, triggers, storage, knowledge. |
Auth is chosen per endpoint, not per client: agent endpoints send Bearer <apiKey>; workspace endpoints send Bearer <pat> when a PAT is configured, and otherwise send no auth header so an injected cookie-bearing fetch/transport can carry the session. Cookie-session-only endpoints reject PATs server-side.
Test-mode agent keys (agent_key_test_…) route every request to mock adapters and never debit your balance — same code, same outcomes, $0.00 cost.
Service requests
Idempotency
create() auto-generates a UUID v4 idempotency key when you don't pass one, which also makes the POST retry-safe. Replays with the same key and identical payload return the cached response; same key with a different payload is a 409.
Async operations: the running state
Reconcilable operations (real voice calls, long provider jobs) may return HTTP 202 with status: "running". Poll get(id) yourself, or let createAndWait() / create_and_wait() poll until a terminal status (executed | failed | blocked) with exponential backoff (2s start, ×1.5, cap 10s, 5-minute default budget):
Streaming chat
chat.sessions manages conversations; chat.turn runs one turn as the session's agent and streams Server-Sent Events. In TypeScript it returns an async-iterable ChatTurnStream; in Python chat.turn is a generator (async generator on AsyncUpiviaClient) of ChatStreamEvents.
Event vocabulary
| Event | Meaning |
|---|---|
| model | Which model is serving the turn. |
| status | Progress message (planning, executing, …). |
| thinking | Reasoning delta (when the model exposes it). |
| message_delta | Live assistant text chunk. |
| tool_planned / tool_executing / tool_done | A governed service call: planned → running → finished (with cost_cents). |
| tool_pending | Tool call paused on approval — resolve via chat.resolveApproval, resume the turn with continue_from. |
| usage | Token counts and cost for the turn. |
| message | Final assembled assistant message. |
| done / error | Terminal events. |
Pagination
List endpoints return next_cursor; resources with cursor pagination also expose iter(), an (async) generator that walks every page for you. Available on auditLogs, agents.activityIter, storage.objects, knowledge.collections, and triggers.
Retries & errors
Automatic retry policy
| Aspect | Behavior |
|---|---|
| What retries | Network errors and HTTP 429 / 502 / 503 / 504. |
| Which requests | GETs always; mutations only when idempotent (service-request creates carry an Idempotency-Key). |
| Retry-After | Honored on 429; also surfaced as err.retryAfter / err.retry_after (seconds). |
| Backoff | Exponential with full jitter: 500ms · 2^attempt, capped at 8s. |
| Attempts | maxRetries / max_retries, default 2 (0 disables). |
Error kinds
All transport failures raise a single UpiviaError; branch on kind: network · unauthorized (401/403) · rate_limited (429) · idempotency_conflict (409) · http (other non-2xx) · invalid_response (body wasn't JSON). The server's error code (err.code) is typed as the ApiErrorCode union — policy_block, insufficient_balance, agent_budget_exceeded, adapter_error, and friends — kept open so new server codes never break compilation.
Agents & orchestration
Agents CRUD
Spawn & delegate
A parent agent can spawn bounded children (services ⊆ parent's, budget deducted from the parent, max chain depth 3) and delegate objectives with a hard budget cap and narrowed permissions. The delegated-task state machine advances accepted → in_progress → completed | failed on the child side, with cancelled reserved for the parent.
Workflows
Workflows are DAGs of governed steps. You create a shell, save versions (steps + edges), request publication, and run. Publishing is governed: publishVersion creates a PublishRequest that an admin must approve in Tasks → Publishing — the version is not live immediately.
Error recovery lives on workflows.runs: cancel, rerunFailed (batch-retry all failed steps), and retryStep for a single step.
Triggers & webhooks
Triggers turn cron schedules and inbound webhooks into governed service requests. The create response contains the signing secret exactly once (never re-readable — rotate via delete + recreate) and, for webhooks, a fire_url. fire() serializes your payload once, signs that exact raw JSON with HMAC-SHA256, and sends X-AgentWallet-Signature: sha256=<hex> — no Bearer header at all.
Storage & knowledge
Deletes are soft with a 7-day restore window (objects.restore); objects.download resolves the time-limited signed URL without following the 302.
Framework integrations
@agentwallet/ai-sdk — Vercel AI SDK
Turns every enabled Upivia service into a typed AI SDK tool with its JSON Schema and a dollar cost hint; each tool returns the same discriminated outcome union the model can branch on.
import { openai } from "@ai-sdk/openai";
import { streamText } from "ai";
import { createAgentWalletTools } from "@agentwallet/ai-sdk";
const tools = await createAgentWalletTools({
apiKey: process.env.UPIVIA_API_KEY!,
baseUrl: "https://www.upivia.com",
});
const result = streamText({
model: openai("gpt-4o"),
tools,
prompt: "Send an email to user@example.com saying hi.",
});@agentwallet/mcp — MCP server
A stdio MCP server exposing the service catalog as tools (email.send → email_send) for Claude Desktop, Cursor, and any MCP-aware client:
{
"mcpServers": {
"upivia": {
"command": "npx",
"args": ["-y", "@agentwallet/mcp"],
"env": {
"AGENTWALLET_API_KEY": "agent_key_test_...",
"AGENTWALLET_BASE_URL": "https://www.upivia.com"
}
}
}
}Python — LangGraph toolkit
upivia.integrations.langgraph wraps governed service operations as LangChain-compatible tools, so LangGraph agents route tool calls through the policy/budget/approval/audit pipeline instead of calling providers directly:
from upivia import UpiviaClient from upivia.integrations.langgraph import UpiviaToolkit client = UpiviaClient() # env: UPIVIA_API_KEY, UPIVIA_BASE_URL toolkit = UpiviaToolkit(client) # or pass explicit (service, op, desc) tuples tools = toolkit.as_langchain_tools() # drop into any LangGraph agent
Resource reference
Every resource, TypeScript name / Python name, and its methods. Python mirrors the TypeScript surface exactly in snake_case (createAndWait → create_and_wait, resolveApproval → resolve_approval, …).
| TypeScript / Python | Methods |
|---|---|
| serviceRequests / service_requests | create, get, createAndWait |
| balance | get({teamId?}) |
| usage | list({agentId?, from?, to?, limit?, includeChart?}) |
| approvals | list, approve, reject |
| auditLogs / audit_logs | list, iter |
| agents | list, create, get, update, delete, resetKey, clone, transfer, setBudget, enableService, disableService, health, fleetHealth, activity, activityIter, skills, removeSkill |
| spawn | create, estimate |
| delegate | create, list, getTask, updateTask, reattach |
| memory | list, search, create, update, delete, graph |
| workflows | list, create, get, update, delete, createVersion, publishVersion, unpublishVersion, share, export, runAndWait · runs.list/create/get/cancel/rerunFailed/retryStep · agents.list/grant/revoke · fromTemplate.list/create |
| scheduledTasks / scheduled_tasks | list, create, get, update, delete, runs |
| agentRequests / agent_requests | list, create, resolve |
| budgetCheck / budget_check | check(agentId) |
| chat | turn (SSE stream), resolveApproval · sessions.list/create/get/delete/deleteAll |
| triggers | list, iter, create, get, update, delete, fire (HMAC-signed) |
| storage | objects.list/iter/get/delete/restore/upload/presign/confirm/download |
| knowledge | collections.list/iter/create/get/delete · documents.create/get/delete |
| services | list (public catalog) |
| teams | list, switch, budget, allocateBudget · members.list/update |
| workspaces | list, switch |
| budgetRequests / budget_requests | create, list, resolve |
| devices | heartbeat · sessions.list/update/command/delete/cwd · commands.update |
| platform | health, readiness, agentDocs |
The machine-readable spec at GET /api/v1/agent-docs (no auth) covers the same surface for agent self-discovery — see the API Reference.