Your 402 Error Message Is Your Agent's First Support Ticket

I watched a developer debug my payment API at 4am through my server logs. Then I fixed my error messages. Here is what I changed — and why it matters more in the agentic era than it ever did before.

What I Saw in the Logs

At 04:10 UTC this morning, a developer on a DigitalOcean server in Santa Clara started hitting my BTC/USD oracle endpoint. The session went like this:

04:10:09 GET /oracle/price/btc/usd/preview
04:10:19 GET /oracle/price/btc/usd → 402
04:11:19 GET /oracle/price/btc/usd → 402
04:11:21 GET /oracle/price/btc/usd → 402
04:13:26 GET /oracle/price/btc/usd → 402
04:14:07 GET /oracle/price/btc/usd → 402
04:14:22 GET /oracle/price/btc/usd → 402
04:14:59 GET /oracle/price/btc/usd → 402
04:15:00 GET /oracle/price/btc/usd → 402
04:17:41 GET /oracle/price/btc/usd → 402
04:17:44 GET /oracle/price/btc/usd

One preview call to understand the response format. Ten paid endpoint attempts over seven minutes. One successful payment at the end. They got there — but it took seven minutes of debugging to implement a payment flow that should take seconds.

The varying intervals between attempts tell the story: rapid bursts when something seemed to work, longer gaps when they were reading the response or adjusting their code. Classic integration debugging. A human at a keyboard, working through it alone, at 4am.

What were they seeing during those seven minutes? This:

Before — what the developer saw
{
  "error": "payment_verification_failed",
  "detail": "invalid_x_payment_encoding: Incorrect padding"
}

Technically accurate. Completely unhelpful. Incorrect padding tells you something is wrong with your base64 encoding. It does not tell you that the X-Payment header must be a base64-encoded JSON object, not raw JSON. It does not tell you where to find an example. It does not tell you anything you can act on without already knowing the answer.


What I Fixed

I dug into the x402 proxy and updated three error paths.

The initial 402 response

Before
{
  "x402Version": 1,
  "accepts": [...],
  "error": "X-PAYMENT header is required"
}
After
{
  "x402Version": 1,
  "accepts": [...],
  "error": "X-PAYMENT header is required",
  "hint": "Base64-encode your JSON payment payload and pass it as the X-Payment header.",
  "docs": "https://myceliasignal.com/docs/agent-payment-setup"
}

The encoding error

Before
{
  "error": "payment_verification_failed",
  "detail": "invalid_x_payment_encoding: Incorrect padding"
}
After
{
  "error": "payment_verification_failed",
  "detail": "invalid_x_payment_encoding: Incorrect padding. The X-Payment header must be a base64-encoded JSON object. See https://myceliasignal.com/docs/agent-payment-setup",
  "docs": "https://myceliasignal.com/docs/agent-payment-setup"
}

Same information. Thirty additional characters. Seven minutes of debugging becomes thirty seconds.


Error Messages Are Documentation

This is not a new observation. Every API developer who has shipped a product has learned it eventually — usually by watching someone struggle with something that seemed obvious in retrospect. The error message is the documentation that gets read when everything else has failed. It needs to be the most actionable thing you ship.

But in the agentic era, the stakes are higher. When a human hits a cryptic error message, they google it, they open a support ticket, they ask a colleague. They have recourse. They can reason about ambiguity.

When an agent hits a cryptic error message, it fails. Or it loops. Or it halts the entire workflow and hands the problem back to a human — which is exactly the failure mode agents are supposed to eliminate.

An agent cannot open a support ticket. It cannot search Stack Overflow. It cannot ask a colleague. Your error message is its only source of guidance when something goes wrong. It needs to be enough to self-correct without human intervention.

The x402 payment standard is designed to make HTTP natively payable for autonomous agents. An agent hits an endpoint, receives a 402, constructs a payment, retries. The entire flow is meant to be frictionless and automatic. But frictionless only works if every step — including failure — provides enough information to proceed. A cryptic error message breaks the autonomy loop at exactly the point where autonomy matters most.


The Broader Point

We can all do better here. If you are building a paid API — on x402, L402, or any other payment rail — your error responses deserve the same care as your success responses. A few principles worth applying:

Be specific about what went wrong. "Incorrect padding" is a symptom. "The X-Payment header must be a base64-encoded JSON object" is a diagnosis. Always provide the diagnosis.

Tell the developer what to do next. Every error response should answer the question: what do I do with this information? A docs link is the minimum. A concrete example of the correct format is better.

Differentiate your error codes. payment_verification_failed covers encoding errors, signature errors, wrong network, wrong recipient address, and insufficient funds. These are very different problems requiring very different fixes. Your error codes should distinguish them.

Assume the reader has no context. The developer debugging at 4am has forgotten everything they knew about your API. The agent retrying at 4am never had context to begin with. Write error messages for someone encountering the problem for the first time.

Watch your own logs. The most valuable signal in a 402-based API is not revenue — it is the pattern of failed payment attempts. A developer making ten attempts before succeeding is showing you exactly where your integration is hard. Fix it before the next developer hits the same wall.


The developer who spent seven minutes debugging at 4am this morning eventually got their payment working. I am glad they persisted. But the next developer who hits the same endpoint will get there in thirty seconds — because I was watching.

That is the contract. Build in public. Watch the logs. Fix what is broken. Make it easier for the next person.

And when that next person is an agent — make sure ymy error messages are good enough that it can fix itself.


Mycelia Signal is a sovereign cryptographic oracle — 56 signed endpoints across crypto, FX, economic indicators, and commodities. Payable by AI agents via Lightning (L402) or USDC on Base (x402). Agent payment setup guide →