# Sardis Sardis is the Payment OS for the Agent Economy, providing infrastructure that enables AI agents to make real financial transactions safely. The platform offers non-custodial MPC wallets with natural language spending policies that prevent financial hallucinations—where agents accidentally spend $10,000 instead of $100. Through a real-time policy firewall, every transaction is validated before execution, ensuring that AI agents from Claude, LangChain, OpenAI, or any other framework operate within programmable guardrails like "Max $100/day on cloud services, only approved vendors." The platform executes stablecoin payments (USDC) primarily on Base with multi-chain funding via CCTP v2 from Ethereum, Polygon, Arbitrum, and Optimism. Sardis integrates with 9+ AI frameworks through MCP, LangChain, CrewAI, OpenAI Functions, Vercel AI SDK, and more. Key features include spending policy engine (production), AP2 mandate verification (production), policy attestation API (production), virtual cards via Stripe Issuing (pilot), and ERC-8183 agentic jobs (pilot). The architecture follows a fail-closed design where any policy, compliance, or security check failure blocks the transaction. ## Installation Install the SDK for your language and framework. ```bash # Python SDK pip install sardis # TypeScript SDK npm install @sardis/sdk # MCP Server (Claude Desktop, Cursor) npx @sardis/mcp-server start # LangChain integration pip install sardis-langchain # CrewAI integration pip install sardis-crewai # Vercel AI SDK npm install @sardis/ai-sdk ``` ## Python SDK - Basic Payment Execute a simple payment from an agent's wallet. ```python import asyncio from sardis import SardisClient async def make_payment(): client = SardisClient(api_key="sk_live_...") # Create a payment result = await client.payments.create( agent_id="agent_abc", amount="50.00", token="USDC", recipient="merchant@example.com" ) print(f"Payment: {result.tx_hash}") print(f"Status: {result.status}") # Output: # Payment: 0xabc123... # Status: confirmed asyncio.run(make_payment()) ``` ## Python SDK - Async Client with Wallets Create agents, wallets, and execute transfers with the async client. ```python import asyncio from sardis_sdk import AsyncSardisClient, RetryConfig, TimeoutConfig async def wallet_operations(): async with AsyncSardisClient( api_key="sk_live_...", base_url="https://api.sardis.sh", timeout=TimeoutConfig(connect=10.0, read=30.0), retry=RetryConfig(max_retries=3), ) as client: # Create an agent agent = await client.agents.create( name="procurement-agent", description="Handles API purchases" ) # Create a wallet for the agent wallet = await client.wallets.create( agent_id=agent.agent_id, chain="base", currency="USDC", limit_per_tx="100.00", limit_daily="500.00" ) # Get wallet balance balance = await client.wallets.get_balance( wallet.wallet_id, token="USDC", chain="base" ) print(f"Balance: {balance.balance} USDC") # Execute a transfer tx = await client.wallets.transfer( wallet.wallet_id, destination="0xRecipient...", amount="25.00", token="USDC", chain="base", memo="API credits purchase" ) print(f"Transaction: {tx.tx_hash}") print(f"Status: {tx.status}") asyncio.run(wallet_operations()) ``` ## TypeScript SDK - Basic Usage Create agents and wallets with the TypeScript SDK. ```typescript import { SardisClient } from '@sardis/sdk'; const client = new SardisClient({ apiKey: 'sk_live_...' }); async function main() { // Create an agent const agent = await client.agents.create({ name: 'my-agent', description: 'Shopping assistant' }); // Create a wallet with spending limits const wallet = await client.wallets.create({ agent_id: agent.agent_id, currency: 'USDC', limit_per_tx: '100.00', limit_daily: '500.00', }); // Execute a transfer const tx = await client.wallets.transfer(wallet.wallet_id, { destination: '0xRecipient...', amount: '25.00', token: 'USDC', chain: 'base', domain: 'openai.com', }); console.log(`Transaction: ${tx.tx_hash}`); console.log(`Status: ${tx.status}`); } main(); ``` ## MCP Server Configuration Configure Sardis MCP server for Claude Desktop or Cursor. ```json { "mcpServers": { "sardis": { "command": "npx", "args": ["@sardis/mcp-server", "start"], "env": { "SARDIS_API_KEY": "sk_live_...", "SARDIS_WALLET_ID": "wallet_abc123", "SARDIS_AGENT_ID": "agent_xyz", "SARDIS_CHAIN": "base", "SARDIS_MODE": "live" } } } } ``` ## MCP Server - Available Tools The MCP server exposes these tools to AI agents. ```typescript // Available MCP tools: // Wallet Operations sardis_get_wallet // Get wallet info sardis_get_balance // Get current balance // Payment Operations sardis_pay // Execute a payment (rate limited: 5/min) sardis_get_transaction // Get transaction details sardis_list_transactions // List transaction history // Policy Operations sardis_check_policy // Validate payment against policy sardis_validate_limits // Check spending limits sardis_check_compliance // Verify compliance rules // Hold Operations (for escrow flows) sardis_create_hold // Create payment hold sardis_capture_hold // Capture held funds sardis_void_hold // Release held funds sardis_get_hold // Get hold status sardis_list_holds // List active holds sardis_extend_hold // Extend hold expiry // Agent Management sardis_create_agent // Create new agent sardis_get_agent // Get agent details sardis_list_agents // List all agents sardis_update_agent // Update agent config ``` ## REST API - Payment Objects Mint and manage payment objects with the REST API. ```bash # Mint a payment object from a mandate curl -X POST https://api.sardis.sh/api/v2/payment-objects/mint \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "mandate_id": "mandate_abc123", "merchant_id": "merch_xyz789", "amount": "25.00", "currency": "USDC", "privacy_tier": "transparent", "memo": "Invoice #1042", "expires_in_seconds": 3600, "metadata": { "order_id": "ord_001" } }' # Response: # { # "object_id": "po_a1b2c3d4e5f6", # "mandate_id": "mandate_abc123", # "merchant_id": "merch_xyz789", # "exact_amount": "25.00", # "currency": "USDC", # "status": "minted", # "privacy_tier": "transparent", # "cell_ids": ["cell_aaa111", "cell_bbb222"], # "expires_at": "2026-03-23T13:00:00+00:00" # } # Present payment to merchant curl -X POST https://api.sardis.sh/api/v2/payment-objects/po_a1b2c3d4e5f6/present \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "merchant_id": "merch_xyz789", "merchant_signature": "0xabc..." }' # Verify payment (merchant-side) curl -X POST https://api.sardis.sh/api/v2/payment-objects/po_a1b2c3d4e5f6/verify \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "merchant_id": "merch_xyz789", "merchant_signature": "0xdef..." }' ``` ## REST API - Funding Commitments Create UTXO-style funding commitments and manage cells. ```bash # Create a funding commitment with fixed denomination cells curl -X POST https://api.sardis.sh/api/v2/funding/commit \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "vault_ref": "0x1234...abcd", "total_value": "1000.00", "currency": "USDC", "cell_strategy": "fixed", "cell_denomination": "100.00", "settlement_preferences": { "chain": "tempo" }, "expires_in_seconds": 604800 }' # Response: # { # "commitment_id": "fcom_a1b2c3d4e5f6", # "total_value": "1000.00", # "remaining_value": "1000.00", # "currency": "USDC", # "cell_count": 10, # "status": "active" # } # Split a cell into smaller denominations curl -X POST https://api.sardis.sh/api/v2/funding/cells/cell_aaa111/split \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "amounts": ["60.00", "40.00"] }' # Merge multiple cells curl -X POST https://api.sardis.sh/api/v2/funding/cells/merge \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "cell_ids": ["cell_aaa111", "cell_bbb222", "cell_ccc333"] }' ``` ## REST API - FX Swaps Get quotes and execute stablecoin swaps. ```bash # Get FX rates curl https://api.sardis.sh/api/v2/fx/rates \ -H "Authorization: Bearer sk_live_..." # Response: # { # "rates": [ # { "from": "USDC", "to": "EURC", "rate": "0.9215", "provider": "tempo_dex" }, # { "from": "EURC", "to": "USDC", "rate": "1.0852", "provider": "tempo_dex" } # ] # } # Get a quote (valid for 30 seconds) curl -X POST https://api.sardis.sh/api/v2/fx/quote \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "from_currency": "USDC", "to_currency": "EURC", "from_amount": "1000.00", "chain": "tempo", "slippage_bps": 50 }' # Execute the swap before expiry curl -X POST https://api.sardis.sh/api/v2/fx/execute \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "quote_id": "fxq_a1b2c3d4e5f6" }' ``` ## REST API - Batch Payments Execute atomic multi-transfer payments on Tempo. ```bash # Batch payroll payment (all succeed or all fail) curl -X POST https://api.sardis.sh/api/v2/payments/batch \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "transfers": [ { "to": "0xAlice...", "amount": "2500.00", "token": "USDC", "memo": "March salary" }, { "to": "0xBob...", "amount": "3000.00", "token": "USDC", "memo": "March salary" }, { "to": "0xCarol...", "amount": "2800.00", "token": "USDC", "memo": "March salary" } ], "chain": "tempo", "mandate_id": "mandate_payroll" }' # Response: # { # "tx_hash": "0xabc123...", # "chain": "tempo", # "transfer_count": 3, # "total_amount": "8300.00", # "status": "confirmed", # "transfers": [ # { "index": 0, "to": "0xAlice...", "amount": "2500.00", "status": "included" }, # { "index": 1, "to": "0xBob...", "amount": "3000.00", "status": "included" }, # { "index": 2, "to": "0xCarol...", "amount": "2800.00", "status": "included" } # ] # } ``` ## REST API - Escrow Flow Create escrow holds with delivery confirmation and dispute handling. ```bash # Create an escrow hold curl -X POST https://api.sardis.sh/api/v2/escrow \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "payment_object_id": "po_a1b2c3d4e5f6", "merchant_id": "merch_xyz789", "amount": "250.00", "currency": "USDC", "timelock_hours": 72, "chain": "tempo", "metadata": { "order_id": "ord_555" } }' # Confirm delivery (releases funds to merchant) curl -X POST https://api.sardis.sh/api/v2/escrow/esc_a1b2c3d4e5f6/confirm-delivery \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "evidence": { "tracking_number": "1Z999AA10123456784" } }' # Or file a dispute curl -X POST https://api.sardis.sh/api/v2/escrow/esc_a1b2c3d4e5f6/dispute \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "reason": "not_delivered", "description": "Item was not delivered within the agreed timeframe." }' # Submit evidence curl -X POST https://api.sardis.sh/api/v2/disputes/disp_xyz789/evidence \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "party": "payer", "evidence_type": "screenshot", "content": { "url": "https://example.com/screenshot.png" }, "description": "Screenshot showing order status: not shipped" }' # Resolve dispute curl -X POST https://api.sardis.sh/api/v2/disputes/disp_xyz789/resolve \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "outcome": "resolved_refund", "payer_amount": "250.00", "merchant_amount": "0.00", "reasoning": "Merchant failed to provide proof of delivery." }' ``` ## REST API - Streaming Payments Open pay-per-use streaming channels for real-time micropayments. ```bash # Open a streaming payment channel curl -X POST https://api.sardis.sh/api/v2/payments/stream/open \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "service_address": "0xServiceProvider...", "deposit_amount": "50.00", "token": "USDC", "unit_price": "0.001", "max_units": 50000, "duration_hours": 24 }' # Response: # { # "stream_id": "stream_a1b2c3d4e5f6", # "channel_id": "ch_xyz789", # "deposit_amount": "50.00", # "unit_price": "0.001", # "status": "open", # "sse_url": "/api/v2/payments/stream/stream_a1b2c3d4e5f6/events" # } # Consume units (e.g., LLM tokens) curl -X POST https://api.sardis.sh/api/v2/payments/stream/stream_a1b2c3d4e5f6/consume \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "stream_id": "stream_a1b2c3d4e5f6", "units": 100, "metadata": { "request_id": "req_001" } }' # Settle and close the stream curl -X POST https://api.sardis.sh/api/v2/payments/stream/stream_a1b2c3d4e5f6/settle \ -H "Authorization: Bearer sk_live_..." ``` ## REST API - Mandate Delegation Create hierarchical mandate trees with narrowed bounds. ```bash # Delegate from parent mandate to child with narrowed limits curl -X POST https://api.sardis.sh/api/v2/mandates/mandate_abc123/delegate \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "agent_id": "agent_research_01", "purpose_scope": "API hosting expenses", "amount_per_tx": "50.00", "amount_daily": "200.00", "amount_monthly": "2000.00", "amount_total": "5000.00", "merchant_scope": { "categories": ["cloud_infrastructure"] }, "allowed_rails": ["usdc"], "allowed_chains": ["tempo", "base"], "allowed_tokens": ["USDC"], "expires_at": "2026-06-23T00:00:00Z", "approval_mode": "auto" }' # Get full delegation tree curl https://api.sardis.sh/api/v2/mandates/mandate_abc123/tree \ -H "Authorization: Bearer sk_live_..." ``` ## LangChain Integration Use Sardis tools with LangChain agents. ```python from langchain.agents import initialize_agent, AgentType from langchain_openai import ChatOpenAI from sardis import SardisClient from sardis_langchain import SardisToolkit # Initialize Sardis client and toolkit client = SardisClient(api_key="sk_live_...") wallet = client.wallets.create( name="langchain-agent", chain="base", policy="Max $100/tx, $500/day" ) toolkit = SardisToolkit(client=client, wallet_id=wallet.wallet_id) tools = toolkit.get_tools() # Create LangChain agent with Sardis tools llm = ChatOpenAI(model="gpt-4o", temperature=0) agent = initialize_agent( tools=tools, llm=llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True ) # Run the agent result = agent.run( "Check my balance, then pay $25 to openai.com for API credits" ) print(result) # Output: Successfully paid $25.00 to openai.com. Transaction: 0xabc123... ``` ## CrewAI Integration Add payment capabilities to CrewAI agents. ```python from crewai import Agent, Task, Crew from sardis import SardisClient from sardis_crewai import create_sardis_toolkit # Initialize Sardis client = SardisClient(api_key="sk_live_...") # Create Sardis toolkit for CrewAI sardis_tools = create_sardis_toolkit( client=client, wallet_id="wallet_abc123" ) # Create a procurement agent with payment tools procurement_agent = Agent( role="Procurement Specialist", goal="Purchase required services within budget limits", backstory="Expert at finding the best deals while staying within policy", tools=sardis_tools, verbose=True ) # Define a procurement task procurement_task = Task( description=""" 1. Check current wallet balance 2. Verify $50 payment to vendor 'anthropic' passes policy 3. If allowed, execute the payment for API credits 4. Report the transaction status """, expected_output="Payment confirmation or policy denial with reason", agent=procurement_agent ) # Run the crew crew = Crew( agents=[procurement_agent], tasks=[procurement_task], verbose=True ) result = crew.kickoff() print(result) ``` ## Vercel AI SDK Integration Enable payments in Vercel AI SDK applications. ```typescript import { generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; import { createSardisTools, SardisProvider } from '@sardis/ai-sdk'; // Option 1: Simple tool creation const tools = createSardisTools({ apiKey: process.env.SARDIS_API_KEY!, walletId: 'wallet_abc123', }); const { text, toolResults } = await generateText({ model: openai('gpt-4o'), tools, prompt: 'Pay $50 to merchant_xyz for API credits', }); console.log(text); console.log(toolResults); // Option 2: Full provider with callbacks const sardis = new SardisProvider({ apiKey: process.env.SARDIS_API_KEY!, walletId: 'wallet_abc123', enableLogging: true, onTransaction: async (event) => { console.log(`Transaction ${event.type}: ${event.tx_hash}`); await logToDatabase(event); }, }); const { text: result } = await generateText({ model: openai('gpt-4o'), tools: sardis.tools, system: sardis.systemPrompt, prompt: 'Check my balance and pay $25 for API credits', }); // Direct API access const balance = await sardis.getBalance(); const payment = await sardis.pay({ to: 'merchant', amount: 25 }); ``` ## Smart Contract - ERC-8183 Job Manager The SardisJobManager implements ERC-8183 for escrow-based agentic jobs. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@sardis/contracts/SardisJobManager.sol"; // Creating a job SardisJobManager jobManager = SardisJobManager(jobManagerAddress); // 1. Create job with provider and evaluator uint256 jobId = jobManager.createJob( provider, // address - service provider evaluator, // address - arbiter/evaluator block.timestamp + 7 days, // expiry "Build smart contract for NFT marketplace", address(0) // optional hook contract ); // 2. Set budget (client or provider can propose) jobManager.setBudget( jobId, 1000 * 1e6, // 1000 USDC (6 decimals) abi.encode(usdcAddress) // token in optParams ); // 3. Fund the job (transitions: Open -> Funded) IERC20(usdc).approve(address(jobManager), 1010 * 1e6); // budget + fee jobManager.fund(jobId, 1000 * 1e6, ""); // 4. Provider submits deliverable (transitions: Funded -> Submitted) bytes32 deliverable = keccak256(abi.encode("ipfs://Qm...")); jobManager.submit(jobId, deliverable, ""); // 5. Evaluator completes the job (transitions: Submitted -> Completed) // Funds are released to provider jobManager.complete(jobId, keccak256("approved"), ""); // Or: Evaluator rejects (transitions: Submitted -> Rejected) // Funds are refunded to client jobManager.reject(jobId, keccak256("quality_issues"), ""); // Or: Client claims refund after expiry (transitions: Funded/Submitted -> Expired) jobManager.claimRefund(jobId); ``` ## Error Handling Handle SDK errors with typed exceptions. ```python from sardis_sdk import AsyncSardisClient from sardis_sdk.models.errors import ( SardisAPIError, AuthenticationError, NotFoundError, ValidationError, RateLimitError, ) async def safe_payment(): async with AsyncSardisClient(api_key="sk_live_...") as client: try: result = await client.wallets.transfer( "wallet_123", destination="0xRecipient...", amount="1000.00", token="USDC" ) return result except AuthenticationError: print("Invalid API key") except NotFoundError as e: print(f"Wallet not found: {e.message}") except ValidationError as e: print(f"Validation failed: {e.details}") except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after}s") except SardisAPIError as e: print(f"API error {e.status_code}: {e.message}") ``` ```typescript import { SardisAPIError, SardisNotFoundError, SardisValidationError, SardisRateLimitError, } from '@sardis/sdk'; try { const tx = await client.wallets.transfer(walletId, { destination: '0xRecipient...', amount: '1000.00', token: 'USDC', }); } catch (e) { if (e instanceof SardisNotFoundError) { console.error('Wallet not found'); } else if (e instanceof SardisValidationError) { console.error(`Validation error: ${e.detail}`); } else if (e instanceof SardisRateLimitError) { console.error(`Rate limited. Retry after ${e.retryAfter}s`); } else if (e instanceof SardisAPIError) { console.error(`API error ${e.statusCode}: ${e.detail}`); } } ``` ## Environment Configuration Configure Sardis via environment variables. ```bash # Required export SARDIS_API_KEY=sk_live_... # Optional - API Configuration export SARDIS_API_URL=https://api.sardis.sh # Default API URL export SARDIS_WALLET_ID=wallet_abc123 # Default wallet export SARDIS_AGENT_ID=agent_xyz # Agent attribution export SARDIS_CHAIN=base # Default chain # Optional - MCP Server Configuration export SARDIS_MODE=live # 'live' or 'simulated' export SARDIS_POLICY_BLOCKED_VENDORS=gambling,adult export SARDIS_POLICY_ALLOWED_VENDORS=openai,anthropic,aws export SARDIS_REQUIRE_EXPLICIT_APPROVAL=false # Optional - Infrastructure export DATABASE_URL=postgresql://... # For self-hosted API export TURNKEY_API_KEY=... # MPC custody export TURNKEY_ORGANIZATION_ID=... ``` ## Supported Chains and Tokens Sardis supports multiple chains and stablecoins. | Chain | Tokens | Status | |-------|--------|--------| | Base | USDC, EURC | Production | | Polygon | USDC, USDT, EURC | Experimental | | Ethereum | USDC, USDT, PYUSD, EURC | Experimental | | Arbitrum | USDC, USDT | Experimental | | Optimism | USDC, USDT | Experimental | | Tempo (Arc) | USDC, EURC | Production | Sardis serves as the financial infrastructure layer for AI agents across the entire agent economy. The primary use cases include autonomous agents making API purchases (OpenAI, Anthropic, cloud providers), multi-agent systems with hierarchical spending mandates, e-commerce agents with escrow-protected transactions, and SaaS agents managing subscription payments. The platform's policy engine enables organizations to safely delegate financial capabilities to AI agents while maintaining strict guardrails and audit trails. Integration patterns typically involve creating an agent identity, provisioning a wallet with natural language policies, and then connecting the SDK/MCP tools to your AI framework. For LangChain and CrewAI, use the dedicated toolkit packages. For Vercel AI SDK, use the provider class. For custom integrations, the REST API provides full access to all platform capabilities. The fail-closed architecture ensures that any transaction that doesn't pass policy checks, compliance validation, or security gates is automatically blocked, making Sardis suitable for production deployment where financial safety is paramount.