fal proxy with x-fal-target-url vs keeping a Sume key on your server
fal documents an 8-step proxy that reads x-fal-target-url and adds a Key header. Sume has no browser SDK: you proxy your own route. A minimal comparison.

fal's server-side integration page says plainly that "exposing API keys in client-side code is not safe" and gives you ready-made proxies plus an eight-step recipe for writing your own. Sume's position is the same, but the shape differs: Sume documents a server-side proxy pattern where your backend calls a fixed Sume endpoint, not a generic forwarder that takes the target from a header.
That difference is worth understanding before you copy a fal-style proxy to a Sume project.
What is fal's proxy pattern?
The fal page lists these steps for a custom proxy: one endpoint (for example /api/fal/proxy) accepting GET and POST; 405 for other methods; read the target URL from the x-fal-target-url header, with 400 if it is missing and 412 if the domain is not *.fal.ai or *.fal.run; 415 for non-JSON bodies; add an authorization header formatted Key <your-api-key> from the FAL_KEY environment variable; return the response body, status code and headers unchanged except content-length and content-encoding. The client library is then pointed at it with fal.config({ proxyUrl: "/api/fal/proxy" }).
So fal's proxy is a generic, allow-listed forwarder: the browser client decides which fal endpoint to call, and the proxy only checks the host.
What does Sume document instead?
Sume's authentication page says browser and mobile clients should call your backend and your backend attaches the key. Keys are workspace-scoped, the secret is shown once at creation, and the example is a route that posts to one fixed endpoint, https://api.sume.com/v1/avatar-1.0/generate, with a fresh Idempotency-Key. The docs add: validate input and enforce your own authorization before forwarding.
There is no Sume client-side proxy library and no proxyUrl configuration in the docs. If you want fal's generic-forwarder shape you would write it yourself, and the allow-list would be your responsibility.
| Aspect | fal docs | Sume docs |
|---|---|---|
| Who picks the upstream endpoint | Browser client, via x-fal-target-url | Your server code, fixed per route |
| Host check | 412 unless *.fal.ai or *.fal.run | Not needed with a fixed URL |
| Auth header added | Key <FAL_KEY> | Authorization: Bearer or x-api-key, one only |
| Prebuilt proxies | Next.js and Express handlers | None documented |
| Retry safety | Not covered on this page | Idempotency-Key on paid submits |
How do I write the Sume version?
This route handler follows the docs pattern. It forwards a body to one endpoint and generates a key per call. For real use, add your own auth check and validate the body before this line, as the docs ask.
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch("https://api.sume.com/v1/videos", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify(body),
});
return new Response(await response.text(), {
status: response.status,
headers: { "Content-Type": "application/json" },
});
}What can go wrong with the Sume proxy?
Three things from the docs. First, send exactly one credential: a request carrying both Authorization: Bearer and x-api-key is rejected with 401, which bites gateways that add their own header. Second, a fresh UUID per call means a client retry creates a second paid job; if your browser retries, derive the key from something stable such as a client-generated request id. Third, a forwarding proxy that passes the user's body straight through lets any signed-in user pick any model and duration, so cap fields before you forward.
What should I take from this?
Both vendors say the same thing: keep the key on a server. fal gives you a generic proxy and a client library that speaks to it; Sume gives you a pattern and expects you to write a narrow route. The narrow route is less convenient and easier to audit.
For key hygiene beyond the proxy, including rotation and scopes, see Sume authentication and key sprawl and rotation.
Sources
Related posts
More in Comparisons
- fal's hint pins a runner; Sume has no runner choice
fal's queue submit takes a hint that routes to the runner used before. Sume hides providers and runners. What to do when you need affinity.
- fal queue has no size limit: what Sume does instead (queue_full)
fal's queue docs say there is no queue size limit and requests are never dropped. Sume caps accepted jobs per plan and returns 429 queue_full. What that means.
- fal low priority and start_timeout vs Sume queue-first admission
fal queues accept a low priority and a start_timeout that 504s. Sume has neither: it queues by plan and rejects with queue_full. What to do when work must wait.
- fal queue_position and logs vs Sume job status, events, usage
fal returns queue_position, runner logs and inference_time. Sume gives status, an events timeline and per-job usage. Which one tells you why a job is slow?
Written by Sume