Web-to-OpenAI-compatible API reverse proxy for FreeModels.Pro. Bridge web chat interfaces into a universal OpenAI API gateway with Agent Tool Calling, Prompt Coercion, and Reasoning Traces across Claude Code, Codex, Cursor, Antigravity and more.
Overview • Features • Quick Start • Models • Clients • Architecture • Guides • Disclaimer • License
- What is Web2API?
- Key Features
- Quick Start
- Model Catalog & Aliases
- Client Integration
- Architecture & Structure
- Advanced Guides
- Development & Testing
- Disclaimer & Legal Notice
- License
Web chat platforms (such as FreeModels.Pro) provide free access to high-end frontier models like Claude Sonnet 5, Claude Fable 5, GPT 5.6 Sol, GPT 5.6 Terra, GLM 5.2, and Kimi K3. However, these platforms do not offer developer APIs or standard OAuth client credentials.
Modern coding agents like Claude Code, Codex, Cursor, Antigravity, OpenCode, etc require an OpenAI-compatible API exposing /v1/chat/completions with support for structured JSON tool/function calling.
Web2API bridges this gap:
- It acts as an intermediary reverse proxy that intercepts requests from coding agents, translates tool specifications into strict plain-text system directives, and forwards requests to the target web backend (
https://freemodels-chat.freemodels.workers.dev/). - It parses and sanitizes raw model output, stripping markdown code fences (
```json ... ```) and conversational preambles to reliably construct OpenAItool_callspayloads. - It supports full Server-Sent Events (SSE) streaming with real-time text delivery,
reasoning_content(thinking trace) forwarding, and smart tool buffering. - It features a dual-runtime architecture: run locally as a zero-dependency Node.js Daemon (
http://localhost:8000) or deploy as a standalone Cloudflare Worker (worker.js).
Disclaimer: This tool is provided strictly for personal educational and interoperability testing purposes. See Disclaimer & Legal Notice.
- Unlock Free Web Models for Agents: Access
claude-sonnet-5,claude-fable-5,sol(GPT 5.6 Sol),terra(GPT 5.6 Terra),glm-5.2, andkimi-k3directly from coding agents. - Dual Operational Modes:
- Local Daemon: Runs on
http://localhost:8000via@hono/node-serverwith instant NPX execution or global CLI install. - Cloudflare Worker: Standalone 82 KB bundle (
worker.js) ready for copy-paste into the Cloudflare Dashboard or deployment via Wrangler.
- Local Daemon: Runs on
- Smart Tool Coercion: Converts OpenAI
toolsdefinitions into strict system instructions, enforcing pure JSON output across web models that lack native function-calling APIs. - Resilient JSON Extractor: Strips markdown fences, extracts outer
{...}or[...]blocks via balanced-brace parsing, and repairs unescaped newlines in diffs. - Streaming SSE with Reasoning Delta: Preserves thinking traces in
delta.reasoning_contentfor real-time rendering in assistants like MiMoCode and Cline. - Upstream Error Normalization: Detects 429 key exhaustion responses (
All providers exhausted. Retry in 20s...) and wraps them in OpenAI-standard error envelopes withRetry-Afterheaders. - Safe & Resource-Bounded:
- Client disconnect cancellation via
AbortSignal. - Browser header emulation (
Origin,Referer,User-Agent) to prevent upstream filtering.
- Client disconnect cancellation via
Run the local proxy daemon immediately with no clone or install needed:
npx web2api-proxyOr with custom port and API key:
npx web2api-proxy start --port 8080 --key sk-my-secretTest upstream connectivity and models:
npx web2api-proxy checkInstall globally to make the web2api command available anywhere on your system:
npm install -g web2api-proxyThen run:
web2api start
web2api check
web2api --help| Flag | Shorthand | Environment Variable | Default | Description |
|---|---|---|---|---|
--port |
-p |
PORT |
8000 |
Port for the local server |
--host |
HOST |
127.0.0.1 |
Host address to bind to | |
--key |
-k |
API_KEY |
(None) | Require Bearer API key authentication |
--upstream |
-u |
UPSTREAM_URL |
https://freemodels-chat... |
Target web chat backend URL |
--model |
-m |
DEFAULT_MODEL |
claude-sonnet-5 |
Default model fallback |
--help |
-h |
Show CLI help and options | ||
--version |
-v |
Show installed version |
git clone https://github.com/IMROVOID/Web2API.git
cd Web2API
npm install
npm run devYour local endpoint is available at http://localhost:8000/v1. Default API key for all clients is sk-web2api-local (or any string when API_KEY is not set).
Deploy a 24/7 serverless gateway without keeping your computer running.
npm run buildThis compiles the standalone zero-dependency bundle to worker.js in the project root.
- Log into the Cloudflare Dashboard.
- Go to Workers & Pages -> Create application -> Create Worker.
- Set the name to
web2apiand click Deploy. - Click Edit code, select all existing code, delete it, and paste the entire copied contents of
worker.js. - Click Deploy in the top right.
In your Worker, go to Settings -> Variables and Secrets and add:
| Variable | Type | Required | Default | Description |
|---|---|---|---|---|
API_KEY |
Secret | Optional | (None) | Client authorization bearer key (e.g. sk-web2api-local). If unset, access is open. |
UPSTREAM_URL |
Text | Optional | https://freemodels-chat.freemodels.workers.dev |
Upstream web chat backend endpoint |
DEFAULT_MODEL |
Text | Optional | claude-sonnet-5 |
Default model when unspecified |
Click Save and deploy.
Your Cloudflare Worker API URL:
https://web2api.<your-subdomain>.workers.dev/v1
If you prefer deploying via the command line:
npx wrangler deployWeb2API automatically maps requested model aliases to canonical upstream models:
| Request Model Alias | Canonical Upstream Model | Provider | Strengths | Type |
|---|---|---|---|---|
claude-sonnet-5, claude-3-5-sonnet, claude-3-sonnet, claude-3-opus |
claude-sonnet-5 |
Anthropic | Thinking, Coding, Analysis | Reasoning |
sol, gpt-4o-mini, claude-3-5-haiku |
sol |
OpenAI | High Speed, Conversational | Fast |
terra, gpt-4o, gpt-4 |
terra |
OpenAI | Deep Reasoning, Math, Science | Reasoning |
claude-fable-5 |
claude-fable-5 |
Anthropic | Creative Writing, Long Form | Creative |
claude-fable-5.1 |
claude-fable-5.1 |
Anthropic | Agentic Coding, Deep Research | Creative |
glm-5.2, glm-4 |
glm-5.2 |
Z.AI | Bilingual, Tools, Knowledge | Pro |
kimi-k3, kimi |
kimi-k3 |
Moonshot AI | 200K+ Context Window, Recall | Long Context |
Note
Architecture Reality Check: While FreeModels.Pro labels its chat options with names like "Claude Sonnet 5", "Claude Fable 5", "GPT 5.6 Sol", "GPT 5.6 Terra", "GLM 5.2", and "Kimi K3", network analysis and response inspection confirm that all requests are actually served by a single open-weights model: nvidia/nemotron-3-super-120b-a12b (hosted via Nvidia NIM / DashScope provider pools).
- Persona Conditioning: The upstream Cloudflare Worker injects system personas instructing the Nemotron model to roleplay as the requested target model. This can be observed directly in the
reasoning_content(thinking trace) chunks where the model references its persona instructions. - Still Completely Usable & Capable: Despite the marketing names, the service is still completely usable and surprisingly capable. With ~120 billion parameters,
nemotron-3-super-120b-a12bis a high-parameter open-weights reasoning model that delivers:- Strong code generation, refactoring, and multi-step logic.
- Native reasoning/thinking traces (
reasoning_content) for transparent chain-of-thought. - High inference throughput and low latency.
- Web2API Bridging: Web2API makes this backend fully compatible with coding agents (MiMoCode, Aider, Claude Code, Cline, Cursor) by handling prompt coercion and JSON extraction so tool calling works reliably regardless of the underlying roleplay persona.
More Info: Full Reverse Engineering & Model Reality Analysis →
Note: For all clients below, replace
http://localhost:8000/v1with your Cloudflare Worker URL (https://web2api.<your-subdomain>.workers.dev/v1) if using serverless deployment. The default API key issk-web2api-local.
9Router
Configuration file path:
~/.9router/db.json
Or configure via Web Dashboard under Providers -> Add Custom Provider:
- Provider Type:
openai - Base URL:
http://localhost:8000/v1 - API Key:
sk-web2api-local - Models:
claude-sonnet-5, terra, sol, glm-5.2, kimi-k3
Configuration entry for ~/.9router/db.json:
{
"providers": [
{
"id": "web2api",
"name": "Web2API",
"type": "openai",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"models": [
"claude-sonnet-5",
"terra",
"sol",
"glm-5.2",
"kimi-k3"
]
}
]
}Aider
Configuration file path:
.aider.conf.yml
Add configuration:
openai-api-base: http://localhost:8000/v1
openai-api-key: sk-web2api-local
model: openai/claude-sonnet-5Or run via CLI:
aider --openai-api-base http://localhost:8000/v1 \
--openai-api-key sk-web2api-local \
--model openai/claude-sonnet-5Antigravity (AGY)
Configuration file path:
~/.gemini/antigravity/antigravity.json
Add configuration:
{
"modelProviders": {
"web2api": {
"type": "openai",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"defaultModel": "claude-sonnet-5"
}
}
}Cherry Studio
Configuration file path:
~/.cherry-studio/config.json
Or configure via UI in Settings -> Providers -> OpenAI:
- Custom Server Address:
http://localhost:8000/v1 - API Key:
sk-web2api-local - Models:
claude-sonnet-5,terra,sol,glm-5.2,kimi-k3
Claude Code
Configuration file path (Global):
~/.claude/settings.json
Configuration file path (Project-level):
.claude/settings.json
Add configuration:
{
"env": {
"OPENAI_BASE_URL": "http://localhost:8000/v1",
"OPENAI_API_KEY": "sk-web2api-local",
"ANTHROPIC_MODEL": "claude-sonnet-5"
}
}Then run:
claudeCline
Configuration file path:
.vscode/settings.json
Add configuration:
{
"cline.apiProvider": "openai-compatible",
"cline.openAiBaseUrl": "http://localhost:8000/v1",
"cline.openAiApiKey": "sk-web2api-local",
"cline.openAiModelId": "claude-sonnet-5"
}Codex
Configuration file path:
~/.codex/config.toml
Add configuration:
[model]
provider = "openai"
base_url = "http://localhost:8000/v1"
api_key = "sk-web2api-local"
model_name = "claude-sonnet-5"Continue.dev
Configuration file path:
~/.continue/config.json
Add configuration:
{
"models": [
{
"title": "Claude Sonnet 5 (Web2API)",
"provider": "openai",
"model": "claude-sonnet-5",
"apiBase": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local"
},
{
"title": "GPT 5.6 Terra (Web2API)",
"provider": "openai",
"model": "terra",
"apiBase": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local"
}
]
}Cursor
Configuration file path (Global):
~/.cursor/User/settings.json
Configuration file path (Project-level):
.vscode/settings.json
Add configuration:
{
"cursor.openaiBaseUrl": "http://localhost:8000/v1",
"cursor.openaiApiKey": "sk-web2api-local",
"cursor.model": "claude-sonnet-5"
}Or configure in Cursor Settings -> Models:
- Toggle Override OpenAI Base URL:
http://localhost:8000/v1 - Set OpenAI API Key:
sk-web2api-local - Add model:
claude-sonnet-5
DeepSeek Harness
Configuration file path:
agent.yaml
Add configuration:
llm:
api_type: openai
base_url: "http://localhost:8000/v1"
api_key: "sk-web2api-local"
model: "claude-sonnet-5"
temperature: 0.7Hermes
Configuration file path:
~/.hermes/config.json
Add configuration:
{
"llm": {
"provider": "openai",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"model": "claude-sonnet-5"
}
}LibreChat
Configuration file path:
librechat.yaml
Add configuration:
endpoints:
custom:
- name: "Web2API"
apiKey: "sk-web2api-local"
baseURL: "http://localhost:8000/v1"
models:
default: ["claude-sonnet-5", "terra", "sol", "glm-5.2", "kimi-k3"]
titleConvo: true
modelDisplayLabel: "Web2API"MiMo Code CLI
Configuration file path (Linux / macOS):
~/.local/share/mimocode/mimocode.jsonc
Configuration file path (Windows):
%LOCALAPPDATA%\mimocode\data\mimocode.jsonc
Add configuration:
Or run mimo, select Custom Provider, and set:
- Base URL:
http://localhost:8000/v1 - API Key:
sk-web2api-local - Model:
claude-sonnet-5
NextChat (ChatGPT-Next-Web)
Configuration file path:
.env.local
Add configuration:
BASE_URL=http://localhost:8000
OPENAI_API_KEY=sk-web2api-local
CUSTOM_MODELS=-all,+claude-sonnet-5,+terra,+sol,+glm-5.2,+kimi-k3OmniRoute
Configuration file path:
~/.omniroute/providers.json
Add configuration via CLI:
omniroute provider add --id web2api --type openai --base-url http://localhost:8000/v1 --api-key sk-web2api-local --models claude-sonnet-5,terra,sol,glm-5.2,kimi-k3Or add configuration to ~/.omniroute/providers.json:
{
"providers": [
{
"id": "web2api",
"name": "Web2API Gateway",
"type": "openai-compatible",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"models": [
"claude-sonnet-5",
"terra",
"sol",
"glm-5.2",
"kimi-k3"
]
}
]
}OpenAI Compatible (Generic / SDKs)
Configuration file path:
.env
Add environment configuration:
OPENAI_BASE_URL="http://localhost:8000/v1"
OPENAI_API_KEY="sk-web2api-local"Python SDK example:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="sk-web2api-local"
)
response = client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Write quicksort in Python."}],
stream=True
)
for chunk in response:
content = chunk.choices[0].delta.content or ""
print(content, end="", flush=True)Node.js SDK example:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://localhost:8000/v1",
apiKey: "sk-web2api-local",
});
const response = await client.chat.completions.create({
model: "claude-sonnet-5",
messages: [{ role: "user", content: "Write quicksort in TypeScript." }],
});
console.log(response.choices[0].message.content);cURL command:
curl -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-web2api-local" \
-d '{"model":"claude-sonnet-5","messages":[{"role":"user","content":"Hello!"}]}'OpenClaw
Configuration file path:
openclaw.json
Add configuration:
{
"providers": {
"web2api": {
"type": "openai-compatible",
"baseURL": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"models": [
"claude-sonnet-5",
"terra",
"sol",
"glm-5.2",
"kimi-k3"
]
}
}
}OpenCode
Configuration file path (Linux / macOS):
~/.local/share/opencode/opencode.jsonc
Configuration file path (Project-level):
opencode.jsonc
Add configuration:
{
"providers": {
"web2api": {
"type": "openai-compatible",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"models": [
"claude-sonnet-5",
"terra",
"sol",
"glm-5.2",
"kimi-k3"
]
}
},
"default_model": "web2api/claude-sonnet-5"
}OpenHands (OpenDevin)
Configuration file path:
config.toml
Add configuration:
[llm]
model = "openai/claude-sonnet-5"
base_url = "http://localhost:8000/v1"
api_key = "sk-web2api-local"Roo Code
Configuration file path:
.vscode/settings.json
Add configuration:
{
"roo-cline.apiProvider": "openai-compatible",
"roo-cline.openAiBaseUrl": "http://localhost:8000/v1",
"roo-cline.openAiApiKey": "sk-web2api-local",
"roo-cline.openAiModelId": "claude-sonnet-5"
}Trae (ByteDance Agentic IDE)
Configuration file path:
~/.trae/config.json
Add configuration:
{
"modelProviders": [
{
"name": "Web2API",
"apiType": "openai",
"endpoint": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"models": [
"claude-sonnet-5",
"terra",
"sol",
"glm-5.2",
"kimi-k3"
]
}
]
}Windsurf
Configuration file path:
~/.codeium/windsurf/model_config.json
Add configuration:
{
"customOpenAI": {
"endpoint": "http://localhost:8000/v1",
"apiKey": "sk-web2api-local",
"model": "claude-sonnet-5"
}
}Web2API/
├── .github/
│ └── workflows/
│ └── test.yml # Automated CI test & typecheck workflow
├── src/
│ ├── types.ts # OpenAI schemas, upstream contracts, model definitions
│ ├── config.ts # Model catalog, aliases, browser headers, defaults
│ ├── services/
│ │ ├── prompt-coercer.ts # Transforms tools into strict JSON system directives
│ │ ├── json-extractor.ts # Strips markdown fences, parses JSON, formats tool_calls
│ │ ├── upstream-client.ts # HTTP client with browser headers and error parsing
│ │ └── stream-transformer.ts# Real-time SSE transformer with reasoning_content
│ ├── routes/
│ │ ├── chat.ts # /v1/chat/completions handler (streaming & tool calls)
│ │ ├── models.ts # /v1/models catalog handler
│ │ └── health.ts # /health service status endpoint
│ ├── index.ts # Universal Hono application instance (CORS & routes)
│ └── server.ts # Local Node.js server launcher (@hono/node-server)
├── worker.js # Standalone Cloudflare Workers bundle (82 KB)
├── dist/
│ └── server.js # Standalone Node.js server bundle (102 KB)
├── docs/
│ ├── Underlying_Model_Reality.md # Nemotron-3 120B reality & trace evidence
│ ├── Freemodels_Reverse_Engineering.md # Upstream architecture analysis
│ ├── Web2API_MVP_Architecture.md # Technical architecture spec
│ └── Web2API_Proxy.md # Original design guide
├── tests/ # 18 automated unit and integration tests
├── public/
│ └── Web2API_Banner.webp # Repository header banner
├── wrangler.toml # Cloudflare Workers configuration
├── package.json # Dependencies and build scripts
└── tsconfig.json # Strict TypeScript configuration
Because web frontends lack native tool_choice or function calling APIs, Web2API coerces tools into an explicit JSON contract:
-
Schema Injection: Injects tool parameters and format rules into the message context:
{ "name": "tool_name", "arguments": { ... } } -
Negative Prompting: Instructs the model to emit only valid JSON without markdown code fences (
```json), conversational greetings, or postscripts. -
History Normalization: Serializes previous assistant tool calls and formats tool result messages so the model maintains multi-turn reasoning context.
To handle non-compliant model outputs:
- Fence Removal: Regex stripping of
json .... - Balanced-Brace Matching: Scans for outermost
{...}or[...]structures. - Repair Pipeline: Fixes unescaped newlines in diffs and strips trailing commas before
}or]. - Validation: Confirms presence of
nameandarguments, constructing standard OpenAItool_callspayloads with unique identifiers (call_...).
The upstream backend aggregates API keys from Nvidia NIM and DashScope. When keys run out of quota:
-
Upstream returns:
{"error": "All providers exhausted. Retry in 20s..."} -
Web2API parses the duration, sets the
Retry-After: 20header, and wraps the error in an OpenAI standard format:{ "error": { "message": "All providers exhausted. Retry in 20s...", "type": "rate_limit_error", "code": 429 } }
| Variable | Mode | Default | Description |
|---|---|---|---|
PORT |
Local | 8000 |
Local HTTP daemon port |
API_KEY |
Both | (None / sk-web2api-local) | Optional client authorization bearer token. If unset, access is open. |
UPSTREAM_URL |
Both | https://freemodels-chat.freemodels.workers.dev |
Upstream web chat backend endpoint |
DEFAULT_MODEL |
Both | claude-sonnet-5 |
Default model when unspecified |
Run TypeScript typecheck:
npm run typecheckRun automated test suite:
npm testBuild standalone bundles:
npm run buildWeb2API includes a GitHub Actions pipeline (.github/workflows/test.yml) that automatically runs on every push and pull_request to main:
- Typechecking (
npm run typecheck) - Full test suite execution (
npm test) - Bundle build verification (
npm run build)
To skip automated tests on documentation or non-functional commits, include any of the following tags in your commit message:
[skip test]or[skip tests][skip ci]or[ci skip]
git commit -m "docs: update README [skip test]"IMPORTANT: Please read this notice carefully before using or deploying Web2API.
- Educational & Research Purposes Only: This project is developed and distributed exclusively for personal educational, research, and non-commercial API interoperability testing purposes.
- Risk of Upstream Changes: Web chat interfaces and reverse-engineered endpoints may change, become rate-limited, or terminate service at any time without warning.
- No Warranty & No Guarantee: The author and contributors make no claims, promises, or guarantees regarding the safety, status, or longevity of upstream access. This software is provided "AS IS", without warranty of any kind, express or implied.
- Assumption of Risk: You assume full and sole responsibility for any outcomes or damages resulting from using this software. Use strictly at your own risk.
- Trademark Attribution: All product names, logos, and brands (such as "Anthropic", "Claude", "OpenAI", "ChatGPT", "Xiaomi", "MiMoCode") are trademarks or registered trademarks of their respective owners. Web2API is an independent open-source project and is neither affiliated with, maintained by, nor endorsed by any of these entities.
This project is licensed under the GNU General Public License v3.0 (GPLv3). See the LICENSE file for details.
{ "providers": { "web2api": { "type": "openai-compatible", "baseUrl": "http://localhost:8000/v1", "apiKey": "sk-web2api-local", "models": [ "claude-sonnet-5", "terra", "sol", "glm-5.2", "kimi-k3" ] } }, "default_model": "web2api/claude-sonnet-5" }