Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
fabianferno avatar

World Agentkit

  • 1 installs
  • 1 repo stars
  • Updated April 6, 2026
  • fabianferno/caas

Server-side reference for integrating Worldcoin AgentKit and x402 to let websites accept verified human-backed agent traffic and configure paid access modes.

About

Reference for building x402 endpoints that authenticate AgentKit-verified agents, configure AgentBook registration, and set free, trial, or discount access modes. A backend developer uses it to gate API endpoints so verified agents pass while bots are blocked.

  • Covers Hono/Express/Next.js server setup and validation helpers
  • Registration on Worldchain plus World Chain/Base payments

World Agentkit by the numbers

  • 1 all-time installs (skills.sh)
  • Ranked #426 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
  • Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/fabianferno/caas --skill world-agentkit

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
repo stars1
Last updatedApril 6, 2026
Repositoryfabianferno/caas

What it does

Server-side reference for integrating Worldcoin AgentKit and x402 to let websites accept verified human-backed agent traffic and configure paid access modes.

Files

SKILL.mdMarkdownGitHub ↗

AgentKit Server Integration & SDK Reference

AgentKit extends x402 allowing websites to distinguish human-backed agents from bots and scripts. Enable agentic traffic to access API endpoints while blocking malicious actors, scalpers, and spam.

Quick Start

Default implementation path:

  • Accepts payments on both World Chain and Base
  • Agent registration on Worldchain
  • AgentBook lookup pinned to Worldchain
  • free-trial mode with 3 uses
  • Hono + @x402/hono as reference server example

Step 1: Install

npm install @worldcoin/agentkit

Step 2: Register the agent in AgentBook

Register the wallet address your agent will sign with:

npx @worldcoin/agentkit-cli register <agent-address>

By default the CLI registers on Worldchain and submits through the hosted relay.

During registration the CLI: 1. Looks up the next nonce for the agent address 2. Prompts the World App verification flow 3. Submits the registration transaction

Step 3: Wire the hooks-based server flow

The example below shows the maintained Hono wrapper path. AgentKit itself is not Hono-only: Express and Next.js route handlers can use the same hooks and low-level helpers.

import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { HTTPFacilitatorClient } from '@x402/core/http'
import { ExactEvmScheme } from '@x402/evm/exact/server'
import {
    paymentMiddlewareFromHTTPServer,
    x402HTTPResourceServer,
    x402ResourceServer,
} from '@x402/hono'
import {
    agentkitResourceServerExtension,
    createAgentBookVerifier,
    createAgentkitHooks,
    declareAgentkitExtension,
    InMemoryAgentKitStorage,
} from '@worldcoin/agentkit'

const WORLD_CHAIN = 'eip155:480'
const BASE = "eip155:8453";
const WORLD_USDC = '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1'
const payTo = '0xYourAddress'

const facilitatorClient = new HTTPFacilitatorClient({
    url: 'https://x402-worldchain.vercel.app/facilitator',
})

const evmScheme = new ExactEvmScheme()
    .registerMoneyParser(async (amount, network) => {
        if (network !== WORLD_CHAIN) return null
        return {
            amount: String(Math.round(amount * 1e6)),
            asset: WORLD_USDC,
            extra: { name: 'USD Coin', version: '2' },
        }
    })

const agentBook = createAgentBookVerifier({ network: 'world' })
const storage = new InMemoryAgentKitStorage()

const hooks = createAgentkitHooks({
    agentBook,
    storage,
    mode: { type: 'free-trial', uses: 3 },
})

const resourceServer = new x402ResourceServer(facilitatorClient)
    .register(WORLD_CHAIN, evmScheme)
    .registerExtension(agentkitResourceServerExtension)

const routes = {
    'GET /data': {
        accepts: [
            { scheme: 'exact', price: '$0.01', network: WORLD_CHAIN, payTo },
            { scheme: 'exact', price: '$0.01', network: BASE, payTo },
        ],
        extensions: declareAgentkitExtension({
            statement: 'Verify your agent is backed by a real human',
            mode: { type: 'free-trial', uses: 3 },
        }),
    },
}

const httpServer = new x402HTTPResourceServer(resourceServer, routes)
    .onProtectedRequest(hooks.requestHook)

const app = new Hono()
app.use(paymentMiddlewareFromHTTPServer(httpServer))

app.get('/data', c => {
    return c.json({ message: 'Protected content' })
})

serve({ fetch: app.fetch, port: 4021 })

Step 4: Configure the default mode and storage

InMemoryAgentKitStorage is fine for local testing but production should persist both usage counters and nonces.

import type { AgentKitStorage } from '@worldcoin/agentkit'

class DatabaseAgentKitStorage implements AgentKitStorage {
    async getUsageCount(endpoint: string, humanId: string) {
        return db.getUsageCount(endpoint, humanId)
    }
    async incrementUsage(endpoint: string, humanId: string) {
        await db.incrementUsage(endpoint, humanId)
    }
    async hasUsedNonce(nonce: string) {
        return db.hasUsedNonce(nonce)
    }
    async recordNonce(nonce: string) {
        await db.recordNonce(nonce)
    }
}

const hooks = createAgentkitHooks({
    agentBook,
    storage: new DatabaseAgentKitStorage(),
    mode: { type: 'free-trial', uses: 3 },
})

---

SDK Reference

Access Modes

Usage counters are tracked per human per endpoint. Two agents backed by the same human share the same counter.

ModeFieldsBehavior
free{ type: "free" }Registered human-backed agents always bypass payment.
free-trial{ type: "free-trial"; uses?: number }Bypass payment the first N times. Default uses is 1.
discount{ type: "discount"; percent: number; uses?: number }Underpay by configured percentage for the first N times.

discount mode requires verifyFailureHook on the facilitator. Without it, discounted underpayments fail settlement verification.

declareAgentkitExtension(options?)

Declare the agentkit extension returned in a 402 response.

ParameterTypeDescription
domainstringServer hostname. Usually auto-derived from request URL.
resourceUristringFull protected resource URI. Usually auto-derived.
network`string \string[]`
statementstringHuman-readable signing purpose.
versionstringCAIP-122 version. Defaults to "1".
expirationSecondsnumberChallenge lifetime in seconds.
modeAgentkitModeAccess mode clients should expect after verification.

agentkitResourceServerExtension

Register once on your x402 resource server. Turns the declaration into a full 402 challenge by:

  • Generating nonce and timestamps
  • Inferring domain and resourceUri from the incoming request when omitted
  • Expanding each supported network into correct signature types

createAgentkitHooks(options)

Creates request-time verification hooks.

OptionTypeDescription
agentBookAgentBookVerifierVerifier to resolve agent wallet to human identifier.
modeAgentkitModeAccess mode. Defaults to { type: "free" }.
storageAgentKitStorageRequired for free-trial and discount.
rpcUrlstringCustom EVM RPC for signature verification.
onEvent(event: AgentkitHookEvent) => voidOptional logging/debug callback.

Returns:

FieldTypeDescription
requestHookfunctionRuns before payment settlement; grants access for free/trial.
verifyFailureHookfunctionPresent only for discount mode. Register on the facilitator.

requestHook expects a context shaped like:

{
  adapter: {
    getHeader(name: string): string | undefined
    getUrl(): string
  }
  path: string
}

Express and Next.js are compatible -- adapt any framework to this minimal contract.

AgentkitHookEvent

Event typeFields
agent_verifiedresource, address, humanId
agent_not_verifiedresource, address
validation_failedresource, error?
discount_appliedresource, address, humanId
discount_exhaustedresource, address, humanId

createAgentBookVerifier(options?)

Creates the verifier to resolve a wallet address to an anonymous human identifier.

Built-in AgentBook deployments:

  • World Chain mainnet: 0xA23aB2712eA7BBa896930544C7d6636a96b944dA
  • Base mainnet: 0xE1D1D3526A6FAa37eb36bD10B933C1b77f4561a4
  • Base Sepolia: 0xA23aB2712eA7BBa896930544C7d6636a96b944dA
OptionTypeDescription
clientPublicClientFully custom viem client. Overrides automatic creation.
contractAddress` 0x${string} `Custom AgentBook contract address.
rpcUrlstringCustom RPC URL for automatic client creation.
networkAgentBookNetworkPin lookup to "world", "base", or "base-sepolia".

Selection behavior:

  • If network is provided, lookup is pinned to that deployment.
  • If network is omitted and incoming chainId matches eip155:480, eip155:8453, or eip155:84532, lookup stays on that chain.
  • Otherwise falls back to World Chain.

Returns:

lookupHuman(address: string, chainId: string): Promise<string | null>

AgentKitStorage Interface

MethodDescription
getUsageCount(endpoint, humanId)Current usage count for a human on a route.
incrementUsage(endpoint, humanId)Increment after successful free-trial or discount.
hasUsedNonce?(nonce)Optional replay check.
recordNonce?(nonce)Optional replay recorder.

InMemoryAgentKitStorage is the reference implementation -- demo only, counters lost on restart.

Validation and Verification Helpers

parseAgentkitHeader(header)

Parses base64-encoded agentkit header into structured payload. Throws on invalid base64, JSON, or schema mismatch.

validateAgentkitMessage(payload, resourceUri, options?)
OptionTypeDescription
maxAgenumberMax age for issuedAt (ms). Default 5min.
checkNonce`(nonce: string) => boolean \Promise<boolean>`

Validation rules:

  • domain must match hostname of protected resource URL
  • uri must resolve to same host as protected resource URL
  • issuedAt must be valid, not in future, not older than maxAge
  • expirationTime (when present) must still be in future
  • notBefore (when present) must already have passed

Returns: { valid: boolean; error?: string }

verifyAgentkitSignature(payload, rpcUrl?)
  • eip155:* payloads: reconstructed into SIWE message, verified with viem
  • solana:* payloads: reconstructed into SIWS message, verified with tweetnacl
  • Unsupported namespaces return { valid: false, error: ... }

Returns: { valid: boolean; address?: string; error?: string }

buildAgentkitSchema()

Returns the JSON schema used in 402 challenge payloads.

Chain Utilities

EVM
ExportDescription
formatSIWEMessageReconstruct SIWE message for signing and verification.
verifyEVMSignatureVerify EVM signature for reconstructed SIWE message.
extractEVMChainIdConvert CAIP-2 eip155:* chain ID to numeric chain ID.

EVM verification uses viem's verifyMessage (covers EOAs and ERC-1271 smart wallets).

Solana
ExportDescription
formatSIWSMessageReconstruct Sign-In With Solana message.
verifySolanaSignatureVerify detached signature against reconstructed message.
decodeBase58 / encodeBase58Base58 encoding/decoding for Solana payloads.
extractSolanaChainReferenceExtract chain reference from CAIP-2 solana:* ID.

Supported Chains

FamilyNamespacePayload typeOptional signatureSchemeMessage Format
EVMeip155:*eip191 or eip1271eip191, eip1271, or eip6492SIWE
Solanasolana:*ed25519siwsSIWS

Solana constants: SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET

Manual Usage Example

Use low-level helpers directly when not using the x402 Hono wrapper:

import {
    AGENTKIT,
    createAgentBookVerifier,
    declareAgentkitExtension,
    parseAgentkitHeader,
    validateAgentkitMessage,
    verifyAgentkitSignature,
} from '@worldcoin/agentkit'

const extensions = declareAgentkitExtension({
    domain: 'api.example.com',
    resourceUri: 'https://api.example.com/data',
    network: 'eip155:480',
    statement: 'Verify your agent is backed by a real human',
})

const agentBook = createAgentBookVerifier({ network: 'base' })

async function handleRequest(request: Request) {
    const header = request.headers.get(AGENTKIT)
    if (!header) return

    const payload = parseAgentkitHeader(header)

    const validation = await validateAgentkitMessage(payload, 'https://api.example.com/data')
    if (!validation.valid) {
        return { error: validation.error }
    }

    const verification = await verifyAgentkitSignature(payload)
    if (!verification.valid || !verification.address) {
        return { error: verification.error }
    }

    const humanId = await agentBook.lookupHuman(verification.address, payload.chainId)
    if (!humanId) {
        return { error: 'Agent is not registered in the AgentBook' }
    }

    return { humanId }
}

Production Notes

  • Treat InMemoryAgentKitStorage as demo-only.
  • Persistent storage is part of the integration, not optional, if you need limited free uses.
  • Wire verifyFailureHook into the facilitator before shipping discount mode.
  • Hono is a reference example, not a framework restriction.

Ecosystem

Find projects that integrate AgentKit at agentbook.world. To add your project, open a PR to the AgentBook registry on GitHub (andy-t-wang/agentbook).

Add the agentkit-x402 skill so your agent knows to use its registration when accessing x402 endpoints:

npx skills add worldcoin/agentkit agentkit-x402

Related skills

Web3 & Blockchainbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.