ProxyBridge API Docs
ProxyBridge lets you route any HTTP request through it to bypass CORS and normalize responses. These docs show you exactly how to call your backend through ProxyBridge from any frontend app.
What is ProxyBridge?
ProxyBridge is a deployed HTTP relay server. Instead of calling your backend API directly from the browser (which often causes CORS errors), you send your request to ProxyBridge and it forwards it to your real API, then returns the response back to you in a clean, consistent shape.
Your Frontend
| fetch("https://proxybridge.focket.app/api/relay/users")
|
v
ProxyBridge --> https://api.yourbackend.com/users
^ |
+------------------------+
normalized responseURL Structure
Every request follows this single pattern.
https://proxybridge.focket.app/api/relay/<your-api-path> ?webUrl=<your-frontend-origin> &baseApiUrl=<your-backend-base-url> &[...any other query params forwarded to backend]
| Part | What it is |
|---|---|
| https://proxybridge.focket.app | The root URL of this ProxyBridge instance (this server) |
| <your-api-path> | The path on your backend API, e.g. users/123 or products |
| webUrl | Your frontend origin -- ProxyBridge uses this to set the CORS header on the response |
| baseApiUrl | The root URL of the backend you want to reach, e.g. https://api.example.com |
| ...rest | Any extra query params are passed through transparently to your backend |
Make Your First Call
Say your ProxyBridge is at https://proxybridge.focket.app, your frontend runs at https://myapp.com, and you want to hit GET https://api.example.com/users.
const PROXY = 'https://proxybridge.focket.app';
const WEB_URL = 'https://myapp.com';
const API_BASE = 'https://api.example.com';
const res = await fetch(
`${PROXY}/api/relay/users` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}`
);
const data = await res.json();
// data.success -> true
// data.data -> the actual payload from your backend
// data.meta -> pagination info (if any)
console.log(data.data);Query Parameters
These are the special parameters ProxyBridge reads. All others are forwarded to your backend.
| Parameter | Required | Description |
|---|---|---|
| webUrl | Required | Your frontend origin URL. ProxyBridge echoes this back in Access-Control-Allow-Origin so the browser allows the response. |
| baseApiUrl | Required | The base URL of your actual backend. ProxyBridge appends the relay path to this and makes the upstream call. |
| acceptHeadersKey | Optional | Comma-separated list of request header names to forward on to the upstream API. Useful for authorization or custom headers. |
| ...anything else | Optional | Any other query params are passed through directly to your backend -- page, limit, search, etc. |
Forwarding Headers
Need to send an Authorization token or a custom header to your backend? Use acceptHeadersKey.
By default, ProxyBridge automatically forwards standard browser headers (Accept, Content-Type, Origin, etc.). To also forward headers like Authorization, pass them by name in acceptHeadersKey.
const res = await fetch(
`${PROXY}/api/relay/orders` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}` +
`&acceptHeadersKey=authorization`, // tell ProxyBridge to forward this header
{
headers: {
Authorization: 'Bearer eyJhbGci...', // your token
},
}
);Passing Query Params to Your Backend
Filtering, pagination, search -- just add them and they flow through.
Any query param that isn't webUrl, baseApiUrl, or acceptHeadersKey is forwarded verbatim to your backend.
// Calls: https://api.example.com/products?page=2&limit=20&search=shoes&category=sport
const params = new URLSearchParams({
webUrl: WEB_URL,
baseApiUrl: API_BASE,
// these go straight to your backend:
page: '2',
limit: '20',
search: 'shoes',
category: 'sport',
});
const res = await fetch(`${PROXY}/api/relay/products?${params}`);
const { data, meta } = await res.json();
console.log(meta.total); // total records
console.log(data); // products arrayPOST / PUT / PATCH / DELETE
Mutation requests work exactly like GET -- add a body and change the method.
All mutation methods follow the same pattern. Each has its own section below with a direct link.
POST
Create a new resource on your backend.
const res = await fetch(
`${PROXY}/api/relay/users` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}` +
`&acceptHeadersKey=authorization`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGci...',
},
body: JSON.stringify({
name: 'Jane Doe',
email: 'jane@example.com',
}),
}
);
const result = await res.json();
// result.success -> true
// result.data -> created user objectPUT
Replace an entire resource on your backend.
const res = await fetch(
`${PROXY}/api/relay/users/42` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}` +
`&acceptHeadersKey=authorization`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGci...',
},
body: JSON.stringify({
name: 'Updated Name',
isActive: true,
}),
}
);
const result = await res.json();PATCH
Partially update a resource -- only send the fields you want to change.
const res = await fetch(
`${PROXY}/api/relay/users/42` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}` +
`&acceptHeadersKey=authorization`,
{
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGci...',
},
body: JSON.stringify({
// only the fields you want to update
isActive: false,
}),
}
);
const result = await res.json();DELETE
Remove a resource from your backend.
const res = await fetch(
`${PROXY}/api/relay/users/42` +
`?webUrl=${encodeURIComponent(WEB_URL)}` +
`&baseApiUrl=${encodeURIComponent(API_BASE)}` +
`&acceptHeadersKey=authorization`,
{
method: 'DELETE',
headers: {
Authorization: 'Bearer eyJhbGci...',
},
}
);
const result = await res.json();
if (result.success) {
console.log('Deleted');
}Response Shape
Every response from ProxyBridge has the same consistent envelope, regardless of what your backend returns.
Success (2xx)
{
"success": true,
"statusCode": 200,
"message": "Successfully Retrieved!",
"meta": {
"total": 100,
"page": 1,
"limit": 20,
"skip": 0
},
"data": [ ...your items... ]
}Error (4xx / 5xx)
{
"success": false,
"statusCode": 404,
"message": "Not Found",
"meta": null,
"data": null
}| Field | Type | Description |
|---|---|---|
| success | boolean | true when the upstream responded with a 2xx status code. |
| statusCode | number | The exact HTTP status code returned by your backend. |
| message | string | A message from your backend, or a default like "Successfully Retrieved!". |
| meta | object | null | Pagination info (total, page, limit, skip) when your backend includes it. |
| data | any | The actual payload your backend returned -- array, object, etc. |
Tip: Always check data.success or res.ok before consuming data.data -- if the upstream call fails, data.data will be null.
Error Handling
Errors from ProxyBridge itself (not your backend) use these status codes.
| Status | When | message |
|---|---|---|
| 400 | webUrl or baseApiUrl is missing | Missing required query parameters: web url or api url |
| 500 | Your backend returned HTML instead of JSON (e.g. a login redirect or error page) | Expected JSON but received non-JSON (likely HTML). |
| 500 | Network error or unexpected crash inside ProxyBridge | Server Error |
Errors from your own backend (e.g. 401 Unauthorized, 404 Not Found) are passed through transparently — success will be false and statusCode will match your backend's response.
TypeScript Types
Import these types to get full type safety when consuming ProxyBridge responses.
// The envelope every ProxyBridge response returns
interface IBaseResponse<D = any> {
success: boolean;
statusCode: number;
message: string;
meta: IMetaResponse | null;
data: D;
}
// Pagination metadata (present when your backend sends it)
interface IMetaResponse {
total: number;
page: number;
limit: number;
skip: number;
}
// Usage example ----------------------------------------
interface User {
id: string;
name: string;
email: string;
}
const res = await fetch(url);
const result: IBaseResponse<User[]> = await res.json();
if (result.success) {
const users: User[] = result.data; // fully typed :)
}