Docs
Factory Droid
Droid's custom models are a JSON array with three required fields. The one that gets misread is baseUrl, because its correct form depends on which of the three provider values you picked.
A customModels entry in ~/.factory/settings.json — model, baseUrl and provider — puts Droid on any endpoint that speaks Anthropic Messages or OpenAI Chat Completions.
// ~/.factory/settings.json (Windows: %USERPROFILE%\.factory\settings.json)
{
"customModels": [
{
"model": "claude-sonnet-5",
"displayName": "Sonnet 5 [Kunavo]",
"baseUrl": "https://api.kunavo.com",
"apiKey": "${KUNAVO_API_KEY}",
"provider": "anthropic"
},
{
"model": "gpt-5-6-sol",
"displayName": "GPT-5.6 Sol [Kunavo]",
"baseUrl": "https://api.kunavo.com/v1",
"apiKey": "${KUNAVO_API_KEY}",
"provider": "generic-chat-completion-api"
}
]
}
// Then, in the shell Droid starts from:
// export KUNAVO_API_KEY=sk-kn-...
// ${VAR_NAME} expansion is a settings.json feature. It does NOT apply to the
// legacy ~/.factory/config.json, which Factory still loads and merges./v1 belongs to one entry and not the other. Factory's documentation settles this with a table rather than a sentence: its Provider reference gives https://api.anthropic.com — origin, no path — for provider: "anthropic", while https://api.openai.com/v1, https://openrouter.ai/api/v1 and https://api.groq.com/openai/v1 all carry the /v1 root. Droid appends the route itself, so the Anthropic entry above is the bare origin and the Chat Completions entry is /v1. Putting /v1 on the Anthropic one asks for /v1/v1/messages, which is a 404 and not an authentication failure — see the base URL reference.curl below is the part you can check in ten seconds; the client's behaviour is between you and Factory.authMode can be left out. Factory documents the default, provider-default, as sending the credential in x-api-key, and Kunavo's Messages endpoint accepts that header as well as Authorization: Bearer. If you ever want the bearer form explicitly, Factory documents authMode: "bearer" for provider: "anthropic" and that also works here.Step by step
- Create a key at
/app/keysand copy it — it is shown once. Export it asKUNAVO_API_KEYin the shell you start Droid from, so the key itself never lands in a settings file. - Open
~/.factory/settings.json(create it if it is not there) and add thecustomModelsarray above. Factory marks exactly three fields required —model,baseUrlandprovider— anddisplayNameis the label the picker shows you. - Check the
providerspelling. It must be exactly one ofanthropic,openaiorgeneric-chat-completion-api; Factory's troubleshooting section lists a typo there as the cause of its"Invalid provider"error. - Run
/modelin the CLI. Your entries appear in a separate Custom models section below Factory's own, labelled with thedisplayNameyou set. Factory watches the settings file, so a save is enough — no restart. - Give it a task that reads and edits a file rather than a greeting. Droid leans on tool calling for nearly everything it does, and that is the part a plain chat turn will not exercise. Then run
/cost, which is where Factory reports cache hit rates — Kunavo serves Anthropic'scache_controlmarkers natively, and Factory's own note is that on the generic Chat Completions provider caching “varies by provider and cannot be guaranteed”.
Checked against Factory's Custom Models (BYOK) page on September 21, 2026. Third-party settings move; if a field name here no longer matches what you see, that page is the authority, not this one.
Verify before you debug the client
One request settles whether a failure is the endpoint, the key, or the configuration file. If this returns JSON, the same base URL and key work in Factory Droid.
# Settles whether a failure is the endpoint, the key, or the client.
curl -sS https://api.kunavo.com/v1/messages \
-H "Authorization: Bearer sk-kn-..." \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-sonnet-5","max_tokens":16,"messages":[{"role":"user","content":"ping"}]}'Which model id to put in the field
Every text model is reachable as a model id — the live list is GET /v1/models, and the catalog with prices is on the models page. Rates are USD per 1M tokens, input / output.
| Model id | Kunavo in / out | Where it fits in Factory Droid |
|---|---|---|
claude-sonnet-5 | $2.00 / $10.00 | the default working model — goes in the provider: "anthropic" entry |
claude-opus-5 | $2.00 / $10.00 | planning a change that would be expensive to get wrong; same anthropic entry |
claude-haiku-4-5 | $0.40 / $2.00 | cheap turns and file triage, where volume dominates; same anthropic entry |
gpt-5-6-sol | $2.00 / $12.00 | a second opinion from another family — needs the generic-chat-completion-api entry |
What a custom model in Droid does not reach
Three limits come from Factory's own pages, and each one changes what you should expect from the config above rather than whether it works.
- Local surfaces only. Factory's BYOK page states that custom models are available in the Droid CLI and the desktop app, which read your local
settings.json, and that they “don't appear in Factory's hosted web or mobile platforms”. Work delegated through the hosted product keeps running on Factory-billed inference whatever key you configured here. - An administrator can switch it off. Factory's enterprise controls document
modelPolicy.allowCustomModelsandallowedBaseUrls, which disable user BYOK outright or pin every custom model to one approved host. On a managed machine, check that before you debug the file. - The plan fee survives. A key here is additive rather than a replacement — what Factory charges past its BYOK allowance, and what that allowance is, is the subject of the cost guide and is not re-derived on this page.
One trap worth knowing before you copy a config from anywhere else: Factory still loads the legacy ~/.factory/config.json with snake_case custom_models and base_url, merging it under settings.json, and it documents that ${VAR_NAME} expansion does not apply there. A key written as a placeholder in that file is sent literally. Use settings.json.
FAQ
How do I add a custom API endpoint to Factory Droid?
Edit ~/.factory/settings.json (%USERPROFILE%\.factory\settings.json on Windows) and add a customModels array. Each entry needs three required fields — model, baseUrl and provider — plus optional ones including displayName, apiKey, authMode, maxOutputTokens and extraHeaders. There is no settings form for this; the JSON file is the interface. Factory watches the file, so after saving, run /model in the CLI and the entry appears under a separate "Custom models" heading.
Does the Factory Droid baseUrl need /v1 at the end?
It depends on the provider value, and Factory's documentation settles it with its Provider reference table rather than a sentence. The Anthropic row gives https://api.anthropic.com with no path, so provider "anthropic" takes the bare origin — https://api.kunavo.com for Kunavo. Every Chat Completions row in that table carries a /v1 root (https://api.openai.com/v1, https://openrouter.ai/api/v1), so provider "generic-chat-completion-api" takes https://api.kunavo.com/v1. Droid appends the route itself, so a /v1 on the Anthropic entry produces /v1/v1/messages and returns 404 rather than an authentication error.
Which provider value should I use for Claude models on a third-party endpoint?
Use "anthropic". Factory documents three provider values and each selects a wire protocol: "anthropic" for the Anthropic Messages API at /v1/messages, "openai" for the OpenAI Responses API, and "generic-chat-completion-api" for OpenAI Chat Completions. The value names the protocol the endpoint speaks, not who bills you, so a gateway that answers /v1/messages takes "anthropic" regardless of whose account the key belongs to. Factory's own instruction is to use "generic-chat-completion-api" unless you are calling OpenAI's or Anthropic's official API — but that is about which protocol is on offer, and an endpoint serving both lets you choose.
Why does Factory Droid report an invalid provider or skip my custom model?
Factory's troubleshooting section names three causes. A model missing from the selector is usually a JSON syntax error in settings.json or a missing required field — model, baseUrl or provider. An "Invalid provider" error is a spelling problem: the value must be exactly anthropic, openai or generic-chat-completion-api. An authentication error means the key or the base URL, and Factory's own advice is to confirm the base URL matches your provider's documentation. Settle which one it is outside the client first with the curl above: JSON back means the endpoint and key are fine and the fault is in the settings file.