One field does all the work.

Held is an ordinary x402 resource server. A client that already speaks x402 needs no changes to buy from it. The only unusual thing is where payTo points.

The challenge this server returns

Ask for the resource without paying and you get a 402 carrying the body beside this text. It is fetched live from our own /work as you load the page, so you are reading the real thing rather than an illustration that drifted out of date.

Why payTo is the mechanism

In a normal x402 flow payTo is the seller. Settlement is final the moment the facilitator verifies the payment, and the buyer has no recourse at all. Here it names an escrow account. Settlement still happens immediately and irreversibly, so the seller knows the money is real, but it lands somewhere neither party can unilaterally take it from.

The extensions.held block then tells a client what happens next in a form it can read, rather than one a human has to look up in documentation.

Why the deferred flow could not be used instead

The Hedera scheme declares paymentFlows.default.supported as ["authorization", "upfront"] with authorization as the default, so at first glance settlement can simply be deferred past the request. It cannot be deferred far enough. The Hedera x402 payload is a partially-signed Hedera transaction, and those expire in minutes. A buyer review window is measured in hours or days. So Held holds the money in an account rather than holding a signature.

402 Payment Requiredfetching…
{
  "x402Version": 2,
  "accepts": [{
    "scheme": "exact",
    "network": "hedera:testnet",
    "asset": "0.0.0",
    "amount": "5000000",
    "payTo": "0.0.10495061",
    "maxTimeoutSeconds": 120
  }],
  "extensions": { "held": { … } }
}

The endpoints

POST /workThe gated route. Send { question }. Without an X-PAYMENT header it answers 402 with the challenge above; with a valid one it returns the deliverable, a claimToken and the escrow state.rate limited to 20 a minutex402
POST /jobs/:id/approveRelease escrow to the seller. Requires the X-Job-Token issued in the payment response.only the SHA-256 is stored, compared with timingSafeEqualbuyer only
POST /jobs/:id/rejectRefund escrow to the buyer. Same authority check.buyer only
GET /jobs/:idOne job and its evidence trail, read back from the consensus topic.open
GET /jobsEvery job. The claim-token hash is stripped before it leaves the process.open
GET /healthWhich tier each subsystem is on, and whether any is degraded.open

See it yourself

No key, no account, nothing to install:

curl -s -X POST https://heldprotocol.xyz/work \
  -H 'content-type: application/json' \
  -d '{"question":"what is a scheduled transaction"}' | jq .

Then confirm the account it names is real, and is not the seller:

curl -s https://testnet.mirrornode.hedera.com/api/v1/accounts/0.0.10495061 | jq .balance

The seller's own fee-payer account is 0.0.7162784. They are different accounts, and that difference is the product.