AgentAddress Generator

Universal identity for AI agents on the internet

AgentAddress is an open-source agent identification system: a unique, verifiable identity that works across any website that accepts AgentAddress authentication.

This tool runs locally in your browser. We don't store anything — your recovery phrase and secret key never leave your device.

Repo: github.com/Apoth3osis-ai/agent-address

Using AgentAddress with AgentPMT credits and workflows: /autonomous-agents

Programmatic no-auth endpoint for agents: POST /api/external/agentaddress

Click Generate New Agent Address to create a new identity.

Works on all EVM-compatible chains

EthereumBaseArbitrumOptimismPolygonBNB ChainAvalanchezkSyncLineaScrollBlastMantleFantomGnosisCronosCeloMoonbeamHarmonyZoraMetisAuroraTaikoSeiSepoliaHoleskyBase SepoliaArbitrum SepoliaOP Sepolia+30 more

API Flow Example (No Auth + x402 + Signed Tool Invoke)

This end-to-end Node/TypeScript example shows how an agent can: call /api/external/agentaddress, buy credits with x402 using a payment signature, and invoke a tool using a wallet signature.

import { createHash, randomBytes, randomUUID } from "node:crypto";
import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base, baseSepolia } from "viem/chains";

const API_BASE_URL = "https://www.agentpmt.com";
const BASE_RPC_URL = process.env.BASE_RPC_URL as string;

if (!BASE_RPC_URL) throw new Error("Set BASE_RPC_URL");

function canonicalize(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(canonicalize);
  if (value && typeof value === "object") {
    return Object.fromEntries(
      Object.keys(value as Record<string, unknown>)
        .sort()
        .map((k) => [k, canonicalize((value as Record<string, unknown>)[k])]),
    );
  }
  return value;
}

function canonicalJson(value: unknown): string {
  return JSON.stringify(canonicalize(value));
}

async function run() {
  // 1) No-auth wallet bootstrap
  const walletResp = await fetch(\`\${API_BASE_URL}/api/external/agentaddress\`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
  });
  const walletJson = await walletResp.json();
  const agent = walletJson.data as {
    evmAddress: \`0x\${string}\`;
    evmPrivateKey: \`0x\${string}\`;
    mnemonic: string;
  };
  const account = privateKeyToAccount(agent.evmPrivateKey);

  // 2) x402 credit purchase (PAYMENT-REQUIRED -> PAYMENT-SIGNATURE)
  const desiredCredits = 500;
  const purchaseInit = await fetch(\`\${API_BASE_URL}/api/external/credits/purchase\`, {
    method: "POST",
    headers: { "Content-Type": "application/json", Accept: "application/json" },
    body: JSON.stringify({
      wallet_address: account.address,
      credits: desiredCredits,
      payment_method: "x402",
    }),
  });
  if (purchaseInit.status !== 402) {
    throw new Error(\`Expected 402, got \${purchaseInit.status}\`);
  }

  const paymentRequiredHeader = purchaseInit.headers.get("PAYMENT-REQUIRED");
  if (!paymentRequiredHeader) throw new Error("Missing PAYMENT-REQUIRED header");
  const paymentRequired = JSON.parse(
    Buffer.from(paymentRequiredHeader, "base64").toString("utf8"),
  ) as {
    accepts: Array<{
      network: string;
      amount: string;
      asset: \`0x\${string}\`;
      payTo: \`0x\${string}\`;
    }>;
  };
  const acceptance = paymentRequired.accepts[0];
  const chainId = Number(acceptance.network.replace("eip155:", ""));
  const chain = chainId === 8453 ? base : chainId === 84532 ? baseSepolia : null;
  if (!chain) throw new Error(\`Unsupported chainId: \${chainId}\`);

  const publicClient = createPublicClient({
    chain,
    transport: http(BASE_RPC_URL),
  });
  const walletClient = createWalletClient({
    account,
    chain,
    transport: http(BASE_RPC_URL),
  });

  const usdcAbi = parseAbi([
    "function name() view returns (string)",
    "function version() view returns (string)",
  ]);
  const [name, version] = await Promise.all([
    publicClient.readContract({
      address: acceptance.asset,
      abi: usdcAbi,
      functionName: "name",
    }),
    publicClient.readContract({
      address: acceptance.asset,
      abi: usdcAbi,
      functionName: "version",
    }),
  ]);

  const validAfter = 0n;
  const validBefore = BigInt(Math.floor(Date.now() / 1000) + 30 * 60);
  const nonce = \`0x\${randomBytes(32).toString("hex")}\` as \`0x\${string}\`;
  const amount = BigInt(acceptance.amount);

  const signature = await walletClient.signTypedData({
    account,
    domain: {
      name,
      version,
      chainId,
      verifyingContract: acceptance.asset,
    },
    primaryType: "TransferWithAuthorization",
    types: {
      TransferWithAuthorization: [
        { name: "from", type: "address" },
        { name: "to", type: "address" },
        { name: "value", type: "uint256" },
        { name: "validAfter", type: "uint256" },
        { name: "validBefore", type: "uint256" },
        { name: "nonce", type: "bytes32" },
      ],
    },
    message: {
      from: account.address,
      to: acceptance.payTo,
      value: amount,
      validAfter,
      validBefore,
      nonce,
    },
  });

  const paymentHeader = Buffer.from(
    JSON.stringify({
      x402Version: 2,
      scheme: "exact",
      network: acceptance.network,
      payload: {
        signature,
        authorization: {
          from: account.address,
          to: acceptance.payTo,
          value: acceptance.amount,
          validAfter: validAfter.toString(),
          validBefore: validBefore.toString(),
          nonce,
        },
      },
    }),
    "utf8",
  ).toString("base64");

  const purchaseResp = await fetch(\`\${API_BASE_URL}/api/external/credits/purchase\`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      "PAYMENT-SIGNATURE": paymentHeader,
    },
    body: JSON.stringify({
      wallet_address: account.address,
      credits: desiredCredits,
      payment_method: "x402",
      request_id: \`purchase-\${randomUUID()}\`,
    }),
  });
  const purchaseJson = await purchaseResp.json();
  if (!purchaseResp.ok) throw new Error(\`Purchase failed: \${JSON.stringify(purchaseJson)}\`);

  // 3) Signed tool invocation using the purchased credits
  const sessionResp = await fetch(\`\${API_BASE_URL}/api/external/auth/session\`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ wallet_address: account.address }),
  });
  const sessionJson = await sessionResp.json();
  const sessionNonce = sessionJson.session_nonce as string;

  const productId = "<productId>";
  const parameters = { action: "get_instructions" };
  const payloadHash = createHash("sha256").update(canonicalJson(parameters)).digest("hex");
  const requestId = \`invoke-\${randomUUID()}\`;
  const signMessage = [
    "agentpmt-external",
    \`wallet:\${account.address.toLowerCase()}\`,
    \`session:\${sessionNonce}\`,
    \`request:\${requestId}\`,
    "action:invoke",
    \`product:\${productId}\`,
    \`payload:\${payloadHash}\`,
  ].join("\n");
  const invokeSignature = await walletClient.signMessage({
    account,
    message: signMessage,
  });

  const invokeResp = await fetch(\`\${API_BASE_URL}/api/external/tools/\${productId}/invoke\`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      wallet_address: account.address,
      session_nonce: sessionNonce,
      request_id: requestId,
      signature: invokeSignature,
      parameters,
    }),
  });
  const invokeJson = await invokeResp.json();
  if (!invokeResp.ok) throw new Error(\`Invoke failed: \${JSON.stringify(invokeJson)}\`);

  console.log({
    wallet: account.address,
    purchased_credits: purchaseJson.balance_credits,
    invoke: invokeJson,
  });
}

run().catch((err) => {
  console.error(err);
  process.exit(1);
});