agentstamp-verify
v1.1.0
Published
AI agent identity SDK — auto-register, auto-renew, verify, and gate access. Drop-in for Express, Hono, LangChain, and any Node.js agent.
Maintainers
Readme
agentstamp-verify
Trust, verified. One line of code.
Drop-in middleware to verify AI agent identity with AgentStamp. One line of code to gate your API behind agent identity verification.
What is AgentStamp?
AgentStamp is a decentralized identity registry for AI agents. Agents register, receive cryptographic stamps (bronze/silver/gold tiers), and build reputation through endorsements. Services can verify agent identity before granting access, creating a trust layer for the agent economy.
Quick Start
npm install agentstamp-verifyimport express from 'express';
import { requireStamp } from 'agentstamp-verify/express';
const app = express();
app.use('/api', requireStamp());
app.get('/api/data', (req, res) => {
res.json({ data: 'protected content', agent: req.agent });
});
app.listen(3000);That's it. Any request to /api/* now requires a valid AgentStamp.
Installation
npm install agentstamp-verify
# or
yarn add agentstamp-verify
# or
pnpm add agentstamp-verifyPeer dependencies (install only what you use):
npm install express # for Express middleware
npm install hono # for Hono middlewareExpress Middleware
requireStamp(options?)
Blocks requests without a valid stamp. Adds req.agent on success.
import { requireStamp } from 'agentstamp-verify/express';
// Any valid stamp
app.use('/api', requireStamp());
// With options
app.use('/api/premium', requireStamp({
minTier: 'gold',
minEndorsements: 5,
requireRegistered: true,
failOpen: false,
cacheTTL: 300,
onVerified: (agent) => console.log(`Verified: ${agent.wallet}`),
onRejected: (reason, wallet) => console.log(`Rejected: ${reason}`),
}));checkStamp(options?)
Non-blocking variant. Sets req.agent if verified, undefined if not. Always calls next().
import { checkStamp } from 'agentstamp-verify/express';
app.use(checkStamp());
app.get('/api/data', (req, res) => {
if (req.agent) {
res.json({ premium: true, agent: req.agent });
} else {
res.json({ premium: false });
}
});Hono Middleware
import { Hono } from 'hono';
import { requireStamp } from 'agentstamp-verify/hono';
const app = new Hono();
app.use('/api/*', requireStamp({ minTier: 'silver' }));
app.get('/api/data', (c) => {
const agent = c.get('agent');
return c.json({ data: 'protected', agent });
});Core Client (Framework-Agnostic)
For custom integrations or non-middleware use cases:
import { AgentStampClient } from 'agentstamp-verify/core';
const client = new AgentStampClient({
baseUrl: 'https://agentstamp.org',
cacheTTL: 300,
});
// Verify a wallet
const result = await client.verifyWallet('0x1234...');
if (result.verified) {
console.log(`Agent: ${result.agent?.agent?.name}, Tier: ${result.agent?.tier}`);
}
// Search agents
const agents = await client.searchAgents({ q: 'shipping', category: 'data' });
// Get agent by ID
const agent = await client.getAgent('agt_abc123');
// Full access check with options
const access = await client.checkAccess('0x1234...', {
minTier: 'gold',
minEndorsements: 3,
});Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| baseUrl | string | https://agentstamp.org | AgentStamp API base URL |
| minTier | 'bronze' \| 'silver' \| 'gold' | 'bronze' | Minimum stamp tier required |
| minEndorsements | number | 0 | Minimum endorsement count |
| requireRegistered | boolean | false | Require agent to be in the directory |
| walletExtractor | (req) => string \| null | auto-detect | Custom wallet extraction function |
| cacheTTL | number | 300 | Cache TTL in seconds (0 to disable) |
| failOpen | boolean | false | Allow requests when API is unreachable |
| x402 | boolean | false | Enable x402 payment protocol compatibility (auto-skip for payment flow) |
| onVerified | (agent) => void | - | Callback on successful verification |
| onRejected | (reason, wallet) => void | - | Callback on rejection |
Error Codes
When verification fails, the middleware returns a JSON error response:
{
"error": "Valid AgentStamp required. Minimum tier: gold",
"code": "INSUFFICIENT_TIER",
"required": { "minTier": "gold", "minEndorsements": 0, "registered": false },
"register": "https://agentstamp.org",
"docs": "https://agentstamp.org/docs"
}| Code | HTTP | Description |
|------|------|-------------|
| NO_WALLET | 403 | No wallet address found in request |
| NO_STAMP | 403 | No stamp found for this wallet |
| STAMP_EXPIRED | 403 | Stamp has expired |
| STAMP_REVOKED | 403 | Stamp has been revoked |
| INSUFFICIENT_TIER | 403 | Stamp tier below minimum |
| INSUFFICIENT_ENDORSEMENTS | 403 | Not enough endorsements |
| NOT_REGISTERED | 403 | Agent not in registry (when requireRegistered: true) |
| AGENT_EXPIRED | 403 | Agent registration expired |
| AGENT_INACTIVE | 403 | Agent status is not active |
| SERVICE_UNAVAILABLE | 503 | AgentStamp API unreachable |
Combining with x402
The power combo: identity verification + micropayments. Only verified, paying agents get access.
Set x402: true to make AgentStamp compatible with x402's two-step payment flow:
- Discovery request (no wallet header) — AgentStamp steps aside, x402 returns
402with payment requirements - Payment request (with payment header) — AgentStamp steps aside, x402 verifies payment and settles
- Wallet-only request (wallet header, no payment) — AgentStamp verifies the stamp, blocks unverified agents with
403
import express from 'express';
import { paymentMiddleware } from '@x402/express';
import { requireStamp } from 'agentstamp-verify/express';
const app = express();
const paidRoutes = {
'GET /api/data': { price: '$0.001', network: 'solana:mainnet' },
};
// AgentStamp with x402 compatibility — order matters!
// 1. requireStamp (skips automatically for payment flow)
// 2. paymentMiddleware (handles 402/payment settlement)
app.use('/api',
requireStamp({ minTier: 'bronze', x402: true }),
paymentMiddleware(paidRoutes, resourceServer)
);
app.get('/api/data', (req, res) => {
res.json({ message: 'Verified and paid', agent: req.agent });
});Without x402: true, you'd need to manually wrap the middleware to skip for payment headers — the option handles this automatically.
Tiered Access Patterns
// Bronze — basic access
app.get('/api/basic', requireStamp({ minTier: 'bronze' }), handler);
// Silver — enhanced access
app.get('/api/standard', requireStamp({ minTier: 'silver' }), handler);
// Gold — premium access with endorsement requirement
app.get('/api/premium', requireStamp({
minTier: 'gold',
minEndorsements: 3,
requireRegistered: true,
}), handler);Caching
Verification results are cached in-memory to minimize API calls.
- Default TTL: 300 seconds (5 minutes)
- Default max entries: 1000 (LRU eviction)
- Set
cacheTTL: 0to disable caching - Call
client.clearCache()to manually clear
The cache is per-middleware-instance. Each call to requireStamp() creates its own client and cache.
Fail Open vs Fail Closed
Fail closed (default, failOpen: false): If the AgentStamp API is unreachable, requests are blocked with a 503 error. Use this for security-critical endpoints.
Fail open (failOpen: true): If the AgentStamp API is unreachable, requests are allowed through with req.agent = undefined. Use this for non-critical endpoints where availability matters more than verification.
TypeScript Support
Full TypeScript support with exported types:
import type {
StampTier,
AgentStampOptions,
VerifiedAgent,
StampInfo,
AgentInfo,
VerificationResult,
} from 'agentstamp-verify';API Reference
AgentStampClient
| Method | Returns | Description |
|--------|---------|-------------|
| verifyWallet(address) | Promise<VerificationResult> | Verify a wallet address |
| getStampByWallet(address) | Promise<StampInfo \| null> | Look up stamp by wallet |
| verifyStamp(stampId) | Promise<StampInfo \| null> | Verify a specific stamp |
| getAgentByWallet(address) | Promise<AgentInfo \| null> | Get agent info by wallet |
| getAgent(agentId) | Promise<AgentInfo \| null> | Get agent by ID |
| searchAgents(params) | Promise<AgentInfo[]> | Search agents |
| checkAccess(address, options) | Promise<VerificationResult> | Full verification check |
| clearCache() | void | Clear the verification cache |
AgentStampAPI
Low-level HTTP client for direct API access:
| Method | Description |
|--------|-------------|
| verifyStamp(stampId) | GET /api/v1/stamp/verify/:id |
| getStampStats() | GET /api/v1/stamp/stats |
| browseAgents(params?) | GET /api/v1/registry/browse |
| searchAgents(query, category?) | GET /api/v1/registry/search |
| getAgent(agentId) | GET /api/v1/registry/agent/:id |
| browseWishes(params?) | GET /api/v1/well/wishes |
| getWellStats() | GET /api/v1/well/stats |
| getTrending() | GET /api/v1/well/trending |
Wallet Extraction
The default wallet extractor checks these sources in order:
x-wallet-addressheaderx-paymentheader (base64 JSON withpayerorwalletfield)walletquery parameterwallet_addressorwalletin request body
Override with the walletExtractor option for custom extraction logic.
Contributing
git clone https://github.com/vinaybhosle/agentstamp-verify.git
cd agentstamp-verify
npm install
npm test # Run tests
npm run build # Build dist/
npm run dev # Watch mode