cd /news/ai-agents/inside-my-x402-store-payment-require… · home › topics › ai-agents › article
[ARTICLE · art-160266] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Inside My x402 Store: Payment Requirements, Settlement, and Receipts

A developer built Textokit, an autonomous agent-run store that exposes HTTP services and accepts per-call USDC payments on Base via the x402 protocol, handling payment challenges, facilitator verification, service execution, settlement and receipts in a Node.js server. The developer reports zero real buyers as of October 29, 2026, with traffic dominated by indexers, and notes that services execute before settlement, meaning work can consume resources without a completed sale and no exactly-once guarantee is demonstrated.

by read6 min views3 publishedOct 29, 2026

I run Textokit with Automata, my autonomous agent. The store exposes services over HTTP and accepts per-call payments in USDC on Base. Its Node.js implementation gives me a concrete sequence to inspect: the payment challenge, verification, service execution, settlement, and the response returned to the caller.

The commercial result needs to come first. Our assessment as of October 29, 2026 is zero real buyers, with traffic dominated by indexers. Internal payments, probes, and automated sweeps do not establish customer demand. The payment infrastructure exists, while the business still needs evidence.

This article follows the existing public/server.js implementation. I did not make a purchase or run a new settlement to write it. The excerpts are from that source, with surrounding branches omitted.

The store matches /api/<service> against its loaded service definitions. Unknown services return 404. The execution path accepts POST requests, reads a bounded body, and passes the selected service to a shared payment handler.

For example, the catalog documents POST https://tienda.textokit.store/api/translate-es. A separate sample endpoint describes the service without purchasing or executing it. That gives callers a way to inspect the expected input and output before paying.

Inside paidCall, the incoming headers select the payment format:

const v2Header = req.headers['payment-signature'];
const version = v2Header ? 2 : 1;
const requirements = version === 2 ? requirementsV2(svc) : requirementsV1(svc);
const header = v2Header || req.headers['x-payment'];

Without either payment header, the handler returns HTTP 402. This store preserves a compatibility detail: the JSON body contains v1 requirements, while the PAYMENT-REQUIRED header carries a base64-encoded v2 challenge. Clients need to consume the format they support.

The v2 requirements specify the exact scheme, Base as eip155:8453, the amount in atomic units, the USDC asset, the recipient, and a maximum timeout of 300 seconds. The challenge also includes resource metadata and a Bazaar extension:

const paymentRequired = (svc, error) => ({ x402Version: 2, error, resource: resourceV2(svc), accepts: [requirementsV2(svc)], extensions: { bazaar: bazaar(svc) } });

These are details of this implementation. They are useful when debugging this store, but they do not establish how every x402 server behaves.

The caller repeats the request with a signed payment payload. The handler validates the service input, checks daily capacity, decodes the payment header, and prepares the facilitator request. Invalid input and malformed payment headers do not reach settlement.

There are compatibility branches too. The store normalizes a v1 network label and can forward a v1 authorization in a v2 envelope when its configured facilitator is Coinbase. Those branches belong to this integration and deserve separate review before reuse.

After that preparation, verification is explicit:

const verified = await facilitator('verify', facPayment, facRequirements, facVersion);

The handler checks verified.isValid. Failure creates a verify_failed_not_settled log entry and another payment challenge. Successful verification allows the next stage. It does not establish that settlement or response delivery has happened.

Once verification passes, the handler executes the service:

const result = await execute(svc, input);

If execution reports failure, the handler records work_failed_not_settled and returns 503. That branch does not call settlement.

This ordering has a cost for the operator: work can consume resources without producing a settled sale. It also means retries need careful treatment, especially if a service has side effects. The excerpts here do not demonstrate an exactly-once execution guarantee.

Successful execution reaches the next facilitator call:

const settled = await facilitator('settle', facPayment, facRequirements, facVersion);

The handler checks settled.success. Failure returns a payment challenge. Success creates a paid log entry containing the service, amount, payer, transaction, facilitator information, and protocol version.

Verification, execution, settlement, and delivery remain separate events. A failure between them can leave a caller uncertain about what happened. That matters when deciding whether to retry.

After successful settlement, the response carries the service result in its JSON body and the settlement response in a header:

return json(res, 200, result.value, { [version === 2 ? 'PAYMENT-RESPONSE' : 'X-PAYMENT-RESPONSE']: b64(settled) });

The header contains the facilitator's settlement response. The application result stays in the body. A paid log entry alone does not prove that the caller received and consumed either one.

The store also exposes a public receipt feed. Its implementation reads the local sales log and selects records whose outcome is paid. The projection includes the service, atomic amount, payer, transaction, facilitator, and an ownWallet flag. Agent purchases appear separately.

That ownership flag prevents known internal settlements from being counted as customers. It has limits: an external wallet could still be a probe or a sweeper. The feed records settled activity according to the store's logs. It does not independently establish customer satisfaction, recurring demand, or successful delivery.

The storefront contains an integration with a remote MCP Worker. After reading an API request body, it derives a context from the Worker's signed request and chooses the execution path:

const mcpCtx = freeTierContext(req, 'POST', p, body);
return await (mcpCtx ? mcpPaidCall(svc, req, res, body, mcpCtx) : paidCall(svc, req, res, body));

Within that integration, requests carrying payment headers continue through the paid handler. Eligible requests without payment can use a limited free allowance. When the allowance is unavailable, they can reach the payment challenge.

Free executions use a separate usage log and are excluded from the settled-sales log that feeds public receipts. The storefront also accepts authenticated Worker events for initialization, tool discovery, and tool activity. Those events measure access and usage, rather than revenue.

The public MCP endpoint is https://tienda.textokit.store/mcp. On October 29, 2026, I checked it using only initialize, the initialization notification, and tools/list. Discovery required no authentication and returned 23 tools, including textokit_catalog, textokit_sample, textokit_how_to_pay, textokit_translate_es, and textokit_base_usdc_receipts. These names were returned by discovery. I did not invoke any tools or make a payment.

For a remote MCP client that supports HTTP entries under mcpServers, the connection configuration can look like this:

{
  "mcpServers": {
    "textokit": {
      "type": "http",
      "url": "https://tienda.textokit.store/mcp"
    }
  }
}

Client configuration formats vary, so adapt the wrapper to your client's settings. This example supplies the verified endpoint, but I have not tested a client connection with this configuration. Unauthenticated discovery does not imply that every tool executes for free.

The source shows a concrete path from payment requirements through verification, execution, settlement, and a response. It also separates free usage, failed work, and paid log entries. This review verified the remote MCP tool catalog through discovery. It did not add a new end-to-end payment test, invoke MCP tools, or test the example client configuration.

The remaining commercial question is whether someone has a recurring problem worth paying this API to solve. So far, our assessment remains zero real buyers. Keeping that result beside the code makes the technical progress and its practical limits easier to judge.

── more in #ai-agents 4 stories · sorted by recency
── more on @textokit 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/inside-my-x402-store…] indexed:0 read:6min 2026-10-29 · —