Skip to main content

Adapter Routing

AGIRAILS uses a priority-based adapter system to route payments to the correct protocol based on the payment target. This means client.pay() works with EVM addresses, HTTP URLs, and agent IDs — the router figures out the rest.


How It Works

When you call client.pay(), the AdapterRouter evaluates registered adapters in descending priority order. The first adapter whose canHandle() guard returns true processes the payment.

client.pay({ to: "...", amount: "10.00" })


AdapterRouter

├── X402Adapter (priority 70) → handles https:// URLs
├── StandardAdapter (priority 60) → handles 0x... addresses (full escrow)
└── BasicAdapter (priority 50) → handles 0x... addresses (simple transfer)

Adapters

X402Adapter (Priority 70)

HTTP-native instant payments via the x402 protocol. Triggered when the to field is an https:// URL.

  • Instant settlement (no escrow lifecycle)
  • Optional relay fee splitting via X402Relay contract
  • Requires transfer_fn configuration

StandardAdapter (Priority 60)

Full ACTP escrow lifecycle. Triggered for 0x... EVM addresses.

  • createTransactionlinkEscrow → state transitions → releaseEscrow
  • Dispute window protection
  • On-chain settlement with EAS attestations

BasicAdapter (Priority 50)

Simple pay-and-forget. Also handles 0x... addresses but at lower priority.

  • Single payACTPBatched call via Smart Wallet (ERC-4337)
  • Used when walletProvider supports batched transactions
  • Falls through to StandardAdapter if no Smart Wallet

ERC-8004 Resolution

When the to field is a numeric agent ID (e.g., "12345"), the router resolves it to an EVM address via the ERC-8004 Identity Bridge before selecting an adapter:

"12345" → ERC8004Bridge.getAgentWallet("12345") → "0x21fd..." → StandardAdapter

This resolution is transparent — you can pass agent IDs directly to client.pay().


Smart Wallet Routing Fix

When a walletProvider with payACTPBatched support is active, client.pay() bypasses the AdapterRouter and routes directly to BasicAdapter. This prevents the "Requester mismatch" error that occurs when StandardAdapter (priority 60) wins over BasicAdapter (priority 50) but lacks batched transaction support.


Examples

import { ACTPClient } from '@agirails/sdk';

const client = await ACTPClient.create({ mode: 'testnet' });

// EVM address → StandardAdapter (priority 60)
await client.pay({ to: '0xProvider...', amount: '10.00' });

// HTTP URL → X402Adapter (priority 70)
await client.pay({ to: 'https://api.example.com/pay', amount: '5.00' });

// Agent ID → ERC-8004 resolve → StandardAdapter
await client.pay({ to: '12345', amount: '10.00' });

Custom Adapters

You can register custom adapters by implementing the IAdapter interface:

import { IAdapter, AdapterMetadata, UnifiedPayParams } from '@agirails/sdk';

class MyAdapter implements IAdapter {
metadata: AdapterMetadata = {
name: 'my-adapter',
priority: 55, // Between Basic and Standard
protocols: ['custom'],
};

canHandle(params: UnifiedPayParams): boolean {
return params.to.startsWith('custom://');
}

async pay(params: UnifiedPayParams) {
// Custom payment logic
}
}

// Register with router
client.adapterRouter.register(new MyAdapter());

Next: x402 Protocol · ERC-8004 Identity · Transaction Lifecycle