create_paywall
Generate paywall URLs that charge agents for accessing protected resources using on-chain payments, returning HTTP 402 until payment is verified.
Instructions
Create an x402 paywall that charges agents/clients for accessing a resource. Returns a public access URL that returns HTTP 402 until paid. Agents pay on-chain, then retry with proof to get the content.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| wallet_id | Yes | Wallet ID to receive payments | |
| name | Yes | Human-readable paywall name (e.g. "Premium API Access") | |
| description | No | Description shown in the 402 response | |
| amount | Yes | Price in human-readable format (e.g. "0.01" for 0.01 USDC) | |
| token_type | No | "erc20" for EVM stablecoins, "spl" for Solana SPL tokens, "native" for ETH/SOL/POL/etc. | erc20 |
| token_address | No | Token contract address (ERC-20 for EVM, SPL mint Base58 for Solana). Required if token_type is "erc20" or "spl". Use get_chains to find stablecoin addresses. | |
| token_decimals | No | Token decimals (6 for USDC, 18 for ETH/most tokens) | |
| token_name | No | Token display name (e.g. "USDC", "ETH") | USDC |
| chain_id | No | Chain ID for payments (8453=Base, 1=Ethereum, etc.) | |
| resource_url | Yes | URL of the protected resource to serve after payment verification | |
| resource_mime | No | MIME type of the resource (e.g. "application/json", "text/plain") | application/json |
Implementation Reference
- src/index.ts:1220-1262 (handler)The 'create_paywall' tool handler. Creates an x402 paywall by converting the human-readable amount to raw token units using parseUnits(), then calls the API endpoint '/x402/paywalls' with all paywall configuration (wallet_id, name, description, amount, token details, chain_id, resource_url, resource_mime). Returns the created paywall data with formatted price string.
server.tool( 'create_paywall', 'Create an x402 paywall that charges agents/clients for accessing a resource. ' + 'Returns a public access URL that returns HTTP 402 until paid. ' + 'Agents pay on-chain, then retry with proof to get the content.', { wallet_id: z.number().int().describe('Wallet ID to receive payments'), name: z.string().describe('Human-readable paywall name (e.g. "Premium API Access")'), description: z.string().default('').describe('Description shown in the 402 response'), amount: z.string().describe('Price in human-readable format (e.g. "0.01" for 0.01 USDC)'), token_type: z.enum(['erc20', 'spl', 'native']).default('erc20').describe('"erc20" for EVM stablecoins, "spl" for Solana SPL tokens, "native" for ETH/SOL/POL/etc.'), token_address: z.string().default('').describe('Token contract address (ERC-20 for EVM, SPL mint Base58 for Solana). Required if token_type is "erc20" or "spl". Use get_chains to find stablecoin addresses.'), token_decimals: z.number().int().default(6).describe('Token decimals (6 for USDC, 18 for ETH/most tokens)'), token_name: z.string().default('USDC').describe('Token display name (e.g. "USDC", "ETH")'), chain_id: z.number().int().default(8453).describe('Chain ID for payments (8453=Base, 1=Ethereum, etc.)'), resource_url: z.string().url().describe('URL of the protected resource to serve after payment verification'), resource_mime: z.string().default('application/json').describe('MIME type of the resource (e.g. "application/json", "text/plain")'), }, async ({ wallet_id, name, description, amount, token_type, token_address, token_decimals, token_name, chain_id, resource_url, resource_mime }) => { // Convert human-readable amount to raw token units const rawAmount = parseUnits(amount, token_decimals); const data = await api('/x402/paywalls', 'POST', { wallet_id, name, description, amount: rawAmount, token_type, token_address, token_decimals, token_name, chain_id, resource_url, resource_mime, }); return jsonResponse({ ...(data as Record<string, unknown>), price: `${amount} ${token_name}`, chain_id, }); }, ); - src/index.ts:1220-1237 (schema)The Zod schema definition for 'create_paywall' tool inputs. Defines 11 parameters: wallet_id (required int), name (required string), description (default ''), amount (required string for human-readable price), token_type (enum: erc20/spl/native, default erc20), token_address (default ''), token_decimals (default 6), token_name (default 'USDC'), chain_id (default 8453 for Base), resource_url (required URL), resource_mime (default 'application/json').
server.tool( 'create_paywall', 'Create an x402 paywall that charges agents/clients for accessing a resource. ' + 'Returns a public access URL that returns HTTP 402 until paid. ' + 'Agents pay on-chain, then retry with proof to get the content.', { wallet_id: z.number().int().describe('Wallet ID to receive payments'), name: z.string().describe('Human-readable paywall name (e.g. "Premium API Access")'), description: z.string().default('').describe('Description shown in the 402 response'), amount: z.string().describe('Price in human-readable format (e.g. "0.01" for 0.01 USDC)'), token_type: z.enum(['erc20', 'spl', 'native']).default('erc20').describe('"erc20" for EVM stablecoins, "spl" for Solana SPL tokens, "native" for ETH/SOL/POL/etc.'), token_address: z.string().default('').describe('Token contract address (ERC-20 for EVM, SPL mint Base58 for Solana). Required if token_type is "erc20" or "spl". Use get_chains to find stablecoin addresses.'), token_decimals: z.number().int().default(6).describe('Token decimals (6 for USDC, 18 for ETH/most tokens)'), token_name: z.string().default('USDC').describe('Token display name (e.g. "USDC", "ETH")'), chain_id: z.number().int().default(8453).describe('Chain ID for payments (8453=Base, 1=Ethereum, etc.)'), resource_url: z.string().url().describe('URL of the protected resource to serve after payment verification'), resource_mime: z.string().default('application/json').describe('MIME type of the resource (e.g. "application/json", "text/plain")'), }, - src/index.ts:1218-1262 (registration)Full registration of 'create_paywall' tool with the MCP server using server.tool(). Includes the tool name, description explaining it creates an x402 paywall that charges agents/clients for accessing resources, the Zod input schema, and the async handler function.
// ─── Tool: create_paywall ──────────────────────────────────────── server.tool( 'create_paywall', 'Create an x402 paywall that charges agents/clients for accessing a resource. ' + 'Returns a public access URL that returns HTTP 402 until paid. ' + 'Agents pay on-chain, then retry with proof to get the content.', { wallet_id: z.number().int().describe('Wallet ID to receive payments'), name: z.string().describe('Human-readable paywall name (e.g. "Premium API Access")'), description: z.string().default('').describe('Description shown in the 402 response'), amount: z.string().describe('Price in human-readable format (e.g. "0.01" for 0.01 USDC)'), token_type: z.enum(['erc20', 'spl', 'native']).default('erc20').describe('"erc20" for EVM stablecoins, "spl" for Solana SPL tokens, "native" for ETH/SOL/POL/etc.'), token_address: z.string().default('').describe('Token contract address (ERC-20 for EVM, SPL mint Base58 for Solana). Required if token_type is "erc20" or "spl". Use get_chains to find stablecoin addresses.'), token_decimals: z.number().int().default(6).describe('Token decimals (6 for USDC, 18 for ETH/most tokens)'), token_name: z.string().default('USDC').describe('Token display name (e.g. "USDC", "ETH")'), chain_id: z.number().int().default(8453).describe('Chain ID for payments (8453=Base, 1=Ethereum, etc.)'), resource_url: z.string().url().describe('URL of the protected resource to serve after payment verification'), resource_mime: z.string().default('application/json').describe('MIME type of the resource (e.g. "application/json", "text/plain")'), }, async ({ wallet_id, name, description, amount, token_type, token_address, token_decimals, token_name, chain_id, resource_url, resource_mime }) => { // Convert human-readable amount to raw token units const rawAmount = parseUnits(amount, token_decimals); const data = await api('/x402/paywalls', 'POST', { wallet_id, name, description, amount: rawAmount, token_type, token_address, token_decimals, token_name, chain_id, resource_url, resource_mime, }); return jsonResponse({ ...(data as Record<string, unknown>), price: `${amount} ${token_name}`, chain_id, }); }, );