Browse all documentation
Developers · 3 of 7

Developer accounts, sandbox, quotas, and Base subscriptions

Create wallet-owned API keys, test fixtures, inspect quota receipts, and subscribe to higher capacity with Base USDC.

betav1 · server 3.0Verified 2026-07-29Owner: ENS.Tools Developer Platform
Open this feature

The developer gateway adds durable identity, idempotency, quotas, and deterministic fixtures without closing the public MCP baseline. The account owner signs an EIP-712 challenge; API key secrets are shown once and only their SHA-256 hashes are retained.

Wallet-owned account and revocable API keys with no setup transaction.
Zero-dependency JavaScript/TypeScript client for live and sandbox calls.
Generated OpenAPI 3.1 document tied directly to the runtime catalogue.
Idempotent live monthly and sandbox daily quota receipts.
One paid path: a plan-sized Base USDC spend permission with a 30-day period.
Capacity subscriptions, agent-job escrow, and ENS/marketplace costs are separate: only the first buys authenticated ENS.Tools capacity.
Human-readable pricing at /developers/pricing and canonical agent-readable pricing at /.well-known/agent-pricing.json.
The direct Operator journey is /developers/console?plan=operator#subscribe; machine-readable pricing publishes a purchase URL for every paid plan.
The wallet-owned developer account and Base billing payer may be different: the account owner signs a one-use EIP-712 link, while the payer, spender, token, amount and period are re-read from Base before charging.
A Base Account is Coinbase’s self-custodial smart wallet, not every wallet connected to the Base network. Existing Base App or Smart Wallet users can sign in; a new payer can create one with email or a passkey without opening a Coinbase exchange account.
The Base Account has its own balance and must hold the selected plan amount in official USDC on Base. USDC held only in MetaMask or on another network is not available to the spend permission.
Approving and linking create no payment: the console remains Not paid until the user clicks the separately priced first-payment action.
Entitlement activates only after an exact official USDC transfer to enstools.eth reaches five Base confirmations.
The console exposes revocation, current period, charge state and onchain receipts; any legacy Stripe/direct records are labelled historical and cannot start or renew a plan.
Stripe, direct-transfer and ETH purchase operations are unavailable.
Request arguments are not stored; append-only usage decisions are retained for 90 days.
Expired wallet challenges are deleted after 24 hours; rate limits use a keyed IP fingerprint rather than a raw IP address.
Production contract

Before you run this workflow

Networks

  • Ethereum mainnet (chain 1) for EIP-712 account ownership
  • Base mainnet (chain 8453) for recurring official USDC settlement

Prerequisites

  • A connected EOA or ERC-1271 wallet
  • A matching Base Account for paid subscriptions
  • USDC on Base
  • A server-side secret manager for API keys
  • A Fetch-compatible JavaScript runtime or direct HTTPS client

Wallet permissions

  • EIP-712 signature for account, session, key creation, and revocation
  • Optional plan-sized Base USDC spend permission with a 30-day period

Expected result

  • One-time API key secret
  • Durable quota receipt on every gateway call
  • Deterministic non-financial sandbox output
  • Confirmed Base USDC charge receipt before paid entitlement

Errors and recovery

  • Rotate a leaked key from the console
  • Reuse idempotency keys only for exact retries
  • Refresh or revoke a subscription from the console
  • Never infer payment from a permission response or submitted transaction hash
Workflow

How to use it

  1. 1

    Create the wallet-owned account

    Open the developer console, connect the owner wallet, read the ten-minute EIP-712 challenge, and sign. This grants no token or transaction permission.

  2. 2

    Store the key once

    Copy the ensk_live_ secret into the runtime secret manager. Do not place it in ENS records, prompts, logs, client-side bundles, or source control.

  3. 3

    Exercise semantic fixtures

    Call the sandbox environment first. Test healthy and unhealthy capability evidence, routing order, active/expired/revoked policy states, and accepted-but-unfunded escrow truth.

  4. 4

    Move the same client live

    Switch from client.sandbox to client.live. Supply a stable Idempotency-Key for every call and retain the returned quota receipt.

  5. 5

    Discover live subscription readiness

    GET /api/developers/billing and require providers.base.available=true. Pin the plan amount, subscription owner, official Base USDC address, enstools.eth recipient and 30-day period.

  6. 6

    Create or sign in to the Base Account

    Open /developers/console?plan=operator#subscribe for the 39 USDC Operator journey, or choose another plan. Your MetaMask or other connected wallet remains the developer-account and ENS owner. Billing opens keys.coinbase.com: sign in if you already use Base App or Smart Wallet, or create a self-custodial Base Account with email or a passkey. A Coinbase exchange account is not required.

  7. 7

    Fund and approve the billing limit

    The Base Account is a distinct wallet and needs the plan amount in official USDC on Base. Use Fund from another wallet if necessary, then approve the capped recurring permission. Approval sets a revocable limit; it does not move USDC or pay for the plan.

  8. 8

    Recover an interrupted approval

    If the approval succeeded but linking failed or the page reloaded, choose Already approved? Recover it. Sign in to the same Base Account so the console can find only that payer’s exact active ENS.Tools permission. Recovery requests no new allowance and makes no payment.

  9. 9

    Link the payer to the owner

    After Base approval, sign the exact account, payer, permission, plan, amount, period, nonce and expiry with the developer-account owner. This is not a transaction, does not move ENS ownership and adds no token permission.

  10. 10

    Review and start the first payment

    Registration leaves the account Not paid. Review the displayed plan and click Pay … USDC now. This separately recorded action is required before any initial or hourly charge job may run.

  11. 11

    Resume a stuck payment request

    If Payment requested does not produce a Base transaction, use Resume payment or POST resume_base_subscription_charge. The worker reuses the already authorised, period-idempotent charge; it does not create a second permission or prove payment.

  12. 12

    Confirm, then rely on entitlement

    A requested payment is not a paid payment. Capacity remains inactive until the console exposes a Base transaction and the exact transfer to enstools.eth reaches five confirmations.

Deterministic sandbox fixtures

lookup_domain — active example name
check_agent_capabilities — healthy or intentionally unhealthy protocol evidence
route_agent_intent — stable ranked candidates and visible score components
verify_agent_policy — active, expired, or revoked state
inspect_erc8183_escrow — accepted job that remains explicitly unfunded

Errors and recovery

401 invalid_api_key — create a new key or check the runtime secret; the full key cannot be recovered.
409 challenge_expired — prepare and sign a fresh wallet challenge.
429 developer_challenge_rate_limited — wait one hour before preparing another challenge.
429 quota_exceeded — wait for the period reset or fund a higher plan.
400 sandbox_fixture_unavailable — use one of the advertised fixtures or switch to live.
503 base_subscription_setup_required — do not request a permission and do not offer a fallback purchase method.
409 subscription_payer_mismatch — the declared Base billing wallet differs from the onchain permission payer; do not register or charge it.
409 billing_link_expired or billing_link_mismatch — prepare a fresh owner-wallet link for the same approved permission. Do not ask for another Base permission first.
Interrupted browser state — use Already approved? Recover it and authenticate the same Base Account. Accept only an exact active payer, spender, token, amount and period match before preparing a new owner link.
401 billing_link_invalid_signature — sign the link with the wallet that owns the developer account.
409 subscription_payment_not_authorized — no first-payment action exists. Do not queue, retry, or claim a charge; show the exact Pay … USDC now action.
Payment requested with no transaction — use resume_base_subscription_charge to requeue the already authorised, period-idempotent charge.
409 subscription_owner_mismatch, subscription_asset_mismatch, or subscription_period_mismatch — reject the permission and review canonical terms.
409 subscription_period_allowance_exhausted — do not retry a charge; refresh status and investigate possible semantic drift.
409 subscription_charge_confirmations_pending — wait for five Base confirmations and do not claim capacity.

Plan contract

Free — 10,000 live calls/month and 1,000 sandbox calls/day.
Operator — 39 USDC, 100,000 live calls/month and 5,000 sandbox calls/day.
Team — 149 USDC, 1,000,000 live calls/month and 25,000 sandbox calls/day.
Scale — 499 USDC, 5,000,000 live calls/month and 100,000 sandbox calls/day.
Identity resolution, verification, revocation, safety, simulation, and canary evidence are not sold as trust upgrades.

Examples

JavaScript · sandbox then live
import { createEnsToolsClient } from 'https://ens.tools/sdk/ens-agent-client.mjs';

const ens = createEnsToolsClient({
  apiKey: process.env.ENS_TOOLS_API_KEY,
});

const fixture = await ens.sandbox(
  'check_agent_capabilities',
  { name: 'unhealthy.agent-fixture.eth' },
  { requestId: 'test:capability:001' },
);

const live = await ens.live(
  'lookup_domain',
  { name: 'vitalik.eth' },
  { requestId: 'production:lookup:001' },
);
HTTP · authenticated gateway
curl https://ens.tools/api/v1/tools \
  -H "Authorization: Bearer $ENS_TOOLS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: production:lookup:001" \
  -d '{
    "environment": "live",
    "tool": "lookup_domain",
    "arguments": { "name": "vitalik.eth" }
  }'