How to Integrate a Custom OpenAI-Compatible Endpoint with FreeLLMAPI
To integrate a custom OpenAI-compatible endpoint with FreeLLMAPI, register the base URL and credentials via the CLI, which stores them in the SQLite api_keys table and automatically discovers available models through the /models endpoint.
FreeLLMAPI functions as a router-plus-proxy that aggregates any service exposing an OpenAI-compatible HTTP API. Whether you are connecting a self-hosted model, a third-party gateway, or a mock server, the system treats your custom endpoint as a generic provider through the OpenAICompatProvider class.
How the OpenAI-Compatible Router Works
FreeLLMAPI delegates all request handling—chat completions, streaming, tool calls, and vision—to a unified provider abstraction. This architecture allows any endpoint mirroring the OpenAI API specification to integrate seamlessly.
The OpenAICompatProvider Class
The core integration logic resides in server/src/providers/openai-compat.ts. The OpenAICompatProvider class handles request building, streaming transformations, and error recovery. When routing requests, the provider constructs the appropriate HTTP headers, manages bearer token injection, and forwards payloads unchanged to the upstream endpoint.
Per-Endpoint Credential Storage
Unlike traditional API gateways that bind credentials to specific models, FreeLLMAPI stores credentials per endpoint URL. This design, implemented in server/src/services/custom-endpoint.ts, enables multi-tenant scenarios where a single base URL hosts multiple API keys. The resolveCustomEndpointKey function manages this by encrypting keys via the encrypt utility and persisting them to the SQLite api_keys table.
Step-by-Step Registration Process
Integrating a custom endpoint requires four distinct phases: registration, credential encryption, model discovery, and request routing.
1. Register via CLI
Use the freellmapi register command to add your endpoint. The CLI transmits a POST request to /api/custom-endpoints with your base_url, optional api_key, and label.
freellmapi register \
--base-url https://my-local-model.example.com/v1 \
--api-key sk-mysecretkey \
--label "My Local Model"
Behind the scenes, the resolveCustomEndpointKey function in server/src/services/custom-endpoint.ts either inserts a new row or updates an existing placeholder (no-key) entry, enabling multiple credentials per URL.
2. Encrypt and Store Credentials
The API key undergoes encryption using the internal encrypt function before storage. If the endpoint already exists in the api_keys table, the touch method updates the row in-place; otherwise, insertKey creates a new encrypted entry.
3. Automatic Model Discovery
Upon the first request requiring model selection, the router invokes provider.fetchModelCatalog(). This method performs a GET ${base_url}/models request to your endpoint, retrieves the raw JSON response, and transforms it into CatalogModel objects. The discovered models are cached and exposed through FreeLLMAPI's own /v1/models endpoint.
curl -s -H "Authorization: Bearer $FREELLMAPI_API_KEY" \
http://localhost:3000/v1/models | jq .
4. Request Routing
When a client sends a request to http://localhost:3000/v1/chat/completions, the router selects the appropriate model (either auto-selected or specified via the model parameter) and forwards the request to your custom endpoint. The chatCompletion and streamChatCompletion methods in OpenAICompatProvider handle the proxying, injecting the stored credential as a bearer token unless the provider operates in keyless mode.
Configuration Examples
Registering with Authentication
For endpoints requiring API keys, include the --api-key flag during registration. The credential is encrypted and associated with the base URL.
freellmapi register \
--base-url https://api.thirdparty.com/v1 \
--api-key sk-abc123 \
--label "Third-Party Gateway"
Configuring Keyless Endpoints
Some providers, such as local inference servers or Kilo's free tier, do not require authentication. Register these using the --keyless flag, which sets the keyless flag in the OpenAICompatProvider constructor and omits the Authorization header from upstream requests.
freellmapi register \
--base-url https://my-anonymous-gateway.example.com/v1 \
--keyless \
--label "Anonymous Gateway"
Verifying the Integration
Test your custom endpoint by sending a standard OpenAI-format request through the FreeLLMAPI proxy:
curl -X POST http://localhost:3000/v1/chat/completions \
-H "Authorization: Bearer $FREELLMAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o",
"messages": [{"role":"user","content":"Hello, world!"}]
}' | jq .
All standard OpenAI parameters—including stream, tools, and max_tokens—pass through transparently to your backend.
Client Integration
Using Standard OpenAI SDKs
Point any OpenAI-compatible client to http://localhost:3000/v1 (or your configured gateway URL). The openapiSpec defined in server/src/docs/openapi.ts ensures compatibility with standard client implementations.
Generating IDE Configuration Files
FreeLLMAPI includes convenience generators in cli/src/tools.ts that emit ready-made configuration files for popular IDE assistants. The getTool function retrieves generators for Claude Code, Codex, Cline, and others, each producing environment-specific config files.
import { getTool } from './cli/src/tools.js';
const ctx = {
url: 'http://localhost:3000',
apiKey: process.env.FREELLMAPI_API_KEY,
homeDir: process.env.HOME,
profile: 'default',
models: [{ id: 'openai/gpt-4o', context_window: 128_000 }],
requestedModelId: undefined,
};
const claudeGen = getTool('claude')?.generate(ctx);
console.log(claudeGen?.files[0].path); // → ~/.claude/settings.json
After generation, tools like Codex automatically route requests through FreeLLMAPI:
freellmapi tools codex
codex --profile default
Advanced Provider Features
Parallel Tool Call Handling
Certain backends, such as NVIDIA NIM, reject parallel tool invocations. The resolveParallelToolCalls logic in OpenAICompatProvider automatically forces parallel_tool_calls: false when the forceSingleToolCall flag is set, ensuring compatibility with restrictive endpoints.
Error Rescue Mechanisms
If an upstream provider returns a tool-call failure with raw text instead of structured JSON—common with Groq and similar services—the provider's rescueFailedGeneration method intercepts the error and reformats it into a valid OpenAI-compatible response, preventing client-side failures.
Summary
- Register endpoints using
freellmapi registerto store encrypted credentials in theapi_keystable viaresolveCustomEndpointKey. - Support multiple keys per URL through the per-endpoint credential model implemented in
server/src/services/custom-endpoint.ts. - Discover models automatically via the
fetchModelCatalogmethod, which queries${BASE_URL}/modelsand caches the results. - Handle keyless providers by passing the
--keylessflag, which disables bearer token injection inOpenAICompatProvider. - Generate client configs using the
toolsmodule incli/src/tools.tsfor instant integration with Claude, Codex, and Cline.
Frequently Asked Questions
Can I use multiple API keys with the same custom endpoint URL?
Yes. FreeLLMAPI stores credentials per-endpoint rather than per-model, allowing you to register multiple keys for the same base URL. The resolveCustomEndpointKey function in server/src/services/custom-endpoint.ts manages this by updating existing rows or inserting new ones, enabling multi-tenant scenarios where different users access the same backend through different credentials.
How does FreeLLMAPI handle custom endpoints that do not require authentication?
Set the --keyless flag during registration. This configures the OpenAICompatProvider class to omit the Authorization header entirely when forwarding requests, as implemented in the provider's authHeader logic. This is essential for local inference servers or public gateways that reject authenticated requests.
What happens if my custom endpoint returns models in a non-standard format?
The fetchModelCatalog method in server/src/providers/openai-compat.ts retrieves the raw /models response and passes it to the router's model-selection logic without strict parsing. As long as your endpoint returns a JSON list containing model identifiers, FreeLLMAPI will surface them through its own /v1/models endpoint, regardless of additional custom fields.
Can I integrate custom endpoints with VS Code extensions or other IDEs?
Yes. Use the tools generators in cli/src/tools.ts to create configuration files for specific IDE assistants. Each generator (e.g., getTool('claude'), getTool('codex')) produces the necessary environment variables and config files to redirect the IDE's AI features to your FreeLLMAPI gateway, which then routes to your custom endpoint.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →