XAgent Blog

Home Blog Market Launch Store

EIP-3009 transferWithAuthorization for agents, explained

The x402 exact scheme settles by calling EIP-3009 transferWithAuthorization. Here is what the agent's signature authorizes, why the nonce is random, and when to use receiveWithAuthorization instead.

By XAgent Team · 2026-08-05

When an AI agent pays over x402 on an EVM chain, it does not send a transaction. It signs a message and hands it to someone else to submit. EIP-3009 transferWithAuthorization for agents is the primitive underneath that flow, and reading it closely is the fastest way to understand what an agent payment actually authorizes — and what it deliberately does not.

What the agent signs

The x402 exact scheme on EVM is explicit about the mechanism. Its spec states that the eip3009 asset transfer method "uses the transferWithAuthorization function directly on token contracts that support it," and that "[s]ettlement is performed via the facilitator calling the transferWithAuthorization function on the EIP-3009 compliant contract with the payload.signature and payload.authorization parameters from the PAYMENT-SIGNATURE header" (x402 exact-EVM scheme).

So two objects travel in the payment payload. The signature is "[t]he 65-byte signature of the transferWithAuthorization operation." The authorization is "[t]he parameters required to reconstruct the signed message." The spec's own example carries the time window and nonce inline:

{
  "authorization": {
    "validAfter":  "1740672089",
    "validBefore": "1740672154",
    "nonce": "0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480"
  }
}

The function the facilitator eventually calls is fixed by the ERC. Every field in that authorization object maps to a parameter:

// ERC-3009. The signer supplies v, r, s; the submitter supplies gas.
function transferWithAuthorization(
    address from,
    address to,
    uint256 value,
    uint256 validAfter,
    uint256 validBefore,
    bytes32 nonce,
    uint8 v,
    bytes32 r,
    bytes32 s
) external;

The division of labour is the point. The party that signs is not the party that submits, so the signer never needs the chain's native token to move a stablecoin. For an agent holding USDC and nothing else, that is the difference between being able to pay and not.

Why EIP-3009 transferWithAuthorization for agents beats an approval

Circle documents four authorization flows for EVM-compatible chains — approve, permit (EIP-2612), transferWithAuthorization (EIP-3009), and Permit2 — in a post published September 16, 2025. The distinction that matters for agents is what each one leaves behind.

Of permit, Circle writes: "User signs off chain, then anyone submits permit(...) to the USDC token. That call writes the allowance in the same mapping as approve, just without the user spending gas to sign." Of transferWithAuthorization, it writes: "No allowance is created. The signed authorization lets a relayer move tokens once within a time window" (Circle).

A standing allowance is a standing liability. It survives the purchase that motivated it, it is denominated in tokens rather than in a specific payment, and revoking it costs a transaction that somebody has to remember to send. That is an awkward fit for software that transacts continuously and unattended. An authorization that covers one transfer inside one window expires by construction — the agent's spending boundary is enforced by the token contract, not by the agent's own restraint. That property is what makes the authorization step in agentic commerce checkable after the fact rather than merely promised.

The nonce is random and the window is narrow, both on purpose

ERC-3009 takes random 32-byte nonces rather than sequential ones, and the spec's rationale explains why: "sequential nonces do not actually help achieve transaction ordering for meta transactions in practice."

For an agent this is the more useful design by some distance. Sequential nonces serialize a payer: authorization n+1 cannot land before n, so one stuck payment blocks the queue behind it. Random nonces make each authorization independent. An agent can hold several signed payments to several merchants in flight at once, and one that never gets submitted does not wedge the others. Each nonce is single-use, tracked per authorizer, and the contract emits AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce) when it is consumed.

The time window does the complementary job. Per the spec, validAfter and validBefore let a payer "schedule a transaction to be only valid in the future or before a specific deadline, protecting the user from potential undesirable effects that may be caused by the submission being made either too late or too early." The example authorization in the x402 scheme spec sets validAfter to 1740672089 and validBefore to 1740672154 — a window measured in seconds.

That is what turns a quote into something binding. A merchant quote with a stated expiry is a promise; an authorization whose validBefore matches that expiry is enforced by the token. If the agent stalls, the payment does not silently execute against a price that has moved. ERC-3009 also specifies cancelAuthorization, which lets the signer void an unused nonce with a second signature — a revocation path that does not depend on the merchant cooperating. Handling these windows on the merchant's behalf is part of what the open execution market runs.

When to use receiveWithAuthorization instead

ERC-3009 ships a second entry point, and its security considerations are direct about when the first one is wrong:

Use receiveWithAuthorization instead of transferWithAuthorization when calling from other smart contracts. It is possible for an attacker watching the transaction pool to extract the transfer authorization and front-run the transferWithAuthorization call to execute the transfer without invoking the wrapper function.

receiveWithAuthorization closes this by checking that the caller is the payee. Circle gives the same guidance in one line: "For contract pulls, use receiveWithAuthorization(...)."

Read the scope carefully before concluding anything about x402. The hazard is specific to a wrapper contract that does bookkeeping around the transfer — crediting an order, minting a receipt, releasing a good. A front-runner can execute the bare transfer and skip the wrapper's side effects, leaving the payer's money moved and the wrapper's state never updated. The x402 exact scheme has the facilitator call transferWithAuthorization directly on the token contract, which is not that case. But if you are building settlement logic that wraps the transfer in your own contract, the caveat lands on you, and the fix is the other function. This is the kind of detail that separates a working integration from one that is fine until it is not — and the reason we treat accepting stablecoin payments from agents as an operations problem rather than a wallet problem.

What's next

Two things about this stack deserve more attention than they get. ERC-3009 is listed on eips.ethereum.org with status Draft, and it requires EIP-20 and EIP-712. A Draft ERC is currently carrying real agent payments — which is normal for Ethereum and still worth knowing before you build on it.

The layer above it moves faster than the ERC beneath. The x402 v2 announcement, published December 11, 2025, described the protocol as using "more modern PAYMENT-SIGNATURE, PAYMENT-REQUIRED, PAYMENT-RESPONSE" headers and removing "deprecated X-* headers for improved compatibility" (x402.org) — a rename an integration keyed to the older names will not survive. The signing primitive has been stable; the envelope around it has not. We cover the envelope in the x402 walkthrough.

Protocol-native, not protocol-limited. If you would rather implement the payment path once and let someone else track which header generation and which entry point each agent arrives with, list your store.

Keep reading

  • What Open USD means for agent payment settlement
  • Agent payment vs traditional checkout: how they compare
  • How to make your Shopify store agent-discoverable