For AI agents: this page is also available as Markdown at https://docs.refabric.com/task-apis/calling-tasks/proxy-setup.md, and the index of every page is https://docs.refabric.com/llms.txt.
Task APIs › Calling tasks
Proxy setup
Let a browser or mobile app use Refabric through your own server, without ever holding your API key.
Keys are for servers: the API refuses any request that carries an Origin header
with 403 api_key_not_allowed_here. A web or mobile app therefore talks to your server, and your
server calls Refabric with the key. The examples below are complete enough to adapt.
How it works
your app ──(your login)──▶ your proxy ──(Authorization: Key …)──▶ https://api.refabric.com- Your app calls your proxy with your user's credentials (a sign-in cookie, a token).
- The proxy checks that user, checks the request against what you allow, and forwards it to Refabric with the API key added.
- The proxy returns Refabric's answer to the app.
Two rules make the forward work:
- Add the key on the server —
Authorization: Key $REFABRIC_API_KEYfrom the environment. - Do not forward the browser's
Originheader. A keyed request that reaches Refabric with it is refused. Send only the headers you choose:Authorization,Content-Type, andIdempotency-KeyorPreferwhen you use them.
Express
import express from "express";
const API = "https://api.refabric.com/v1";
const ALLOWED_TASKS = new Set(["image.change_background", "image.upscale"]);
const app = express();
app.use(express.json());
const forward = async (res, path, init = {}) => {
const r = await fetch(`${API}${path}`, {
...init,
headers: { Authorization: `Key ${process.env.REFABRIC_API_KEY}`, "Content-Type": "application/json", ...init.headers },
});
res.status(r.status).type("application/json").send(await r.text());
};
app.post("/api/refabric/tasks/:name", requireUser, async (req, res) => {
if (!ALLOWED_TASKS.has(req.params.name)) return res.status(403).json({ error: "task not allowed" });
await forward(res, `/tasks/${req.params.name}`, {
method: "POST",
body: JSON.stringify(req.body),
headers: { "Idempotency-Key": req.get("Idempotency-Key") ?? crypto.randomUUID() },
});
});
app.get("/api/refabric/jobs/:id", requireUser, (req, res) => forward(res, `/jobs/${encodeURIComponent(req.params.id)}`));
app.get("/api/refabric/jobs/:id/result", requireUser, (req, res) => forward(res, `/jobs/${encodeURIComponent(req.params.id)}/result`));
app.listen(3001);requireUser is your own authentication middleware.
Next.js (route handler)
// app/api/refabric/tasks/[name]/route.js
const API = "https://api.refabric.com/v1";
const ALLOWED_TASKS = new Set(["image.change_background", "image.upscale"]);
export async function POST(request, { params }) {
const user = await currentUser(request); // your own sign-in check
if (!user) return Response.json({ error: "sign in" }, { status: 401 });
if (!ALLOWED_TASKS.has(params.name)) return Response.json({ error: "task not allowed" }, { status: 403 });
const r = await fetch(`${API}/tasks/${params.name}`, {
method: "POST",
headers: {
Authorization: `Key ${process.env.REFABRIC_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": request.headers.get("Idempotency-Key") ?? crypto.randomUUID(),
},
body: await request.text(),
});
return new Response(await r.text(), { status: r.status, headers: { "Content-Type": "application/json" } });
}What your proxy must check
| Check | Why |
|---|---|
| Task allowlist | forward only the tasks your app uses; everything else is refused by you |
| End-user authentication | only your signed-in users reach the proxy |
| Per-user rate limit | one user cannot spend your whole Refabric rate or balance |
| Job ownership | a user reads only the jobs they started — keep the job_id with your user |
| Body size | refuse bodies larger than your app sends |
An open proxy spends your credits. Anyone who finds a proxy without authentication and an allowlist can run any task on your balance. Every job it starts is yours, charged to your account.