POST /api/v1/enhance now accepts x402 settlement as authentication.
Send the PAYMENT-SIGNATURE header, settle USDC on Base (Sepolia in
test, mainnet in prod), and the producer returns a 202 carrying a
freshly-minted pollToken:
{
"jobId": "...",
"status": "queued",
"statusUrl": "/api/v1/enhance/jobs/...",
"estimatedSeconds": 240,
"pollToken": "Rh3...n_w"
}
Re-present that token as Authorization: Bearer <pollToken> on the
follow-up calls — GET /api/v1/enhance/jobs/:id, POST .../cancel, and
GET /api/v1/artifacts/:id/{pdf|source}. The server hashes the
presented token and matches against the job row's stored
pollTokenHash. Mismatch returns the same 404 shape as an authed
owner-mismatch, so jobIds can't be probed.
The token is bearer-equivalent for that one job's lifetime — agentic
callers persist it, humans wouldn't drive this path directly. Replaying
the same PAYMENT-SIGNATURE within the 5-minute idempotency cache
window returns the cached 202 verbatim, including the original
pollToken; this is the supported retry path for connection drops
between settlement and 202.
Why this matters: x402 itself is stateless request/response, but the
spec doesn't preclude polling — a 202 with { jobId, pollToken } is
fully conformant. /enhance takes minutes (vision per page, multiple
LLM calls, in-place tagging), well past the 30s Workers CPU budget, so
synchronous fulfilment was never on the table. Wallet-authenticated
polling closes the loop and unblocks the route's listing in the CDP
Bazaar discovery index.
Listing is the one operation wallet callers can't do — GET /api/v1/enhance/jobs stays user-scoped. You know your jobIds because
we returned them.
One caveat for SDK authors. Idempotency-Key replays (same key, same
wallet, second submission) return the existing jobId but with
pollToken: null — the original raw token isn't recoverable from its
stored hash. Use the signature replay path (the same
PAYMENT-SIGNATURE within the 5-minute cache window) when you need the
original pollToken back; use Idempotency-Key only when you've held
onto the first pollToken yourself.