Hardcoding "a few cents to send" into an agent's code is a bug waiting for the day DimeBox's pricing changes — and pricing is explicitly not fixed forever; the API reference reads every price live from this deployment's own configuration rather than a static table, which means your code shouldn't treat today's number as permanent either. DimeBox exposes that same live data at a dedicated discovery endpoint precisely so a caller never has to guess.
A price baked into a constant works fine until it's wrong, and the failure mode isn't a loud error — it's a signed payment for the wrong amount, which a 402 response rejects the same way it rejects a missing payment entirely. An agent that silently retries on every rejection just burns calls instead of fixing the actual problem: it signed for an amount that's stale. What a 402 response teaches about API economics covers the broader shape of this — the protocol wants the client to know the exact price before it pays, not to assume one.
curl -s https://dimebox.app/api/discovery/resources | jq .
This returns the live price, network, and settlement asset for every paid route on this deployment — exactly what "nothing here can drift out of sync with what you're actually charged" means in practice. Read it directly rather than copying numbers out of a blog post, including this one, into a constant somewhere.
Resist the urge to immediately destructure specific fields you're guessing at. Print the raw entries the first time you call this, confirm the shape against what this deployment actually returns, and build your lookup from there:
import httpx
resp = httpx.get("https://dimebox.app/api/discovery/resources")
resp.raise_for_status()
for resource in resp.json():
print(resource) # inspect the real keys before building logic around them
Once you've confirmed the shape, caching the result for a short period (minutes, not days) and checking it before a batch of calls is a reasonable middle ground between fetching it on every single call and hardcoding it forever:
import time
_cache = {"fetched_at": 0, "resources": None}
TTL_SECONDS = 300
def get_resources() -> list:
if time.time() - _cache["fetched_at"] > TTL_SECONDS:
resp = httpx.get("https://dimebox.app/api/discovery/resources")
resp.raise_for_status()
_cache["resources"] = resp.json()
_cache["fetched_at"] = time.time()
return _cache["resources"]
A five-minute TTL means a long-running process picks up a price change within minutes of it happening, without hitting the discovery endpoint on every single paid call it's about to make.
If an agent is about to fire off a batch of outbound email, checking the current send price against a wallet's daily spend limit before starting is cheap insurance against discovering mid-batch that the math no longer works. This is also the right place to decide whether a task is even worth running — see how much it actually costs to send one email for the numbers to compare against.
Knowing what a call costs is only half of the budgeting question — the other half is whether whatever's funding the call actually has that much left. A card-funded wallet has its own balance and spend-limit state, covered in how the wallet's closed-loop credit works, which discovery knows nothing about; it describes the API's prices, not your account's standing. A well-built pre-flight check reads both: the live price from discovery, and the remaining balance from whatever's actually paying.
A human developer who hardcodes a price and happens to be wrong notices almost immediately — a curl command returns a 402 for an unexpected reason, and the obvious next step is to go check the docs. An unattended agent doesn't have that instinct. It either retries the same wrong amount indefinitely, silently fails a task that a correct price would have let it complete, or — worse — succeeds at something adjacent to what you intended because it fell back to a default that happened to work by coincidence. Machine-checkable discovery exists precisely because the caller on the other end usually isn't a person who'll notice something looks off.
If you've generated a typed client from the OpenAPI spec, that client's types are frozen at the moment you generated them — useful for request and response shapes, which change rarely, and wrong to rely on for price, which can change independently of the schema. Keep the two separate: codegen for shapes, discovery for price, checked live, every time it actually matters.
Full details on what each paid route costs, as of today, are also in the API reference — the discovery endpoint is the same data, meant for your code to read instead of your eyes.