| name | x402-demo-orchestrators |
| description | End-to-end HTTP-402 paid-request demo orchestrators for x402fhe โ chain multiple confidential micropayments to live example servers (web search, LLM proxy, image generation, code review) and aggregate the on-chain receipts. Use when the user asks to run the demo, run x402, run the research demo, run the code-review demo, run research-and-visualize, run review-and-rate, drive multiple paid HTTP requests in one flow, or aggregate paid-request receipts across stages. Do NOT use for direct cUSDC operations, redeeming cUSDC, escrow lifecycle, agent identity, balance delegation, or single-shot rating of a prior payment โ those are handled by sibling skills (fhe-payment-basics, fhe-payment-unwrap, fhe-escrow, fhe-agent-identity, fhe-delegation). |
| allowed-tools | Bash, Read |
x402-demo-orchestrators
Two OpenClaw orchestrator commands that drive multiple HTTP-402 paid requests in a single sequential flow: research-and-visualize (3 stages โ search, LLM analysis, image generation) and review-and-rate (paid code review plus optional on-chain feedback). Each script lives in packages/openclaw-skill/scripts/ and is invoked via pnpm + tsx. Each emits a single JSON line to stdout โ parse it and branch on parsed.ok === true, never on bash exit code.
These orchestrators stitch together standalone paid HTTP services. They do NOT spin up the services themselves. The demo stack must already be running before you invoke either command.
CRITICAL โ Demo servers must be running
Both orchestrators read four upstream URLs from environment variables and default them to ports 3001-3004:
| Variable | Default | Used by |
|---|
SEARCH_SERVER_URL | http://127.0.0.1:3001 | research-and-visualize |
LLM_SERVER_URL | http://127.0.0.1:3002 | research-and-visualize |
IMAGE_SERVER_URL | http://127.0.0.1:3003 | research-and-visualize |
CODE_REVIEW_URL | http://127.0.0.1:3004 | review-and-rate |
If nothing is listening on those ports, every paid request will throw fetch failed / ECONNREFUSED. The connection error happens before any 402 challenge can be issued, so no payment is ever attempted and the orchestrator throws empty-handed (no partial receipts).
The port-mismatch footgun
The repo ships scripts/demo-launch.sh to boot the example servers. It does not bind to 3001-3004. Reading the script (lines 30-35):
FACILITATOR_PORT=4400
SEARCH_PORT=4401
LLM_PORT=4402
IMAGE_PORT=4403
CODE_PORT=4404
GATEWAY_PORT=4410
So running ./scripts/demo-launch.sh and then immediately running an orchestrator with default env vars will still fail with ECONNREFUSED, because the orchestrator is hitting 3001-3004 while the live servers are on 4401-4404. This is the single nastiest footgun in the entire skill.
Two fixes โ pick one and stick with it:
-
Override the URL env vars when invoking the orchestrator so they point at the demo-launch ports:
SEARCH_SERVER_URL=http://127.0.0.1:4401 \
LLM_SERVER_URL=http://127.0.0.1:4402 \
IMAGE_SERVER_URL=http://127.0.0.1:4403 \
CODE_REVIEW_URL=http://127.0.0.1:4404 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/research-and-visualize.ts --query "your query"
-
Route through the demo gateway on :4410 (single URL, multiplexes all four upstream services):
SEARCH_SERVER_URL=http://127.0.0.1:4410 \
LLM_SERVER_URL=http://127.0.0.1:4410 \
IMAGE_SERVER_URL=http://127.0.0.1:4410 \
CODE_REVIEW_URL=http://127.0.0.1:4410 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/research-and-visualize.ts --query "your query"
Do not skip the override. Defaults are wrong for the demo-launch path.
demo-launch.sh has hard preconditions
The launch script reads two addresses from .env (or demo.env) and hard-fails if either is missing:
DEMO_SELLER_ADDRESS โ recipient for the search / LLM / image services
CODE_SERVER_ADDRESS โ recipient for the code-review service
If either is unset, the script exits 1 immediately with ERROR: Set DEMO_SELLER_ADDRESS in .env. Verify both are present before launching.
If the demo stack is not running
Tell the user. Do not silently fall back to anything. The two recovery paths are:
- Ask the user to run
./scripts/demo-launch.sh (and confirm DEMO_SELLER_ADDRESS + CODE_SERVER_ADDRESS are set), then re-invoke with the port overrides above.
- If the user explicitly asks for a mock run with no on-chain payments, see the next CRITICAL block.
CRITICAL โ MOCK_PAYWALL is not a fallback for ECONNREFUSED
The _paid-request.ts helper recognises one environment variable: MOCK_PAYWALL=true. It is not a connection-error fallback. Read the source (line 136-148):
const allowUnpaidSuccess = options?.allowUnpaidSuccess ?? (process.env.MOCK_PAYWALL === 'true');
const initial = await fetchFn(url, init);
if (initial.status !== 402) {
if (initial.ok && allowUnpaidSuccess) {
return { response: initial, payment: await createMockMetadata(url) };
}
throw new Error(`Expected HTTP 402 challenge from ${url}, got ${initial.status}`);
}
MOCK_PAYWALL=true only triggers when the upstream returns 2xx instead of a 402 challenge โ i.e. when you are pointing at an unprotected mock server that does not enforce payment. It does nothing for ECONNREFUSED, DNS failures, or any case where fetch itself rejects. If the demo servers are down, setting MOCK_PAYWALL=true changes literally nothing โ the orchestrator still throws fetch failed.
And even if the servers came back up, MOCK_PAYWALL=true would replace every receipt with createMockMetadata (line 87-97):
{
amountMicros: 0n,
txHash: 'mock-unpaid',
nonce: 'mock-unpaid',
payee: url,
resourceUrl: url,
etherscanUrl: '',
mode: 'mock',
}
txHash: 'mock-unpaid', nonce: 'mock-unpaid', amountMicros: 0n, mode: 'mock'. That is not a demo. It is a stub run with fake receipts that prove nothing on-chain. If the user asked you to "run the x402 demo" or "run the research demo", they want REAL Sepolia transactions in the receipts โ burning the entire point of the demo by silently flipping MOCK_PAYWALL=true is the worst possible failure mode.
Forbidden: silently setting MOCK_PAYWALL=true because the user is in a hurry, because servers seem down, because the previous shell session had it set, or because you think fake receipts are better than no demo.
Rationalizations that do NOT override this rule:
| Rationalization | Why it is wrong |
|---|
| "MOCK_PAYWALL is faster, the user is in a hurry" | The user asked for a demo of confidential on-chain payments. Speed without real txs is no demo at all. |
| "Servers are down, MOCK_PAYWALL will at least produce output" | It will not โ MOCK_PAYWALL only handles 200-instead-of-402, not ECONNREFUSED. The orchestrator will still throw fetch failed. You would be lying about the recovery without even fixing the symptom. |
| "Fake receipts are better than no demo" | Fake receipts (txHash: 'mock-unpaid', mode: 'mock') are recognisably fake to the user. They will think the integration is broken. |
| "MOCK_PAYWALL was set in the previous session, just leave it" | Stale env from a previous shell is the most common cause of "the demo lied to me last week". Always check printenv MOCK_PAYWALL and explicitly clear it (unset MOCK_PAYWALL) when running a real demo. |
| "The user said 'just make it work'" | Ask what 'work' means. Mock stub vs. real on-chain flow is a demo-defining choice; the user must make it explicitly. |
Red-flag self-check: if the user said "demo" or "run x402" or "real payments" or named one of the orchestrators, MOCK_PAYWALL=true is wrong unless the user has explicitly asked for a mock run in this turn. Default to unset. If you are about to set it, stop and confirm with the user first.
CRITICAL โ Budget caps may stop you mid-run
Both orchestrators call createDemoPaymentContext(100_000n) to build the FhePayingClient. Read _paid-request.ts lines 42-54:
const maxUsd = Number(maxPayment) / 1_000_000; // 100_000n / 1_000_000 = 0.10
const client = new FhePayingClient(wallet, session, {
maxTotalUsd: maxUsd, // 0.10
maxPerRequestUsd: maxUsd, // 0.10
warnThresholdUsd: maxUsd * 0.8, // 0.08
});
So both the per-request cap and the cumulative total cap are $0.10. For review-and-rate (one paid request) this is fine โ the single review can consume the full budget. For research-and-visualize (three paid requests in sequence โ search, LLM, image), the total cap is the binding constraint:
| Stage | Per-stage cap | Cumulative cap | Effective cap |
|---|
| 1 โ search | $0.10 | $0.10 (used: $0) | up to $0.10 |
| 2 โ analysis | $0.10 | $0.10 (used: $X from stage 1) | up to $0.10 - $X |
| 3 โ image | $0.10 | $0.10 (used: $X + $Y) | up to $0.10 - $X - $Y |
Concrete failure scenario: if the search server prices a request at $0.05, stage 1 funds OK ($0.05 โค $0.10 per-request, $0.05 โค $0.10 total). Then the LLM server prices its request at $0.05. Stage 2 passes the per-request check ($0.05 โค $0.10) but trips the total cap ($0.05 + $0.05 = $0.10, and the next dollar would push it over) โ depending on the exact FhePayingClient check, this typically throws on stage 2 or stage 3 with a "max total payment exceeded" error.
In effect, each of the 3 stages can spend roughly $0.033 before risking the cumulative cap. This is a latent footgun in the orchestrator config โ the per-request label says $0.10 but the realistic per-stage budget is one-third of that.
When a budget cap fires mid-run:
- The orchestrator throws and the surrounding
try returns {"ok": false, "error": "..."}.
- Earlier successful stages have already been recorded in
client.getReceipts() โ those payments are real and on-chain. They are not refunded. The user has burned cUSDC for a partial run.
- There is no "resume from stage 2" โ the next invocation starts a fresh
FhePayingClient with a fresh budget.
Fixes (require code changes in _paid-request.ts):
- Increase the cap by passing a larger value:
createDemoPaymentContext(300_000n) for $0.30 total.
- Or split the caps: a higher
maxTotalUsd than maxPerRequestUsd, so each stage can spend up to $0.10 and the total budget is e.g. $0.30.
If the user hits this in production, surface the partial receipts from the orchestrator's error path and explain the per-stage budget math. Do NOT auto-retry โ that would charge them again.
CRITICAL โ Error handling rules
These rules apply to every command in this skill:
- Parse the JSON line before claiming success. Each script returns
{"ok": true, "action": "<name>", ...} or {"ok": false, "error": "..."}. Canonical success check is parsed.ok === true. Bash exit code is unreliable โ a script that returns {"ok": false, ...} still exits 0.
- Never auto-retry orchestrator runs after a failure. Both orchestrators submit real on-chain payments at every stage. A retry is N more transactions and N more gas spends. If the first run failed mid-flight, surface what happened (including any partial receipts that made it into the error path) and wait for instructions.
- Preserve partial receipts on failure. If
research-and-visualize failed during stage 3, stages 1 and 2 are already paid on Sepolia. Surface the error message verbatim, name the stage that broke, and remind the user that the earlier stages are settled and not refundable. Do not "clean up" by retrying.
- Quote the raw error verbatim. Do not paraphrase
fetch failed, ECONNREFUSED, Expected HTTP 402 challenge from ..., got 200, or max total payment exceeded into your own words. The exact text is the diagnostic.
- Escalate unknowns. If the error does not match the troubleshooting table below, stop and ask the user. Do not guess at remediation, and absolutely do not try
MOCK_PAYWALL=true as a "maybe this fixes it" attempt.
IMPORTANT โ Long-running operation
Both orchestrators are sequential and stateful. End-to-end timing on Sepolia:
research-and-visualize: ~30-90 seconds. Three HTTP round-trips with on-chain payment in between each. Each stage waits for the previous stage's payment to confirm before starting the next.
review-and-rate: ~20-60 seconds. One paid HTTP round-trip, then optionally one more on-chain transaction for the feedback step.
Warn the user before invoking โ they will sit watching the bash output for up to 90 seconds and may assume it is hung. Tell them the expected duration up front.
Do NOT split into parallel sub-calls. The research-and-visualize stages share state (LLM input depends on search output, image prompt depends on LLM output) and the FhePayingClient budget tracker is shared across all three. Running them in parallel breaks both data dependencies and the budget bookkeeping.
IMPORTANT โ Invocation form
Every command in this skill MUST be invoked through the workspace filter, exactly like this:
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/<command>.ts --flag value
The plugin-local package.json has only "test": "vitest run". There is no shortcut script. Bare node / npx tsx / ts-node from a non-workspace cwd will all fail to resolve the @x402fhe/core workspace import in _paid-request.ts.
Before you start
You need a real wallet, an RPC URL, and the demo stack running. See ../../references/wallet-setup.md for the three wallet modes and ../../references/env-vars.md for the full env list.
Minimum dev env:
export WALLET_MODE=user
export USER_PRIVATE_KEY=0x...
export RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
Preflight checklist (run before either orchestrator):
-
Are the demo servers reachable? Probe each upstream port with curl or lsof:
lsof -nP -iTCP:3001 -sTCP:LISTEN
lsof -nP -iTCP:3002 -sTCP:LISTEN
lsof -nP -iTCP:3003 -sTCP:LISTEN
lsof -nP -iTCP:3004 -sTCP:LISTEN
lsof -nP -iTCP:4401 -sTCP:LISTEN
lsof -nP -iTCP:4402 -sTCP:LISTEN
lsof -nP -iTCP:4403 -sTCP:LISTEN
lsof -nP -iTCP:4404 -sTCP:LISTEN
No output = no listener = orchestrator will throw ECONNREFUSED. Start the stack first.
-
If you are about to run ./scripts/demo-launch.sh, verify both required addresses are set:
printenv DEMO_SELLER_ADDRESS
printenv CODE_SERVER_ADDRESS
Both must print a non-empty 0x... address. If either is empty, ask the user to set them in .env or demo.env first.
-
Confirm the payer wallet has cUSDC balance. Real on-chain payments consume cUSDC. The orchestrator caps total spend at $0.10 by default, so a working dev balance is ~1 USDC wrapped to cUSDC via the fhe-payment-basics skill (wrap --amount 1). For research-and-visualize budget every stage assuming roughly $0.033 each.
-
Make sure MOCK_PAYWALL is not stuck on from a previous shell:
printenv MOCK_PAYWALL
unset MOCK_PAYWALL
-
For review-and-rate only: the on-chain feedback step is conditional. If CODE_REVIEW_AGENT_ID is unset, the feedback step is skipped (returned as {submitted: false, skipped: true, reason: "CODE_REVIEW_AGENT_ID is not configured"}) โ the paid review still runs. If the user wants the feedback to land on-chain, set CODE_REVIEW_AGENT_ID=<numeric agent id> first.
Commands
1. research-and-visualize
When to use: the user asks to run the demo, run the research demo, run x402 with a query, or chain search โ analysis โ image generation across paid services. Three sequential paid stages.
Invocation (substitute the URL overrides for whichever set of ports your demo stack is using โ see CRITICAL block):
SEARCH_SERVER_URL=http://127.0.0.1:4401 \
LLM_SERVER_URL=http://127.0.0.1:4402 \
IMAGE_SERVER_URL=http://127.0.0.1:4403 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/research-and-visualize.ts --query "fully homomorphic encryption use cases 2026"
Required args:
--query <text> โ the search query, used as the prompt for stage 1 and (truncated) for stage 3.
Required env: RPC_URL, one wallet mode, sufficient cUSDC. Optionally SEARCH_SERVER_URL / LLM_SERVER_URL / IMAGE_SERVER_URL (defaults are 3001/3002/3003 โ almost always wrong, see CRITICAL).
What it does, in order:
- Validates
--query is non-empty.
- Builds a
FhePayingClient with $0.10 total / $0.10 per-request budget caps.
- Stage 1 โ search:
POST {searchUrl}/api/search with {query, count: 5}. Expects 402, mints an x402 payment via the verifier relay, retries with x-payment header.
- Stage 2 โ analysis:
POST {llmUrl}/api/chat with model: 'gpt-4o-mini', system prompt "Summarize these search results into 3 concise insights", and the first 3 results from stage 1.
- Stage 3 โ image:
POST {imageUrl}/api/generate with prompt: "Visual summary of: " + analysis.slice(0, 200) and size: '512x512'. Returned as binary; the orchestrator records only contentType, bytes, and the x-generation-id header.
- Aggregates the three receipts into
steps[] and totals.
Returns:
{
"ok": true,
"action": "research_and_visualize",
"query": "fully homomorphic encryption use cases 2026",
"steps": [
{
"step": "search",
"amountMicros": "33000",
"txHash": "0x...",
"nonce": "0x...",
"etherscanUrl": "https://sepolia.etherscan.io/tx/0x..."
},
{
"step": "analysis",
"amountMicros": "33000",
"txHash": "0x...",
"nonce": "0x...",
"etherscanUrl": "https://sepolia.etherscan.io/tx/0x..."
},
{
"step": "image",
"amountMicros": "33000",
"txHash": "0x...",
"nonce": "0x...",
"etherscanUrl": "https://sepolia.etherscan.io/tx/0x..."
}
],
"searchResults": [{"title": "...", "url": "...", "snippet": "..."}],
"analysis": "...",
"image": {
"contentType": "image/png",
"generationId": "...",
"bytes": 12345
},
"totalMicros": "99000",
"totalUsd": "0.099",
"note": "3 encrypted x402 payments on Sepolia. Observers can see the txs, not the amounts."
}
When MOCK_PAYWALL=true is in effect, each step gets "mode": "mock" and txHash/nonce will be the literal string "mock-unpaid". Treat any "mode": "mock" value as a red flag โ surface it to the user and confirm whether they actually wanted a real demo.
Common errors:
fetch failed / ECONNREFUSED 127.0.0.1:3001 (or 3002/3003) โ the URL env vars default to 3001-3003 and nothing is listening there. Use the demo-launch port overrides (4401-4403) or start a stack on the default ports. See CRITICAL.
Expected HTTP 402 challenge from ..., got 200 โ the upstream is reachable but is NOT enforcing the paywall (e.g. MOCK_PAYWALL=true was set on the server side, or the example server was started without the paywall middleware). You would need MOCK_PAYWALL=true on the orchestrator side to consume those unpaid responses, but only if the user explicitly wants that.
max total payment exceeded / budget cap throw on stage 2 or 3 โ see the budget cap CRITICAL block. Partial receipts from earlier stages are real and on-chain.
--query is required โ missing required arg.
2. review-and-rate
When to use: the user asks to run the code-review demo, run review-and-rate, get a paid AI code review, or chain a paid review with on-chain rating in one shot.
Invocation:
CODE_REVIEW_URL=http://127.0.0.1:4404 \
CODE_REVIEW_AGENT_ID=42 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/review-and-rate.ts \
--code "function add(a, b) { return a + b }" \
--language javascript \
--score 90
Required args:
--code <text> โ the source code to review. Pass it as a single shell-quoted string. Multi-line code requires careful escaping.
Optional args:
--language <name> โ language hint for the review server. Default typescript.
--score <int> โ rating to leave for the agent if CODE_REVIEW_AGENT_ID is set. Default 80. Must parse as a BigInt (positive or negative integer); validated before the paid request, so an invalid score does not cost money.
Required env: RPC_URL, one wallet mode, sufficient cUSDC. Optionally CODE_REVIEW_URL (default 3004 โ almost always wrong, see CRITICAL) and CODE_REVIEW_AGENT_ID (numeric; if unset, the on-chain rating step is skipped).
What it does, in order:
- Validates
--code is non-empty and --score parses as BigInt.
- Builds a
FhePayingClient with $0.10 total / $0.10 per-request budget caps.
- Paid stage:
POST {codeReviewUrl}/api/review with {code, language}. Expects 402, mints an x402 payment, retries with x-payment header.
- Optional rating stage: if
CODE_REVIEW_AGENT_ID is set in env, calls the local give-feedback.ts run() directly with {agentId, score, nonce: review.payment.nonce, tag1: 'demo', tag2: 'code-review'}. The nonce from the paid review is used as the proof-of-payment binding for the on-chain rating. If the rating step itself fails after the review succeeded, the entire orchestrator returns an error (the paid review is still settled on-chain โ surface it).
- If
CODE_REVIEW_AGENT_ID is unset, the feedback object is {submitted: false, skipped: true, reason: "CODE_REVIEW_AGENT_ID is not configured"} and the orchestrator still returns ok: true.
Returns: (with on-chain rating)
{
"ok": true,
"action": "review_and_rate",
"payment": {
"amountMicros": "50000",
"txHash": "0x...",
"nonce": "0x...",
"etherscanUrl": "https://sepolia.etherscan.io/tx/0x..."
},
"review": {
"issues": [{"line": 1, "severity": "info", "message": "..."}],
"summary": "..."
},
"feedback": {
"submitted": true,
"agentId": "42",
"txHash": "0x..."
}
}
Returns: (without on-chain rating, CODE_REVIEW_AGENT_ID unset)
{
"ok": true,
"action": "review_and_rate",
"payment": { "...": "..." },
"review": { "...": "..." },
"feedback": {
"submitted": false,
"skipped": true,
"reason": "CODE_REVIEW_AGENT_ID is not configured"
}
}
Common errors:
--code is required โ missing required arg.
--score must be an integer (e.g. 80, -10) โ non-numeric score. Validated before the paid request, so no money was spent.
fetch failed / ECONNREFUSED 127.0.0.1:3004 โ code-review server not running, or default port mismatch. Override CODE_REVIEW_URL. See CRITICAL.
Expected HTTP 402 challenge from ..., got 200 โ code-review server is reachable but not enforcing the paywall. Same diagnosis as research-and-visualize.
Feedback failed after successful paid review: ... โ the paid review settled on-chain but the rating step failed. The review payment is real and not refundable. Surface the inner error verbatim (it came from give-feedback.ts) and ask the user how to proceed.
Examples
Example 1 โ Servers down, agent must NOT silently fall back to MOCK_PAYWALL
User: "Run the x402 research demo with query 'FHE research roadmap'."
Step 1, preflight probe:
lsof -nP -iTCP:4401 -sTCP:LISTEN
No output. Probe also returns nothing for 4402, 4403, 4404, 3001, 3002, 3003, 3004. The demo stack is not running.
Reply:
The demo stack is not running โ none of the expected ports (3001-3004 or 4401-4404) have a listener. I will not silently substitute a mock run because that would produce fake receipts (txHash: 'mock-unpaid') instead of the real on-chain payments the demo is meant to showcase. Two options:
- Start the live demo stack (recommended). Confirm
DEMO_SELLER_ADDRESS and CODE_SERVER_ADDRESS are set in .env or demo.env, then run ./scripts/demo-launch.sh. It binds to ports 4400-4410. I will then invoke the orchestrator with the matching URL overrides:
SEARCH_SERVER_URL=http://127.0.0.1:4401 LLM_SERVER_URL=http://127.0.0.1:4402 IMAGE_SERVER_URL=http://127.0.0.1:4403 pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/research-and-visualize.ts --query "FHE research roadmap"
- Run a mock stub with no real payments and
txHash: 'mock-unpaid' in every receipt. This requires you to start unprotected mock servers AND set MOCK_PAYWALL=true on the orchestrator side. Useful for a UI walkthrough but not a real x402 demo.
Which would you like?
Wait for the user to choose. Do NOT proceed until they pick.
Example 2 โ Happy path
User: "Run the research demo on 'confidential payments on Ethereum'. Demo stack is already up via demo-launch.sh."
Step 1, preflight (assume the user is correct, but verify):
lsof -nP -iTCP:4401 -sTCP:LISTEN
Returns a tsx process. Good.
Step 2, warn about duration:
This will take roughly 30-90 seconds โ three sequential paid HTTP requests with an on-chain payment between each. Starting now.
Step 3, run with port overrides:
SEARCH_SERVER_URL=http://127.0.0.1:4401 \
LLM_SERVER_URL=http://127.0.0.1:4402 \
IMAGE_SERVER_URL=http://127.0.0.1:4403 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/research-and-visualize.ts --query "confidential payments on Ethereum"
Parse the JSON. If ok: true and action: "research_and_visualize", reply:
Three encrypted x402 payments settled on Sepolia. Total: $0.099 (99,000 micros).
| Stage | Amount | Tx |
|---|
| search | $0.033 | https://sepolia.etherscan.io/tx/0x... |
| analysis | $0.033 | https://sepolia.etherscan.io/tx/0x... |
| image | $0.033 | https://sepolia.etherscan.io/tx/0x... |
The encrypted amounts are not visible to chain observers โ only the txs themselves. Stage 3 produced a 512x512 PNG (12,345 bytes, generation id ...).
Search returned 5 results, analysis distilled them into 3 insights: ...
If any step has "mode": "mock", flag it explicitly to the user โ do NOT silently treat it as a real run.
Example 3 โ review-and-rate without an agent ID
User: "Get a paid review of this code: function add(a, b) { return a + b }. Skip the rating."
Step 1, preflight lsof -nP -iTCP:4404 -sTCP:LISTEN returns a listener.
Step 2, confirm CODE_REVIEW_AGENT_ID is unset (so the feedback step will be skipped automatically):
printenv CODE_REVIEW_AGENT_ID
Step 3, run:
CODE_REVIEW_URL=http://127.0.0.1:4404 \
pnpm --filter @x402fhe/openclaw-skill exec tsx scripts/review-and-rate.ts \
--code "function add(a, b) { return a + b }" \
--language javascript
Reply with the review summary, the paid txHash, and explicitly note: "On-chain rating skipped โ CODE_REVIEW_AGENT_ID is not set. To leave a rating bound to this payment, set CODE_REVIEW_AGENT_ID=<id> and re-run, or use the give-feedback command in the fhe-agent-identity skill with the nonce from this payment."
Troubleshooting
| Error text (regex / substring) | Cause | Remediation |
|---|
fetch failed / ECONNREFUSED 127.0.0.1:3001 (or 3002 / 3003 / 3004) | Demo servers not running on the orchestrator's default ports | Start ./scripts/demo-launch.sh AND override SEARCH_SERVER_URL / LLM_SERVER_URL / IMAGE_SERVER_URL / CODE_REVIEW_URL to point at 4401-4404 (or 4410 for the gateway). See CRITICAL. Do NOT set MOCK_PAYWALL=true โ it does not help with ECONNREFUSED. |
fetch failed / ECONNREFUSED 127.0.0.1:4401 (or 4402-4404) | Demo stack started, then died, or you are pointing at the right ports but the process crashed | Re-run ./scripts/demo-launch.sh and confirm all six lines [1/6] through [6/6] print "ready" |
Expected HTTP 402 challenge from ..., got 200 | Server is up but is not enforcing the paywall (likely started with MOCK_PAYWALL=true on the server side, or paywall middleware not registered) | Either restart the server with MOCK_PAYWALL=false, OR set MOCK_PAYWALL=true on the orchestrator side too โ but ONLY if the user explicitly wants a mock run with txHash: 'mock-unpaid' receipts |
Expected HTTP 402 challenge from ..., got 404 | Wrong path on the upstream server, or upstream is a completely different service | Verify the URL matches the example server. The orchestrator hits POST /api/search, POST /api/chat, POST /api/generate, POST /api/review |
max total payment exceeded / max per-request payment exceeded mid-run | Cumulative budget cap of $0.10 tripped (or per-request $0.10) | Earlier stages are already on-chain and not refundable. Surface the partial receipts. To re-run with more budget, change createDemoPaymentContext(100_000n) in the script โ there is no flag for it. See the budget CRITICAL. |
feedback: {submitted: false, skipped: true, reason: "CODE_REVIEW_AGENT_ID is not configured"} | Not an error โ feedback step skipped because env var unset | If feedback was wanted, set CODE_REVIEW_AGENT_ID=<id> and re-run (will incur a second paid review). Or use give-feedback from fhe-agent-identity with the nonce already returned by this run. |
Feedback failed after successful paid review: ... | Paid review settled on-chain, but the on-chain rating step threw | The review payment is real and not refundable. Quote the inner error verbatim โ it came from give-feedback.ts. Do NOT auto-retry. |
--query is required / --code is required | Missing required arg | Add the flag |
--score must be an integer (e.g. 80, -10) | Non-numeric score on review-and-rate | Use a plain integer; validated before the paid request, so no money was spent |
demo-launch.sh: ERROR: Set DEMO_SELLER_ADDRESS in .env | demo-launch.sh hard-fail precondition | Set DEMO_SELLER_ADDRESS in .env or demo.env (the recipient address for search / LLM / image servers) |
demo-launch.sh: ERROR: Set CODE_SERVER_ADDRESS in .env | demo-launch.sh hard-fail precondition | Set CODE_SERVER_ADDRESS in .env or demo.env (the recipient address for the code-review server) |
demo-launch.sh: ERROR: ... port 44XX is already in use | Demo stack already running, or another process is holding the port | lsof -iTCP:44XX -sTCP:LISTEN to find the process, then either reuse the running stack or kill the conflicting process |
| Bash exit โ 0 with stack trace, NOT a JSON line | Orchestrator init crashed before returning JSON โ usually _wallet.ts env error or RPC unreachable | Run info from fhe-payment-basics first to verify wallet env vars and RPC connectivity. If info works, the bug is in the orchestrator path itself โ escalate. |
mode: "mock" in any receipt | MOCK_PAYWALL=true was set somewhere (orchestrator env or inherited from the shell) | Check printenv MOCK_PAYWALL, unset it, and re-run. If the user genuinely wanted a mock run, surface this and confirm. |
Scope boundary
This skill covers ONLY the multi-stage HTTP-402 demo orchestrators research-and-visualize and review-and-rate. Do not use it for:
info / balance / wrap / pay (direct cUSDC operations) โ see fhe-payment-basics
unwrap / finalize-unwrap (redeeming cUSDC back to USDC) โ see fhe-payment-unwrap
create-job / fund-job / submit / complete-job (encrypted escrow lifecycle) โ see fhe-escrow
register-agent / give-feedback invoked directly (single-shot rating of a prior payment, with no paid review in front of it) โ see fhe-agent-identity
grant-view / revoke-view / view-as (delegation setup and delegated reads) โ see fhe-delegation