DimeBox publishes a full OpenAPI document at /openapi.json — every route, every request and response shape, kept in sync with the actual API rather than hand-maintained separately. That's enough to generate a typed client in either TypeScript or Python without writing the types yourself. It is not enough on its own to make paid calls work, because nothing in an OpenAPI spec describes a 402 payment handshake — that's x402's layer, sitting below whatever a generated client gives you.
curl -s https://dimebox.app/openapi.json -o dimebox-openapi.json
With openapi-typescript, this produces a types-only file — no runtime code, just interfaces matching every documented request and response:
npx openapi-typescript dimebox-openapi.json -o src/dimebox.d.ts
Pair the generated types with openapi-fetch's client, and hand it the payment-aware fetch from the Node quickstart instead of the global one — the generated client doesn't know or care that its underlying fetch happens to sign payments against eip155:84532 (Base Sepolia) or whichever network you've configured; see Base Sepolia vs Base mainnet before changing that:
import createClient from "openapi-fetch";
import type { paths } from "./dimebox";
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: "eip155:84532", client: new ExactEvmScheme(account) }],
});
const client = createClient<paths>({
baseUrl: "https://dimebox.app",
fetch: fetchWithPayment,
});
const { data, error } = await client.POST("/api/emails/generate", {
body: { recipient: "[email protected]", purpose: "follow up" },
});
Everything about request and response shape is now type-checked at compile time; everything about payment still happens exactly the way it does in the plain quickstart, because it's the same fetchWithPayment doing the same work underneath a thin typed layer.
openapi-python-client does the equivalent job for Python, producing a package with request/response models and a generated HTTP client:
pip install openapi-python-client
openapi-python-client generate --url https://dimebox.app/openapi.json
The generated client's underlying transport is still httpx — wrap it the same way as the plain Python quickstart, catching the 402 and retrying with a signed payment, just inside the generated client's request path instead of a bare httpx.AsyncClient. The generated code doesn't add payment awareness on its own; it only saves you from hand-writing the request and response models.
Treat the generated file the same way you'd treat any other build artifact: regenerated automatically rather than hand-edited and committed as source of truth. A small script run in CI, or a pre-build hook, keeps it from silently drifting from whatever /openapi.json currently returns:
{
"scripts": {
"generate:dimebox": "openapi-typescript https://dimebox.app/openapi.json -o src/dimebox.d.ts"
}
}
Running that as a dedicated step — rather than folding spec-fetching into the same script that also handles payments — keeps the two concerns from tangling: one script asks "what does the API look like," the other asks "how do I pay for it," and neither needs to know about the other's internals.
An OpenAPI document can describe that a route expects a PAYMENT-SIGNATURE header or an Authorization header, as a documented parameter — that much is just metadata about the request shape, and codegen tools will happily generate a typed parameter for it. What the spec cannot describe is how to produce the value that goes in that header: computing a valid x402 signature, or obtaining a wallet secret, are both processes that happen entirely outside the API's own interface description. Don't expect a generated client's types to save you from reading how the two auth models actually work first.
Neither tool knows anything about x402, wallet bearer tokens, or DimeBox's pricing — they only read the OpenAPI document, which describes HTTP shapes, not payment semantics. That means a generated client still needs the same pay-and-retry wrapper as a hand-written one, every time, for every paid route it touches, whichever payment method you've chosen — see API keys vs wallet secrets vs x402 signatures if you haven't settled that yet.
It also means a generated client is frozen at generation time: if DimeBox's documented request shape changes, your types go stale until you regenerate. Pricing is a separate, faster-moving concern entirely — discovering live prices programmatically covers why you shouldn't bake a price into a client, generated or not, in the first place.
Regenerate the client whenever /openapi.json changes, and keep the payment wrapper as a separate, small piece of code that sits in front of whichever client you're using — generated or hand-written, the wrapper doesn't care. The split is worth preserving even once both pieces feel stable: a codegen tool upgrade shouldn't require touching your payment logic, and swapping payment methods later shouldn't require regenerating a single type.