# Sardis - Complete Reference for LLMs

> Payment OS for the Agent Economy
> Prevent Financial Hallucinations with Non-custodial MPC wallets and natural language spending policies

---

## Table of Contents

1. Overview
2. Core Concepts
3. Python SDK
4. TypeScript SDK
5. MCP Server
6. REST API
7. Protocols (AP2, TAP, UCP, A2A, x402)
8. Fiat Rails
9. Virtual Cards
10. Compliance
11. Error Handling
12. Best Practices

---

## 1. Overview

### What is Sardis?

Sardis is the **Policy Firewall for Agent Payments** - payment infrastructure that enables AI agents to make real financial transactions while staying within human-defined guardrails. It solves the fundamental problem of agent autonomy vs. control, preventing "financial hallucinations" where agents overspend or transact inappropriately.

### The Problem

AI agents need to spend money to be useful (API credits, subscriptions, services), but:
- Giving agents full access is dangerous (they may overspend)
- Manual approval for everything defeats automation
- API keys with crude limits lack nuance
- Agents get blocked by 2FA, CAPTCHAs, and human-centric security

### The Solution

Sardis provides:
- **Non-custodial wallets**: Agents control wallets via MPC, users maintain ownership
- **Natural language policies**: Define rules in plain English ("Max $100/day on cloud services")
- **Real-time enforcement**: Every transaction checked against policies before signing
- **Complete audit trail**: Full visibility into agent spending
- **Multi-rail payments**: Crypto (stablecoins) + fiat (virtual cards, bank transfers)

### Key Differentiators

| Feature | Sardis | Traditional |
|---------|--------|-------------|
| Custody | Non-custodial (MPC) | Custodial |
| Policies | Natural language | Code/JSON only |
| Protocols | AP2, TAP, UCP, A2A, x402 | Proprietary |
| Chains | 5 (Base, Polygon, ETH, Arb, OP) | Usually 1-2 |
| Cards | Virtual cards (Lithic) | Rarely |
| Fiat Rails | ACH, Wire, Card funding | Crypto only |
| Compliance | KYC + AML built-in | Add-on |

---

## 2. Core Concepts

### Wallets

Sardis wallets are non-custodial smart contract wallets powered by Turnkey MPC:

```python
wallet = client.wallets.create(
    name="my-agent-wallet",
    chain="base",  # base, polygon, ethereum, arbitrum, optimism
    policy={
        "max_daily": "100.00",
        "max_per_tx": "25.00",
        "allowed_merchants": ["openai.com"],
        "require_approval_above": "50.00"
    }
)

# Wallet properties
wallet.id          # Unique identifier
wallet.address     # On-chain address (0x...)
wallet.chain       # Chain identifier
wallet.balance     # Current balance
wallet.policy      # Active policy
```

### Policies

Policies define what an agent can and cannot do:

#### Natural Language Format
```python
policy = "Max $100/day on cloud services, only approved vendors, require approval over $50"
```

#### Structured Format
```python
policy = {
    "max_daily": "100.00",           # Maximum per day
    "max_per_tx": "50.00",           # Maximum per transaction
    "max_monthly": "2000.00",        # Maximum per month
    "allowed_merchants": [            # Whitelist
        "openai.com",
        "anthropic.com",
        "aws.amazon.com"
    ],
    "blocked_categories": [           # Blacklist by category
        "gambling",
        "adult",
        "crypto_exchange"
    ],
    "require_approval_above": "50.00", # Human approval threshold
    "allowed_hours": {                 # Time restrictions
        "start": "09:00",
        "end": "18:00",
        "timezone": "America/New_York"
    },
    "allowed_days": ["mon", "tue", "wed", "thu", "fri"]
}
```

#### Policy Validation
```python
# Check if a transaction would be allowed
result = wallet.check_policy(
    amount="75.00",
    merchant="openai.com"
)

if result.allowed:
    wallet.pay(...)
else:
    print(f"Blocked: {result.reason}")
    # "Blocked: Amount exceeds require_approval_above threshold"
```

### Transactions

```python
# Simple payment
tx = wallet.pay(
    to="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
    amount="25.00",
    token="USDC"
)

# Payment with metadata
tx = wallet.pay(
    to="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD68",
    amount="25.00",
    token="USDC",
    memo="Monthly API credits",
    metadata={
        "invoice_id": "INV-001",
        "agent_reasoning": "Purchasing credits for next month"
    }
)

# Transaction result
tx.id           # Transaction ID
tx.tx_hash      # On-chain transaction hash
tx.status       # pending, confirmed, failed
tx.amount       # Amount in token
tx.token        # Token symbol
tx.to           # Recipient address
tx.created_at   # Timestamp
tx.policy_check # Policy validation result
```

### Holds (Pre-authorization)

```python
# Create a hold (reserve funds without spending)
hold = wallet.create_hold(
    amount="100.00",
    token="USDC",
    merchant="travel-service.com",
    expires_in=3600  # 1 hour
)

# Capture the hold (complete the transaction)
tx = hold.capture(amount="85.00")  # Capture partial amount

# Release the hold (cancel)
hold.release()
```

---

## 3. Python SDK

### Installation

```bash
pip install sardis
```

### Initialization

```python
from sardis import Sardis

# With API key
client = Sardis(api_key="sk_live_...")

# With environment variable (SARDIS_API_KEY)
client = Sardis()

# Sandbox mode
client = Sardis(api_key="sk_test_...", sandbox=True)
```

### Wallet Operations

```python
# Create wallet
wallet = client.wallets.create(
    name="agent-wallet",
    chain="base",
    policy="Max $100/day"
)

# List wallets
wallets = client.wallets.list()

# Get wallet by ID
wallet = client.wallets.get("wallet_123")

# Get balance
balance = wallet.balance()
# {"USDC": "150.00", "EURC": "50.00"}

# Update policy
wallet.update_policy("Max $200/day, require approval over $100")

# Fund wallet (returns deposit address)
deposit = wallet.get_deposit_address()
```

### Transaction Operations

```python
# Make payment
tx = wallet.pay(
    to="0x...",
    amount="50.00",
    token="USDC",
    memo="API credits"
)

# List transactions
txs = wallet.transactions.list(
    limit=50,
    status="confirmed"
)

# Get transaction
tx = wallet.transactions.get("tx_123")

# Wait for confirmation
tx.wait_for_confirmation(timeout=60)
```

### Async Support

```python
import asyncio
from sardis import AsyncSardis

async def main():
    client = AsyncSardis(api_key="sk_...")

    wallet = await client.wallets.create(
        name="async-wallet",
        chain="base",
        policy="Max $100/day"
    )

    tx = await wallet.pay(
        to="0x...",
        amount="25.00",
        token="USDC"
    )

asyncio.run(main())
```

### LangChain Integration

```python
from langchain_community.tools.sardis import (
    SardisPaymentTool,
    SardisBalanceTool,
    SardisTransactionsTool
)
from langchain.agents import create_react_agent

tools = [
    SardisPaymentTool(
        api_key="sk_...",
        wallet_id="wallet_123"
    ),
    SardisBalanceTool(api_key="sk_..."),
    SardisTransactionsTool(api_key="sk_...")
]

agent = create_react_agent(
    llm=ChatOpenAI(model="gpt-4o"),
    tools=tools,
    prompt=prompt
)
```

---

## 4. TypeScript SDK

### Installation

```bash
npm install @sardis/sdk
# or
pnpm add @sardis/sdk
```

### Initialization

```typescript
import { Sardis } from '@sardis/sdk';

const client = new Sardis({
  apiKey: 'sk_live_...',
  // sandbox: true  // for testing
});
```

### Wallet Operations

```typescript
// Create wallet
const wallet = await client.wallets.create({
  name: 'agent-wallet',
  chain: 'base',
  policy: {
    maxDaily: '100.00',
    maxPerTx: '25.00',
    allowedMerchants: ['openai.com']
  }
});

// Get balance
const balance = await wallet.balance();
// { USDC: '150.00', EURC: '50.00' }

// Make payment
const tx = await wallet.pay({
  to: '0x...',
  amount: '25.00',
  token: 'USDC',
  memo: 'API credits'
});
```

### Vercel AI SDK Integration

```typescript
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { sardisTools } from '@sardis/vercel-ai';

const result = await generateText({
  model: openai('gpt-4o'),
  tools: sardisTools({
    apiKey: process.env.SARDIS_API_KEY!,
    walletId: 'wallet_123'
  }),
  prompt: 'Buy $20 worth of API credits from OpenAI'
});
```

### Type Definitions

```typescript
interface Wallet {
  id: string;
  name: string;
  address: string;
  chain: Chain;
  policy: Policy;
  createdAt: Date;
}

interface Policy {
  maxDaily?: string;
  maxPerTx?: string;
  maxMonthly?: string;
  allowedMerchants?: string[];
  blockedCategories?: string[];
  requireApprovalAbove?: string;
}

interface Transaction {
  id: string;
  txHash: string;
  status: 'pending' | 'confirmed' | 'failed';
  amount: string;
  token: Token;
  to: string;
  memo?: string;
  createdAt: Date;
}

type Chain = 'base' | 'polygon' | 'ethereum' | 'arbitrum' | 'optimism';
type Token = 'USDC' | 'USDT' | 'EURC' | 'PYUSD';
```

---

## 5. MCP Server

### Installation

```bash
npx @sardis/mcp-server start
```

### Claude Desktop Configuration

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "sardis": {
      "command": "npx",
      "args": ["@sardis/mcp-server", "start"],
      "env": {
        "SARDIS_API_KEY": "sk_..."
      }
    }
  }
}
```

### Cursor Configuration

Add to `.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "sardis": {
      "command": "npx",
      "args": ["@sardis/mcp-server", "start"],
      "env": {
        "SARDIS_API_KEY": "sk_..."
      }
    }
  }
}
```

### Available MCP Tools

| Tool | Description |
|------|-------------|
| `sardis_get_balance` | Get wallet balance |
| `sardis_pay` | Make a payment (policy enforced) |
| `sardis_get_transactions` | List recent transactions |
| `sardis_check_policy` | Check if payment would be allowed |
| `sardis_request_approval` | Request human approval |
| `sardis_get_wallet_info` | Get wallet details |

### Tool Schemas

```typescript
// sardis_pay
{
  to: string;       // Recipient address or merchant
  amount: string;   // Amount to pay
  token?: string;   // Token (default: USDC)
  memo?: string;    // Transaction memo
}

// sardis_check_policy
{
  amount: string;   // Amount to check
  merchant?: string; // Merchant to check
}

// sardis_request_approval
{
  amount: string;   // Amount needing approval
  reason: string;   // Why approval is needed
}

// sardis_create_hold
{
  amount: string;   // Amount to reserve
  token?: string;   // Token (default: USDC)
  merchant?: string; // Merchant identifier
  expires_in?: number; // Seconds until expiry
}

// sardis_capture_hold
{
  hold_id: string;  // Hold to capture
  amount?: string;  // Amount (can be less than hold)
}

// sardis_issue_card
{
  spending_limit: string;    // Card limit
  merchant_category?: string; // Optional category restriction
  expires_in_days?: number;  // Card validity
}
```

### Full Tool List (46 tools)

| Category | Tools |
|----------|-------|
| Wallet | `get_balance`, `get_wallet_info`, `list_wallets`, `freeze_wallet`, `unfreeze_wallet` |
| Payments | `pay`, `check_policy`, `request_approval`, `batch_transfer` |
| Transactions | `get_transactions`, `get_transaction` |
| Holds | `create_hold`, `capture_hold`, `release_hold`, `list_holds` |
| Cards | `issue_card`, `list_cards`, `cancel_card`, `get_card_transactions` |
| Policies | `get_policy`, `update_policy`, `validate_policy` |
| Compliance | `screen_address`, `get_kyc_status`, `initiate_kyc`, `mcc_lookup` |
| Fiat | `fund_wallet`, `withdraw_to_bank`, `get_funding_status` |
| Approvals | `create_approval`, `get_approval`, `list_approvals`, `approve`, `deny`, `cancel_approval` |
| Invoices | `create_invoice`, `get_invoice`, `list_invoices`, `update_invoice` |
| Sandbox | `sandbox_demo` - Guided walkthrough of all capabilities |

---

## 6. REST API

### Base URL

```
Production: https://sardis.sh/api/v2
Sandbox:    https://sardis.sh/api/v2
```

### Authentication

```bash
curl https://sardis.sh/api/v2/wallets \
  -H "Authorization: Bearer sk_live_..."
```

### Endpoints

#### Wallets

```bash
# Create wallet
POST /wallets
{
  "name": "my-wallet",
  "chain": "base",
  "policy": {
    "max_daily": "100.00"
  }
}

# List wallets
GET /wallets

# Get wallet
GET /wallets/{wallet_id}

# Get balance
GET /wallets/{wallet_id}/balance

# Update policy
PATCH /wallets/{wallet_id}/policy
{
  "policy": {
    "max_daily": "200.00"
  }
}
```

#### Transactions

```bash
# Create transaction
POST /transactions
{
  "wallet_id": "wallet_123",
  "to": "0x...",
  "amount": "25.00",
  "token": "USDC",
  "memo": "API credits"
}

# List transactions
GET /transactions?wallet_id=wallet_123&limit=50

# Get transaction
GET /transactions/{tx_id}
```

#### Policies

```bash
# Parse natural language policy
POST /policies/parse
{
  "text": "Max $100/day on cloud services, require approval over $50"
}

# Validate policy
POST /policies/validate
{
  "policy": {
    "max_daily": "100.00",
    "require_approval_above": "50.00"
  }
}
```

#### Cards

```bash
# Issue virtual card
POST /cards
{
  "wallet_id": "wallet_123",
  "spending_limit": "500.00",
  "merchant_category": "software"
}

# List cards
GET /cards?wallet_id=wallet_123

# Cancel card
DELETE /cards/{card_id}
```

### Response Format

```json
{
  "data": { ... },
  "meta": {
    "request_id": "req_123",
    "timestamp": "2026-01-24T12:00:00Z"
  }
}
```

### Error Format

```json
{
  "error": {
    "code": "POLICY_VIOLATION",
    "message": "Transaction amount exceeds daily limit",
    "details": {
      "limit": "100.00",
      "requested": "150.00",
      "remaining": "25.00"
    }
  }
}
```

---

## 7. Protocols

### AP2 (Agent Payment Protocol)

Industry standard from Google, PayPal, Mastercard, Visa (60+ partners).

```python
from sardis.protocols import AP2

# Create AP2 mandate
mandate = AP2.create_mandate(
    intent={
        "action": "purchase",
        "amount": "50.00",
        "merchant": "openai.com"
    },
    cart={
        "items": [{"name": "API Credits", "amount": "50.00"}]
    }
)

# Execute with mandate
tx = wallet.pay_with_mandate(mandate)
```

### TAP (Trust Anchor Protocol)

Cryptographic identity verification for agents.

```python
from sardis.protocols import TAP

# Verify agent identity
identity = TAP.create_identity(
    agent_id="agent_123",
    public_key="ed25519:...",
    attestations=["anthropic", "verified_developer"]
)

# Attach to transaction
tx = wallet.pay(
    to="0x...",
    amount="25.00",
    identity=identity
)
```

### A2A (Agent-to-Agent)

Multi-agent payment protocol developed by Google.

```python
# Agent A sends to Agent B
tx = wallet_a.pay_agent(
    to_agent="agent_b_wallet_id",
    amount="10.00",
    protocol="a2a",
    message={
        "task": "research_complete",
        "deliverable": "report.pdf"
    }
)

# Discover agent capabilities via .well-known
from sardis.protocols import A2A

agent_info = await A2A.discover("https://agent.example.com")
print(agent_info.capabilities)  # ["payments", "research", "booking"]
```

### UCP (Universal Commerce Protocol)

Standardized checkout flows for agents.

```python
from sardis.protocols import UCP

# Create a cart
cart = UCP.create_cart(
    merchant="store.example.com",
    items=[
        {"sku": "API-CREDITS-100", "quantity": 1, "price": "10.00"},
        {"sku": "SUPPORT-ADDON", "quantity": 1, "price": "5.00"}
    ]
)

# Apply discount
cart = UCP.apply_discount(cart, code="AGENT10")

# Checkout
checkout = UCP.checkout(cart, wallet=wallet)
print(checkout.status)  # "completed"
print(checkout.receipt)  # Full receipt with line items
```

### x402 (HTTP 402 Micropayments)

Coinbase-developed protocol for pay-per-API-call.

```python
from sardis.protocols import X402

# Make a paid API request
response = await X402.request(
    url="https://api.example.com/expensive-endpoint",
    wallet=wallet,
    max_amount="0.01"  # Maximum willing to pay
)

# The x402 client automatically:
# 1. Receives 402 Payment Required response
# 2. Parses payment requirements from headers
# 3. Makes payment via Sardis wallet
# 4. Retries request with payment proof

print(response.data)       # API response
print(response.amount_paid)  # "0.005" (actual cost)
```

```typescript
// TypeScript
import { X402Client } from '@sardis/x402';

const x402 = new X402Client({ wallet });

const response = await x402.fetch('https://api.example.com/data', {
  maxPayment: '0.01'
});
```

---

## 8. Fiat Rails

### Overview

Sardis bridges traditional banking with agentic commerce, allowing wallets to be funded from and withdrawn to bank accounts.

### Funding Wallets

```python
from sardis import SardisFiatRamp

ramp = SardisFiatRamp(
    sardis_key="sk_...",
    bridge_key="bridge_..."
)

# Fund wallet via ACH
funding = await ramp.fund_wallet(
    wallet_id="wallet_123",
    amount_usd=1000,
    method="bank"  # "bank", "card", or "crypto"
)

print(funding.ach_instructions)  # Bank transfer details
# {
#   "account_number": "...",
#   "routing_number": "...",
#   "bank_name": "...",
#   "reference": "SARDIS-wallet_123"
# }

# Fund via card (higher fees, instant)
card_funding = await ramp.fund_wallet(
    wallet_id="wallet_123",
    amount_usd=100,
    method="card",
    card_token="tok_..."
)
```

### Withdrawals

```python
# Withdraw to bank (policy-checked)
withdrawal = await ramp.withdraw_to_bank(
    wallet_id="wallet_123",
    amount_usd=500,
    bank_account={
        "account_number": "...",
        "routing_number": "...",
        "account_type": "checking"
    }
)

print(withdrawal.status)  # "pending", "processing", "completed"
print(withdrawal.estimated_arrival)  # Same-day ACH or T+2 wire
```

### Merchant Payouts

```python
# Pay merchant directly in USD
payment = await ramp.pay_merchant_fiat(
    wallet_id="wallet_123",
    amount_usd=99.99,
    merchant={
        "name": "ACME Corp",
        "bank_account": {...}
    }
)
```

### Fee Structure

| Method | Fee | Speed |
|--------|-----|-------|
| ACH Funding | 0.5% | 2-3 business days |
| Wire Funding | 0.25% | Same day |
| Card Funding | 2.9% + $0.30 | Instant |
| ACH Withdrawal | 0.25% | Same day |
| Wire Withdrawal | $25 flat | Same day |

---

## 9. Virtual Cards

### Issuance

```python
card = wallet.cards.create(
    spending_limit="500.00",
    merchant_category="software",
    expires_in_days=30
)

# Card details
card.number      # 4242...1234
card.cvv         # 123
card.expiry      # 12/26
card.billing     # Billing address
```

### Management

```python
# List cards
cards = wallet.cards.list()

# Update limit
card.update(spending_limit="1000.00")

# Cancel card
card.cancel()

# Get transactions
txs = card.transactions()
```

---

## 10. Compliance

### KYC (Know Your Customer)

```python
# Require KYC for wallet
wallet = client.wallets.create(
    name="kyc-wallet",
    chain="base",
    require_kyc=True
)

# Check KYC status
kyc_status = wallet.kyc_status()
# "verified", "pending", "required"

# Initiate KYC
kyc_link = wallet.initiate_kyc()
# Returns Persona verification link
```

### AML (Anti-Money Laundering)

```python
# Screen address
result = client.compliance.screen_address("0x...")
# {"risk": "low", "flags": []}

# Screen transaction
result = client.compliance.screen_transaction(tx)
# {"risk": "medium", "flags": ["high_value"]}
```

---

## 11. Error Handling

### Error Codes

| Code | HTTP | Description |
|------|------|-------------|
| POLICY_VIOLATION | 400 | Transaction violates policy |
| INSUFFICIENT_BALANCE | 400 | Not enough funds |
| INVALID_MERCHANT | 400 | Merchant not allowed |
| APPROVAL_REQUIRED | 400 | Needs human approval |
| INVALID_ADDRESS | 400 | Invalid recipient address |
| WALLET_NOT_FOUND | 404 | Wallet does not exist |
| TX_NOT_FOUND | 404 | Transaction does not exist |
| UNAUTHORIZED | 401 | Invalid API key |
| RATE_LIMITED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Server error |

### Handling Errors

```python
from sardis.exceptions import (
    PolicyViolation,
    InsufficientBalance,
    ApprovalRequired
)

try:
    tx = wallet.pay(to="0x...", amount="1000.00")
except PolicyViolation as e:
    print(f"Policy blocked: {e.reason}")
    print(f"Limit: {e.limit}, Requested: {e.requested}")
except InsufficientBalance as e:
    print(f"Need {e.required}, have {e.available}")
except ApprovalRequired as e:
    # Request human approval
    approval = wallet.request_approval(
        amount="1000.00",
        reason="Large purchase for infrastructure"
    )
```

---

## 12. Best Practices

### Wallet Management

1. **One wallet per agent** - Easier to track and manage
2. **Descriptive names** - `shopping-agent-prod` not `wallet1`
3. **Start restrictive** - Begin with tight limits, loosen as needed
4. **Regular audits** - Review transaction logs weekly

### Policy Design

1. **Layer policies** - Daily + per-tx + monthly limits
2. **Whitelist over blacklist** - Safer to allow specific merchants
3. **Human approval for large transactions** - Set threshold at 10-20% of daily limit
4. **Time restrictions for non-critical agents** - Business hours only

### Security

1. **Never expose API keys** - Use environment variables
2. **Use sandbox for testing** - `sk_test_...` keys
3. **Monitor for anomalies** - Set up alerts for unusual patterns
4. **Rotate keys regularly** - Every 90 days recommended

### Integration

1. **Handle all error cases** - Don't assume transactions succeed
2. **Implement retries with backoff** - For network errors
3. **Log everything** - Keep your own audit trail
4. **Test policy changes in sandbox first** - Before production

---

## Quick Reference Card

```python
from sardis import Sardis

client = Sardis(api_key="sk_...")

# Create wallet
wallet = client.wallets.create(name="agent-wallet", chain="base", policy="Max $100/day")

# Check balance
balance = wallet.balance()  # {"USDC": "150.00", "EURC": "50.00"}

# Make payment (policy enforced)
tx = wallet.pay(to="0x...", amount="25.00", token="USDC")

# Pre-check if payment would be allowed
result = wallet.check_policy(amount="50.00", merchant="openai.com")
if result.allowed:
    wallet.pay(...)

# Request human approval for large transactions
approval = wallet.request_approval(amount="200.00", reason="Annual subscription")

# Create hold (pre-authorization)
hold = wallet.create_hold(amount="100.00", token="USDC", expires_in=3600)
tx = hold.capture(amount="85.00")  # Capture partial amount

# Issue virtual card
card = wallet.cards.create(spending_limit="500.00", merchant_category="software")

# Fund from bank
from sardis import SardisFiatRamp
ramp = SardisFiatRamp(sardis_key="sk_...", bridge_key="bridge_...")
funding = await ramp.fund_wallet(wallet_id="wallet_123", amount_usd=1000, method="bank")
```

## MCP Server Quick Start

```bash
# Install and start
npx @sardis/mcp-server start

# Or add to Claude Desktop config
# ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "sardis": {
      "command": "npx",
      "args": ["@sardis/mcp-server", "start"],
      "env": { "SARDIS_API_KEY": "sk_..." }
    }
  }
}
```

## Stablecoin-Only Token Allowlist (On-Chain)

The smart contract enforces a token allowlist at the EVM level:

```solidity
// Only Sardis (platform) can whitelist tokens
function allowToken(address token) external onlySardis;
function removeToken(address token) external onlySardis;

// Enforced in pay(), payWithCoSign(), createHold()
// Reverts with "Token not allowed (stablecoins only)" for non-whitelisted tokens
```

**Key guarantees:**
- Only approved stablecoins (USDC, USDT, EURC, PYUSD) can be transferred out
- If someone sends NFTs, DOGE, or meme coins to the wallet — they're stuck, the agent can't use them
- This is an **on-chain guarantee**, not just API filtering
- Sardis can toggle enforcement off for emergency token recovery

## Status

- **Current Version**: v0.8.5 (Production Retry + Async Wrapping)
- **MCP Server**: v0.2.5 on npm (1,000+ installs, 46 tools)
- **Infrastructure**: Live on Base Sepolia testnet, staging API on Cloud Run
- **Mainnet Launch**: Q2 2026
- **Protocols Implemented**: AP2, UCP, A2A, TAP, x402

## What's New in v0.8.5 (February 2026)

### Production-Grade Retry & Async Wrapping
All external provider calls now use configurable retry with exponential backoff, circuit breakers, and rate limiting.

### Sandbox Demo Tool
```bash
# In MCP server, call sardis_sandbox_demo for a guided tour
# Categories: quickstart, payments, cards, policy, holds, fiat, all
```

### SAR Persistence
Suspicious Activity Reports now persisted to PostgreSQL with FinCEN 5-year retention compliance.

## What's New in v0.8.4 (February 2026)

### Lithic Sandbox Cards
```python
# Issue a real sandbox card via Lithic
card = wallet.cards.create(spending_limit="500.00")

# Simulate a purchase — returns real Lithic authorization ID
tx = card.simulate_purchase(amount="25.00", merchant="Demo Coffee Shop")
print(tx.provider_tx_id)  # Real Lithic transaction token
```

### Stablecoin-Only Smart Contract
On-chain token allowlist prevents non-stablecoin transfers. See "Stablecoin-Only Token Allowlist" section above.

### Goal Drift Detection
Detect when agent spending patterns deviate from intended goals — alerts before financial hallucinations happen.

### Dashboard Cards Page
Custom Sardis-branded card UI with issue, freeze, simulate purchase, and transaction history with Lithic TX IDs.

### Previous (v0.8.0)

### Human Approval Workflows
```python
# Create an approval request
approval = wallet.request_approval(
    amount="500.00",
    reason="Large infrastructure purchase",
    expires_in=3600  # 1 hour
)

# Check approval status
if approval.status == "approved":
    tx = wallet.pay(to="0x...", amount="500.00")
```

### Wallet Freeze
```python
# Freeze wallet (blocks all transactions)
wallet.freeze(reason="Suspicious activity detected")

# Unfreeze wallet
wallet.unfreeze()
```

### Batch Transfers
```python
# Send multiple payments in one transaction
results = wallet.batch_transfer([
    {"to": "0x123...", "amount": "10.00", "token": "USDC"},
    {"to": "0x456...", "amount": "25.00", "token": "USDC"},
    {"to": "0x789...", "amount": "15.00", "token": "USDC"},
])
```

### Velocity Limits (Off-Ramp)
```python
policy = {
    "off_ramp_limits": {
        "daily": "1000.00",
        "weekly": "5000.00",
        "monthly": "15000.00"
    }
}
```

### New Features Summary
- **Background Job Scheduler** - APScheduler for approval expiration, hold cleanup, spending limit reset
- **Alembic Migrations** - Database schema versioning with 6 migrations
- **EIP-2771 Meta-Transactions** - Gasless transactions support
- **Invoices API** - Full CRUD for merchant invoice management
- **Fireblocks Integration** - Institutional-grade MPC signing option
- **Prometheus Metrics** - Production monitoring at `/metrics`
- **Sentry Integration** - Error tracking and alerting
- **MCC Lookup** - Merchant Category Code lookup service
- **SAR Generation** - Suspicious Activity Report generation

## Links

- Website: https://sardis.sh
- Documentation: https://sardis.sh/docs
- GitHub: https://github.com/EfeDurmaz16/sardis
- npm: https://www.npmjs.com/package/@sardis/mcp-server

---

*Last updated: February 2026*
*Version: 2.3*
