A gateway built to be doubted.
One base_url change puts Recovea between your app and your provider: your keys, our meter, fail-open at every step. This is the whole path, end to end.
The request path
Three hops, one line of config. Recovea forwards to your provider with your own key, and gets out of the way the moment anything on our side goes wrong.
Fail-open at every step, with one deliberate exception: an armed spend cap refuses rather than let spend leak past your budget. That is what a cap is for.
The meter starts
Your request arrives with your Recovea key. If metering itself ever fails, the request still goes through: a lost meter reading, never a lost response.
Fails openCaps are checked
Budget caps and rate limits are checked locally, before anything is forwarded, with no extra network hop. An armed hard cap is designed to refuse here, before the request reaches your provider.
Fails closed, by designForwarded on your key
The request goes to your provider on your own key. BYO, we never resell tokens. If Recovea degrades, your traffic goes straight to the provider.
Fails openThe receipt is written
The response streams back to you first; the receipt is written after, off the hot path. Writing it can never delay or drop a response.
Fails open"You want to sit in my request path?"
The right first question. Yes, and you should make us earn it. Here is what we can put behind that today.
Milliseconds, with the label attached
~1ms p50 / 2ms p95 local gateway overhead (measured July 2026, non-production). That is the only latency figure we publish, and its label and its date travel with it everywhere it appears: it is a benchmark of the gateway hop taken off production, so you can weigh how old it is rather than read a number with no age. Production numbers ship when they are measured, not before.
measured July 2026, non-production
If we degrade, we disappear
Gateway trouble is designed not to become your outage: a timeout, a crash, or a bad deploy on our side, and your traffic goes straight to the provider. You lose a meter reading; your users still get their response.
Beside your traffic first
You do not have to route through us to start. Run us beside your traffic first: point staging or a mirror at the gateway, read the meter, and check it against your provider's bill before you ever let us route production.
Priced from a frozen list, blind to your content
Metering turns provider-reported usage into money. Two rules keep that number trustworthy:
- The price list is frozen. Every request is priced against a versioned reference price list, pinned on the receipt as
refPriceVersion. A published version never changes, so a number you saw once can never quietly become a different number later. - The meter is body-free. We meter what the provider reports (models, token counts, finish reason, status), and we never store message content. Your prompts and completions pass through the gateway; they are not our data.
Body-free by design: the meter reads the usage object, not the conversation.
The levers
Everything that can change a request ships off. The first two levers are deliberately boring: they only ever return exactly what the provider would have.
Byte-identical or nothing
A cached answer is served only when the request bytes are identical to one we have already seen, and the stored response is fully validated before the first byte reaches you. Never "close enough", never a half-written hit. Any doubt is a miss, and a miss just forwards.
Identical requests, one flight
When identical requests are in flight at the same moment, one goes to the provider and the rest receive the same byte-identical response: bounded coalescing, with every fault treated as a miss, never an error.
Observe by default, concierge to live
Every route starts in observe: levers off, meter on. A lever moves off → shadow → live only with your sign-off, activated by a human on our side, never a silent default.
When a lever saves money, the saving reads measured, never verified, until the evaluation gate is calibrated on real traffic. Gain-share is off · proof pending.
Proof you can recompute without us
- Every request gets a receipt. Each metered request becomes a ledger row under
recovea-chain-v1: a SHA-256 over the recipe id, the previous row's hash, and twelve canonical fields in a published order. Recompute it offline; if it disagrees with the storedrowHash, the row was altered after the fact. - Settled rows are hash-chained. Each ledger row commits to the hash of the row before it, so editing history means breaking every link that follows. Export the ledger and re-derive the whole chain on your side.
- No trust required. The recipes are published and the re-derivation runs offline. The check needs the export file, not our word.
{
"recipe": "recovea-chain-v1",
"previousHash": "7c41d9e8…a02b",
"requestId": "req_9f2ke01xa41v",
"timestampMs": 1783000991482,
"provider": "openai",
"model": "gpt-4o",
"route": "/v1/chat/completions",
"tokensIn": 1842,
"tokensOut": 506,
"tokensCached": 1024,
"costMicroUsd": 8385,
"priceListVersion": "rpl-2026-08-05",
"basis": "measured",
"mandateId": null,
"rowHash": "3e1f0c9a…b47d",
"ts": "2026-07-02T14:03:11.482Z",
"cost": "0.00838500",
"lever": "observe"
}The hash input is the first fourteen fields above — the recipe id, the previous row's hash, then the twelve canonical fields — joined with U+001F and SHA-256'd; rowHash is the output you compare against. ts, cost and lever are display companions, outside the hash input. Values hash exactly as stored, and null hashes as the empty string. (Example values shown.)
A cap that acts, and exactly what your app sees
Budget alerts at 50, 80, and 95% tell you. The cap and the kill-switch act:
- At the cap, we refuse before we forward. A refused request is not sent to your provider, so it carries no provider spend. The counter is read before this request's own estimate lands, though, so expect to finish roughly one request over the cap. A hard cap returns the 402 shown here; a pause-style cap returns a
429carrying the samebudget_exceededcode plus aRetry-After, so retry loops back off on their own. - The error is OpenAI-shaped. Your SDK parses it natively, and
code: "budget_exceeded"tells your app it hit your wall, not the provider's quota. - The kill-switch is the same wall, thrown by hand. Flip it and the next request is refused the same way. Nothing to redeploy, nothing to roll back.
- Fail-closed, on purpose. If we cannot verify you are under your cap, we refuse with
code: "budget_unverifiable"rather than let spend leak. The breaker is the one part of Recovea that fails closed: a cap that fails open is not a cap. - Real limits, published. Sustained, per tier: Free 100 requests/min, 200K tokens/min. Developer and Team 600 requests/min, 1M tokens/min. Growth 1,200 requests/min, 2M tokens/min. Scale 3,000 requests/min, 5M tokens/min. Rate limits are indicative, never a guarantee: the limiter runs inside each gateway process, so the throughput you actually get can land above or below the published figure.
HTTP/1.1 402 Payment Required
{
"error": {
"message": "Monthly budget reached. Traffic resumes at reset, or raise the cap.",
"type": "insufficient_quota",
"param": null,
"code": "budget_exceeded"
}
}What your app sees when a hard cap is reached. Alerts at 50, 80, and 95% warn you on the way up; a fast burst can reach the cap between checks.