ERC-8004 agents
How a registered agent signs its requests to reach the proven tier.
ERC-8004 ("Trustless Agents") is an on-chain agent registry. An agent that
signs a request with its registered wallet reaches the proven tier. A
registration alone doesn't change a request's tier.
Overview
- An agent registers in a per-chain Identity Registry and gets an
agentId. - The
agentIdpoints to a registration file that describes the agent: name, services, trust models. - The registration is public and durable. Anyone can check it without seeing a request.
- The registration file is off-chain and can change.
- The standard defines no header and no signature on an HTTP request.
- Because the registry is public, anyone can present a registered name. A registration isn't evidence that a request came from that agent.
| On-chain fact | Effect on a request |
|---|---|
| A registration exists | nothing |
| The registration is linked to an agent DNA verifies another way | an attribute on that agent, never a tier |
| The agent signed this request with its registered wallet | proven, from the signature |
How it works
- DNA reads the Identity Registry on Ethereum mainnet. A new registration, or a change to its file, is picked up within a day.
- A registration on its own doesn't verify a request; a signature does.
- When a registration belongs to an agent DNA already recognises, the agent's identity notes it.
Proving a request
An ERC-8004 agent reaches proven by signing the request with the wallet its
registration names on-chain.
- The chain binds that wallet to the registration, with the wallet's consent.
- The signature proves the wallet signed this request, for this host, inside a freshness window.
Signature format
The envelope is RFC 9421 HTTP
message signatures, the same shape Web Bot Auth uses. The tag parameter routes
it to the wallet check.
| Parameter | Rule |
|---|---|
tag | erc8004 |
keyid | {agentRegistry}/{agentId}, the registration's CAIP-style key |
alg | must be absent; the tag pins the algorithm |
created | required; it is the replay bound |
| components | must cover @authority; add content-digest when the request carries a body |
The signature value is the wallet's EIP-191 personal_sign over the RFC 9421
signature base (signMessage in viem or ethers). No custom crypto is needed.
Signature-Input: sig1=("@authority");created=1756800000;expires=1756800300;
keyid="eip155:1:0x8004a169fb4a3325136eb29fa0ceb6d2e539a432/42";tag="erc8004"
Signature: sig1=:BASE64(personal_sign(signature base)):- The host and the freshness window are signed, so a captured signature can't be replayed at another site.
- A signature stops working when its window closes, five minutes by default.
- The
keyidis signed, so a wallet bound to several registrations proves only the one it names.
Outcomes
| Request | Tier |
|---|---|
| Recovers to the wallet the chain names | proven |
| Recovers to a different signer, and that wallet is a plain account | spoofed |
| Names a registration DNA holds no wallet for yet | claimed; the daily sync picks it up |
| Wallet is a contract, or not yet confirmed as one or the other | claimed |
Signed for the www/apex sibling of the host it actually reached | claimed |
| Carries a body that couldn't be checked against the signature | claimed |
| Malformed profile, stale, or expired | unverified, with the reason |
A proven request is logged as the agent the registration is linked to. With
no link, it is logged as the keyid. That proves the wallet, not who owns it.
For site owners
- No configuration is needed.
- An agent that signs this way shows as Verified in your log.
- An agent that doesn't sign gets one of the other labels.