@pearldigital/p3-agentic-registry-sdk
v3.0.0
Published
Off-chain companion to the Pearl Path Protocol (P3) — DelegationCredential builder, Proof-of-Agency hashing, EIP-3009 x402 micropayments, boundary policy engine, and MCP tooling for autonomous AI agents.
Readme
P3 Agentic Registry SDK
P3 Agentic Registry SDK is the off-chain companion to the Pearl Path Protocol (P3), the smart contract layer for the Pearl Digital Agentic Registry.
P3 is purpose-built for the machine economy: gasless x402 and HTTP-native settlement, autonomous agent micropayments, and yield-bearing stablecoins — all under pre-settlement compliance enforcement.
What is This?
This SDK provides the tooling for AI agents and their Principals to interact with the Agentic Registry and execute within the protocol:
- DelegationCredential Builder — DSL for constructing Know Your Agent (KYA) credentials that define an agent's scope, quantitative value limits, and validity period.
- Mandate Seal Generation — Canonical serialization and Keccak256 hashing that produces the Proof-of-Agency (PoA) hash stored on-chain by
registerAgent(). Hash output is byte-identical to the Solidity equivalent. - EIP-3009 Signing —
transferWithAuthorizationhelpers for gasless, concurrent x402 micropayments using PRLUSD and FLASHD without holding native gas tokens. - Boundary Policy Engine — Validates agent actions against the limits and constraints defined in their DelegationCredential before submission.
- MCP Tooling — Model Context Protocol server and tools enabling AI agents to autonomously interact with the Agentic Registry, build credentials, and execute payments within their delegated authority.
Agents operate autonomously but never independently — always anchored to a verified Principal, always within the boundaries of their Proof of Agency.
import { P3Registry } from "@pearldigital/p3-agentic-registry-sdk";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount("0xYOUR_AGENT_KEY");
const registry = await P3Registry.connect({
apiUrl: "https://testagentic.pearldigital.com/api/v1",
chainId: 11155111, // required — the chain to read/pay on
wallet: { address: account.address, signTypedData: (args) => account.signTypedData(args) },
});
const status = await registry.agents.getStatus("0x23e5..."); // $0.001
const record = await registry.agents.getRecord("0x23e5..."); // $0.01
const cred = await registry.credentials.build({ ... }); // $0.01Every paid call is transparent — the SDK signs an EIP-3009 payment, the API settles it on-chain, and data comes back. One function call, one result.
How x402 Payment Works
Agent calls paid endpoint
│
▼
API returns 402 with price + payTo + accepted tokens
│
▼
SDK signs EIP-3009 transferWithAuthorization (PRLUSD → API treasury)
│
▼
SDK encodes signature as PAYMENT-SIGNATURE header, retries request
│
▼
API facilitator verifies signature, settles transfer on-chain
│
▼
API returns data ✓The agent never sees the 402. The SDK handles the full payment cycle internally.
Architecture
┌───────────────────┐ ┌─────────────────────┐ ┌──────────────────┐
│ AI Agent │ x402 │ P3 Registry API │ viem │ Smart Contracts │
│ │───────▶│ │───────▶│ (multichain) │
│ P3Registry SDK │ HTTP │ Hono + Redis │ │ Sepolia / Base /│
│ (this package) │ │ x402 payment gate │ │ Fuji / ADI │
│ │ │ claim signing │ │ P3Registry │
│ No admin keys │ │ MLRO auto-approve │ │ PRLUSD / FlashD │
│ No contract calls│ │ chainId-aware exec │ │ ERC-8004 · Compl.│
└───────────────────┘ └─────────────────────┘ └──────────────────┘Fee settlement follows ?chainId= — the API settles the x402 payment on whichever chain the caller targets. All supported chains are equally operational, and chainId is required: there is no default, so a call can never silently read or pay on the wrong network.
| Layer | Responsibility | |-------|---------------| | SDK | HTTP client, x402 payment signing, typed responses, agent contract helpers | | Registry API | On-chain reads/writes, claim signing, gas sponsorship, MLRO operations | | Smart Contracts | Agent registry, token transfers, compliance, reputation |
What goes through the API vs. direct contract calls
| Operation | Via API (P3Registry) | Via contract (agent is msg.sender) |
|-----------|---------------------|--------------------------------------|
| Query agent status/record/reputation/limits | x | |
| Register an agent | x | |
| Build/verify credentials | x | |
| Push reputation scores | x | |
| EIP-3009 transfer signing | | x |
| Stablecoin swap (PRLUSD ↔ FlashD) | | x |
| ERC-20 on-ramp (USDT → FlashD) | | x |
The SDK handles both paths. API calls go through P3Registry with automatic x402 payment. Direct contract operations use the agent contract helpers with viem.
Install
pnpm add @pearldigital/p3-agentic-registry-sdk viemQuick Start
1. Connect to the API
import { privateKeyToAccount } from "viem/accounts";
import { P3Registry } from "@pearldigital/p3-agentic-registry-sdk";
const account = privateKeyToAccount("0xYOUR_AGENT_KEY");
// P3Registry.connect() discovers chain config from the API automatically
const registry = await P3Registry.connect({
apiUrl: "https://testagentic.pearldigital.com/api/v1",
chainId: 11155111, // required — the chain to read/pay on
wallet: {
address: account.address,
signTypedData: (args) => account.signTypedData(args),
},
});The wallet only needs address and signTypedData. No RPC connection, no PublicClient, no ABIs.
Multichain
Every endpoint is multichain. chainId is required on the client and can be overridden per call — reads send it as ?chainId=, writes send it in the body, and x402 settlement targets that same chain.
// Chain for every call (required)
const registry = await P3Registry.connect({ apiUrl, wallet, chainId: 84532 }); // Base Sepolia
// Per-call override wins over the client's chain
const onFuji = await registry.agents.getStatus("0x23e5...", { chainId: 43113 });
await registry.agents.register({ ...req }, { chainId: 84532 });Supported chains — all equally operational: 11155111 (Ethereum Sepolia), 84532 (Base Sepolia), 43113 (Avalanche Fuji), 99999 (ADI Testnet). Token addresses are chain-specific — discovered from GET /chains, never hardcoded. All registry features — including ERC-8004 reputation — are available on every supported chain.
2. Query Agent Data (Paid — x402)
const status = await registry.agents.getStatus("0x23e5..."); // $0.001
const record = await registry.agents.getRecord("0x23e5..."); // $0.01
const reputation = await registry.agents.getReputation("0x23e5..."); // $0.01
const limits = await registry.agents.getLimits("0x23e5..."); // $0.001
const balances = await registry.agents.getBalances("0x23e5..."); // $0.001
// balances.balances === [{ symbol: "prlusd", contractAddress: "0x...", balance: "5000000" }]
// optional filter: registry.agents.getBalances("0x23e5...", ["prlusd", "flashd"])Prefer not to pay per call? Read balances directly on-chain with the getTokenBalances
helper (needs a viem PublicClient):
import { getTokenBalances } from "@pearldigital/p3-agentic-registry-sdk";
const { chains } = await registry.info.chains();
const onchain = await getTokenBalances(publicClient, {
wallet: "0x23e5...",
tokens: chains[0].tokens, // symbol → address map
});
onchain.prlusd.formatted; // "5"3. Build & Verify Credentials (Paid — x402)
const { credential, poaHash } = await registry.credentials.build({
principal: "0xPrincipalAddress",
agent: "0xAgentAddress",
capabilities: [
{ action: "transfer", target: "*", maxValue: "10000000000" },
{ action: "receive", target: "*" },
],
policy: {
jurisdictions: [48], // Bahrain (ISO 3166-1 numeric)
notBefore: Math.floor(Date.now() / 1000),
notAfter: Math.floor(Date.now() / 1000) + 365 * 86400,
},
label: "Treasury rebalancing agent",
});
// Cost: $0.01
const verified = await registry.credentials.verify({
credential,
expectedHash: poaHash,
});
// Cost: $0.0014. Register an Agent (Paid — x402, $9.95)
The principal pays the registration fee — the agent can't hold tokens before it's registered.
import { hashCredential, hashCapabilities, hashPolicy } from "@pearldigital/p3-agentic-registry-sdk";
// Build the credential and compute hashes
const credential = { version: "1.0.0", principal: "0xPrin...", agent: "0xAgent...", capabilities, policy };
const poaHash = hashCredential(credential);
const capsetHash = hashCapabilities(credential);
const policyHash = hashPolicy(credential);
// Register — the API verifies the credential, signs the TREX claim, and returns
// the calldata to submit from the principal wallet.
const result = await registry.agents.register({
agentAddress: "0xAgentAddress",
principalAddress: "0xPrincipalAddress",
poaHash,
capsetHash,
policyHash,
riskClass: 1, // LOW
capabilities: 15, // TRANSFER | BURN | MINT | RECEIVE
validFrom: now.toString(),
validUntil: (now + 365 * 86400).toString(),
singleSendLimit: "10000000000", // $10,000
rollingWindowLimit: "50000000000", // $50,000
windowDuration: 86400, // 24 hours
bufferSize: 8,
credential, // required — API checks keccak256(credential) === poaHash
principalSignature, // optional but recommended (EOA → ECDSA, contract → ERC-1271)
});
// result.transactions[] is ordered calldata to submit FROM the principal wallet:
// [0] registerAgent() → agent enters PENDING_MLRO
// [1] setAgentCapabilities() → after MLRO approval (when capabilities > 0)
for (const tx of result.transactions) {
await walletClient.sendTransaction({ to: tx.to, data: tx.data });
}
// result.agentId, result.predictedIdentity, result.claimSignature also returned5. Push Reputation (Paid — x402, $0.05)
await registry.reputation.push({
agentAddress: "0xAgent...",
score: "85000000", // 85.0 (6 decimal precision)
uri: "https://oracle.example.com/report/agent-123",
});6. Query Principals
const agents = await registry.principals.getAgents("0xPrincipal..."); // $0.01
// agents.agentCount === "3"7. Free Endpoints (No Payment)
const health = await registry.info.health(); // Server status
const chains = await registry.info.chains(); // Contract addresses
const pricing = await registry.info.pricing(); // Per-endpoint prices
const spec = await registry.info.openapi(); // OpenAPI YAML8. Pricing Cache
// Cached for 5 minutes
const pricing = await registry.getPricing();
// Force refresh
const fresh = await registry.refreshPricing();Agent Contract Helpers
For operations where the agent must be msg.sender on-chain (not routed through the API). These need a viem PublicClient / WalletClient pointed at the chain's RPC.
RPC endpoints. Bring your own viem client for any RPC — the SDK never overrides it. The exported
resolveRpcUrl(chainId, secret?)helper returns the chain's public RPC by default, or Pearl's private gateway whenP3_RPC_GATEWAY_SECRET(or thesecretarg) is set — no secret is bundled:import { resolveRpcUrl } from "@pearldigital/p3-agentic-registry-sdk"; import { createPublicClient, http } from "viem"; const client = createPublicClient({ transport: http(resolveRpcUrl(84532)) }); // public; gateway when the secret is setToken/contract addresses come from
GET /chainsat runtime — never hardcode. ADI Testnet (99999) has no public RPC and requires the gateway secret.
EIP-3009 Transfer Signing
import { signTransferAuthorization, generateNonce } from "@pearldigital/p3-agentic-registry-sdk";
const signed = await signTransferAuthorization(walletClient, {
from: account.address,
to: "0xRecipient",
value: 1_000_000n, // $1.00
validAfter: 0n,
validBefore: BigInt(Math.floor(Date.now() / 1000) + 3600),
nonce: generateNonce(),
}, tokenAddress, "Pearl U.S Dollar (USD)", 43113);Stablecoin Swap
import { sweepToYield, simulateSwap } from "@pearldigital/p3-agentic-registry-sdk";
// Preview
const amountOut = await simulateSwap(publicClient, {
fromToken: "0x9D81...", // PRLUSD
toToken: "0x64fF...", // FlashD
amount: 1_000_000n,
swapContract: "0x5f1f...",
}, account);
// Execute (agent is msg.sender — must be permissioned)
const result = await sweepToYield(publicClient, walletClient, {
fromToken: "0x9D81...",
toToken: "0x64fF...",
amount: 1_000_000n,
swapContract: "0x5f1f...",
// Optional slippage + deadline guards (on-chain swap requires both; sensible
// defaults are applied): 0.5% slippage off the simulated quote, 5-min deadline.
slippageBps: 50, // or set minAmountOut directly
deadlineSeconds: 300, // or set an absolute deadline (unix seconds)
});ERC-20 On-Ramp to FlashD (Treasury Yield)
Swap external stablecoins into yield-bearing FlashD via P3StablecoinSwap:
import { onRampSweepToYield } from "@pearldigital/p3-agentic-registry-sdk";
const result = await onRampSweepToYield(publicClient, walletClient, {
fromToken: "0x7dFD...", // USDT (or any supported ERC-20)
toToken: "0x64fF...", // FlashD (yield-bearing)
amount: 10_000_000n, // 10 USDT
swapContract: "0x5f1f...",
});
// result.amountOut === 10000000n (FlashD)
// result.approvalRequired === true (first time)Batched Nanopayments
Pay multiple recipients in a single on-chain transaction. All authorizations are
signed in parallel and submitted atomically via the token's native
batchTransferWithAuthorization — the batch either fully settles or fully reverts.
A simulateBatch pre-flight runs automatically before broadcasting. Recipients that
would fail on-chain (unverified, frozen, expired TTL) are stripped and returned in
result.skipped — no gas is wasted on a reverting batch.
Gas is amortised across all payments: ~77% lower per-payment vs individual submissions at 50 payments. Only the relayer pays gas — individual payers pay nothing beyond the token amount.
Relayer requirement:
walletClientmust be the registered P3 distributor wallet for thefromaddresses in the batch. For agents, use the API-mediated path (POST /payments/batch) where the Registry API's permissioned relayer handles submission.
import { batchNanopay } from "@pearldigital/p3-agentic-registry-sdk";
const result = await batchNanopay(publicClient, distributorWalletClient, {
chainId: 43113,
payments: [
{ to: "0xAPI_Provider", value: 1_000n, tokenAddress: PRLUSD, tokenName: "Pearl U.S Dollar (USD)" },
{ to: "0xOracle_Node", value: 500n, tokenAddress: PRLUSD, tokenName: "Pearl U.S Dollar (USD)" },
{ to: "0xStorage_Node", value: 250n, tokenAddress: PRLUSD, tokenName: "Pearl U.S Dollar (USD)" },
{ to: "0xCompute_Node", value: 100n, tokenAddress: PRLUSD, tokenName: "Pearl U.S Dollar (USD)" },
],
// validForSeconds: 300, // optional TTL (default 5 min)
});
console.log(`${result.count} payments settled in ${result.txHash}`);
console.log(`Total: $${Number(result.totalValue) / 1_000_000}`);
if (result.skipped.length > 0) {
console.warn(`${result.skipped.length} payments skipped:`, result.skipped);
}
// result.signed — all SignedTransferAuthorizations for receipts / auditAll payments in one batch must use the same tokenAddress — batchTransferWithAuthorization
is a method on the token contract itself. To pay across multiple tokens, call batchNanopay
once per token (they can run concurrently via Promise.all):
const [prlusdResult, flashdResult] = await Promise.all([
batchNanopay(publicClient, walletClient, { chainId, payments: prlusdPayments }),
batchNanopay(publicClient, walletClient, { chainId, payments: flashdPayments }),
]);Payments API
Batch Relay (agent-signed, API-submitted)
When the agent isn't a registered relayer, sign EIP-3009 authorizations and submit them through the API's permissioned relayer. Up to 100 per call, atomic, same token.
const result = await registry.payments.batch({
payments: [
{ from: agent, to: "0xAPI", value: "1000", validAfter: "0", validBefore: "9999999999",
nonce: "0x…", signature: "0x…", tokenAddress: PRLUSD },
// … up to 100, all same tokenAddress
],
});
// result.count settled, result.totalValue, result.txHash
// result.skipped[] — entries that failed pre-flight (not charged gas), each with a reasonPayment Request Links (one-time)
Create a link a payer resolves and fulfills — useful for invoicing between agents.
// Creator (paid, $0.001)
const link = await registry.payments.createRequest({
amount: "1000000", // 1.00 (6 decimals)
token: "PRLUSD",
description: "Inference run #42",
expiresIn: 3600, // seconds
});
// Payer resolves it (free), signs EIP-3009 for link.amount → link.payTo, then fulfills (free)
const details = await registry.payments.getRequest(link.id);
const done = await registry.payments.fulfillRequest(link.id, {
from: payer, validAfter: "0", validBefore: "9999999999", nonce: "0x…", signature: "0x…",
});
// Poll status (free)
const status = await registry.payments.getRequestStatus(link.id); // "pending" | "fulfilled" | "expired"Gasless Registration (meta-transactions)
On chains with a P3TrustedForwarder, the principal can register without holding gas — sign a ForwardRequest and the API relays it (server pays gas, ERC-2771).
// 1. registerAgent() calldata comes from registry.agents.register(...) → result.transactions[0]
// 2. Read the forwarder nonce (free; throws 501 if the chain has no forwarder)
const { nonce, forwarder } = await registry.agents.getForwarderNonce(principalAddress);
// 3. Principal signs the EIP-712 ForwardRequest { from, to: registry, value, gas, nonce, data }
// then relay it (free — server pays gas):
const relayed = await registry.agents.submitRegistration({
forwardRequest: { from: principalAddress, to: registryAddress, value: "0", gas: "1000000", nonce, data: calldata },
signature: forwardSignature,
});
// relayed.state === "PENDING_MLRO"Tether WDK Integration
Connect a Tether WDK wallet to the P3 Agentic Registry with a single adapter call:
import { WalletManagerEvm } from "@tetherto/wdk-wallet-evm";
import { P3Registry, fromWdkAccount } from "@pearldigital/p3-agentic-registry-sdk";
const account = await new WalletManagerEvm(process.env.SEED_PHRASE, {
provider: "https://api.avax-test.network/ext/bc/C/rpc",
}).getAccount();
const signer = await fromWdkAccount(account);
const registry = await P3Registry.connect({ apiUrl: "https://testagentic.pearldigital.com/api/v1", chainId: 11155111, wallet: signer });Add P3 identity tools to the WDK MCP Toolkit:
import { registerP3Tools } from "@pearldigital/p3-agentic-registry-sdk";
registerP3Tools(wdkMcpServer.server, { registry });
// Adds: p3_check_agent, p3_get_reputation, p3_validate_credential, sweep_to_yield, ...See docs/integrations/TetherWDK/ for the full integration guide.
x402 Seller Middleware
Gate your own Express endpoints behind x402 payments — let other agents pay you:
import express from "express";
import { createP3PaymentMiddleware } from "@pearldigital/p3-agentic-registry-sdk";
const app = express();
app.use(createP3PaymentMiddleware({
routes: {
"GET /api/data": { price: "$0.01", description: "Premium data feed" },
"POST /api/inference": { price: "$0.05", description: "AI inference" },
},
payTo: "0xYourAgentWallet",
network: "eip155:43113",
tokenAddress: "0x9D811a758DD09caA6d3c92eA72c2243bCcB86266",
}));
app.get("/api/data", (req, res) => {
res.json({ data: "paid content" });
});API Reference
P3Registry Class
class P3Registry {
readonly agents: AgentsNamespace;
readonly principals: PrincipalsNamespace;
readonly credentials: CredentialsNamespace;
readonly reputation: ReputationNamespace;
readonly payments: PaymentsNamespace;
readonly info: InfoNamespace;
static async connect(config: Omit<P3RegistryConfig, "tokenDomains">): Promise<P3Registry>;
async getPricing(): Promise<PricingResponse>;
async refreshPricing(): Promise<PricingResponse>;
}Endpoint Pricing
| Namespace | Method | Endpoint | Cost |
|-----------|--------|----------|------|
| agents | getStatus(address) | GET /agents/:address/status | $0.001 |
| agents | getRecord(address) | GET /agents/:address/record | $0.01 |
| agents | getReputation(address) | GET /agents/:address/reputation | $0.01 |
| agents | getLimits(address) | GET /agents/:address/limits | $0.001 |
| agents | getBalances(address, tokens?) | GET /agents/:address/balances | $0.001 |
| agents | getKyc(address) | GET /agents/:address/kyc | $0.001 |
| agents | register(request) | POST /agents/register | $9.95 |
| agents | getForwarderNonce(address) | GET /agents/forwarder/nonce/:address | Free |
| agents | submitRegistration(request) | POST /agents/register/submit | Free |
| principals | getAgents(address) | GET /principals/:address/agents | $0.01 |
| credentials | build(request) | POST /credentials/build | $0.01 |
| credentials | verify(request) | POST /credentials/verify | $0.001 |
| reputation | push(request) | POST /reputation/push | $0.05 |
| payments | batch(request) | POST /payments/batch | $0.05 |
| payments | createRequest(request) | POST /payments/request | $0.001 |
| payments | getRequest(id) | GET /payments/request/:id | Free |
| payments | fulfillRequest(id, request) | POST /payments/request/:id/fulfill | Free |
| payments | getRequestStatus(id) | GET /payments/request/:id/status | Free |
| info | health() | GET /health | Free |
| info | chains() | GET /chains | Free |
| info | pricing() | GET /pricing | Free |
| info | openapi() | GET /openapi.yaml | Free |
Agent Contract Helpers
| Export | Purpose | Needs viem? |
|--------|---------|-------------|
| signTransferAuthorization() | Sign EIP-3009 transferWithAuthorization | Yes |
| generateNonce() | Random bytes32 nonce for EIP-3009 | No |
| buildTransferAuthorizationTypedData() | Build EIP-712 typed data | No |
| batchNanopay() | Batch N gasless nanopayments into one on-chain tx via batchTransferWithAuthorization | Yes |
| SkippedPayment | Type for payments excluded by simulateBatch pre-flight | — |
| sweepToYield() | Swap P3 stablecoins (e.g. PRLUSD → FlashD) | Yes |
| onRampSweepToYield() | On-ramp ERC-20 stablecoins to yield (e.g. USDT → FlashD) | Yes |
| simulateSwap() | Preview swap output | Yes |
| isPairSupported() | Check if swap pair exists | Yes |
| getTokenBalances() | Read ERC-20 balances on-chain (multicall), no API cost | Yes |
x402 Payment Helpers
| Export | Purpose |
|--------|---------|
| buildXPaymentPayload(signer, accept, opts?) | Sign an EIP-3009 authorization for a 402 requirement → base64 X-PAYMENT payload |
| generateXPaymentNonce() | Random bytes32 nonce for a payment authorization |
| X_PAYMENT_HEADER / PAYMENT_SIGNATURE_HEADER | Header names the API accepts for the payload |
P3Registry retries 402s automatically — you only need buildXPaymentPayload to pay from your own fetch/HTTP client:
import { buildXPaymentPayload } from "@pearldigital/p3-agentic-registry-sdk";
const res = await fetch(url); // 402 Payment Required
const { accepts } = await res.json();
const header = await buildXPaymentPayload(signer, accepts[0]); // signs + base64
await fetch(url, { headers: { "X-PAYMENT": header } }); // replay, settledCredential Primitives (from @pearldigital/p3-agentic-credential-schemas)
| Export | Purpose |
|--------|---------|
| hashCredential(credential) | Compute poaHash (keccak256 of canonical form) |
| hashCapabilities(credential) | Compute capsetHash |
| hashPolicy(credential) | Compute policyHash |
| canonicalize(credential) | Canonical JSON serialization |
| validateCredential(credential) | Schema validation |
| evaluatePolicy(credential, context) | Runtime policy evaluation |
MCP Server
The SDK includes an MCP server that exposes P3 Registry tools to Claude and other MCP clients.
Setup
P3_API_URL=https://testagentic.pearldigital.com/api/v1 \
P3_SIGNER_KEY=0xYOUR_AGENT_KEY \
npx p3-mcp-serverClaude Code Configuration
{
"mcpServers": {
"p3-registry": {
"command": "npx",
"args": ["p3-mcp-server"],
"env": {
"P3_API_URL": "http://localhost:3001/api/v1",
"P3_SIGNER_KEY": "0xYOUR_AGENT_KEY"
}
}
}
}Available Tools
createP3McpServer(registry) registers 14 tools. Read tools accept an optional chainId to target a specific chain (defaults to the server's configured P3_CHAIN_ID). The Tether WDK plugin (registerP3Tools) registers a 9-tool subset.
| Tool | Description | Cost |
|------|------------|------|
| check_agent | Is this wallet an active agent? | $0.001 |
| get_agent_record | Full on-chain agent record | $0.01 |
| get_balance | Token balances | $0.001 |
| get_kyc | Wallet KYC / permissioning status (roles, validity, expiry) | $0.001 |
| get_agent_limits | Rolling window usage | $0.001 |
| register_agent | Register an agent — verifies credential, signs TREX claim, returns calldata | $9.95 |
| get_reputation | ERC-8004 reputation score | $0.01 |
| build_credential | Build + hash a DelegationCredential | $0.01 |
| validate_credential | Validate against schema + runtime | Free (local) |
| sweep_to_yield | Resolve swap routing + swap contract (execute with a wallet helper) | Free |
| search_agents | Search agents by capabilities, risk, principal, reputation | $0.001 |
| list_principal_agents | List all agents under a principal | $0.001 |
| list_chains | Supported chains + addresses | Free |
| get_pricing | Per-endpoint pricing | Free |
Claude Skills
| Skill | Description |
|-------|------------|
| /onboard-principal | Bootstrap a distributor or investor wallet on testnet |
| /create-agent | Generate wallet, register agent via API, fund it |
| /fund-agent | Drip testnet tokens to an agent wallet |
| /agentic-commerce | Pre-flight checks, payments, swaps, credentials |
| /push-reputation | Push an ERC-8004 reputation score |
Full Demo Flow
/onboard-principal KYB "Demo Investor" → creates funded principal
/create-agent "My Trading Agent" → registers agent under principal
/fund-agent 0xNewAgent... → drips PRLUSD to agent
/agentic-commerce check 0xNewAgent... → pre-flight status
/push-reputation 0xNewAgent... 75 → initial reputation scoreExamples
All examples run against a local API at localhost:3001:
# Free endpoints — no wallet needed
npx tsx examples/03-free-endpoints.ts
# Query an agent ($0.022 in x402 payments)
PRIVATE_KEY=0x... npx tsx examples/01-query-agent.ts
# Build a credential ($0.01)
PRIVATE_KEY=0x... npx tsx examples/02-build-credential.ts
# Full lifecycle: create → register → fund → query (~$10)
PRIVATE_KEY=0x... npx tsx examples/04-agent-lifecycle.ts# WDK wallet → P3 identity → sweep USDT to FlashD for yield
PRIVATE_KEY=0x... npx tsx examples/06-wdk-treasury-yield.ts
# WalletConnect Pay — merchant creates payment, polls for settlement
WC_PAY_API_KEY=wc_pk_... WC_PAY_MERCHANT_ID=merchant_... npx tsx examples/06-wcpay-merchant.ts
# WalletConnect Pay — agent pays a merchant with P3 credential
WC_PAY_AGENT_API_KEY=wc_pk_... PRIVATE_KEY=0x... npx tsx examples/07-wcpay-agent-pays.ts <paymentId>See examples/05-mcp-demo.md for the MCP demo walkthrough.
Security Model
| Concern | How it's handled |
|---------|-----------------|
| No admin keys in SDK | All admin operations go through the API |
| No private keys stored | Consumer passes wallet at construction time |
| Payment signing | EIP-3009 transferWithAuthorization — standard, auditable, on-chain |
| Agent isolation | Each agent has its own wallet and pays for its own queries |
| Compliance enforcement | P3 tokens check isPermissioned() — unregistered wallets can't transact |
| Replay protection | EIP-3009 nonces are unique per authorization |
| Sponsor model | Principals pay for agent registration — agents can't self-register |
WalletConnect Pay Integration
Accept crypto payments via WalletConnect Pay with P3 payer-side compliance:
import { WcPayMerchant, WcPayAgent, P3CredentialPresenter } from "@pearldigital/p3-agentic-registry-sdk";
// Merchant: create a $25 payment
const merchant = new WcPayMerchant({ apiUrl: "https://api.pay.walletconnect.com", apiKey: "wc_pk_...", merchantId: "merchant_..." });
const payment = await merchant.createPayment({ referenceId: "ORDER-001", amount: { unit: "iso4217/USD", value: "2500" } });
console.log(payment.gatewayUrl); // QR code / redirect
// Agent: pay a merchant (headless, API-first)
const agent = new WcPayAgent({ gatewayUrl: "https://api.pay.walletconnect.com", apiKey: "wc_pk_..." });
const result = await agent.pay(walletClient, payment.paymentId, {
credential: await new P3CredentialPresenter(registry).buildPresentation(agentAddress),
});
// Poll until settled
const status = await merchant.awaitPayment(payment.paymentId);| Class | Purpose |
|-------|---------|
| WcPayMerchant | Create payments, poll status, cancel, list, merchant management |
| WcPayAgent | API-first wallet flow: options → sign → confirm |
| P3CredentialPresenter | Bridge P3 credentials into WC Pay's collectData for payer verification |
See docs/integrations/WalletConnectPay/ for the full integration guide.
Agent Discovery
The first searchable registry of verified, compliant AI agents on a public blockchain. Agents can find other agents by capability, risk class, principal, reputation, and validity — then verify credentials and engage, all programmatically.
import { P3Registry, AGENT_CAPABILITY } from "@pearldigital/p3-agentic-registry-sdk";
const registry = await P3Registry.connect({ apiUrl, wallet, chainId: 11155111 });
// Find LOW risk agents that can transfer and receive
const partners = await registry.agents.search({
riskClass: 1,
capabilities: AGENT_CAPABILITY.TRANSFER | AGENT_CAPABILITY.RECEIVE,
state: "APPROVED_ACTIVE",
});
// → 9 agents found across 3 principals
// Find all agents under a specific principal
const fleet = await registry.principals.listAgents("0xc1A071Dd...", {
state: "APPROVED_ACTIVE",
});
// → 8 agents: 6 LOW risk, 1 MEDIUM, 1 HIGH
// Sort by risk class, exclude self
const sorted = await registry.agents.search({
sortBy: "riskClass",
excludeAddress: myAgentAddress,
capabilities: AGENT_CAPABILITY.TRANSFER,
});
// Paginate through all agents
let cursor = partners.nextCursor;
while (cursor) {
const page = await registry.agents.search({ cursor });
cursor = page.nextCursor;
}Search Filters
| Filter | Description |
|--------|-------------|
| state | Lifecycle state: APPROVED_ACTIVE, PENDING_MLRO, SUSPENDED, REVOKED |
| riskClass | 1=LOW, 2=MEDIUM, 3=HIGH, 4=CRITICAL |
| capabilities | Bitmask: TRANSFER(1) \| BURN(2) \| MINT(4) \| RECEIVE(8) — AND matching |
| principal | Exact match on principal address |
| minReputation | Minimum ERC-8004 reputation score |
| validAt | Only agents valid at this timestamp (default: now — expired excluded) |
| excludeAddress | Exclude an address (e.g. self) |
| registeredAfter / registeredBefore | Time range on registration date |
| sortBy | registeredAt (default) or riskClass |
| limit / cursor | Pagination (1–100 per page) |
Capability Constants
import { AGENT_CAPABILITY } from "@pearldigital/p3-agentic-registry-sdk";
AGENT_CAPABILITY.TRANSFER // 1 — can send tokens
AGENT_CAPABILITY.BURN // 2 — can redeem tokens
AGENT_CAPABILITY.MINT // 4 — can create tokens
AGENT_CAPABILITY.RECEIVE // 8 — can receive tokens
// Combine with bitwise OR
const TRADER = AGENT_CAPABILITY.TRANSFER | AGENT_CAPABILITY.RECEIVE; // 9
const FULL = AGENT_CAPABILITY.TRANSFER | AGENT_CAPABILITY.BURN | AGENT_CAPABILITY.MINT | AGENT_CAPABILITY.RECEIVE; // 15Cost: $0.01 per search page. See docs/features/AgentDiscovery.md for the complete guide including cross-jurisdiction commerce, privacy model, and competitive analysis.
Development
pnpm build # TypeScript compile
pnpm test # Unit tests (221 tests, 22 files)
pnpm test:integration # Integration tests (35 tests, live API + on-chain settlement)
pnpm test:watch # Watch mode
pnpm lint # ESLintTest Coverage
| Suite | Tests | What it covers | |-------|-------|---------------| | Unit | 221 | P3Registry, HttpTransport, namespaces, x402, swap, WDK adapter/plugin, WC Pay merchant/agent/presenter, exports | | Integration | 35 | Full onboarding flow: bootstrap principal → fund → x402 paid queries → bootstrap agent → agent autonomous operations → credential build+verify. Real EIP-3009 settlements on Avalanche Fuji |
Dependencies
| Package | Purpose | Required? |
|---------|---------|-----------|
| viem | Wallet signing, contract helpers (peer dep) | Yes |
| @pearldigital/p3-agentic-credential-schemas | Credential types, hashing, validation | Yes |
| @pearldigital/p3-abis | Contract ABIs for swap + token helpers | Yes |
| @x402/core | Core x402 payment types + encoding | Yes |
| @x402/evm | ClientEvmSigner type, toClientEvmSigner helper | Yes |
| @x402/fetch | x402-aware fetch wrapper (automatic 402 retry) | Yes |
| @x402/express | Seller middleware (only if gating your own endpoints) | Yes |
| @modelcontextprotocol/sdk | MCP server (only for MCP integration) | Yes |
| zod | Schema validation (MCP tools) | Yes |
Integration Guides
| Integration | Description | Docs | |-------------|-------------|------| | Tether WDK | WDK wallet adapter, MCP plugin, treasury yield, x402 interop | docs/integrations/TetherWDK/ | | WalletConnect Pay | Merchant payments, agent payments, P3 compliance | docs/integrations/WalletConnectPay/ |
Key URLs
| Resource | URL | |----------|-----| | Protocol repo | https://gitlab.com/pearl-digital/pearl-path-protocol | | SDK repo | https://gitlab.com/pearl-digital/p3-agentic-registry-sdk | | Credential schemas | https://gitlab.com/pearl-digital/p3-agentic-credential-schemas | | API base URL | https://testagentic.pearldigital.com/api/v1 | | Schema base URL | https://agentic.pearldigital.com/schemas/p3/ | | Onboarding portal | https://onboarding.pearldigital.com |
License
Pearl Digital Source-Available License v1.0 — see LICENSE.
