DEV Community

chilies4114
chilies4114

Posted on AI-assisted

What I learned building a one-cent x402 API on Base

I built GLP1LAUNCH to test a narrow product idea: can an API sell one useful response for $0.01 without requiring an account, API key, subscription, or checkout page?

The live project has three free indexes: GLP-1 questions, supplement interactions, and peptide/longevity questions. Each has a paid counterpart that returns a longer research brief with named source links. The paid routes use x402 on Base and cost $0.01 USDC per call.

The health topics are the sample domain, not the claim. This is research information, not medical advice, and the interesting engineering questions are broader:

  • What belongs in the free response?
  • What is worth paying for one call at a time?
  • How much wallet setup is too much friction?
  • How do you measure conversion without collecting sensitive data?
  • What breaks on a real phone even when the protocol works?

Here is what I learned from shipping and testing the full flow.

The payment gate was the easy part

At a high level, x402 turns HTTP 402 into a payment negotiation:

  1. A client requests a paid resource.
  2. The server returns payment requirements.
  3. The client signs a payment authorization.
  4. The request is retried with the payment payload.
  5. A facilitator verifies and settles the payment.
  6. The server returns the paid response.

For this project, the buyer pays $0.01 USDC on Base. The client signs an authorization in MetaMask rather than submitting a normal gas-paying wallet transaction. The facilitator handles settlement.

The Node client starts with:

npm install @x402/fetch @x402/evm viem
Enter fullscreen mode Exit fullscreen mode

Then the client wraps fetch with an EVM signer and calls a paid route. The current runnable snippet is in the repository and live demo rather than duplicated here, because payment-library APIs change and stale payment code is worse than no example.

This part worked as designed. The harder work was making the product around it understandable.

Free versus paid is the real product decision

A payment protocol can tell a client how to pay. It cannot decide what is worth paying for.

GLP1LAUNCH uses a simple split:

  • Free routes return question indexes and basic metadata.
  • Paid routes return longer research briefs with named sources and links.

That makes the free response useful on its own. A developer or agent can inspect the available topics before spending anything. The paid response adds depth and provenance instead of removing basic usability from the free tier.

I would use the same test for another metered API:

Free should answer, "Is this resource relevant?" Paid should answer, "Is the deeper result worth consuming now?"

A weak split makes the free route a teaser and the paid route a toll. A stronger split lets the free route support discovery, routing, and evaluation while reserving expensive or higher-value work for the paid call.

One cent is useful for testing this boundary because the price is low enough that checkout overhead would be absurd. The payment has to happen inside the request flow or the product does not make sense.

Wallet friction still matters

The first end-to-end payment attempt failed even though the integration path was healthy. No onchain transfer had been submitted. The likely problem was simpler: the wallet did not yet have USDC on Base.

That exposed an important distinction:

  • The user did not need ETH for gas in this flow.
  • The user did need the correct asset on the correct network.

"Connect MetaMask" is not enough onboarding. A useful payment screen should make the prerequisites explicit:

  • Network: Base mainnet
  • Asset: USDC on Base
  • Price: $0.01
  • Gas: handled by the x402 flow
  • Action: sign a payment authorization

The interface originally collapsed facilitator failures into a generic "Payment failed" message. That was a bad debugging experience. The interface now surfaces the facilitator's specific rejection reason when available, such as insufficient funds.

That is not merely developer convenience. Precise failure messages prevent users from signing the same authorization repeatedly without knowing what they are fixing.

Mobile needed its own path

Desktop wallet assumptions did not hold on a phone. When no injected wallet provider was present, telling a mobile visitor to install MetaMask was a dead end.

The mobile flow now uses a MetaMask app deep link when a provider is missing. That gives the visitor a path into the wallet app instead of showing desktop-only advice.

The lesson is not specific to MetaMask: a payment demo is not mobile-ready because the page is responsive. Wallet discovery, network selection, app switching, and the return path all need to be tested on an actual phone.

Privacy-preserving metrics are still data

The first stats endpoint counted requests per route and paid unlocks. It intentionally stored no health queries, wallet addresses, IP addresses, or user agents.

That was privacy-friendly, but it could not answer two launch questions:

  • How many unique free users tried the API?
  • Did anyone make a repeat paid call within seven days?

The project now uses pseudonymous measurement with a deliberately narrow design:

  1. The browser creates a random first-party ID and keeps it in local storage as an HMAC key.
  2. It sends only a monthly rotating HMAC-SHA-256 pseudonym in an X-Launch-Visitor header.
  3. The server keeps pseudonyms and paid-call dates in memory for aggregate counts.
  4. The public stats response exposes counts, never pseudonyms.

The aggregate endpoint can now report:

{
  "unique_free_users": 0,
  "unique_paid_users": 0,
  "repeat_paid_users_7d": 0
}
Enter fullscreen mode Exit fullscreen mode

A repeat paid user means the same pseudonym completed at least two paid calls in the trailing seven days. Paid activity dates stay in memory for eight days so the seven-day window can be calculated.

The exclusions are as important as the counts. The stats system does not store:

  • health queries
  • wallet addresses
  • IP addresses
  • user agents
  • request bodies
  • payment headers
  • query strings

Tests also check that raw or malformed visitor identifiers are rejected and that pseudonyms never appear in the public snapshot.

I do not call this anonymous analytics. A rotating HMAC is pseudonymous data. It reduces linkability and avoids direct identifiers, but it still exists to recognize repeat activity inside a bounded window. The privacy copy says that directly.

The measurement has real limits

This design trades durability and attribution for data minimization.

The current server runs on a free Render instance, and the metrics are held in memory. A restart or redeploy resets every counter and pseudonymous record. Clearing browser storage creates a new local ID. API clients that omit the visitor header count as requests but not unique users. Monthly rotation also means the same browser receives a new pseudonym at the start of a UTC month.

Those are not footnotes to hide. They define what the numbers mean.

For an early launch, I prefer a small set of honest, disposable metrics over durable tracking that quietly collects more than the product needs. If the project grows, the next step would be a short-retention store with explicit deletion and the same narrow event model, not a general analytics SDK added by default.

Documentation is part of the product

The API now exposes:

  • an OpenAPI specification
  • an ai.txt file for machine-readable discovery
  • a 60-second Node quickstart
  • a public aggregate stats endpoint
  • cited source links in paid responses

It also labels trending_score correctly as an editorial priority score, not live trend data. That wording matters. An API field can be technically valid and still mislead clients if its name implies a data source that does not exist.

For agent-facing APIs, machine-readable docs, payment requirements, failure behavior, and data provenance are not launch polish. They are the interface.

What I would do differently next

If I started again, I would test in this order:

  1. A free request from a cold server.
  2. A paid request from a wallet that definitely has Base USDC.
  3. The same request from a wallet with no Base USDC.
  4. Mobile with and without an injected provider.
  5. A facilitator rejection with the raw error preserved.
  6. A successful paid response with source links checked.
  7. Analytics behavior across repeat calls, malformed headers, and a server restart.

I would also define the free-versus-paid contract before writing payment middleware. The protocol can be integrated quickly. Deciding what the paid call should earn is the longer product conversation.

GLP1LAUNCH is still a small experiment. The current server can cold-start, the metrics reset, and the early traffic is too small for conversion claims. But the complete loop works: discovery, free response, one-cent authorization, settlement, paid response, source links, and bounded measurement.

Live demo: https://glp1launch-1.onrender.com/

Source: https://github.com/chilies4114/GLP1LAUNCH

x402 overview: https://docs.cdp.coinbase.com/x402/welcome

What would make a one-cent API call useful enough for you to integrate, and what would still make the payment step feel too expensive?


Disclosure: I built the original project and used an AI assistant during launch hardening, testing, and article editing. I reviewed the technical claims against the live project and documentation and take responsibility for the final text.

Top comments (0)