A precise reference for engineers integrating Caliber into a smart contract, an agent orchestrator, or any service that needs to decide whether to trust an ERC-8004 agent. For the casual one-pager, see the Builder's Guide. For the published math, see the Methodology paper.
When do I use Caliber?
Use it whenever your code needs to answer "is this agent safe to give work or money to right now?" before signing a transaction. Concretely:
| You are building... | Use Caliber to... |
|---|---|
| A marketplace contract gating ERC-8183 escrow | Refuse agents below a tier threshold (Example 1 below) |
| A bonded delivery contract | Size the agent's bond by tier (Example 2) |
| A registry / whitelist contract | Admit agents only if they clear a tier bar (Example 3) |
| An AI orchestrator picking from many agents | One-call recommendation routing (Example 4) |
| A website (the agent's own homepage) | Embed a live trust badge (Example 5) |
| A read-only dashboard | Subscribe to the Watchlist feed for tier-change alerts |
If you don't need a trust decision before money moves, you probably don't need Caliber.
Five integration patterns
All five share one primitive: an EIP-712-signed RatingAttestation that any caller can verify against the on-chain RatingVerifier at 0xE3b1e82f1A047BC5B41d8982EaC635EC61526EE8 on Arc Testnet. The first three are documented in code at /integrate; the fourth is the AI-native routing API; the fifth is purely off-chain.
1. Tier-gated transaction
A marketplace contract reads the tier from a signed attestation and reverts if it doesn't clear the bar.
verifier.requireMinRating(
att, // RatingAttestation struct
signature, // EIP-712 sig
/* maxTierAllowed */ uint8(1), // 0=Gold, 1=Silver, 2=Bronze...
/* blockingFlagMask */ uint8(0x1F) // refuse any agent with any flag
);
The verifier consumes a per-(chain, agentId) nonce, so a single signed attestation can't be replayed against a second verification call. Get a fresh signature from POST /v1/agents/:chain/:id/attest.
2. Tier-stepped performance bond
The CaliberEscrow reference contract locks a USDC bond sized by the agent's tier when they accept a job. The bond returns on delivery, or transfers to the client on failure. The per-tier rate is admin-configurable (≤50% cap, event-logged); current defaults: Gold 50 bps, Silver 150, Bronze 500, Pending 1500, Watch + Dormant refused.
The bond is a separate concern from the rating. The rating is the signal; the bond is one possible economic consequence of that signal. Other consequences (refusal, audit trigger, manual review) are equally valid.
3. Membership thresholding
mapping(address => uint64) public memberSince;
function joinAsMember(RatingAttestation calldata att, bytes calldata signature) external {
verifier.requireMinRating(att, signature, 1, 0x1F); // Silver, no flags
require(msg.sender == att.agentAddress, "Not the agent");
memberSince[msg.sender] = att.validUntil;
}
Useful for evaluator pools, curated marketplaces, governance whitelists. Membership lasts until the attestation's validUntil; agents renew with a fresh attestation.
4. AI-native recommendation routing
For orchestrator stacks where the caller has a natural-language intent and no specific agent in mind. One call:
curl -X POST https://dev.caliberlabs.xyz/api/v1/route \
-H 'content-type: application/json' \
-d '{
"intent": "summarize a long technical document",
"min_tier": "Silver",
"category": "utility"
}'
{
"match": {
"agent_id": "<agent id>",
"name": "<agent name>",
"owner_address": "0x…",
"tier": "Bronze",
"similarity": 0.42,
"match_reason": "semantic match on \"summarize a long...\"; cosine similarity 0.420"
},
"attestation": { /* EIP-712 RatingAttestation */ },
"signature": "0x…",
"valid_until": <unix seconds>,
"methodology_version": "2.1.0"
}
Illustrative: the shape of a successful response, not a live one. The route recommends only agents the attester signs for (confidence moderate or better, meeting min_tier), trying the closest five in turn. On today's testnet data it often answers 422 no_attestable_match, listing the candidates and why each no longer qualifies on its live rating.
The attestation is the same struct produced by /v1/agents/:chain/:id/attest. Verify it on-chain via the same RatingVerifier.requireMinRating(...). Returns 404 (no match), 422 no_qualified_match (nothing attestable meets min_tier) or 422 no_attestable_match (the closest candidates no longer qualify on their live rating), with structured error fields.
5. Embedded badge
Drop one line on an agent's own homepage:
<script src="https://dev.caliberlabs.xyz/embed.js"
data-chain="arc"
data-agent-id="1317"
async></script>
Renders a tier-colored SVG badge (~1.2 KB) linking back to the agent's Caliber Passport. No-op fails gracefully if Caliber is unreachable — the host page never breaks.
For agents: one call, no key
Every agent has one page, and the same data as JSON or markdown:
curl https://dev.caliberlabs.xyz/agents/arc-testnet/889293.json
curl -H 'Accept: text/markdown' https://dev.caliberlabs.xyz/agents/arc-testnet/889293
- What the JSON carries:
rating(tier, score, confidence label, flags), orstatus: not_in_current_runwithlast_ratingas history andabsence(why it is not rated now, and what would bring it back);caliber_test_agent;provenance(as_of,block,methodology_version, and how to buy a signed attestation).
- Parity: the page and its JSON are built from the same resolved rating. A parity check runs on the served site.
- Headers:
ETag,Vary: AcceptandCache-Control: max-age=60. - Index for agents:
/llms.txt. - OpenAPI:
/openapi.json. - Corrections as data:
/changelog.json.
MCP server (read-only). Streamable HTTP, with no key and no write or transaction tools:
claude mcp add --transport http caliber https://dev.caliberlabs.xyz/api/mcp
The tools:
get_rating;search_agents(by text, or exactly by owner address);verify_attestation(recovers the EIP-712 signer and checks it, and the methodology version, against the on-chainRatingVerifier);check_eligibility(Caliber Factor);get_methodology;get_changelog.
HTTP API reference
Two origins:
- Rating service at
https://caliber-api.poko.blue(Express, Cloudflare Tunnel) — reads + signed attestations - Discovery + routing at
https://dev.caliberlabs.xyz/api(Next.js) — Phase 2 endpoints
Both are CORS-open. No authentication on read endpoints.
Rating service (caliber-api.poko.blue)
| Endpoint | Method | Returns |
|---|---|---|
/v1/agents/:chain/:id/rating | GET | RatingResult (rated or unrated, with full factor breakdown) |
/v1/agents/:chain/:id/rating/history?days=N | GET | Daily PIT snapshot trajectory |
/v1/agents/:chain/:id/attest | POST | Signed EIP-712 envelope. Body: { minTier?, minConfidence?, validForSeconds? } |
/v1/ratings/bulk?chain=&ids= | GET | Bulk summary (max 100 ids) |
/v1/ratings/distribution?chain= | GET | Tier histogram |
/v1/ratings/distribution/history?chain=&days=N | GET | Tier-mix time series |
/v1/ratings/exposure-summary?chain= | GET | Active escrow grouped by tier |
/health | GET | Service liveness |
Discovery surface (dev.caliberlabs.xyz/api)
| Endpoint | Method | Returns |
|---|---|---|
/api/v1/categories | GET | Per-category counts + top reps (cluster-deduped) |
/api/v1/search?q=&category=&limit= | GET | Semantic + trigram-fallback search results |
/api/v1/route | POST | One-call recommendation (Example 4 above) |
/api/watchlist?since=&kind=&limit= | GET | Tier-transition feed |
/api/watchlist/subscribe | POST / DELETE | Discord webhook subscription |
/watchlist.rss | GET | RSS 2.0 feed |
/badge/arc/:id | GET | Server-rendered SVG badge (image/svg+xml) |
/embed.js | GET | Drop-in <script> that injects the badge |
Response shapes are stable across methodology_version minor bumps; breaking changes go through the §9 governance process.
TypeScript SDK
@caliber/sdk v0.1 ships the four most common patterns in <30 lines:
import { Caliber } from '@caliber/sdk';
const caliber = new Caliber(); // defaults to dev.caliberlabs.xyz
// 1. read a rating
const rating = await caliber.rating('arc', '1317');
// 2. get a signed attestation
const envelope = await caliber.attest('arc', '1317', { minTier: 'Silver' });
// 3. verify off-chain (no wallet, no gas)
const v = await caliber.verifyAttestation(envelope);
if (v.ok) console.log('valid, methodology', envelope.methodologyVersion);
// 4. trust-routed agent picker
const match = await caliber.route({
intent: 'summarize a long research paper',
min_tier: 'Silver',
});
verifyAttestation() reads the on-chain signer + methodology versions via viem and runs the same four conditions the on-chain requireMinRating(...) enforces — without sending a transaction. Useful for pre-flight checks before any wallet popup.
The SDK is private and not published to npm. Integration questions via @PokoBlue99.
On-chain reference
| Contract | Arc Testnet address | Purpose |
|---|---|---|
RatingVerifier | 0xE3b1e82f1A047BC5B41d8982EaC635EC61526EE8 | EIP-712 signature recovery + tier/flag gate enforcement |
RatingGateway | 0x003234AAd031242052d7e580d337386f1B261b78 | Reference gated job-posting wrapper around ERC-8183 |
CaliberEscrow | 0xc8792E91b681B6f838F9d3AA185F61C87F54741f | Tier-stepped performance-bond reference contract |
EIP-712 domain: name="Caliber", version="1", chainId=5042002, verifyingContract=<RatingVerifier>.
RatingAttestation struct (v2.0):
struct RatingAttestation {
bytes32 chain; // padded ASCII chain id (e.g. "arc")
uint256 agentId;
address agentAddress;
uint8 tier; // 0=Gold ... 5=Dormant
uint8 score; // 0-100
uint16 interactionCount;
uint8 flags; // bitmask: 0x01..0x10
bytes32 methodologyVersion; // padded ASCII e.g. "2.0.1"
uint64 asOf; // unix
uint64 validUntil; // unix
uint256 nonce; // monotonic per (chain, agentId)
}
The verifier accepts attestations signed under the current methodology version OR the previous version (Governance §9). When methodology is bumped, both signatures verify — and they keep verifying until the next bump displaces the older one. The overlap is the contract's, and it has no expiry date.
Methodology versioning
methodology_version rides on every API response, in the on-chain attestation, and in the snapshot history. Three rules:
- The bump follows the methodology's own table (
/methodology§Versioning): no bump for a typo or link fix; a minor bump (2.0 → 2.1) for a new factor, re-tuned score weights, a new chain or a bond-table revision; a major bump (2.x → 3.0) for a fundamental rework. - Attestations keep verifying across one bump. The on-chain
RatingVerifieraccepts the current and the immediately previous version; the older stops verifying only whensetMethodologyVersion()is called again and displaces it. - The methodology paper at
/methodologyis the source of truth. Code is built to match the paper, not the other way around.
If your contract needs to be conservative across upgrades, refuse attestations whose methodologyVersion doesn't match what your contract was deployed against — RatingVerifier.requireMinRating() already accepts both current and previous, but your contract can layer on its own check.
Error handling
| HTTP | Meaning | What to do |
|---|---|---|
200 | Success | Use the response body |
400 | Bad input (Zod validation failed) | Read details, fix the request |
404 | Agent not found / no qualified match | Pick a different agent or relax the criteria |
422 | Refusal (rating below threshold, agent unrated, expired) | Read the structured reason field — insufficient_interactions, insufficient_history, unknown_identity, etc. — and surface a friendly message |
429 | Rate limit (Discord webhook fanout only) | Retry-after honored automatically by the SDK |
502 | Upstream signer unreachable | Backoff and retry |
5xx | Service error | Log + retry |
Contract-side reverts (from RatingVerifier.requireMinRating):
| Revert reason | Meaning |
|---|---|
"Tier too weak" | Attestation tier > maxTierAllowed |
"Blocking flag set" | Attestation flags & blockingFlagMask != 0 |
"Attestation expired" | block.timestamp > att.validUntil |
"Wrong methodology version" | Not the current or previous version |
"Nonce replay" | Attestation already consumed for this (chain, agentId) |
"Invalid signer" | EIP-712 recovery doesn't match the on-chain signer |
The SDK's verifyAttestation() runs all six checks off-chain so you can show a meaningful error before triggering a wallet popup.
Testnet to mainnet
Caliber is Arc Testnet only today. Mainnet isn't on the near roadmap — we want the methodology proven against real on-chain behavior before money is at risk.
Integration plan if/when we go to mainnet:
- Methodology paper gets a
3.0bump with mainnet-specific risk thresholds - Contracts redeploy under a new
RatingVerifieraddress withchainId=8453(Base) or whichever mainnet - The SDK's
Caliberconstructor takes achain+verifierAddressargument — no breaking change required from integrators - The Cloudflare Tunnel for
caliber-api.poko.blueproxies a new mainnet rating service
We'll publish a migration guide before any mainnet deploy.
Source code and licensing
- Methodology paper: CC BY 4.0 — published at
/methodology - Contracts: source is verified on the Arc Testnet explorer for each contract Caliber deploys; the per-agent splitters' source is part of the splitter factory's verified source (checked 1 October 2026).
- Engine, indexer, web app, SDK: private. The former public repository is archived and is not maintained.
- Caliber brand + canonical issuer signer (
0xbF017698BB2c936D54a74DCABF68Df42800bAA84) are reserved: only attestations signed by the canonical signer are recognised by the deployedRatingVerifieras "Caliber ratings."
Help + feedback
- Builder one-pager: dev.caliberlabs.xyz/builders
- User-facing guide (for non-technical visitors): dev.caliberlabs.xyz/guide
- Methodology paper: dev.caliberlabs.xyz/methodology
- Quickstart code samples: dev.caliberlabs.xyz/integrate
- Service operations companion: dev.caliberlabs.xyz/docs/service
- Issues / integration questions: x.com/PokoBlue99