@ovra/ts-sdk
v0.5.4
Published
Official TypeScript SDK for the Ovra API — payment infrastructure for AI agents.
Maintainers
Readme
Ovra SDK for TypeScript
The Ovra SDK for TypeScript provides access to the Ovra API — payment infrastructure for AI agents — from server-side TypeScript or JavaScript.
Documentation
Installation
npm install @ovra/ts-sdkGetting started
import { Ovra } from "@ovra/ts-sdk";
const ovra = new Ovra({
apiKey: process.env.OVRA_API_KEY!, // sk_test_… in sandbox, sk_live_… in prod
});
const result = await ovra.pay({
agentId: "agt_…",
offerId: "aic_openai-1000",
merchant: "OpenAI",
amount: 10.0,
purpose: "Top up OpenAI credits",
});
console.log(result.orderId); // cmo_…ovra.pay() declares the intent, runs the policy gate, debits the wallet,
mints the DPAN, signs the 4-mandate AP2 chain, captures with the merchant,
and returns the order envelope in a single round-trip.
Need the lower-level primitives (custom approval UI, manual intent, raw generated operations)? See the docs.
Requirements
Node.js 20+, or any runtime with global fetch (Bun, Deno, Cloudflare
Workers, Vercel Edge).
Authentication
The constructor accepts any Ovra credential prefix. Pick the smallest scope that fits the call site.
| Prefix | What | Use when |
| -------------- | --------------------- | ------------------------------------------------------------------------------ |
| sk_live_… | Full live key | Server-side prod code that mints / rotates / manages. |
| sk_test_… | Full sandbox key | Local dev + CI. Every envelope returns livemode: false. |
| rk_… | Restricted key | Read + scoped writes. Blocked from keys / webhooks / billing / policies. |
| at_… | Agent token | Bound to one agent with a hard spend cap. Safe to ship to an agent runtime. |
const ovra = new Ovra({
apiKey: process.env.OVRA_API_KEY!,
appInfo: { name: "AcmeCRM", version: "1.4.2" }, // X-Ovra-Client-App
});
// Dev-time scope hint (not enforced — server is the source of truth):
console.log(ovra.keyScope); // "full" | "restricted" | "agent" | "unknown"Errors
Errors are typed exceptions per category — branch on e.code (machine-
readable), show e.message to humans, link to e.docUrl from your own UI.
import { OvraError } from "@ovra/ts-sdk";
try {
await ovra.pay({ agentId, offerId, merchant, amount });
} catch (e) {
if (!(e instanceof OvraError)) throw e;
switch (e.code) {
case "E_INSUFFICIENT_FUNDS": return topUpAndRetry();
case "E_POLICY_LIMIT_EXCEEDED": return showLimits(e.message);
case "E_OFFER_EXPIRED": return refreshOffer();
case "E_FSM_INVALID_TRANSITION": return refetchOrder();
default: return reportError(e.message, e.docUrl);
}
}Every envelope carries code, type, message, param, docUrl,
requestId, status.
Idempotency
Every mutating call is idempotent by default — the SDK mints a UUID
Idempotency-Key per logical operation and reuses it across retries.
Replays inside the 24h dedup window return the original response with
X-Idempotent-Replayed: true. Pass your own key for cross-process dedup:
await ovra.intents.create({
body: { agent: "agt_…", merchant: "Notion", amount: { amount: 7900, currency: "eur" }, purpose: "…" },
headers: { "Idempotency-Key": "your-stable-key" },
});MCP server
Want to call Ovra from Claude / Cursor / any MCP client? The same surface
ships as @ovra/mcp (10 tools).
Add to .mcp.json:
{
"mcpServers": {
"ovra": {
"command": "npx",
"args": ["-y", "@ovra/mcp"],
"env": { "OVRA_API_KEY": "sk_test_…" }
}
}
}Resource coverage
33 typed namespaces — agents, cards, wallets, intents, transactions, agentic-commerce (search / buy / order / refund / verify), policies, delegations, customers, disputes, webhooks, audit, billing, and 20 more. Generated functions for every operation are also accessible as raw exports.
Support
License
UNLICENSED — internal use only until the public release lands.
