Model Allowlist
The model allowlist lets operators enable or disable specific models for all API keys at once. A model disabled here is blocked regardless of per-key allowed_models settings.
List entries
Section titled “List entries”GET https://api.bve.me/admin/model-allowlistAuthorization: Bearer admin_bve_YOUR_ADMIN_KEYReturns all registered model entries, annotated with BVE registry metadata.
Query parameters
Section titled “Query parameters”| Parameter | Type | Description |
|---|---|---|
enabled | "true" | "false" | Filter to only allowed (true) or only blocked (false) entries. Omit to return all entries. Returns 400 for any other value. |
search | string | Case-insensitive substring search on the model ID. Only entries whose model ID contains the search string are returned. Combine with ?enabled= to filter by both name and status. An empty string is treated as no filter. |
Response (200)
Section titled “Response (200)”{ "models": [ { "model": "gpt-4o", "enabled": true, "created_at": "2026-05-21T11:00:00.000Z", "bve_category": "chat", "bve_provider": "openai", "bve_reasoning": false, "bve_vision": true, "bve_web_search": false, "bve_audio_input": false, "bve_tool_use": true, "bve_json_mode": true, "bve_thinking": false, "bve_computer_use": false, "registry_availability": "callable", "registry_working": true, "registry_broken": false }, { "model": "gpt-4o-mini", "enabled": false, "created_at": "2026-05-21T12:00:00.000Z", "bve_category": "chat", "bve_provider": "openai", "bve_reasoning": false, "bve_vision": true, "bve_web_search": false, "bve_audio_input": false, "bve_tool_use": true, "bve_json_mode": true, "bve_thinking": false, "bve_computer_use": false, "registry_availability": "callable", "registry_working": true, "registry_broken": false } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
model | string | Model ID (unique) |
enabled | boolean | true = model is permitted; false = model is blocked |
created_at | string | ISO 8601 timestamp of when the entry was first registered |
bve_category | string | null | Model type: chat, embedding, image, tts, transcription, ocr, or null if unrecognized |
bve_provider | string | null | Inferred upstream creator: openai, anthropic, google, meta, mistral, cohere, cursor, deepseek, wasikan, or null if unrecognized |
bve_reasoning | boolean | true for reasoning/thinking models (o3, o3-mini, o4-mini and dated variants) |
bve_vision | boolean | true for models that accept image inputs in chat requests (e.g. gpt-4o, claude-sonnet-4, gemini-2.0-flash); false for text-only or image-generation models |
bve_web_search | boolean | true for models with native web_search_options support (gpt-4o-search-preview, gpt-4.1 family); false for all others |
bve_audio_input | boolean | true for models that accept audio content blocks as inline input in POST /v1/chat/completions (gpt-4o-audio-preview, gpt-4o-mini-audio-preview families); false for all others |
bve_tool_use | boolean | true for models that accept the tools parameter for function calling in POST /v1/chat/completions; false for embedding, TTS, STT, image-generation, and legacy completion-only models |
bve_json_mode | boolean | true for models that support "response_format": { "type": "json_object" } or structured output in chat completions; false for embedding, TTS, STT, image-generation, and non-JSON-capable models |
bve_thinking | boolean | true for models that support the thinking parameter for extended thinking (e.g. claude-3-7-sonnet and later Anthropic models with extended thinking enabled); false for all others |
bve_computer_use | boolean | true for models that support Anthropic computer use built-in tool types in POST /v1/messages; false for all others |
registry_availability | string | Default gateway availability from the local registry + live Fuelix snapshot: callable, listed_unavailable, registry_broken, snapshot_excluded, or unknown |
registry_working | boolean | true if the model is in the gateway’s static working-models registry |
registry_broken | boolean | true if the model is flagged in the gateway’s known-broken list |
cURL — list all entries
Section titled “cURL — list all entries”curl "https://api.bve.me/admin/model-allowlist" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"cURL — list only blocked models
Section titled “cURL — list only blocked models”curl "https://api.bve.me/admin/model-allowlist?enabled=false" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"cURL — list only permitted models
Section titled “cURL — list only permitted models”curl "https://api.bve.me/admin/model-allowlist?enabled=true" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"cURL — search by model name substring
Section titled “cURL — search by model name substring”# All entries whose model ID contains "gpt"curl "https://api.bve.me/admin/model-allowlist?search=gpt" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Combine search with enabled filter: blocked Claude models onlycurl "https://api.bve.me/admin/model-allowlist?search=claude&enabled=false" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Inspect a single model
Section titled “Inspect a single model”GET https://api.bve.me/admin/model-allowlist/:modelAuthorization: Bearer admin_bve_YOUR_ADMIN_KEYReturns allowlist status and registry metadata for one model. Always returns 200 — there is no 404 response even if the model is unknown or unregistered.
Path parameter
Section titled “Path parameter”| Parameter | Description |
|---|---|
model | The model ID to inspect (URL-encode if it contains slashes) |
Response (200) — registered working model
Section titled “Response (200) — registered working model”{ "model": "gpt-4o", "available": true, "category": "chat", "bve_category": "chat", "bve_provider": "openai", "bve_reasoning": false, "bve_vision": true, "bve_web_search": false, "bve_audio_input": false, "bve_tool_use": true, "bve_json_mode": true, "bve_thinking": false, "bve_computer_use": false, "registry": { "availability": "callable", "working": true, "broken": false }, "allowlist": { "enabled": true, "created_at": "2026-05-21T11:00:00.000Z" }}Response (200) — reasoning model
Section titled “Response (200) — reasoning model”{ "model": "o3-mini", "available": true, "category": "reasoning", "bve_category": "chat", "bve_provider": "openai", "bve_reasoning": true, "bve_vision": false, "bve_web_search": false, "bve_audio_input": false, "bve_tool_use": true, "bve_json_mode": false, "bve_thinking": false, "bve_computer_use": false, "registry": { "availability": "callable", "working": true, "broken": false }, "allowlist": null}Response (200) — unregistered or unknown model
Section titled “Response (200) — unregistered or unknown model”For a model that has never been registered in the global allowlist, allowlist is null:
{ "model": "some-new-model", "available": false, "category": null, "bve_category": null, "bve_provider": null, "bve_reasoning": false, "bve_vision": false, "bve_web_search": false, "bve_audio_input": false, "bve_tool_use": true, "bve_json_mode": false, "bve_thinking": false, "bve_computer_use": false, "registry": { "availability": "unknown", "working": false, "broken": false }, "allowlist": null}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
model | string | The queried model ID |
available | boolean | true if the model is usable — see availability logic below |
category | string | null | Model type from the registry (may differ from bve_category for legacy reasons) |
bve_category | string | null | Canonical BVE category: chat, embedding, image, tts, transcription, ocr, or null if unrecognized |
bve_provider | string | null | Inferred model creator: openai, anthropic, google, meta, mistral, cohere, cursor, deepseek, wasikan, or null if unrecognized |
bve_reasoning | boolean | true for reasoning/thinking models (o3, o3-mini, o4-mini and dated variants) |
bve_vision | boolean | true for models that accept image inputs in chat requests (e.g. gpt-4o, claude-sonnet-4, gemini-2.0-flash); false for text-only or image-generation models |
bve_web_search | boolean | true for models with native web_search_options support (gpt-4o-search-preview, gpt-4.1 family); false for all others |
bve_audio_input | boolean | true for models that accept audio content blocks as inline input in POST /v1/chat/completions (gpt-4o-audio-preview, gpt-4o-mini-audio-preview families); false for all others |
bve_tool_use | boolean | true for models that accept the tools parameter for function calling in POST /v1/chat/completions; false for embedding, TTS, STT, image-generation, and legacy completion-only models |
bve_json_mode | boolean | true for models that support "response_format": { "type": "json_object" } or structured output in chat completions; false for non-JSON-capable models |
bve_thinking | boolean | true for models that support the thinking parameter for extended thinking (Anthropic claude-3-7-sonnet and later); false for all others |
bve_computer_use | boolean | true for models that support Anthropic computer use built-in tool types in POST /v1/messages; false for all others |
registry.availability | string | Default gateway availability from the local registry + live Fuelix snapshot before any D1 override: callable, listed_unavailable, registry_broken, snapshot_excluded, or unknown |
registry.working | boolean | true if the model is in the gateway’s static working-models registry |
registry.broken | boolean | true if the model is in the gateway’s known-broken list |
allowlist | object | null | The D1 allowlist entry if present; null if the model has never been registered |
allowlist.enabled | boolean | true = globally permitted; false = globally blocked |
allowlist.created_at | string | ISO 8601 timestamp of when the entry was first registered |
Availability logic
Section titled “Availability logic”available: true requires both of the following:
- The model is not globally blocked (
allowlistis absent orallowlist.enabled: true) - The model is callable by default (
registry.availability: "callable") or Fuelix/modelsstill lists it live for the current account while the local registry remains unclassified (registry.availability: "unknown")
allowlist.enabled: true no longer widens availability by itself. It keeps the row out of the global-block path, but the model must still be callable in the local snapshot or currently listed by the live Fuelix catalog for the active account. It does not override registry_broken, listed_unavailable, or snapshot_excluded.
Use this endpoint to check why a model is blocked before attempting to re-enable it via POST /admin/model-allowlist.
Using bve_reasoning to detect reasoning models
Section titled “Using bve_reasoning to detect reasoning models”bve_reasoning: true means the model supports reasoning_effort (and the thinking block for Anthropic extended-thinking variants). Use this field to gate UI controls or API clients that conditionally add reasoning_effort without hard-coding model name lists.
Using bve_vision to detect vision-capable models
Section titled “Using bve_vision to detect vision-capable models”bve_vision: true means the model accepts image_url content blocks in chat completion messages — it can analyse images sent alongside text. Use this field to conditionally enable image upload controls in your UI without maintaining your own model name list. Image-generation models (e.g. imagen-3, gpt-image-1) always have bve_vision: false — they produce images rather than accept them as input.
Using bve_web_search to detect native web search support
Section titled “Using bve_web_search to detect native web search support”bve_web_search: true means the model natively processes the web_search_options parameter in POST /v1/chat/completions to perform live web searches before generating a response. Currently covers the gpt-4o-search-preview, gpt-4o-mini-search-preview, and gpt-4.1 families (including gpt-4.1-mini and gpt-4.1-nano).
Using bve_audio_input to detect inline audio input support
Section titled “Using bve_audio_input to detect inline audio input support”bve_audio_input: true means the model accepts input_audio content blocks — raw Base64-encoded audio data — as inline input in POST /v1/chat/completions messages. Distinct from TTS models (which generate audio at /v1/audio/speech) and STT models (which transcribe audio files at /v1/audio/transcriptions). Currently covers the gpt-4o-audio-preview and gpt-4o-mini-audio-preview families.
Using bve_tool_use to detect function calling support
Section titled “Using bve_tool_use to detect function calling support”bve_tool_use: true means the model accepts the tools array parameter in POST /v1/chat/completions for structured function calling. All chat models and OCR models return true. Embedding, TTS, STT, image-generation, and legacy completion-only models return false — sending tools to these models would be rejected by the upstream provider.
cURL — inspect a known working model
Section titled “cURL — inspect a known working model”curl "https://api.bve.me/admin/model-allowlist/gpt-4o" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"cURL — inspect an unregistered or unknown model
Section titled “cURL — inspect an unregistered or unknown model”curl "https://api.bve.me/admin/model-allowlist/some-custom-model" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Returns available: false and allowlist: null for models absent from both the static registry and D1. Historical D1 rows may still exist for stale models, but new writes now require the model to be present in the live Fuelix catalog for the current account.
Add or update an entry
Section titled “Add or update an entry”POST https://api.bve.me/admin/model-allowlistAuthorization: Bearer admin_bve_YOUR_ADMIN_KEYContent-Type: application/jsonCreates a new entry or updates enabled if the model is already registered. This operation is idempotent — posting the same model twice simply updates it. The model value must be an exact live Fuelix model ID at write time.
Request body
Section titled “Request body”{ "model": "gpt-4o-mini", "enabled": false}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | Yes | — | Exact live Fuelix model ID currently present in GET /v1/models |
enabled | boolean | No | true | Whether the model is permitted |
Response (200)
Section titled “Response (200)”{ "model": "gpt-4o-mini", "enabled": false, "created_at": "2026-05-21T12:00:00.000Z"}cURL — block a model
Section titled “cURL — block a model”curl -X POST https://api.bve.me/admin/model-allowlist \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o-mini", "enabled": false}'cURL — re-enable a blocked model
Section titled “cURL — re-enable a blocked model”curl -X POST https://api.bve.me/admin/model-allowlist \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o-mini", "enabled": true}'Delete an entry
Section titled “Delete an entry”DELETE https://api.bve.me/admin/model-allowlist/:modelAuthorization: Bearer admin_bve_YOUR_ADMIN_KEYRemoves a model from the D1 global allowlist entirely. After deletion, the model is no longer explicitly tracked as globally allowed or blocked, but requests still remain subject to per-key allowlists and the live Fuelix-backed availability checks. This is also the cleanup path for historical D1 rows that no longer exist in the live Fuelix catalog.
Path parameter
Section titled “Path parameter”| Parameter | Description |
|---|---|
model | The model ID to remove (URL-encode if it contains slashes) |
Response (200)
Section titled “Response (200)”{ "deleted": true, "model": "gpt-4o-mini"}Response (404)
Section titled “Response (404)”{ "error": { "message": "Model not found in allowlist", "type": "invalid_request_error", "code": "not_found" }}cURL example
Section titled “cURL example”curl -X DELETE "https://api.bve.me/admin/model-allowlist/gpt-4o-mini" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Caching behavior
Section titled “Caching behavior”The gateway caches allowlist lookups in memory to avoid a D1 query on every request. This uses a Stale-While-Revalidate (SWR) strategy with two TTL thresholds:
| Cache type | Soft TTL | Hard TTL |
|---|---|---|
| Per-model lookup (request path) | 20 s | 30 s |
| Full allowlist (GET /v1/models filter) | 45 s | 60 s |
How SWR works:
- Within the soft TTL: the cached value is returned immediately (no D1 hit).
- Between soft and hard TTL: the stale value is returned immediately, and a background D1 refresh is scheduled via
ctx.waitUntilso the next request gets the fresh value. - Past the hard TTL: the cache entry is evicted and the next request blocks on a synchronous D1 query.
Operational implication: After you disable a model via POST /admin/model-allowlist, in-flight requests in warm isolates may still be accepted for up to 30 seconds before the cache expires. This is by design — it trades strict consistency for lower latency on every request.
If you need immediate enforcement, restart the Worker (via the Cloudflare dashboard or bunx wrangler deploy) to clear all isolate-level caches.
How model filtering works
Section titled “How model filtering works”When a JSON request arrives at a /v1/* endpoint, the gateway applies two checks in order:
-
Global allowlist — if the model appears in this registry with
enabled: false, the request is rejected immediately with403 model_not_available. This check runs for every key. -
Per-key allowlist — if the key has a non-null
allowed_modelsarray (set viaPOST /admin/api-keysorPATCH /admin/api-keys/:id), the requested model must match at least one entry in that list. Requests for unlisted models return403 model_not_allowed. -
Default registry + live snapshot availability — if the model is
registry_broken,listed_unavailable, orsnapshot_excluded, the gateway rejects it with403 model_not_availableeven if a D1 allow entry exists. Forunknownmodels, the gateway only allows a D1 override when Fuelix/modelscurrently lists that model live.
If neither check blocks the request, it is forwarded to Fuelix.
Legacy wildcard prefixes on older keys
Section titled “Legacy wildcard prefixes on older keys”Older API keys may still contain allowed_models entries ending with * from before exact-live validation was enforced. The gateway continues to honor those already-stored prefixes at request time so existing keys do not break immediately.
New admin writes do not accept wildcard prefixes. POST /admin/api-keys, PATCH /admin/api-keys/:id, and key clone operations now require every allowed_models entry to be an exact model ID currently present in the live Fuelix /models catalog.
To clean up an older key:
- Read its current
allowed_models. - Expand each legacy prefix against the current live Fuelix
/modelsresponse. - Save the resulting exact model IDs back to the key, or set
allowed_modelstonull/[]to remove the restriction entirely.
- Models not registered in the global allowlist are not blocked by default — only explicitly registered and disabled models are blocked.
enabled: trueis no longer a standalone routability override. It only prevents a global block; the model must still pass the live Fuelix-backed availability checks before requests can route.- New writes validate model IDs against the live Fuelix catalog before saving them.
POST /admin/model-allowlistrejects models that are not currently listed by Fuelix for the active account, and it also fails closed when the live Fuelix catalog is unavailable. - Legacy wildcard prefixes may still appear on older API key records and continue to match at runtime until the key is normalized, but new admin writes reject them in favor of exact live Fuelix model IDs.
bve_category,bve_provider,bve_reasoning, andbve_visionon allowlist endpoints are derived from the gateway’s static registry and do not depend on the D1 allowlist state. They are present even for models withallowlist: null.