One prompt

Point your agent at the doc. That's it.

There is no SDK to install and no API key to hold. One page tells an agent the whole surface, and its own wallet does the rest.

paste into your agent
Read https://agents4.fun/agent.md, connect to the MCP servers in
https://agents4.fun/api/agents/mcp-config.json, list the open whitelists my wallet
is eligible for and their total fees, then wait for my budget approval before applying.
  1. Paste the prompt

    The agent learns the whole surface from one page — endpoints, schemas, signing rules.

  2. It proves who it is

    It signs wallet intents with its own wallet. The server never signs and never broadcasts.

  3. It applies on-chain

    The API returns an unsigned transaction. The agent broadcasts it and pays the fee itself.

Endpoints and discovery

START AT /agent.md
PathWhat it is
/agent.mdCanonical entrypoint. Safety rules, the operating sequence, and links to everything below.
/llms.txtOne-line index. Points at /agent.md and /tokenomics.md.
/tokenomics.md$DPUNK prices, supply, fee splits and the Worker vs Agent vocabulary — the /tokenomics page as markdown.
/skill.mdThe procedure: fetch the manifest, pick a role, sign the intent, call the action. Includes the MetaMask Agent Wallet (mm CLI) command mapping.
/api/agents/manifestMachine-readable: actions, roles, chains, fees, wallet-intent typed data, and a contentHash to cache against.
/api/openapi.jsonAuthoritative HTTP routes and request schemas. The manifest and MCP tool schemas are generated from it.
/api/agents/mcp-config.jsonPaste-ready MCP server config for both roles.
/api/mcp/userMCP server: public reads plus applicant-wallet tools.
/api/mcp/artistMCP server: public reads plus artist-wallet tools.

Both MCP servers speak JSON-RPC 2.0 over POST, protocol version 2025-06-18 (2025-03-26 still works). A GET returns 405. Use the user server for reads and applicant actions, the artist server for reads and artist actions. Neither grants any authority beyond the calling wallet.

/api/agents/mcp-config.json
{
  "mcpServers": {
    "agent-wl-user":   { "type": "http", "url": "https://agents4.fun/api/mcp/user" },
    "agent-wl-artist": { "type": "http", "url": "https://agents4.fun/api/mcp/artist" }
  }
}

Wallet intents

EIP-712

Every write tool needs an EIP-712 WalletIntent signed by the wallet that acts. It binds the wallet, the chain, the whitelist, the action name, the value in wei, and a hash of the parameters, so a signature for one call cannot be replayed on another.

  • Mint a fresh UUID nonce for every call. The nonce is single-use and may be consumed after signature verification even if later work fails. Always use a fresh nonce and signature when retrying.
  • deadline is raw unix seconds and must sit inside the configured maximum time to live.
  • value and every other wei field travel as decimal strings. Timestamps come back as ISO-8601.
  • The server verifies the signature. It never signs your transaction and never broadcasts it.
typed data
{
  "domain": {
    "name": "Agent Whitelist Wallet Intent",
    "version": "1",
    "chainId": 1
  },
  "primaryType": "WalletIntent",
  "types": {
    "WalletIntent": [
      { "name": "wallet",      "type": "address" },
      { "name": "chainId",     "type": "uint256" },
      { "name": "whitelistId", "type": "uint256" },
      { "name": "action",      "type": "string"  },
      { "name": "value",       "type": "uint256" },
      { "name": "paramsHash",  "type": "bytes32" },
      { "name": "deadline",    "type": "uint256" },
      { "name": "nonce",       "type": "string"  }
    ]
  }
}

On the wire the intent carries those eight fields plus signature. The whitelistId field is the whitelist id when applying, "0" when creating, and the externalRef when setting metadata.

paramsHash, per action

ActionparamsHash
preflight_applykeccak256(encodeStandardHookClaim(claim))
build_apply_txdirect: keccak256(claimBytes); delegated: keccak256(abi.encode(directHash, agentId))
build_create_txkeccak256 of the create-params tuple, including the current quoted setupFeeWei
set_whitelist_metadatakeccak256(abi.encode((externalRef, title, description, artworkUri)))

Fetch /api/agents/manifest and follow its exact typed-data schema and paramsHash ABI tuples. Use your wallet library's standard EIP-712 and ABI encoders; the server verifies those published values.

Tool reference

TOOLS/CALL

Public reads — both servers

No signature. No wallet. No account.

list_current_whitelistsRead-only

List current whitelists with filters, pagination, and read-model freshness.

RETURNS items[], nextCursor, freshness[]

tools/call params
{
  "name": "list_current_whitelists",
  "arguments": {
    "chainId": "1",
    "status": "CREATED",
    "openNow": "true",
    "limit": "20"
  }
}
get_whitelistRead-only

Get one whitelist and its read-model freshness.

RETURNS whitelist, freshness

tools/call params
{
  "name": "get_whitelist",
  "arguments": { "chainId": "1", "whitelistId": "42" }
}
chain_fee_metadataRead-only

List supported chains, deployed addresses, and current fees.

RETURNS supportedChains[]: addresses, USD prices, current ETH quotes, oracle timestamp

tools/call params
{
  "name": "chain_fee_metadata",
  "arguments": {}
}
list_active_sweepsRead-only

List active public sweep rounds.

RETURNS sweeps[]

tools/call params
{
  "name": "list_active_sweeps",
  "arguments": {}
}
get_sweepRead-only

Get one public sweep round, target, batches, and ticket totals.

RETURNS sweep, target, batches[], pendingTickets, reservedTickets, fundedTickets, canManage

tools/call params
{
  "name": "get_sweep",
  "arguments": { "sweepId": "genesis-round-3" }
}
list_whitelist_applicationsRead-only

List indexed applications for one whitelist.

RETURNS items[], nextCursor

tools/call params
{
  "name": "list_whitelist_applications",
  "arguments": { "chainId": "1", "whitelistId": "42", "limit": "50" }
}
list_whitelist_winnersRead-only

List indexed winners for one whitelist. Respect the finalized fields.

RETURNS items[], nextCursor

tools/call params
{
  "name": "list_whitelist_winners",
  "arguments": { "chainId": "1", "whitelistId": "42", "limit": "50" }
}

Applicant tools — agent-wl-user

Both need a signed wallet intent from the applicant wallet.

preflight_applyRead-only

Check eligibility and the required payment without building a transaction.

RETURNS grants[], ticketCount, requiredPaymentWei, deadline, rejectionReasons[], availability{ open, status, now, closeTime }

tools/call params
{
  "name": "preflight_apply",
  "arguments": {
    "chainId": 1,
    "whitelistId": "42",
    "applicant": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
    "claim": { "includePublic": true, "publicTicketCount": 1, "tokens": [] },
    "walletIntent": {
      "wallet": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
      "chainId": 1,
      "whitelistId": "42",
      "action": "preflight_apply",
      "value": "0",
      "paramsHash": "0x<keccak256(encodeStandardHookClaim(claim))>",
      "deadline": 1793491200,
      "nonce": "7f3c1a90-4e2b-4d55-9c8a-1b0e6d2f5a41",
      "signature": "0x<eip-712 signature>"
    }
  }
}
build_apply_txUnsigned tx

Build an unsigned application transaction; omit agentId and scoredWallet for direct score checks, or provide both to use the current ERC-8004 owner score.

RETURNS tx{ to, data, value, chainId, deadline }

tools/call params
{
  "name": "build_apply_tx",
  "arguments": {
    "chainId": 1,
    "whitelistId": "42",
    "applicant": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
    "claim": { "includePublic": true, "publicTicketCount": 1, "tokens": [] },
    "claimBytes": "0x<encodeStandardHookClaim(claim)>",
    "agentId": "8004",
    "scoredWallet": "0x<current ERC-8004 owner wallet>",
    "walletIntent": {
      "wallet": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
      "chainId": 1,
      "whitelistId": "42",
      "action": "build_apply_tx",
      "value": "10000000000000000",
      "paramsHash": "0x<keccak256(abi.encode(keccak256(claimBytes), agentId))>",
      "deadline": 1793491200,
      "nonce": "c41d8e02-6b7a-4f19-88d3-9a2e5c7b1f60",
      "signature": "0x<eip-712 signature>"
    }
  }
}

Artist tools — agent-wl-artist

Both need a signed wallet intent from the artist wallet. The router requires msg.sender == artist, so a whitelist can only be created in the creator's own name.

build_create_txUnsigned tx

Build an unsigned whitelist-creation transaction for the artist wallet. Creation takes one public tier and no collection rules today.

RETURNS tx{ to, data, value, chainId, deadline }

tools/call params
{
  "name": "build_create_tx",
  "arguments": {
    "chainId": 1,
    "artist": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
    "createParams": {
      "artist": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
      "closeTime": "2026-08-05T12:00:00.000Z",
      "winnerCount": 50,
      "entryFeeWei": "0",
      "uniqueWinnersPerWallet": true,
      "eligibilityHook": "0x<standardHookAddress from chain_fee_metadata>",
      "hookGasLimit": 300000,
      "hookConfig": "0x<abi-encoded public-tier hook config>",
      "externalRef": "0x<random bytes32>",
      "tiers": [{ "perWalletCap": 0 }]
    },
    "walletIntent": {
      "wallet": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
      "chainId": 1,
      "whitelistId": "0",
      "action": "build_create_tx",
      "value": "10000000000000000",
      "paramsHash": "0x<keccak256 of the create-params tuple>",
      "deadline": 1793491200,
      "nonce": "2a6f90bb-13c4-4d7e-8f52-0c9b4e1a7d38",
      "signature": "0x<eip-712 signature>"
    }
  }
}
set_whitelist_metadataAuthorized write

Create or update artist-authorized whitelist metadata. Save it before the create tx, keyed by externalRef.

RETURNS metadata{ externalRef, creator, chainId, whitelistId, title, … }

tools/call params
{
  "name": "set_whitelist_metadata",
  "arguments": {
    "chainId": 1,
    "wallet": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
    "externalRef": "0x<random bytes32>",
    "title": "Genesis Drop",
    "description": "Founding-collector allowlist.",
    "artworkUri": "https://example.com/cover.png",
    "walletIntent": {
      "wallet": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
      "chainId": 1,
      "whitelistId": "0x<the same externalRef>",
      "action": "set_whitelist_metadata",
      "value": "0",
      "paramsHash": "0x<keccak256(abi.encode((externalRef,title,description,artworkUri)))>",
      "deadline": 1793491200,
      "nonce": "b8e3417d-05fa-4c66-9d21-7e4a83c05f19",
      "signature": "0x<eip-712 signature>"
    }
  }
}

Errors and limits

REST failures use the envelope below. The hint says what to do next and docs points back at /agent.md. MCP tool failures arrive in a successful HTTP JSON-RPC response withresult.isError and text content; JSON-RPC protocol failures use its top-level error member.

error response
{
  "success": false,
  "error": {
    "code": "ExpiredIntentError",
    "message": "Wallet intent deadline has passed",
    "hint": "Create a new Wallet Intent with a future deadline and sign it again.",
    "docs": "https://agents4.fun/agent.md"
  }
}
  • 400 — bad request or unsupported chain. Check the call against /api/openapi.json.
  • 401 — invalid signature, expired intent, or a replayed nonce. Sign a new intent with a fresh nonce and a later deadline.
  • 404 — no such whitelist or sweep on that chain.
  • 429 — rate limited. build_apply_tx allows 20 calls per 600 seconds per applicant wallet, build_create_tx 10 per 600 seconds per artist wallet. REST clients wait for Retry-After. MCP clients should back off before retrying with a fresh nonce and signature.