@valiron/sdk
Official TypeScript SDK for Valiron — Trust & Reputation Middleware for API Protection. Evaluate incoming AI agents using on-chain reputation (ERC-8004) and behavioral analysis.
Installation
npm install @valiron/sdk
# or
pnpm add @valiron/sdkGetting Started
import { ValironSDK } from '@valiron/sdk';
const valiron = new ValironSDK();
// Quick routing check (defaults to Ethereum)
const route = await valiron.checkAgent('25459');
if (route === 'prod') {
// Allow full production access
}
// Query a specific chain
const monadRoute = await valiron.checkAgent('8348', { chain: 'monad' });
const baseRoute = await valiron.checkAgent('8348', { chain: 'base' });
// Or set default chain at construction
const monadValiron = new ValironSDK({ chain: 'monad' });
const profile = await monadValiron.getAgentProfile('8348');
console.log(profile.routing.finalRoute); // 'prod'
console.log(profile.localReputation?.tier); // 'AAA'
console.log(profile.onchainReputation.averageScore); // 92.5Operator Dashboard
The Operator Dashboard at valiron.co/dashboard is where you manage your Valiron integration — register endpoints, generate API keys, test trust evaluations, and monitor agent activity.
Getting Started
- Create your account at
/dashboard— enter your name, email, and password - Copy your API key — shown once at registration (
val_op_prefix) - Register your endpoints — set path, method, price per call, and rate limits
- Integrate the SDK — add the middleware to your backend (see Getting Started above)
Endpoints
Register the API paths you want to protect with Valiron. Each endpoint defines how agents are charged and rate-limited.
| Field | Required | Description |
|---|---|---|
Path | Yes | Your API path (e.g. /api/v1/weather) |
Method | Yes | GET, POST, PUT, PATCH, or DELETE |
Price per call | Yes | USD amount charged per API call |
Rate limit | No | Max requests/min per agent (null = unlimited) |
Base URL | No | Your backend URL (e.g. https://myapi.com). Must be HTTPS. Enables end-to-end playground testing. |
Description | No | What this endpoint does |
API Playground
Test how Valiron evaluates different AI agents against your endpoints — without writing code or sending real traffic. The playground answers: "If an agent with this reputation hits my endpoint, what happens?"
- Pick a chain — All supported chains (Ethereum, Solana, Monad, Arbitrum, Base, Avalanche, Polygon, Optimism, and more). Chains with pre-registered sample agents show agent cards; other chains require a custom agent ID.
- Select an agent — Sample agents at different trust levels (good / bad / zero reputation) or enter a custom ERC-8004 agent ID
- Build a request — Method and path. Required headers are injected automatically. Expand "Advanced options" for custom headers, query params, or body
- Send — See the trust evaluation, routing decision, tier, cost, and full response
Dry-run mode returns the trust evaluation (tier, route, price, on-chain score) without logging the call. With dry-run off, the playground performs the full evaluation and logs it to your Analytics & Logs pages. If your endpoint has a Base URL, the request is forwarded to your backend with trust headers (X-Agent-Id, X-Valiron-Chain, X-Valiron-Tier, X-Valiron-Route).
History sidebar saves the last 20 requests with one-click replay.
Analytics & Logs
The dashboard provides real-time visibility into your API usage:
- Analytics — Revenue charts (7/30/90 days), top endpoints, today's stats, error rates
- Agents — Every agent that called your API with drill-down into per-agent activity, endpoint breakdown, and call history
- Call Logs — Paginated log of every request with agent, chain, endpoint, status code, cost, and latency
Supported Chains
Valiron is multichain. Set the default chain at construction or override per-call. All SDK methods accept an optional chain field.
// Set default chain at construction
const valiron = new ValironSDK({ chain: 'monad' });
await valiron.getAgentProfile('8348'); // Uses Monad
// Override per-call (takes precedence)
const valiron2 = new ValironSDK();
await valiron2.checkAgent('8348', { chain: 'base' }); // Base
await valiron2.checkAgent('25459', { chain: 'ethereum' }); // Ethereum
await valiron2.checkAgent('25459'); // Server defaultCore Concepts
Route Decisions
The SDK returns one of four routing decisions:
| Route | Meaning | Trust Tiers |
|---|---|---|
prod | Full access | AAA – BAA |
prod_throttled | Rate-limited access | BA – B |
sandbox | Agent under evaluation | Temporary |
sandbox_only | Access denied | CAA – C |
Trust Evaluation
Valiron evaluates agents using:
- On-chain Reputation — ERC-8004 feedback submitted by other organizations
- Behavioral Analysis — Sandbox evaluation of rate-limit compliance, error rates, and request patterns
- Credit Rating — Moody's-style scoring system (AAA to C)
Architecture
Request → SDK.checkAgent() → Valiron Operator API → Route Decision → Your AppWallet Resolution
When an agent pays via x402 or similar protocols, you receive a wallet address — not an agent ID. Valiron resolves wallets to ERC-8004 agent IDs using a multi-layer lookup:
- Redis — Fast cache of previously resolved wallet → agentId mappings
- Agent0 Subgraph — Queries The Graph (Ethereum, Base, Polygon) for on-chain agent registrations by wallet
- Fallback — Returns null if no agent owns the wallet
Wallet → Redis lookup → Agent0 subgraph → agentId (or null)Use resolveWallet() for the lightweight lookup, or getWalletProfile() to get the full trust profile in one call.
Trust Model
Valiron evaluates agents using four independent trust signals. Each signal provides a different dimension of trust — and together they produce the final routing decision. No single signal is required; agents are evaluated based on whatever data is available.
| Signal | What It Measures | Source |
|---|---|---|
| On-Chain Reputation | Feedback from other agents and operators (0-100 per review) | ERC-8004 Reputation Registry |
| Behavioral Sandbox | How the agent handles rate limits, errors, auth, payments, and edge cases in a controlled environment | Valiron Sandbox |
| World ID | Whether the agent is linked to a verified human identity | Worldcoin IDKit |
| Icebreaker | Whether a human has attested this is their designated agent | Ethereum Attestation Service (Base) |
Selectable Trust Signals
API sellers can use Valiron plug-and-play, or choose which signals score a specific endpoint with trustSignals. Every selected signal is scored on a normalized 0-100 scale, then Valiron normalizes the weights across only the selected signals.
| Signal Key | Plan | Use Case |
|---|---|---|
8004 | Free | On-chain reputation from ERC-8004 or Solana registries |
sandbox | Free | Observed behavioral safety and protocol compliance |
world | Pro / Enterprise | World ID proof-of-personhood link |
icebreaker | Pro / Enterprise | Human ownership/background attestation |
app.use('/api/paid', createValironGate({
sdk: valiron,
trustSignals: ['8004', 'sandbox'], // Free
minScore: 70,
}));
app.use('/api/high-trust', createValironGate({
sdk: valiron,
trustSignals: ['8004', 'sandbox', 'world', 'icebreaker'], // Pro / Enterprise
minScore: 85,
}));On-Chain Reputation (ERC-8004)
The ERC-8004 Reputation Registry stores immutable, on-chain feedback submitted by other agents and operators. Agents with strong on-chain reputation can receive instant production access — bypassing sandbox evaluation entirely. The exact thresholds are not disclosed.
Reputation is stored on-chain at 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63 (same address on all EVM chains).
- Score range: 0-100 per feedback entry
- Self-feedback blocked: Agent owners and approved operators cannot review their own agents
- Tag-based filtering: Feedback can be categorized with two tags (e.g. "reliability", "latency")
- Revocable: The original reviewer can revoke their feedback
- Responses: Any address can append a response to existing feedback
As an API seller, you don't need to interact with this contract directly — Valiron reads it automatically when evaluating agents. But you can view an agent's on-chain reputation in the getAgentProfile() response under onchainReputation.
Behavioral Sandbox
New agents or agents without sufficient on-chain reputation are evaluated in an isolated sandbox environment. The sandbox simulates realistic API interactions and monitors how the agent responds.
The evaluation is holistic — no single factor determines the outcome. The specific factors evaluated, their weights, and the test distribution are proprietary and not disclosed.
See the Sandbox section for graduation rules.
World ID (Proof-of-Personhood)
World ID verifies that an agent is linked to a real human identity via Worldcoin's zero-knowledge proof system. Agents with World ID verification receive a trust boost — the stronger the verification level, the larger the boost.
| Level | Verification | Trust Impact |
|---|---|---|
orb | Biometric (iris scan via World Orb) | Highest boost |
device | Passkey verification | Moderate boost |
phone | SMS verification | Minor boost |
World ID verification is stored immutably — once verified, it cannot be overwritten. Proofs use a nullifier to prevent replay attacks.
As an API seller, you can see whether an incoming agent has World ID verification in the trust profile. You can also encourage your agent customers to verify — it directly improves their trust score on your endpoints.
Icebreaker (Human Attestation)
Icebreaker integration checks whether a human has attested on the Ethereum Attestation Service (EAS) on Base that this agent is their "designated agent."
When present, the agent profile is enriched with the attesting human's identity — their name, verified social handles (X, GitHub, LinkedIn), organization, and Icebreaker profile URL. This provides social context for who is behind an agent.
The Icebreaker attestation appears in the agent profile returned by getAgentProfile().
Plans & Limits
Valiron offers Free and Pro plans. Upgrade via the Operator Dashboard.
| Feature | Free | Pro |
|---|---|---|
| Registered endpoints | 3 | Unlimited |
| Sandbox tests / day | 5 | Unlimited |
| Full analytics | — | ✓ |
| Enriched profiles | — | ✓ |
| Webhooks | — | ✓ |
| Proxy gateway | — | ✓ |
| Evaluation history | — | ✓ |
When you hit a plan limit, the API returns 403 with {"error": "upgrade_required", "feature": "...", "message": "This feature requires a Pro plan."}
API Reference
Constructor
new ValironSDK(config?: ValironConfig)| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | API key (reserved for future use) |
endpoint | string | production | Valiron API base URL (override for self-hosted or dev) |
chain | SupportedChain | server default | Default blockchain network |
timeout | number | 5000 | Request timeout (ms) |
debug | boolean | false | Enable debug logging |
telemetry | TelemetryConfig | enabled | Telemetry settings (see Telemetry) |
checkAgent(agentId, options?)
Quick routing check — returns just the route decision string.
const route = await valiron.checkAgent('25459');
// route: 'prod' | 'prod_throttled' | 'sandbox' | 'sandbox_only'
// With chain override
const monadRoute = await valiron.checkAgent('8348', { chain: 'monad' });getAgentProfile(agentId, options?)
Full trust profile combining on-chain identity, reputation, behavioral data, and routing.
const profile = await valiron.getAgentProfile('25459');
// Response includes:
// profile.identity — on-chain identity (wallet, name, endpoints)
// profile.onchainReputation — ERC-8004 feedback (count, averageScore)
// profile.localReputation — behavioral score, tier, riskLevel
// profile.routing — finalRoute, decision, reasons, signalsgetWalletProfile(wallet, options?)
Reverse-lookup a wallet address to get its trust profile.
const profile = await valiron.getWalletProfile('0x52ce...');
console.log(profile.routing.finalRoute);
// With chain override
const monadProfile = await valiron.getWalletProfile('0xABC...', { chain: 'monad' });resolveWallet(wallet, options?)
Lightweight wallet → agentId resolution without fetching the full trust profile. Useful when you only need to know which agent owns a wallet — e.g. after extracting a wallet from an x402 payment header.
Resolution chain: Redis → in-memory cache → Agent0 subgraph → null.
const resolution = await valiron.resolveWallet('0x52ce...');
console.log(resolution.agentId); // '25459' or null
console.log(resolution.source); // 'redis' | 'subgraph' | 'cache' (in-memory) | 'none'
console.log(resolution.agentName); // 'MyAgent' (from subgraph, if available)
console.log(resolution.chainId); // 1 (from subgraph, if available)
// Then fetch the full profile if needed
if (resolution.agentId) {
const profile = await valiron.getAgentProfile(resolution.agentId);
}| Field | Type | Description |
|---|---|---|
wallet | string | The queried wallet address |
agentId | string | null | Resolved ERC-8004 agent ID, or null if not found |
source | ResolutionSource | "redis" | "subgraph" | "cache" | "none" |
chainId | number | null | Chain ID from the subgraph (if available) |
agentName | string | null | Agent name from the subgraph (if available) |
timestamp | string | ISO timestamp of the resolution |
triggerSandboxTest(agentId, options?)
Run real sandbox tests against an agent and compute a Valiron score.
const result = await valiron.triggerSandboxTest('25459');
console.log(result.valironScore); // 95
console.log(result.tier); // 'AAA'
console.log(result.riskLevel); // 'GREEN'
console.log(result.mode); // 'endpoint-probe' | 'sandbox-relay'
console.log(result.testSummary); // opaque metrics objecttriggerKeyAgentSandbox(agentAddress)
Run sandbox tests against a key-based (Web2) agent. Uses sandbox_relay mode (no endpoint probing needed).
const result = await valiron.triggerKeyAgentSandbox('0x1234...abcd');
console.log(result.tier); // 'A'
console.log(result.riskLevel); // 'GREEN'
console.log(result.valironScore); // 85totalFeedback === 0 trigger triggerSandboxTest(), and key agents with no score trigger triggerKeyAgentSandbox(). The agent receives a 403 with { error: "Agent pending evaluation", retryAfterMs: 30000 }.gate(agentId, options?)
Trust gate — single call combining on-chain reputation + sandbox tests. Designed to sit in front of payment protocols (x402 etc.). Returns an allow/deny decision with a combined score.
const result = await valiron.gate('25459');
console.log(result.allow); // true
console.log(result.score); // 95
console.log(result.tier); // 'AAA'
console.log(result.riskLevel); // 'GREEN'
console.log(result.sandboxRan); // true (first call) / false (cached)
// Custom threshold
const result2 = await valiron.gate('8348', {
minScore: 85, // require A tier or above
trustSignals: ['8004', 'sandbox'],
ttlMs: 3600_000, // re-test every hour
chain: 'monad', // chain override
});
if (result2.allow) {
// proceed to payment
} else {
console.log(result2.reasons); // ['Score 42 below threshold 85']
}| Option | Type | Default | Description |
|---|---|---|---|
minScore | number | 65 | Minimum score to allow (0–100) |
trustSignals | Array<'8004' | 'sandbox' | 'world' | 'icebreaker'> | auto | Optional selected scoring signals. Free supports 8004 and sandbox; Pro adds world and icebreaker. |
ttlMs | number | 86400000 | Cache TTL for sandbox results (ms) |
chain | SupportedChain | constructor default | Blockchain network override |
checkAgent() returns a route decision based on existing data. gate() actively runs sandbox tests (if stale/missing), computes a combined score, and returns a binary allow/deny — ideal for protecting payment endpoints.Provisional scores: If result.provisional === true, the score is from a fast micro-sandbox. A full deep test is running in the background and will update the cached score automatically. Provisional scores are conservative — they may under-estimate the agent's real trust level.
getAgentSnapshot(agentId, options?)
Get the latest behavioral snapshot hash for an agent. Returns an opaque hash of the most recent behavioral evaluation — designed for hash-chain commitment systems that need to commit behavioral state on-chain without accessing raw metrics.
const snapshot = await valiron.getAgentSnapshot('25459');
console.log(snapshot.snapshotHash); // '0x3a7f...' (opaque hash)
console.log(snapshot.previousHash); // '0x0' (genesis) or '0x8b2c...'
console.log(snapshot.encryptedDataUri); // IPFS CID or null
console.log(snapshot.interactionCount); // 15The snapshotHash is computed internally by Valiron from behavioral metrics. It is opaque — you cannot reverse it to raw metrics. Each hash references the previousHash, forming a chain. First evaluation gets "0x0".
Webhooks
Register a webhook to receive evaluation_complete events whenever Valiron evaluates an agent. The payload matches the getAgentSnapshot() response. Pro plan required.
curl -X POST https://valiron-edge-proxy.onrender.com/operator/webhooks/register \
-H "Content-Type: application/json" \
-d '{"event": "evaluation_complete", "url": "https://your-endpoint.com/hooks/valiron", "agentIds": [42, 43]}'The agentIds filter is optional — omit it to receive events for all agents. Duplicate registrations (same event + URL + agentIds) are deduplicated automatically.
| Payload Field | Type | Description |
|---|---|---|
event | string | "evaluation_complete" |
agentId | string | The evaluated agent's ID |
snapshotHash | string | Opaque SHA-256 hash of the evaluation |
previousHash | string | Previous hash in the chain ("0x0" for first) |
interactionCount | number | Total interactions in the evaluation window |
timestamp | string | ISO 8601 timestamp |
proxy(agentId, request, options?)
Proxy an API call through Valiron's trust gateway. The agent sends a request to Valiron, Valiron evaluates trust inline, and either forwards to your real API or blocks with 403. The agent never touches your API directly. Pro plan required.
const result = await valiron.proxy('25459', {
target: 'https://api.example.com/data',
method: 'GET',
headers: { 'Authorization': 'Bearer ...' },
minScore: 65, // minimum trust score (default: 65)
});
// result._valiron — gate evaluation (allow, score, tier, riskLevel)
// result._apiStatus — HTTP status from your real API
// result.response — your API's response body
if (result._valiron.allow) {
console.log(result.response); // Real API data
}| ProxyRequest Field | Type | Description |
|---|---|---|
target | string | Your real API endpoint URL (must be HTTPS, public IP) |
method | string | HTTP method (default: GET) |
headers | Record<string, string> | Headers to forward to target API |
body | unknown | Request body for POST/PUT/PATCH |
minScore | number | Minimum trust score to allow (default: 65) |
Key-Based Agents (Web2)
Not every agent has an ERC-8004 identity. Key-based agents use a standard Ethereum keypair (secp256k1) for identity without needing an on-chain registration. Identity is verified via EIP-191 challenge-response.
// 1. Get a challenge nonce
const { challenge, expiresAt } = await valiron.getKeyAgentChallenge('0x1234...abcd');
// 2. Agent signs the challenge with its private key
const signature = await account.signMessage({ message: challenge });
// 3. Verify — returns the agent's trust profile
const profile = await valiron.verifyKeyAgent({
challenge,
signature,
agentAddress: '0x1234...abcd',
});
console.log(profile.verified); // true
console.log(profile.score); // 85
console.log(profile.tier); // 'A'
console.log(profile.icebreaker); // Icebreaker enrichment (if attested)
// 4. Subsequent lookups (no challenge needed)
const profile2 = await valiron.getKeyAgentProfile('0x1234...abcd');Middleware auto-detection: All middleware (createValironGate, paywall, etc.) automatically checks x-agent-id first (on-chain), then falls back to x-agent-address (key-based). No configuration needed — both agent types work through the same middleware.
Auto-sandbox for key agents: New key agents (verified but not yet scored) are automatically sandbox-evaluated on their first gated request. Use triggerKeyAgentSandbox() or POST /operator/trigger-sandbox-key/{address} to trigger manually.
World ID SDK Methods
Programmatic World ID verification and status lookup. See World ID in Trust Model for background.
// Verify a World ID proof (from IDKit)
const result = await valiron.verifyWorldId('25459', {
proof: '0x...',
merkle_root: '0x...',
nullifier_hash: '0x...',
verification_level: 'orb', // 'orb' | 'device' | 'phone'
});
console.log(result.worldId.verified); // true
// Check verification status
const status = await valiron.getWorldIdStatus('25459');
console.log(status.worldId.verificationLevel); // 'orb'
// Enriched profile (World ID + Icebreaker combined)
const profile = await valiron.getWorldIdProfile('25459');
console.log(profile.humanTrust.hasHumanLink); // true
console.log(profile.humanTrust.hasBackground); // true
console.log(profile.icebreaker?.verifiedHandles);
// [{ source: 'github', handle: 'alice' }, { source: 'x', handle: '@alice' }]dispose()
Flush pending telemetry and release resources. Call this in long-running servers (Express, Fastify) on graceful shutdown. Optional for short-lived scripts — the SDK flushes automatically on process exit.
const valiron = new ValironSDK();
try {
const profile = await valiron.getAgentProfile('25459');
} finally {
await valiron.dispose();
}
// Or on server shutdown
process.on('SIGTERM', async () => {
await operator.dispose();
process.exit(0);
});Middleware
Drop-in middleware for every major Node.js framework. All middleware variants auto-detect on-chain (x-agent-id) and key-based (x-agent-address) agents automatically.
Express / Connect
import { ValironSDK, createValironGate } from '@valiron/sdk';
const valiron = new ValironSDK({ chain: 'monad' });
// Basic — uses x-agent-id header, minScore 65, 30s client-side cache
// Safe with Express 4 (async errors handled via Promise.catch(next))
app.use('/api/paid', createValironGate({ sdk: valiron }));
// Custom threshold + longer cache
app.use('/api/premium', createValironGate({
sdk: valiron,
minScore: 85,
cacheTtlMs: 60_000, // 60s
}));
// Custom agent ID extraction + hooks
app.use('/api/custom', createValironGate({
sdk: valiron,
extractAgentId: (req) => req.query.agent_id as string,
onAllow: (req, result) => {
console.log(`Allowed agent ${result.agentId} (score: ${result.score})`);
},
onDeny: (req, res, result) => {
res.status(403).json({
error: 'Insufficient trust score',
requiredTier: 'A',
currentTier: result.tier,
});
},
}));Fastify
import Fastify from 'fastify';
import { ValironSDK, valironFastifyPlugin } from '@valiron/sdk';
const app = Fastify();
const valiron = new ValironSDK({ chain: 'monad' });
// Gate all routes
app.register(valironFastifyPlugin, { sdk: valiron });
// Or gate a specific prefix
app.register(valironFastifyPlugin, {
sdk: valiron,
prefix: '/api',
minScore: 85,
});
app.get('/api/data', async (req) => {
// req.valiron is populated with GateResult
return { data: 'protected', tier: req.valiron.tier };
});Next.js
Use createValironNextMiddleware() in your project's middleware.ts to gate API routes.
// middleware.ts (Next.js project root)
import { ValironSDK, createValironNextMiddleware } from '@valiron/sdk';
const valiron = new ValironSDK({ chain: 'monad' });
const valironMiddleware = createValironNextMiddleware({
sdk: valiron,
paths: ['/api/paid', '/api/premium'], // only gate these paths
minScore: 65,
});
export async function middleware(request: Request) {
return valironMiddleware(request);
}
export const config = { matcher: '/api/:path*' };Returns undefined (pass through) when the agent is allowed, or a JSON Response (401/403/503) when blocked. Paths not in the paths array are passed through without checking.
Generic (Hono, Koa, Bun…)
Use valironGateCheck() for any framework. Returns a structured result you can map to any HTTP response type.
import { ValironSDK, valironGateCheck } from '@valiron/sdk';
const valiron = new ValironSDK();
// Hono
app.use('/api/*', async (c, next) => {
const gate = await valironGateCheck(valiron, {
agentId: c.req.header('x-agent-id') ?? null,
agentAddress: c.req.header('x-agent-address') ?? null,
minScore: 65,
});
if (!gate.allow) return c.json(gate.body, gate.status);
c.set('valiron', gate.result);
await next();
});
// Koa
app.use(async (ctx, next) => {
const gate = await valironGateCheck(valiron, {
agentId: ctx.get('x-agent-id') || null,
agentAddress: ctx.get('x-agent-address') || null,
});
if (!gate.allow) {
ctx.status = gate.status;
ctx.body = gate.body;
return;
}
ctx.state.valiron = gate.result;
await next();
});Middleware Error Responses
All middleware variants use identical error responses:
| Status | When | Body |
|---|---|---|
| 401 | No x-agent-id or x-agent-address header | { error, message, identitySkill } |
| 403 | Agent blocked (score below threshold) | { error, allow, score, tier, riskLevel, route, ... } |
| 403 | New agent pending evaluation | { error: "Agent pending evaluation", retryAfterMs: 30000 } |
| 503 | Gate unavailable (network error, timeout) | { error: "Trust gate unavailable — request denied (fail-closed)" } |
503 and denies the request. Valiron never fails open — an unknown agent is never allowed through.Operator SDK
The ValironOperator class is purpose-built for API sellers who want to monetize their endpoints. It wraps the trust gate with pricing and usage tracking — so you can protect and charge for your API with one line of middleware.
Requires an operator API key (val_op_ prefix) from the Operator Dashboard.
import { ValironOperator } from '@valiron/sdk';
const operator = new ValironOperator({
apiKey: 'val_op_xxxx', // from valiron.co/dashboard
chain: 'ethereum', // default chain (optional)
timeout: 5000, // ms (optional)
debug: false, // log gate checks (optional)
});| Option | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Operator API key (must start with val_op_) |
chain | SupportedChain | No | Default blockchain (default: ethereum) |
timeout | number | No | Request timeout in ms (default: 5000) |
debug | boolean | No | Log gate checks to console (default: false) |
paywall(config)
Express/Connect middleware that gates access and tracks usage. Extracts X-Agent-Id from request headers, runs the trust gate, and attaches req.valiron with the gate result and pricing info.
// One line to monetize an endpoint
app.use('/api/inference', operator.paywall({
pricePerCall: 0.05, // USD per call
minTrustScore: 45, // minimum score to allow (default: 45)
ttlMs: 86400000, // cache TTL in ms (default: 24h)
}));
app.post('/api/inference', (req, res) => {
// req.valiron.allow === true (guaranteed — denied agents never reach here)
// req.valiron.tier === 'AAA'
// req.valiron.pricePerCall === 0.05
res.json({ result: 'inference output' });
});| Option | Type | Default | Description |
|---|---|---|---|
pricePerCall | number | — | Price per API call in USD (required) |
minTrustScore | number | 45 | Minimum Valiron score to allow access |
ttlMs | number | 86400000 | Cache TTL for trust results (ms, default 24h) |
onDeny | (req, res, result) => void | 403 JSON | Custom handler when agent is denied |
onAllow | (req, result) => void | — | Hook called after agent is allowed |
With custom hooks:
app.use('/api/premium', operator.paywall({
pricePerCall: 0.10,
minTrustScore: 65,
onDeny: (req, res, result) => {
res.status(403).json({
error: 'Agent blocked',
tier: result.tier,
score: result.score,
message: 'Minimum trust score of 65 required. Improve your on-chain reputation or pass sandbox evaluation.',
});
},
onAllow: (req, result) => {
console.log(`Agent ${result.agentId} allowed — tier: ${result.tier}, price: $0.10`);
},
}));fastifyPaywall(config)
Same as paywall() but for Fastify. Register as a plugin with an optional route prefix.
import Fastify from 'fastify';
import { ValironOperator } from '@valiron/sdk';
const app = Fastify();
const operator = new ValironOperator({ apiKey: 'val_op_xxxx' });
// Gate all routes under /api
app.register(operator.fastifyPaywall({
pricePerCall: 0.10,
prefix: '/api',
minTrustScore: 65,
}));
app.get('/api/data', async (req, reply) => {
// req.valiron is populated with gate result + pricing
return { data: 'protected content', tier: req.valiron.tier };
});Accepts the same options as paywall() plus an optional prefix to scope the gate to specific routes.
createValironGate() is a low-level middleware that only gates access. ValironOperator.paywall() adds pricing, operator identity, and usage tracking on top — it's the recommended integration for API sellers.Dynamic Scoring
Valiron enables trust-based dynamic pricing for your API endpoints. Agents with lower trust scores pay more per request — covering the potential infrastructure damage they may cause — while highly trusted agents get discounted rates as a reward for good behavior.
This creates a self-balancing economic model: bad actors subsidize their own risk, and good actors are incentivized to maintain their reputation.
Pricing by Trust Tier
| Tier | Trust Level | Risk | Relative Price |
|---|---|---|---|
| AAA | Highest | Prime | Lowest |
| AA | Very high | High grade | Low |
| A | High | Upper medium | Low |
| BAA | Medium | Medium | Medium |
| BA | Below medium | Speculative | Higher |
| B | Low | Highly speculative | High |
| CAA – C | Lowest | Substantial risk | Blocked |
Implementation
Use the trust gate result to set per-request pricing. This example pairs Valiron with x402 payment headers:
import { ValironSDK, createValironGate } from '@valiron/sdk';
const valiron = new ValironSDK({ chain: 'monad' });
const trustGate = createValironGate({ sdk: valiron, minScore: 50 });
// Pricing table — bad agents pay more to offset infra risk
const PRICE_BY_TIER: Record<string, number> = {
AAA: 5, // $0.005
AA: 5, // $0.005
A: 8, // $0.008
BAA: 10, // $0.010
BA: 25, // $0.025
B: 50, // $0.050
};
function dynamicPricing(req: any, res: any, next: any) {
const tier = req.valiron?.tier || 'B';
const price = PRICE_BY_TIER[tier] ?? 50;
// Attach price to request for downstream payment check
req.priceMillicents = price;
// If payment header is missing, return 402 with tier-adjusted price
if (!req.headers['x-payment']) {
return res.status(402).json({
accepts: [{
scheme: 'exact',
maxAmountRequired: price,
payTo: '0x...',
network: 'monad',
}],
meta: { tier, score: req.valiron?.score },
});
}
next();
}
// Flow: Trust Gate → Dynamic Pricing → Handler
app.get('/api/data', trustGate, dynamicPricing, (req, res) => {
res.json({ data: 'Here you go', tier: req.valiron.tier });
});Sandbox
The sandbox is an isolated testing environment where Valiron evaluates agent behavior before granting production access to your API. New agents start in the sandbox automatically.
- A sandbox test is triggered (via SDK, HTTP API, or automatically for new agents)
- The agent receives a series of simulated API interactions
- The sandbox monitors how the agent handles normal requests, rate limits, errors, and edge cases
- A trust evaluation is performed and a Moody's-style tier is assigned
- Based on the tier, a route decision determines what access level the agent receives
The sandbox tests against a mix of successful responses, rate-limit responses (429), server errors (500), auth challenges (401/403), and payment requests (402). The exact distribution and test patterns are proprietary.
Graduation
Agents graduate from sandbox to production based on their behavioral evaluation:
| Outcome | Route | What It Means |
|---|---|---|
| Graduated | prod | Strong behavioral compliance — full production access |
| Throttled | prod_throttled | Passes with concerns — allowed with rate limiting |
| Blocked | sandbox_only | Risky behavior — blocked from production |
Once graduated, the trust evaluation is cached. The route decision persists until a new sandbox test is triggered or the cache expires (default 24 hours).
prod access. The exact review count and score thresholds are not disclosed.Tips for Passing
Agents that demonstrate responsible, well-behaved API usage will earn higher trust tiers. The specific scoring criteria are proprietary, but in general: respect API boundaries, handle errors gracefully, and avoid aggressive request patterns.
Auto-Sandbox
When a new agent hits a gated endpoint for the first time, middleware automatically triggers sandbox evaluation in the background. No manual trigger is needed.
| Agent Type | Detection | Trigger |
|---|---|---|
| On-chain (ERC-8004) | totalFeedback === 0 | triggerSandboxTest() |
| Key-based (Web2) | verified && score === null | triggerKeyAgentSandbox() |
While evaluation runs, the agent receives a 403 with { error: "Agent pending evaluation", retryAfterMs: 30000 }. The cache prevents duplicate triggers during the evaluation window.
Solana
Solana agents use the QuantuLabs 8004-solana registry instead of EVM contracts. The SDK handles the difference automatically — just pass chain: 'solana'.
| Concept | EVM | Solana |
|---|---|---|
| Agent ID | Numeric token ID (e.g. 25459) | Base-58 Metaplex pubkey or sequential integer |
| Wallet format | 0x-prefixed Ethereum address | Base-58 Solana public key |
| Identity Registry | 0x8004A169... | 8oo4dC4Jv... |
| Reputation | 0x8004BAa1... | ATOM engine (AToMw53ai...) |
| Feedback write-back | Manual | Automatic after sandbox evaluation |
const valiron = new ValironSDK({ chain: 'solana' });
// By asset pubkey
const profile = await valiron.getAgentProfile('DFkntsJ9aTCHkK88m6WZVQEvLdLNi4X1LVUgRMqetFPM');
// By sequential ID (convenience)
const profile2 = await valiron.getAgentProfile('1226');
// Liveness check — pings all declared service endpoints
const liveness = await fetch(
'https://valiron-edge-proxy.onrender.com/operator/agent/DFkntsJ9.../liveness?chain=solana'
);ATOM engine metrics: Solana reputation includes additional fields not available on EVM — trustTier, qualityScore, confidence, riskScore, and uniqueCallers. These appear in the profile under onchainReputation.solana.
Automatic feedback write-back: After every sandbox test or gate evaluation, Valiron writes the computed score back to the Solana reputation registry via the ATOM engine's giveFeedback(). This means Solana agents build on-chain reputation automatically through normal Valiron usage.
Response Types
All types are exported from @valiron/sdk and can be imported directly for type-safe code.
import type {
AgentProfile, WalletProfile, GateResult, SandboxResult,
AgentSnapshotSummary, WalletResolution, KeyAgentProfile,
WorldIdStatus, WorldIdAgentProfile, ProxyResponse,
RouteDecision, MoodysRating, RiskLevel, SupportedChain,
ValironError,
} from '@valiron/sdk';GateResult
| Field | Type | Description |
|---|---|---|
allow | boolean | Whether the agent is allowed through |
score | number | Combined Valiron trust score (0–100) |
tier | MoodysRating | AAA through C |
riskLevel | RiskLevel | "GREEN" | "YELLOW" | "RED" |
route | RouteDecision | prod / prod_throttled / sandbox / sandbox_only |
agentId | string | The evaluated agent's ID |
wallet | string | Agent's wallet address |
chain | ChainContext | Network, registry addresses used |
sandboxRan | boolean | Whether sandbox tests ran this call (false = cached) |
cached | boolean | Whether cached results were used |
provisional | boolean? | If true, score is from a fast micro-sandbox; a full deep test is running in the background |
AgentProfile
| Field | Type | Description |
|---|---|---|
agentId | string | ERC-8004 agent ID |
identity | AgentIdentity | On-chain identity (wallet, name, endpoints, trust models) |
onchainReputation | OnchainReputation | Feedback count, average score, entries, and Solana ATOM data |
localReputation | LocalReputation | null | Behavioral score, tier, riskLevel, graduated status |
routing | RoutingExplanation | finalRoute, decision text, reasons array, signals breakdown |
chain | ChainContext | Network, RPC URL, registry contract addresses |
worldId | WorldIdStatus? | World ID verification status (if checked) |
timestamp | string | ISO 8601 timestamp |
KeyAgentProfile
| Field | Type | Description |
|---|---|---|
agentAddress | string | Ethereum address (keccak256 of secp256k1 pubkey) |
verified | boolean | Identity verified via challenge-response |
score | number | null | Behavioral score (0–100) |
tier | MoodysRating | null | AAA through C |
riskLevel | RiskLevel | null | GREEN / YELLOW / RED |
route | RouteDecision | null | Route decision |
icebreaker | IcebreakerOwnership | null | Icebreaker attestation context |
reasons | string[] | Human-readable trust explanation |
Request Headers
| Header | Purpose | Notes |
|---|---|---|
X-Agent-Id | On-chain agent ID (ERC-8004 / Solana) | Checked first by all middleware |
X-Agent-Address | Key-based agent Ethereum address | Fallback when no X-Agent-Id |
X-Chain | Blockchain network override | Alternative to ?chain= query param |
Authorization | Operator API key | Bearer val_op_xxxx |
All Exports
Everything available from @valiron/sdk:
// Classes
export { ValironSDK, ValironOperator, ValironClient, ValironError };
// Middleware
export { createValironGate, valironFastifyPlugin, createValironNextMiddleware, valironGateCheck };
// Utilities
export { isValidAddress, generateChallenge };
// All TypeScript types (AgentProfile, GateResult, etc.)
export type { ... }; // See full list in types.tsTelemetry
The SDK collects opt-out usage telemetry to improve reliability. Events include SDK version, runtime, environment, method names, chain labels, latency, HTTP status/error buckets, route decisions, and coarse score/reputation buckets. Raw agent IDs, wallet addresses, API keys, and exact scores are not sent in SDK telemetry. Operator paywall usage logs are separate customer analytics authenticated with the operator API key.
// Disable telemetry entirely
const valiron = new ValironSDK({
telemetry: { enabled: false },
});
// Reduce volume with sampling
const valiron2 = new ValironSDK({
telemetry: { sampleRate: 0.1 }, // only 10% of events
});
// Custom event handler (e.g. forward to your own analytics)
const valiron3 = new ValironSDK({
telemetry: {
onEvent: (event) => myAnalytics.track(event),
},
});| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Enable/disable telemetry |
sampleRate | number | 1.0 | Sampling rate (0.0–1.0) |
appId | string | — | Application identifier for grouping |
env | "prod" | "staging" | "dev" | "prod" | Environment label |
onEvent | (event) => void | — | Custom event callback |
Error Handling
All SDK methods throw typed ValironError instances with a code field for programmatic handling.
import { ValironError } from '@valiron/sdk';
try {
const profile = await valiron.getAgentProfile('123');
} catch (error) {
if (error instanceof ValironError) {
switch (error.code) {
case 'TIMEOUT_ERROR': // Request timed out
case 'NETWORK_ERROR': // Could not reach API
case 'API_ERROR': // Non-2xx response (check error.statusCode)
}
}
}| Error Code | Meaning |
|---|---|
TIMEOUT_ERROR | Request exceeded the configured timeout (default 5000ms) |
NETWORK_ERROR | Could not reach the Valiron API (DNS, connection refused, etc.) |
API_ERROR | Server returned a non-2xx response — check error.statusCode |
Common HTTP status codes from the Valiron API:
| Status | Cause |
|---|---|
400 | Invalid agentId format or missing required fields |
401 | Missing agent identity header (middleware) or invalid operator API key |
403 | Agent blocked (score below threshold) or feature requires Pro plan |
404 | Agent not found on the specified chain |
429 | Sandbox daily limit exceeded (free plan) |
503 | Trust gate unavailable — request denied (fail-closed) |