mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
Commerce is called at /v1, the indexer at /v1/indexer, and the operator serves /v1/clusters. The console's unused fleet helpers called a /api base nothing serves; they are gone. The legacy Quart env files named an app that no longer exists. Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
796 lines
31 KiB
TypeScript
796 lines
31 KiB
TypeScript
"use client"
|
|
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { DocsLayout } from "@/components/docs-layout"
|
|
import { docsConfig } from "@/lib/docs-config"
|
|
|
|
function Endpoint({
|
|
method,
|
|
path,
|
|
description,
|
|
params,
|
|
request,
|
|
response,
|
|
}: {
|
|
method: "GET" | "POST" | "PATCH" | "DELETE" | "WS"
|
|
path: string
|
|
description: string
|
|
params?: { name: string; type: string; description: string; required?: boolean }[]
|
|
request?: string
|
|
response: string
|
|
}) {
|
|
const methodColors: Record<string, string> = {
|
|
GET: "bg-green-500/10 text-green-500 border-green-500/20",
|
|
POST: "bg-blue-500/10 text-blue-500 border-blue-500/20",
|
|
PATCH: "bg-yellow-500/10 text-yellow-500 border-yellow-500/20",
|
|
DELETE: "bg-red-500/10 text-red-500 border-red-500/20",
|
|
WS: "bg-purple-500/10 text-purple-500 border-purple-500/20",
|
|
}
|
|
|
|
return (
|
|
<Card id={path.replace(/[/{}\s]/g, "-").replace(/^-+|-+$/g, "")}>
|
|
<CardHeader>
|
|
<div className="flex items-center gap-3 flex-wrap">
|
|
<Badge className={`font-mono text-xs ${methodColors[method]}`}>{method}</Badge>
|
|
<code className="text-sm font-mono">{path}</code>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground mt-2">{description}</p>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{params && params.length > 0 && (
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-2">Parameters</h4>
|
|
<div className="overflow-x-auto border rounded-lg">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="border-b bg-muted/50">
|
|
<th className="text-left p-3 font-medium">Name</th>
|
|
<th className="text-left p-3 font-medium">Type</th>
|
|
<th className="text-left p-3 font-medium">Required</th>
|
|
<th className="text-left p-3 font-medium">Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{params.map((p) => (
|
|
<tr key={p.name} className="border-b last:border-0">
|
|
<td className="p-3 font-mono text-xs">{p.name}</td>
|
|
<td className="p-3 text-muted-foreground">{p.type}</td>
|
|
<td className="p-3">{p.required !== false ? "Yes" : "No"}</td>
|
|
<td className="p-3 text-muted-foreground">{p.description}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{request && (
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-2">Request</h4>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{request}</code>
|
|
</pre>
|
|
</div>
|
|
)}
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-2">Response</h4>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{response}</code>
|
|
</pre>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
export default function ApiReferencePage() {
|
|
return (
|
|
<DocsLayout>
|
|
<div className="space-y-10">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-4xl font-bold mb-4">API Reference</h1>
|
|
<p className="text-lg text-muted-foreground">
|
|
Complete reference for all {docsConfig.brandName} REST and JSON-RPC endpoints.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Authentication */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Authentication</h2>
|
|
<p className="text-muted-foreground">
|
|
All API requests require authentication via one of two methods:
|
|
</p>
|
|
<div className="space-y-2">
|
|
<div className="border rounded-lg p-4">
|
|
<p className="font-medium text-sm mb-1">API Key Header</p>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{`X-API-Key: ${docsConfig.apiKeyPrefix}live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6`}</code>
|
|
</pre>
|
|
</div>
|
|
<div className="border rounded-lg p-4">
|
|
<p className="font-medium text-sm mb-1">Bearer Token</p>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{`Authorization: Bearer ${docsConfig.apiKeyPrefix}live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6`}</code>
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Base URL */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Base URL</h2>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{`${docsConfig.apiUrl}/v1`}</code>
|
|
</pre>
|
|
</section>
|
|
|
|
{/* Rate Limits */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Rate Limits</h2>
|
|
<div className="overflow-x-auto border rounded-lg">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="border-b bg-muted/50">
|
|
<th className="text-left p-3 font-medium">Plan</th>
|
|
<th className="text-left p-3 font-medium">Requests / second</th>
|
|
<th className="text-left p-3 font-medium">Requests / day</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr className="border-b">
|
|
<td className="p-3">Free</td>
|
|
<td className="p-3">10</td>
|
|
<td className="p-3">100,000</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3">Growth</td>
|
|
<td className="p-3">100</td>
|
|
<td className="p-3">5,000,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-3">Enterprise</td>
|
|
<td className="p-3">Unlimited</td>
|
|
<td className="p-3">Unlimited</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Rate limit headers are included in every response:
|
|
</p>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{`X-RateLimit-Limit: 100
|
|
X-RateLimit-Remaining: 97
|
|
X-RateLimit-Reset: 1706400000`}</code>
|
|
</pre>
|
|
</section>
|
|
|
|
{/* RPC */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">RPC</h2>
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/rpc/{chain}/{network}"
|
|
description="Proxy a JSON-RPC request to any supported blockchain. Supports all standard JSON-RPC methods for EVM chains, and chain-specific methods for non-EVM chains like Solana."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier (ethereum, polygon, solana, base, arbitrum, etc.)" },
|
|
{ name: "network", type: "string", description: "Network name (mainnet, sepolia, devnet, etc.)" },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/rpc/ethereum/mainnet \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"method": "eth_blockNumber",
|
|
"params": []
|
|
}'`}
|
|
response={`{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": "0x13a5e7f"
|
|
}`}
|
|
/>
|
|
</section>
|
|
|
|
{/* Tokens */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Tokens</h2>
|
|
<div className="space-y-6">
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/tokens/{chain}/balances/{address}"
|
|
description="Get all ERC-20 token balances for a wallet address, including token metadata and USD values."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier (ethereum, polygon, base, etc.)" },
|
|
{ name: "address", type: "string", description: "Wallet address (0x-prefixed hex)" },
|
|
{ name: "page", type: "integer", description: "Page number for pagination (default: 1)", required: false },
|
|
{ name: "limit", type: "integer", description: "Results per page, max 100 (default: 50)", required: false },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/tokens/ethereum/balances/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum",
|
|
"tokens": [
|
|
{
|
|
"contract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
"symbol": "USDC",
|
|
"name": "USD Coin",
|
|
"decimals": 6,
|
|
"balance": "15230500000",
|
|
"formatted_balance": "15230.50",
|
|
"usd_value": "15230.50",
|
|
"logo_url": "https://assets.web3.hanzo.ai/tokens/usdc.png"
|
|
},
|
|
{
|
|
"contract": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
"symbol": "USDT",
|
|
"name": "Tether USD",
|
|
"decimals": 6,
|
|
"balance": "8500000000",
|
|
"formatted_balance": "8500.00",
|
|
"usd_value": "8500.00",
|
|
"logo_url": "https://assets.web3.hanzo.ai/tokens/usdt.png"
|
|
}
|
|
],
|
|
"page": 1,
|
|
"total": 2
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/tokens/{chain}/metadata/{contract}"
|
|
description="Get metadata for a specific ERC-20 token contract, including name, symbol, decimals, total supply, and current price."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "contract", type: "string", description: "Token contract address (0x-prefixed hex)" },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/tokens/ethereum/metadata/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"contract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
"chain": "ethereum",
|
|
"name": "USD Coin",
|
|
"symbol": "USDC",
|
|
"decimals": 6,
|
|
"total_supply": "26000000000000000",
|
|
"formatted_total_supply": "26000000000.00",
|
|
"price_usd": "1.00",
|
|
"market_cap_usd": "26000000000.00",
|
|
"logo_url": "https://assets.web3.hanzo.ai/tokens/usdc.png"
|
|
}`}
|
|
/>
|
|
</div>
|
|
</section>
|
|
|
|
{/* NFTs */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">NFTs</h2>
|
|
<div className="space-y-6">
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/nfts/{chain}/metadata/{contract}/{token_id}"
|
|
description="Get metadata for a specific NFT including name, description, image URL, traits, and ownership info."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "contract", type: "string", description: "NFT contract address" },
|
|
{ name: "token_id", type: "string", description: "Token ID" },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/nfts/ethereum/metadata/0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D/1234 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"contract": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
|
|
"token_id": "1234",
|
|
"name": "Bored Ape #1234",
|
|
"description": "A unique Bored Ape Yacht Club NFT.",
|
|
"image_url": "ipfs://QmRRPWG96cmgTn2qSzjwr2qvfNEuhunv6FNeMFGa9bx6mQ",
|
|
"image_gateway_url": "https://ipfs.web3.hanzo.ai/ipfs/QmRRPWG96cmgTn2qSzjwr2qvfNEuhunv6FNeMFGa9bx6mQ",
|
|
"standard": "ERC721",
|
|
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"traits": [
|
|
{ "trait_type": "Background", "value": "Aquamarine" },
|
|
{ "trait_type": "Fur", "value": "Dark Brown" },
|
|
{ "trait_type": "Eyes", "value": "Bored" },
|
|
{ "trait_type": "Mouth", "value": "Grin" }
|
|
]
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/nfts/{chain}/collection/{contract}"
|
|
description="Get collection-level metadata for an NFT contract, including name, floor price, total supply, and stats."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "contract", type: "string", description: "NFT contract address" },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/nfts/ethereum/collection/0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"contract": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
|
|
"chain": "ethereum",
|
|
"name": "Bored Ape Yacht Club",
|
|
"symbol": "BAYC",
|
|
"standard": "ERC721",
|
|
"total_supply": 10000,
|
|
"num_owners": 6432,
|
|
"floor_price_eth": "12.50",
|
|
"floor_price_usd": "25000.00",
|
|
"banner_url": "https://assets.web3.hanzo.ai/collections/bayc-banner.png",
|
|
"image_url": "https://assets.web3.hanzo.ai/collections/bayc.png",
|
|
"description": "The Bored Ape Yacht Club is a collection of 10,000 unique Bored Ape NFTs."
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/nfts/{chain}/owned/{address}"
|
|
description="Get all NFTs owned by a wallet address across all collections on the given chain."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "address", type: "string", description: "Wallet address" },
|
|
{ name: "page", type: "integer", description: "Page number (default: 1)", required: false },
|
|
{ name: "limit", type: "integer", description: "Results per page, max 100 (default: 50)", required: false },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/nfts/ethereum/owned/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum",
|
|
"nfts": [
|
|
{
|
|
"contract": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
|
|
"token_id": "1234",
|
|
"name": "Bored Ape #1234",
|
|
"collection_name": "Bored Ape Yacht Club",
|
|
"image_url": "ipfs://QmRRPWG96cmgTn2qSzjwr2qvfNEuhunv6FNeMFGa9bx6mQ",
|
|
"standard": "ERC721"
|
|
}
|
|
],
|
|
"page": 1,
|
|
"total": 1
|
|
}`}
|
|
/>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Wallets */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Wallets</h2>
|
|
<div className="space-y-6">
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/wallets/create"
|
|
description="Create a new ERC-4337 smart wallet. The wallet is counterfactually deployed -- it exists at a deterministic address but is only deployed on-chain when the first transaction is sent."
|
|
params={[
|
|
{ name: "owner", type: "string", description: "EOA address that owns this smart wallet" },
|
|
{ name: "chain", type: "string", description: "Chain to deploy on (ethereum, base, polygon, etc.)" },
|
|
{ name: "salt", type: "string", description: "Optional salt for deterministic address generation", required: false },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/wallets/create \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum"
|
|
}'`}
|
|
response={`{
|
|
"address": "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
|
|
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum",
|
|
"status": "counterfactual",
|
|
"factory": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/wallets/{address}"
|
|
description="Get details of a specific smart wallet including its on-chain deployment status, owner, and transaction count."
|
|
params={[
|
|
{ name: "address", type: "string", description: "Smart wallet address" },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/wallets/0x7A0b3e4C5F1234567890abcdef1234567890ABCD \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"address": "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
|
|
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum",
|
|
"status": "deployed",
|
|
"factory": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
"nonce": 5,
|
|
"created_at": "2026-01-15T10:30:00Z",
|
|
"deployed_at": "2026-01-15T10:35:22Z",
|
|
"deploy_tx": "0xabc123..."
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/wallets"
|
|
description="List all smart wallets associated with your API key, with pagination."
|
|
params={[
|
|
{ name: "page", type: "integer", description: "Page number (default: 1)", required: false },
|
|
{ name: "limit", type: "integer", description: "Results per page, max 100 (default: 25)", required: false },
|
|
{ name: "chain", type: "string", description: "Filter by chain", required: false },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/wallets?chain=ethereum&limit=10 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"wallets": [
|
|
{
|
|
"address": "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
|
|
"owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
"chain": "ethereum",
|
|
"status": "deployed",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}
|
|
],
|
|
"page": 1,
|
|
"total": 1
|
|
}`}
|
|
/>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Webhooks */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Webhooks</h2>
|
|
<div className="space-y-6">
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/webhooks"
|
|
description={`Create a new webhook subscription. ${docsConfig.brandName} will POST events to your URL as they occur on-chain.`}
|
|
params={[
|
|
{ name: "url", type: "string", description: "HTTPS endpoint to receive webhook events" },
|
|
{ name: "chain", type: "string", description: "Chain to monitor" },
|
|
{ name: "event_type", type: "string", description: "Event type: address_activity, token_transfer, nft_transfer, mined_transaction, log" },
|
|
{ name: "config", type: "object", description: "Event-specific filter configuration", required: false },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/webhooks \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"url": "https://myapp.com/webhooks/bootnode",
|
|
"chain": "ethereum",
|
|
"event_type": "address_activity",
|
|
"config": {
|
|
"addresses": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]
|
|
}
|
|
}'`}
|
|
response={`{
|
|
"id": "wh_a1b2c3d4e5f6",
|
|
"url": "https://myapp.com/webhooks/bootnode",
|
|
"chain": "ethereum",
|
|
"event_type": "address_activity",
|
|
"config": {
|
|
"addresses": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]
|
|
},
|
|
"signing_secret": "whsec_k7m9p2q4r6s8t0v2w4x6y8z0",
|
|
"status": "active",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/webhooks"
|
|
description="List all webhook subscriptions for your account."
|
|
params={[
|
|
{ name: "page", type: "integer", description: "Page number (default: 1)", required: false },
|
|
{ name: "limit", type: "integer", description: "Results per page, max 100 (default: 25)", required: false },
|
|
{ name: "status", type: "string", description: "Filter by status: active, paused, disabled", required: false },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/webhooks \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"webhooks": [
|
|
{
|
|
"id": "wh_a1b2c3d4e5f6",
|
|
"url": "https://myapp.com/webhooks/bootnode",
|
|
"chain": "ethereum",
|
|
"event_type": "address_activity",
|
|
"status": "active",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}
|
|
],
|
|
"page": 1,
|
|
"total": 1
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="PATCH"
|
|
path="/v1/webhooks/{id}"
|
|
description="Update a webhook subscription. You can change the URL, status, or filter configuration."
|
|
params={[
|
|
{ name: "id", type: "string", description: "Webhook ID (e.g. wh_a1b2c3d4e5f6)" },
|
|
{ name: "url", type: "string", description: "New webhook URL", required: false },
|
|
{ name: "status", type: "string", description: "Set status: active, paused", required: false },
|
|
{ name: "config", type: "object", description: "Updated filter configuration", required: false },
|
|
]}
|
|
request={`curl -X PATCH ${docsConfig.apiUrl}/v1/webhooks/wh_a1b2c3d4e5f6 \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"status": "paused"
|
|
}'`}
|
|
response={`{
|
|
"id": "wh_a1b2c3d4e5f6",
|
|
"url": "https://myapp.com/webhooks/bootnode",
|
|
"chain": "ethereum",
|
|
"event_type": "address_activity",
|
|
"status": "paused",
|
|
"updated_at": "2026-01-15T12:00:00Z"
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="DELETE"
|
|
path="/v1/webhooks/{id}"
|
|
description="Permanently delete a webhook subscription. This action cannot be undone."
|
|
params={[
|
|
{ name: "id", type: "string", description: "Webhook ID" },
|
|
]}
|
|
request={`curl -X DELETE ${docsConfig.apiUrl}/v1/webhooks/wh_a1b2c3d4e5f6 \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"id": "wh_a1b2c3d4e5f6",
|
|
"deleted": true
|
|
}`}
|
|
/>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Gas */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Gas</h2>
|
|
<div className="space-y-6">
|
|
<Endpoint
|
|
method="GET"
|
|
path="/v1/gas/{chain}/prices"
|
|
description="Get current gas prices for a chain, including slow, standard, and fast estimates."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier (ethereum, polygon, base, etc.)" },
|
|
]}
|
|
request={`curl ${docsConfig.apiUrl}/v1/gas/ethereum/prices \\
|
|
-H "X-API-Key: YOUR_API_KEY"`}
|
|
response={`{
|
|
"chain": "ethereum",
|
|
"block_number": 20574335,
|
|
"base_fee_gwei": "12.50",
|
|
"estimates": {
|
|
"slow": {
|
|
"max_fee_gwei": "14.00",
|
|
"max_priority_fee_gwei": "0.50",
|
|
"estimated_seconds": 60
|
|
},
|
|
"standard": {
|
|
"max_fee_gwei": "16.00",
|
|
"max_priority_fee_gwei": "1.50",
|
|
"estimated_seconds": 15
|
|
},
|
|
"fast": {
|
|
"max_fee_gwei": "20.00",
|
|
"max_priority_fee_gwei": "3.00",
|
|
"estimated_seconds": 5
|
|
}
|
|
},
|
|
"updated_at": "2026-01-15T10:30:00Z"
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/gas/policies"
|
|
description={`Create a gas sponsorship policy. Policies define rules for when ${docsConfig.brandName} will pay gas fees on behalf of your users.`}
|
|
params={[
|
|
{ name: "name", type: "string", description: "Human-readable policy name" },
|
|
{ name: "chain", type: "string", description: "Chain this policy applies to" },
|
|
{ name: "rules", type: "object", description: "Sponsorship rules (max_gas_usd, allowed_contracts, rate_limit, etc.)" },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/gas/policies \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"name": "My App Free Gas",
|
|
"chain": "base",
|
|
"rules": {
|
|
"max_gas_usd": "0.50",
|
|
"max_per_user_per_day": 10,
|
|
"allowed_contracts": [
|
|
"0x1234567890abcdef1234567890abcdef12345678"
|
|
],
|
|
"allowed_methods": ["transfer", "approve", "mint"]
|
|
}
|
|
}'`}
|
|
response={`{
|
|
"id": "gp_x1y2z3w4v5u6",
|
|
"name": "My App Free Gas",
|
|
"chain": "base",
|
|
"rules": {
|
|
"max_gas_usd": "0.50",
|
|
"max_per_user_per_day": 10,
|
|
"allowed_contracts": [
|
|
"0x1234567890abcdef1234567890abcdef12345678"
|
|
],
|
|
"allowed_methods": ["transfer", "approve", "mint"]
|
|
},
|
|
"status": "active",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}`}
|
|
/>
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/gas/sponsor"
|
|
description="Sponsor a specific UserOperation. Returns a signed paymaster data field to include in the UserOperation."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "policy_id", type: "string", description: "Gas policy ID" },
|
|
{ name: "user_operation", type: "object", description: "The UserOperation to sponsor" },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/gas/sponsor \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"chain": "base",
|
|
"policy_id": "gp_x1y2z3w4v5u6",
|
|
"user_operation": {
|
|
"sender": "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
|
|
"nonce": "0x0",
|
|
"callData": "0xb61d27f6...",
|
|
"callGasLimit": "0x5208",
|
|
"verificationGasLimit": "0x186a0",
|
|
"preVerificationGas": "0xc350",
|
|
"maxFeePerGas": "0x3b9aca00",
|
|
"maxPriorityFeePerGas": "0x59682f00"
|
|
}
|
|
}'`}
|
|
response={`{
|
|
"paymaster": "0xBootnodePaymasterAddress",
|
|
"paymasterData": "0x0000000067b2c3d4...signed_data",
|
|
"paymasterVerificationGasLimit": "0x30000",
|
|
"paymasterPostOpGasLimit": "0x10000",
|
|
"sponsored_gas_usd": "0.03"
|
|
}`}
|
|
/>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Bundler */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Bundler</h2>
|
|
<Endpoint
|
|
method="POST"
|
|
path="/v1/bundler/{chain}/{network}"
|
|
description="ERC-4337 bundler JSON-RPC endpoint. Supports eth_sendUserOperation, eth_estimateUserOperationGas, eth_getUserOperationByHash, eth_getUserOperationReceipt, and eth_supportedEntryPoints."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "network", type: "string", description: "Network name (mainnet, sepolia, etc.)" },
|
|
]}
|
|
request={`curl -X POST ${docsConfig.apiUrl}/v1/bundler/ethereum/mainnet \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "X-API-Key: YOUR_API_KEY" \\
|
|
-d '{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"method": "eth_sendUserOperation",
|
|
"params": [
|
|
{
|
|
"sender": "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
|
|
"nonce": "0x0",
|
|
"initCode": "0x",
|
|
"callData": "0xb61d27f6...",
|
|
"callGasLimit": "0x5208",
|
|
"verificationGasLimit": "0x186a0",
|
|
"preVerificationGas": "0xc350",
|
|
"maxFeePerGas": "0x3b9aca00",
|
|
"maxPriorityFeePerGas": "0x59682f00",
|
|
"paymasterAndData": "0x",
|
|
"signature": "0xabcdef..."
|
|
},
|
|
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
|
|
]
|
|
}'`}
|
|
response={`{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
|
}`}
|
|
/>
|
|
</section>
|
|
|
|
{/* WebSocket */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">WebSocket</h2>
|
|
<Endpoint
|
|
method="WS"
|
|
path="/v1/ws/{chain}/{network}"
|
|
description="WebSocket endpoint for real-time blockchain subscriptions. Supports eth_subscribe for newHeads, logs, newPendingTransactions, and syncing."
|
|
params={[
|
|
{ name: "chain", type: "string", description: "Chain identifier" },
|
|
{ name: "network", type: "string", description: "Network name (mainnet, sepolia, etc.)" },
|
|
]}
|
|
request={`wscat -c "${docsConfig.wsUrl}/v1/ws/ethereum/mainnet?apiKey=YOUR_API_KEY"
|
|
|
|
> {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}`}
|
|
response={`{"jsonrpc":"2.0","id":1,"result":"0x1a2b3c4d"}
|
|
|
|
// Subsequent messages:
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "eth_subscription",
|
|
"params": {
|
|
"subscription": "0x1a2b3c4d",
|
|
"result": {
|
|
"number": "0x13a5e80",
|
|
"hash": "0xabc123...",
|
|
"parentHash": "0xdef456...",
|
|
"timestamp": "0x67890abc",
|
|
"gasUsed": "0xe4e1c0",
|
|
"gasLimit": "0x1c9c380",
|
|
"baseFeePerGas": "0x2e90edd00"
|
|
}
|
|
}
|
|
}`}
|
|
/>
|
|
</section>
|
|
|
|
{/* Error Codes */}
|
|
<section className="space-y-4">
|
|
<h2 className="text-2xl font-semibold">Error Codes</h2>
|
|
<div className="overflow-x-auto border rounded-lg">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="border-b bg-muted/50">
|
|
<th className="text-left p-3 font-medium">HTTP Status</th>
|
|
<th className="text-left p-3 font-medium">Error Code</th>
|
|
<th className="text-left p-3 font-medium">Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono">400</td>
|
|
<td className="p-3 font-mono">invalid_request</td>
|
|
<td className="p-3 text-muted-foreground">Malformed request body or missing required parameters</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono">401</td>
|
|
<td className="p-3 font-mono">unauthorized</td>
|
|
<td className="p-3 text-muted-foreground">Missing or invalid API key</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono">403</td>
|
|
<td className="p-3 font-mono">forbidden</td>
|
|
<td className="p-3 text-muted-foreground">API key does not have access to this resource</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono">404</td>
|
|
<td className="p-3 font-mono">not_found</td>
|
|
<td className="p-3 text-muted-foreground">Resource does not exist</td>
|
|
</tr>
|
|
<tr className="border-b">
|
|
<td className="p-3 font-mono">429</td>
|
|
<td className="p-3 font-mono">rate_limited</td>
|
|
<td className="p-3 text-muted-foreground">Rate limit exceeded. Check X-RateLimit headers.</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-3 font-mono">500</td>
|
|
<td className="p-3 font-mono">internal_error</td>
|
|
<td className="p-3 text-muted-foreground">Internal server error. Retry with exponential backoff.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">All error responses follow this format:</p>
|
|
<pre className="overflow-x-auto rounded-lg bg-zinc-950 p-4 text-sm text-zinc-100">
|
|
<code>{`{
|
|
"error": {
|
|
"code": "rate_limited",
|
|
"message": "Rate limit exceeded. Retry after 1 second.",
|
|
"status": 429
|
|
}
|
|
}`}</code>
|
|
</pre>
|
|
</section>
|
|
</div>
|
|
</DocsLayout>
|
|
)
|
|
}
|