Integration guide / testnets
Merchant wallets, native roles and setup flow →See every service field with example values →One verification stack.
Two ways to sign.
ENS publishes service configuration. ENS402 compares the real HTTP 402, screens the recipient, and checks your approval before payment. Choose who controls the signing wallet.
Discover before you approve
Search the public catalog without a wallet. The API, SDK and read-only MCP use the same candidate data. Resolve the chosen ENS name again in Console before approving a payment.
import { discover } from "@ens402/sdk/discovery";
const candidates = await discover(
{ query: "Tokyo weather", mode: "hybrid", maxPricePerRequestAtomic: "10000" },
{ apiUrl: "https://ens402.vercel.app/api/discover" }
);
// 10000 atomic units = 0.01 USDC. Search never grants payment authority.
// Check candidates.semantic, fixture labels and the source checkpoint.MCP URL: /api/mcp (Streamable HTTP). Tools: discover_services and resolve_service. No payment or approval tools. Service descriptions and schemas are untrusted provider content.
Publish ens402.call with an explicit GET or POST method, input/output schemas and optional examples for verified publication. GET calls currently use the exact published URL. POST purchases support JSON bodies up to 8192 bytes and require a merchant that verifies ENS402 request binding, including the assigned orderId.
Publish and govern your services
Set up a provider namespace, publish service records, then track listing status and observed payments in the merchant workspace. Ops edits the endpoint and call metadata; Treasury edits payment terms. Native ENS contracts enforce every wallet-signed change.
New payment records use schema v3: the service name holder is the recipient. Transferring that name changes who gets paid and requires renewed buyer approval. Contract holders must also prove control of a deployed wallet on Base Sepolia. Treasury role replacement alone does not change the recipient.
First-time platform owners can initialize their registry in the same setup page. Connect the wallet that already holds the parent ENS name, then review and sign the deploy and link transactions. Email login alone does not grant control of that name.
Make your endpoint ready for publication
Return resource.description and the ens402.service extension in your unsigned HTTP 402 challenge. This is an ENS402 application format. The form probes it before both commit and reveal; Guard compares it again before payment. Missing metadata cannot pass as verified.
import { metadataExtension } from "@ens402/sdk/metadata";
const description = "Weather forecast for Tokyo";
const call = {
verification: "ens402.service.v1",
method: "GET",
inputSchema: { type: "object", properties: {}, additionalProperties: false },
outputSchema: { type: "object", properties: { temperatureC: { type: "number" } } }
} as const;
// Publish this same description and call object in ENS.
const challenge = {
x402Version: 2,
resource: { url: endpoint, description, mimeType: "application/json" },
accepts: paymentRequirements,
extensions: metadataExtension(description, call)
};Description: at most 1,024 UTF-8 bytes. Call metadata: at most 16,384 bytes, with both schemas. Object key order is ignored; array order is preserved. Schema references are not supported. This verifies declared configuration consistency, not service quality or response conformance.
Using the verification SDK directly
After resolving ENS, attach fresh destination evidence with checkNameOwnerRecipient from @ens402/sdk/recipient before calling verifyRequest. The hosted server already performs this check. Use serializePaymentRecord when writing schema v3 so the derived recipient is not copied into the stored record. Sign only after terms, consent, limits and screening pass.
Managed agent wallet
Sign in with Privy, inspect a service, and approve its recipient, exact endpoints, amount and expiry. ENS402 creates a dedicated Privy wallet. Fund that address with Base Sepolia USDC, then create an agent API key for that approval.
Privy enforces per-signature policy. Our database reserves the daily budget. ENS402 controls the wallet and can change policy. This is a trusted platform service.
Your own signer
Connect your wallet and choose “Use my own signer.” ENS402 prepares the exact payment after checks. You sign it; ENS402 verifies the signature, rechecks ENS and risk, and submits once.
No platform wallet is created. Your wallet needs test USDC. Payments outside ENS402 bypass its controls; our limits do not restrict your wallet globally. The current signing flow supports EOA EIP-3009 signatures.
Human approval → agent key → purchase
- 01You choose a service and approve a scope.
- 02Your agent gets a key for that approval only.
- 03ENS402 resolves, verifies and screens each purchase.
- 04Privy or your signer signs. The merchant settles and returns data.
A key cannot create wallets, raise limits or approve a different service. A new service or recipient needs human approval. Endpoint updates continue only if the new exact URL was already approved. The resource API supports GET and bounded JSON POST requests at the ENS-published URL. POST orders require a UUID v4 orderId and a merchant supporting ENS402 request binding: the signed USDC nonce commits to the endpoint and exact body. Authentication headers are never forwarded.
Call the hosted API from an agent
The SDK is currently a workspace package in this repository, not a published npm release. Import its platform entry point from a linked checkout. Keep the API key in the agent runtime, outside prompts and browser bundles.
import { ENS402Client } from '@ens402/sdk/platform';
const client = new ENS402Client({
baseUrl: 'https://ens402.vercel.app',
apiKey: process.env.ENS402_AGENT_KEY!,
});
// Persist this ID before making the request.
const id = crypto.randomUUID();
const result = await client.purchase({ id, approvalId });
// If the connection drops, query this ID. Do not make a new payment.
const status = await client.execution(id);For your signer, use purchaseWithSigner({ id, approvalId, approval, signer }). The local approval is independently checked before signing. Advanced clients can call prepare and submit separately.
POST /api/v1
Authorization: Bearer <agent key>
Content-Type: application/json
{"action":"execute","id":"<persisted UUID>","approvalId":"<approved UUID>"}Agent operations: inspect, execute, prepare-external, submit-external, execution, balance, cancel and reconcile. An uncertain or submitting payment retains its budget until an actual USDC transfer and nonce are reconciled. A valid signature can still be submitted by someone who already possesses it after an app-level revocation.
Example: buy a subname for a recipient
Approve the ENS service pointing to /api/merchant/register. Purchase with a JSON POST order. The merchant settles Base Sepolia USDC and registers the native Sepolia subname directly to the recipient. No resolver is included, so the merchant retains no resolver administrator role.
await client.purchase({
id: crypto.randomUUID(), approvalId,
request: { method: "POST", body: JSON.stringify({
orderId: crypto.randomUUID(),
label: "alice", recipient: "0x..."
}) }
});Keep both IDs when recovering. Check GET /api/merchant/registration-orders/<orderId> for payment and registration transactions. A paid but incomplete order requires operator recovery, never another payment. Setup needs an enabled parent registry, a funded Sepolia worker with ROLE_REGISTRAR, a published service and a Base Sepolia USDC payer. This is a subname purchase, not arbitrary .eth registration.
Run the core yourself
Use @ens402/sdk/ens, /http, /intercepta and an independent signer. Your infrastructure supplies authentication, request transport, nonce persistence and settlement checks. Neither our database nor a Privy account is required for the core. A Skill explains this workflow to an agent; code and wallet policies enforce it.
Publish kevinweather.ens402.eth
This is a planned namespace until its parent and registrar are configured. For the demo, register the parent on ENSv2 Sepolia at app.ens.dev. A mainnet registration at app.ens.domains is a separate asset and is not required to run the testnet demo.
- Register the testnet parent and retain its owner wallet with Sepolia ETH.
- Deploy a native UserRegistry for its children. Point the parent at that registry.
- Deploy ServiceRegistrar for that exact parent and grant it only native ROLE_REGISTRAR.
- Configure ENS_PARENT_NAME and SERVICE_REGISTRAR_ADDRESS on the platform.
- For the default shared-provider flow, an authorized publisher registers the name and initializes its records in one transaction. Existing provider delegates retain their native permissions. Older isolated ServiceRegistrar deployments still use commit-reveal with a 60-second delay.
Current native setter permissions are per key within a resolver. Every provider shares a resolver by default; isolated deployments remain available. Provider Admin retains text administration and name owners retain resolver-pointer authority; parent administrators and ancestor expiry remain trust boundaries. Registrations have a fixed namespace expiry and no platform renewal flow yet. These names do not certify service quality.
Open service registrationWhat runs where?
| Component | Responsibility |
|---|---|
| ENS contracts on Sepolia | Public records, native ownership and EAC write permissions |
| ENS402 on Vercel | Authentication, ownership checks, verification, screening, execution and reconciliation |
| Neon PostgreSQL | User-wallet associations, hashed agent keys, daily reservations and decision records |
| Privy | Login verification, hosted private keys and per-signature policy enforcement |
| Your signer | User-controlled signing in the external mode |
| Merchant / facilitator | Accept x402 payment, settle on Base Sepolia, deliver the API response |
Testnet prototype. A running login screen does not prove a funded end-to-end payment. See README.md and SETUP.md in the repository for deployment gates and validation evidence.