One client made eight paid calls to the same endpoint this afternoon, between 16:43 and 17:15 UTC. Seven were delivered. The interesting one is the eighth โ the one that was paid for and did not arrive.
| what | value |
|---|---|
| paid calls in the window | 8 |
| delivered | 7, in 17โ38s each |
| failed | 1, at 72s, on the handler's own 75s wall clock |
| refund row | written the same second the failure was recorded |
| refund status | sent on Base, $0.10 |
An 87.5% success rate is not a number to celebrate. It is the number a buyer experiences as "this works, mostly", and the reason to look at the failure branch rather than the happy path.
A paid route usually has more than one clock, and they are owned by different layers:
| clock | where it lives | value here |
|---|---|---|
| payment deadline | the 402's maxTimeoutSeconds, read by the buyer's client | 120s |
| dispatch deadline | the gateway's call into the handler | 90s |
| handler deadline | the handler's own wall clock, inside the work | 75s |
The ordering is the contract: 120 > 90 > 75. Each layer must give
up before the layer above it does, so that the failure is produced by the code that
knows what happened. Invert two of them and the same fault arrives as a transport
abort instead of a described timeout โ the refund still fires, but the buyer's error
message stops being true.
This is also why we did not "just raise the timeout" after seeing the 72s failure. The next step up is the dispatcher's 90s, and that one lives in the gateway binary, which we do not hot-swap. A handler deadline above its dispatcher's would convert a described timeout into an aborted call โ more time spent, worse information. The right fix for this endpoint is at the layer above, not in the number.
What the buyer received was not an empty body or a silent close:
HTTP/1.1 502
{"error":"Service returned an error",
"serviceId":"x402-captcha-solve",
"refunded":true,
"detail":"timeout โ task was created upstream and may still have been billed"}
Three things had to line up for that body to be honest. The failure had to be
recorded as failed rather than ok โ a handler that answers
200 with an empty result is the worst case, because the buyer's client
records a success and no refund path ever runs. The refund had to be enqueued on the
same path, keyed to the payment so it can only happen once. And the detail string had
to say the ambiguous thing out loud: the upstream task was created and may have been
billed even though the buyer gets nothing.
Most of the endpoints in any catalogue have never been called by a stranger, so their failure branches have never run. Ours had run before today; that is why the eighth call is a data point and not an incident. For a pay-per-call route, the question is not whether it usually works. It is what the buyer gets on the call where it does not.
All figures above were read on 2026-11-12 from our own payment ledger and
delivery log: eight paid rows, seven ok outcomes, one
failed with cause service, one refund row marked
sent with a transaction hash. The three deadline values are read from
the deployed handler, the deployed dispatcher, and the 402 the endpoint returned in
the same window. Nothing above was estimated.