Skip to main content

Overview

The @sardis/ai-sdk package provides native Vercel AI SDK tools for executing payments with built-in policy guardrails. Works with generateText, streamText, and all AI SDK model providers.

When to Use Vercel AI SDK

  • TypeScript/JavaScript Agents: Build agents in Node.js or Edge Runtime
  • Streaming Responses: Real-time payment execution with streamText
  • Multi-Model Support: Works with OpenAI, Anthropic, Google, and all AI SDK providers
  • Next.js Integration: Build payment-enabled chatbots in Next.js
  • Edge Runtime: Deploy payment agents on Vercel Edge

Installation

npm install @sardis/ai-sdk ai
# or
pnpm add @sardis/ai-sdk ai
# or
yarn add @sardis/ai-sdk ai
Requires Vercel AI SDK v3.0.0+ and Node.js 18+

Quick Start

import { generateText } from 'ai'
import { openai } from '@ai-sdk/openai'
import { createSardisTools } from '@sardis/ai-sdk'

const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

const { text, toolResults } = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Check my balance and pay $50 to merchant_xyz for API credits',
})

console.log(text)
// "I've checked your balance (1,000 USDC available) and successfully 
//  paid $50 to merchant_xyz. Transaction ID: tx_abc123"

Available Tools

The createSardisTools function returns 7 pre-configured tools:

sardis_pay

Execute payment from wallet

sardis_create_hold

Pre-authorize funds for future payment

sardis_capture_hold

Capture previously authorized hold

sardis_void_hold

Cancel hold and release funds

sardis_check_policy

Validate payment against policy

sardis_get_balance

Get current wallet balance

sardis_get_spending

Get spending summary and analytics

Tool Details

sardis_pay

Execute a payment with policy enforcement:
import { createSardisTools } from '@sardis/ai-sdk'

const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

// The tool is called automatically by the model
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Pay $50 to openai.com for API credits',
})
Returns:
{
  success: true,
  transactionId: "tx_abc123",
  txHash: "0x7f3b...a2c9",
  amount: 50,
  token: "USDC",
  chain: "base",
  status: "confirmed",
  timestamp: "2024-01-15T10:30:00Z"
}

sardis_create_hold

Create a hold (pre-authorization) for variable amounts:
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Reserve $100 for a hotel booking (final amount TBD)',
})
Returns:
{
  success: true,
  holdId: "hold_abc123",
  amount: 100,
  merchant: "hotel.com",
  expiresAt: "2024-01-20T10:30:00Z",
  status: "active"
}

sardis_capture_hold

Capture a hold with optional partial amount:
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Capture hold_abc123 for the final amount of $87.50',
})

sardis_check_policy

Validate before executing:
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Can I spend $500 on aws.amazon.com?',
})
Returns:
{
  allowed: true,
  reason: "Payment within limits and allowed merchant"
}

Configuration

Basic Configuration

const tools = createSardisTools({
  apiKey: string,        // Required: Your Sardis API key
  walletId: string,      // Required: Wallet to operate on
})

Advanced Configuration

const tools = createSardisTools({
  // Required
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  
  // Optional
  agentId: 'agent_xyz789',           // Agent identifier for attribution
  baseUrl: 'https://api.sardis.sh',  // Custom API URL
  simulationMode: false,             // Test without real transactions
  
  // Policy Guardrails
  maxPaymentAmount: 100,             // Max single payment limit ($)
  blockedCategories: ['gambling', 'adult'],
  allowedMerchants: ['openai.com', 'anthropic.com', 'aws.com'],
})

Tool Sets

Use different tool sets for different use cases:
import {
  createSardisTools,           // Full 7-tool set
  createMinimalSardisTools,    // Just pay + balance
  createReadOnlySardisTools,   // Analytics only (no payments)
} from '@sardis/ai-sdk'

// Minimal agent (2 tools)
const minimalTools = createMinimalSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

// Observer agent (3 tools)
const readOnlyTools = createReadOnlySardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

Streaming

Use with streamText for real-time responses:
import { streamText } from 'ai'
import { openai } from '@ai-sdk/openai'
import { createSardisTools } from '@sardis/ai-sdk'

const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

const result = streamText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Pay $25 to merchant_abc for API credits',
})

for await (const chunk of result.textStream) {
  process.stdout.write(chunk)
}

// Output:
// "Checking your balance..."
// "Balance confirmed: 1,000 USDC available."
// "Executing payment of $25..."
// "Payment successful! Transaction ID: tx_abc123"

Multi-Model Support

Works with all Vercel AI SDK model providers:
import { openai } from '@ai-sdk/openai'

const result = await generateText({
  model: openai('gpt-4o'),
  tools: sardis.tools,
  prompt: 'Pay $50 to AWS',
})

SardisProvider

Use the provider for advanced features:
import { SardisProvider } from '@sardis/ai-sdk'

const sardis = new SardisProvider({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  enableLogging: true,
  onTransaction: async (event) => {
    // Log to database
    await db.transactions.insert({
      id: event.transactionId,
      amount: event.amount,
      recipient: event.to,
      status: event.status,
      timestamp: event.timestamp,
    })
  },
})

const { text } = await generateText({
  model: openai('gpt-4o'),
  tools: sardis.tools,
  system: sardis.systemPrompt,  // Includes payment guidelines
  prompt: 'Check balance and pay $25 for API credits',
})

Direct API Access

The provider exposes the Sardis API directly:
const sardis = new SardisProvider({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

// Check balance
const balance = await sardis.getBalance()
console.log(`Available: $${balance.available}`)

// Execute payment
const result = await sardis.pay({
  to: 'merchant_openai',
  amount: 50,
  token: 'USDC',
  memo: 'API credits',
})

if (result.success) {
  console.log(`Paid! TX: ${result.txHash}`)
}

Policy Enforcement

Set guardrails to prevent unauthorized spending:
const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  
  // Enforce limits
  maxPaymentAmount: 100,  // Block payments over $100
  
  // Block categories
  blockedCategories: ['gambling', 'adult', 'weapons'],
  
  // Whitelist merchants (optional)
  allowedMerchants: ['openai.com', 'anthropic.com', 'aws.com'],
})

// This will fail with policy violation
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Pay $500 to some_casino.com',
})
// Agent: "I cannot process this payment. It violates the spending policy: 
//         Amount $500 exceeds maximum allowed payment of $100"

Holds (Pre-Authorization)

Use holds when the final amount isn’t known:
const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: `
    I need to book a hotel room for 2 nights at approximately $150/night.
    Create a hold for the estimated total, then when I confirm the
    exact price of $287.50, capture that amount.
  `,
})

// Agent will:
// 1. Create hold for $300 (estimated)
// 2. Receive confirmation of $287.50
// 3. Capture hold for $287.50 (partial capture)
// 4. Remaining $12.50 released back to wallet

Next.js Integration

app/api/chat/route.ts
import { streamText } from 'ai'
import { openai } from '@ai-sdk/openai'
import { createSardisTools } from '@sardis/ai-sdk'

export const runtime = 'edge'

export async function POST(req: Request) {
  const { messages } = await req.json()
  
  const tools = createSardisTools({
    apiKey: process.env.SARDIS_API_KEY!,
    walletId: req.headers.get('x-wallet-id')!,
  })
  
  const result = streamText({
    model: openai('gpt-4o'),
    tools,
    messages,
  })
  
  return result.toDataStreamResponse()
}

Error Handling

import { createSardisTools } from '@sardis/ai-sdk'

const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

const result = await generateText({
  model: openai('gpt-4o'),
  tools,
  prompt: 'Pay $1000 to merchant_xyz',
})

// Check tool results
for (const toolResult of result.toolResults) {
  if (toolResult.toolName === 'sardis_pay') {
    const paymentResult = toolResult.result as PaymentResult
    
    if (!paymentResult.success) {
      console.error(`Payment failed: ${paymentResult.error}`)
      // Handle: insufficient_balance, policy_violation, network_error
    }
  }
}

TypeScript Types

Full TypeScript support:
import type {
  SardisToolsConfig,
  PaymentResult,
  HoldResult,
  PolicyCheckResult,
  BalanceResult,
  TransactionEvent,
} from '@sardis/ai-sdk'

const config: SardisToolsConfig = {
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  maxPaymentAmount: 100,
}

const onTransaction = (event: TransactionEvent) => {
  console.log(`Transaction ${event.transactionId}: ${event.status}`)
}

Best Practices

1. Use Environment Variables

// ✓ Good
const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: process.env.SARDIS_WALLET_ID!,
})

// ❌ Bad - Hardcoded secrets
const tools = createSardisTools({
  apiKey: 'sk_live_abc123...',
  walletId: 'wallet_xyz789',
})

2. Set Policy Guardrails

const tools = createSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  maxPaymentAmount: 100,  // Prevent large payments
  allowedMerchants: ['openai.com', 'anthropic.com'],  // Whitelist
})

3. Log Transactions

const sardis = new SardisProvider({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
  onTransaction: async (event) => {
    await db.transactions.insert(event)
  },
})

4. Use Minimal Tools When Possible

// For simple payment agents
const tools = createMinimalSardisTools({
  apiKey: process.env.SARDIS_API_KEY!,
  walletId: 'wallet_abc123',
})

Next Steps

OpenAI Integration

Use function calling with OpenAI

Anthropic Claude

Build Claude agents with Sardis

Policy Engine

Understand spending policy rules

TypeScript SDK

Full TypeScript SDK reference

Build docs developers (and LLMs) love