You write the logic.
Relay it to us.
We execute the rest.
Backfire is one endpoint for outbound HTTP. Your app sends a URL, a method and a body; we validate the key, guard the target, make the call, and hand back one predictable JSON envelope. Retries, branching and mapping stay in your code, where they belong.
no card · no subscription · balance never expires
1 trip = 1 complete roundtrip (1 uptrip + 1 downtrip)
600 forwards a minute per key · 10 s cooldown past that, never charged
no trace log · trip data purged the moment it completes
backfirebearer
backfire_••••
body
JSON envelope
trail
full log
The problem
Outbound HTTP is where careful applications quietly get unsafe.
Every application eventually calls someone else's API. In a serverless function, an agent tool call or a webhook handler, that URL is frequently supplied by whoever is on the other end — which makes an ordinary fetch() an untrusted network primitive.
Writing the safe version yourself means re-implementing the same four things in every project: target validation that actually resists SSRF, timeouts that are enforced rather than hoped for, size limits, and a record of what was called. Most teams ship the call and skip the rest.
Backfire exists so the safe version is shorter than the unsafe one: one authenticated POST, one predictable envelope, one log line per attempt.

SSRF is one fetch() away
Timeouts nobody enforces
SSRF is one fetch() away
The URL often comes from a user, a model or a webhook. Resolve it carelessly once and the request lands on a metadata service or an internal admin port.
Timeouts nobody enforces
A slow upstream holds your invocation open, your retry pile doubles, and the failure looks like your bug in production.
Bodies with no ceiling
Without a size bound, one oversized response turns into a memory spike and a page for whoever is on call.
No record of what happened
After an incident, "we called their API" is not an answer. You need the target, the status, the timing and the byte counts.
How it works
Three steps from a key to a guarded call.
- 01
Mint a key
Create an account, open the console and mint a backfire_…_api key. The full value is shown exactly once; only a hash and a display prefix are kept.
- 02
Send one JSON POST
Point your app at the forward endpoint with your key as a bearer token. Name the target, the method, any headers and the body you want forwarded.
- 03
Read the envelope
You get ok, the upstream status and headers, the parsed body, the metering figures and your remaining balance — in one predictable shape.
POST /functions/forward
Authorization: Bearer backfire_…_api
Content-Type: application/json
{
"url": "https://api.github.com/zen",
"method": "GET",
"timeout_ms": 8000
}Nothing else to install. No SDK, no agent to deploy and no egress sidecar. If your runtime can send an HTTPS POST, it can use the relay — which is also why the same key works from Node, Python, Go, a shell script or an edge worker.
The contract
JSON in. JSON envelope out.
Upstream JSON comes back parsed. Anything else comes back as text, or base64 with an encoding flag. Usage is always in the envelope — no separate metering API to poll.
POST /functions/forward
Authorization: Bearer backfire_4c9aE7Qp…_api
{
"url": "https://api.stripe.com/v1/charges",
"method": "POST",
"headers": { "Idempotency-Key": "ord_8123" },
"body": { "amount": 4200, "currency": "usd" },
"timeout_ms": 12000
}{
"ok": true,
"upstream": { "status": 200, "status_text": "OK" },
"body": { "encoding": "json", "json": { "id": "ch_3Pq…" } },
"meta": {
"bytes_in": 96,
"bytes_out": 1482,
"trips_charged": 1,
"duration_ms": 214,
"target_host": "api.stripe.com"
},
"quota": { "remaining": 4999, "unit": "trips" }
}Code
Same three fields in every language.
There is no Backfire SDK to learn. The request is a JSON object with a target, a method and an optional timeout — so the examples below differ only in syntax.
bodyaccepts an object (sent as JSON) or a string (sent as text).body_base64sends binary payloads and takes precedence over body.- Language-specific guides: Node, Python, Go, PHP, Ruby, curl.
curl -sS https://backfireapi.base44.app/functions/forward \
-H "Authorization: Bearer $BACKFIRE_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.github.com/zen",
"method": "GET",
"timeout_ms": 8000
}'Use cases
The calls worth putting behind a guard.
Each one below has its own page with the request shape, the failure modes and the errors you will actually see.
Agent tool calls
AI agents & tool calls
An agent that can call arbitrary URLs is an agent that can be talked into calling your metadata service.
User-supplied URLs
User-supplied URLs
The moment your product fetches a URL a user typed, an attacker controls your outbound request.
Serverless & edge
Serverless egress
Serverless functions make outbound calls in a dozen places, each with its own timeout, its own error handling and no shared record.
Webhook delivery
Webhook delivery
Outbound webhook delivery is outbound HTTP with extra ways to fail: customer endpoints go down, DNS breaks, and every retry needs to be explicable.
Pipelines & backfills
Data pipelines
Pipelines are bursts: quiet for a week, then a hundred thousand calls during a backfill.
Customer integrations
Multi-tenant integrations
When every customer brings their own API endpoint, your outbound code becomes a multi-tenant system with a single point of failure.
MCP & remote tools
MCP servers
An MCP server is a request executor for clients you do not control.
Ingestion & retrieval
RAG ingestion
Retrieval pipelines fetch whatever a source document happens to link to.
Health checks
Uptime monitoring
A monitor is only useful if its failure modes are boring.
Scheduled crawls
Scheduled crawls
A crawl is a loop you leave alone.
Asset pipelines
Asset pipelines
Asset pipelines fetch URLs chosen by users and partners: an avatar link, a storefront image, a scanned receipt.
Testing & CI
Integration tests
Tests that reach real third-party APIs fail for reasons unrelated to your code.
Compare
What you stop rebuilding.
Backfire is not a replacement for your application logic, and it is not an API gateway. It replaces the safety, credential and audit layer around outbound calls — the part that has to be correct before anything else in your integration matters.
SSRF guard on every target
- fetch()
- You build it
- proxy fn
- You build it
- Backfire
- Included
Fails closed on ambiguous DNS
- fetch()
- Depends
- proxy fn
- Depends
- Backfire
- Included
Redirects never auto-followed
- fetch()
- Configure it
- proxy fn
- Configure it
- Backfire
- Default
Bearer keys hashed at rest
- fetch()
- You build it
- proxy fn
- You build it
- Backfire
- Included
Revocation on the next request
- fetch()
- —
- proxy fn
- Redeploy
- Backfire
- One click
Per-call audit log with detail
- fetch()
- —
- proxy fn
- You build it
- Backfire
- Included
Usage metering in the response
- fetch()
- —
- proxy fn
- —
- Backfire
- Included
Bounded payload and timeout
- fetch()
- You set it
- proxy fn
- You set it
- Backfire
- Enforced
Code you own and maintain
- fetch()
- ~10 lines
- proxy fn
- An endpoint + IAM
- Backfire
- One POST
"You build it" means the capability is achievable in your own code — it is simply work you own, test and keep current.

Target safety, checked before the call
- Private, loopback, link-local, multicast and cloud-metadata ranges blocked on IPv4 and IPv6.
- DNS failures and ambiguous answers fail closed rather than guessing.
- Redirects are never followed; a 3xx comes back to you with its location header.
Credentials that are not stored
- Keys are shown once and kept as a SHA-256 hash plus a display prefix.
- Revocation applies to the very next request — no cache window.
- Only the forward endpoint accepts a relay key, so a leaked key cannot read your balance.
Transport that is always encrypted
- Every interaction — sign-in, key management, relays, log reads — travels over HTTPS.
- A request made over plain HTTP is redirected to HTTPS before it is served.
- Keys are compared as hashes, never stored or echoed back in plaintext.
Limits that are enforced, not advisory
- Timeouts capped at 30 seconds and clamped to your value.
- Per-call size allowances keep any single request bounded.
- 600 forwards a minute per key — bursts past that cool down for 10 seconds and are never charged.
- A completed trip leaves its counters and nothing else — target, headers, body and response go the moment it ends.
What Backfire is not: it is not an anonymity layer, not a WAF, and not a replacement for your own application-level allow-lists. Every call is attributable to the key that made it. A refused attempt keeps its full detail — target, redacted headers, reason — so you can audit it; a completed trip keeps its counters and nothing else. None of this has been independently audited, and there is no SLA: these are the controls as implemented, not a certification.
Throughput, stated up front
600 forwards a minute. Then a ten-second breath.
Backfire is not a dumb socket. Every forward is authorised, checked and metered against a ledger on both legs: your key and the target on the way out — the uptrip — and the response, byte counts and the balance that follows on the way back, the downtrip.
That ledger is the whole product. It is why revoking a key stops the very next request, why a loopback or metadata address is refused before a connection ever opens, and why a balance always settles to the exact trip. It runs in its own database, so metering never queues behind anything else the app is doing — the ceiling below is capacity, not a shared budget.
So each key gets a burst budget of 600 forwards per rolling minute, and each account 1,200, spendable all at once. Cross it and the call comes back immediately with 429 rate_limited and a retry_after_seconds of 10 — one ten-second cooldown, then try again. Nothing is sent upstream, nothing is metered, and the minute keeps draining while you wait.
And nothing about the trip outlives it. There is no trace log and no retained copy: the target, the headers, the body you sent and the answer that came back are wiped the instant the roundtrip completes, so the only thing that survives is its counters — host, status, byte counts and trips.
in a rolling minute — the whole budget can go at once
handed back on every refusal as retry_after_seconds
no upstream connection is opened at all
the refusal
{ "ok": false,
"error": { "code": "rate_limited" },
"retry_after_seconds": 10 }Need to move faster than 600 a minute? Three patterns keep real traffic comfortably inside the budget:
Queue, do not fan out
One worker per key with a short pause between calls stays inside the burst budget for as long as you like — 600 a minute sustained, indefinitely.
Batch upstream
Most APIs accept many items per request. One forward carrying ten records is one trip and one ledger entry, not ten of each.
Stream it instead
Anything long-lived belongs on the socket bridge: one ticket holds the connection open and relays frames, instead of one forward per message.
Why it exists
Controlled execution, not a workflow builder.
The hard parts of running an outbound relay are safety, metering and revocation. That is the whole feature list.
SSRF-guarded by default
Every target is resolved and checked against private, loopback, link-local and cloud-metadata ranges on IPv4 and IPv6. Ambiguous DNS fails closed.
Keys hashed at rest
backfire_…_api keys are shown once, stored as a one-way hash plus a display prefix. Revocation takes effect on the very next request.
A balance, not invoices
Top up once with a pack that never expires. No subscription, no seats, no renewal date — and the console shows what every call drew.
Redirects off
We do not chase hops for you. Hop-by-hop headers are stripped, CR/LF is rejected, and unsafe upstream behavior stays off unless you ask for it.
Capped everywhere
Bounded payloads, a 30 second ceiling, per-key and per-account rate limits. Predictable failure beats an open relay.
Audit trail, in the open
Every call, deny and key change is logged line by line with its full detail — readable in the dashboard and exportable as JSON, CSV or Markdown.
Backfire is
- An authenticated HTTP relay for developers
- One endpoint, bearer keys, a balance you top up
- A safety layer in front of your outbound calls
- Infrastructure you can revoke in one click
Backfire is not
- An anonymous open proxy
- A browser extension or consumer link tool
- A full enterprise API gateway
- A place where you upload proxy code for us to run
Billing
A balance,
not a bill.
Your account carries a balance of trips. One trip is one complete roundtrip: your request goes up, the answer comes back down, and the trip is spent once. Everything you have left stays yours.
What one trip is
One uptrip carries your request to the target, one downtrip carries its answer back. A call that reaches the network draws one trip; a request rejected before it does draws none.

Rejected requests cost nothing
A bad key, a blocked target, a rate limit or an oversized body never touches your balance.
Completed calls are charged once
One trip is one complete roundtrip — an uptrip out and a downtrip back. The exact draw is written into the envelope and the log.
The balance never expires
Top up once and spend it whenever, across every key on the account. No renewal, no seats, nothing to cancel.
FAQ
Questions developers actually ask.
If something is not answered here, the reference covers the request shape, the envelope and every error code in detail.
Read the documentation →Go deeper
Pick the page that matches your problem.
Use cases
Agents, MCP servers, user URLs, crawls, CI — twelve pages
Works with
Vercel, Cloudflare Workers, Lambda, GitHub Actions, n8n
Comparisons
Against a raw fetch, your own function, inbound tunnels
Language guides
Node, Python, Go, PHP, Ruby and plain curl
Error reference
Every code, what caused it and how to fix it
Documentation
The request shape, envelope, limits and playground
Start with 5,000 free trips
Point your app at one endpoint.
Mint a key, run a forward, read the envelope. Most developers get their first 200 back in under five minutes.