skip to contentas of

//developer_guide

Build with Caliber

The precise integration reference. Five patterns, full HTTP API, SDK quickstart, on-chain ABI, and error tables. For the gentle intro, see /builders.

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 escrowRefuse agents below a tier threshold (Example 1 below)
A bonded delivery contractSize the agent's bond by tier (Example 2)
A registry / whitelist contractAdmit agents only if they clear a tier bar (Example 3)
An AI orchestrator picking from many agentsOne-call recommendation routing (Example 4)
A website (the agent's own homepage)Embed a live trust badge (Example 5)
A read-only dashboardSubscribe 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), or status: not_in_current_run with last_rating as history and absence (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: Accept and Cache-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-chain RatingVerifier);
  • 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)

EndpointMethodReturns
/v1/agents/:chain/:id/ratingGETRatingResult (rated or unrated, with full factor breakdown)
/v1/agents/:chain/:id/rating/history?days=NGETDaily PIT snapshot trajectory
/v1/agents/:chain/:id/attestPOSTSigned EIP-712 envelope. Body: { minTier?, minConfidence?, validForSeconds? }
/v1/ratings/bulk?chain=&ids=GETBulk summary (max 100 ids)
/v1/ratings/distribution?chain=GETTier histogram
/v1/ratings/distribution/history?chain=&days=NGETTier-mix time series
/v1/ratings/exposure-summary?chain=GETActive escrow grouped by tier
/healthGETService liveness

Discovery surface (dev.caliberlabs.xyz/api)

EndpointMethodReturns
/api/v1/categoriesGETPer-category counts + top reps (cluster-deduped)
/api/v1/search?q=&category=&limit=GETSemantic + trigram-fallback search results
/api/v1/routePOSTOne-call recommendation (Example 4 above)
/api/watchlist?since=&kind=&limit=GETTier-transition feed
/api/watchlist/subscribePOST / DELETEDiscord webhook subscription
/watchlist.rssGETRSS 2.0 feed
/badge/arc/:idGETServer-rendered SVG badge (image/svg+xml)
/embed.jsGETDrop-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

ContractArc Testnet addressPurpose
RatingVerifier0xE3b1e82f1A047BC5B41d8982EaC635EC61526EE8EIP-712 signature recovery + tier/flag gate enforcement
RatingGateway0x003234AAd031242052d7e580d337386f1B261b78Reference gated job-posting wrapper around ERC-8183
CaliberEscrow0xc8792E91b681B6f838F9d3AA185F61C87F54741fTier-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 RatingVerifier accepts the current and the immediately previous version; the older stops verifying only when setMethodologyVersion() is called again and displaces it.
  • The methodology paper at /methodology is 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

HTTPMeaningWhat to do
200SuccessUse the response body
400Bad input (Zod validation failed)Read details, fix the request
404Agent not found / no qualified matchPick a different agent or relax the criteria
422Refusal (rating below threshold, agent unrated, expired)Read the structured reason field — insufficient_interactions, insufficient_history, unknown_identity, etc. — and surface a friendly message
429Rate limit (Discord webhook fanout only)Retry-after honored automatically by the SDK
502Upstream signer unreachableBackoff and retry
5xxService errorLog + retry

Contract-side reverts (from RatingVerifier.requireMinRating):

Revert reasonMeaning
"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:

  1. Methodology paper gets a 3.0 bump with mainnet-specific risk thresholds
  2. Contracts redeploy under a new RatingVerifier address with chainId=8453 (Base) or whichever mainnet
  3. The SDK's Caliber constructor takes a chain + verifierAddress argument — no breaking change required from integrators
  4. The Cloudflare Tunnel for caliber-api.poko.blue proxies 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 deployed RatingVerifier as "Caliber ratings."

Help + feedback

see also