Documentation
Model allowlists
Restrict a project to approved models with allowed_models. Exact IDs and vendor wildcards, a 403 model_not_allowed refusal, and fallback interaction.
Every project can carry a model allowlist: the set of models its keys are permitted to call. Set allowed_models on the project and INFRO refuses anything outside the list before provider selection — on every endpoint, so one policy covers chat, images, video, and audio.
Absent or empty, the allowlist does nothing and all 120+ catalog models are available. Add one when the model set is a decision someone has already made — procurement approved specific vendors, a compliance review cleared an EU-only set, or a development project has no reason to touch a frontier video model. The refusal is a stable 403 your client can branch on.
The allowed_models field
allowed_modelsstring[]- List of permitted entries — exact model IDs, vendor wildcards, or a mix. Set per project via
PATCH /v1/projects/{id}or in the console. An empty array or absent field means no restriction.
| Entry | Matches | Example |
|---|---|---|
| Exact ID | One model, in canonical vendor/model-name form | anthropic/claude-sonnet-5 |
vendor/* | Every model from that vendor, including models the catalog adds later | bfl/* matches bfl/flux-2-pro |
[] or absent | No restriction — the full catalog is available | The default for every new project |
Entries are validated on write: an exact ID that isn't in the catalog, or a wildcard whose vendor doesn't exist, is rejected with 400 invalid_request_error — a typo fails at PATCH time, not silently in production. Matching runs after alias resolution, so when a retired ID aliases to its successor (see the deprecation policy), the request passes only if the successor is allowed. Keep lists in canonical IDs from GET /v1/models.
Set an allowlist
PATCH the project with the full list — the field is replaced, not merged. Changing it requires the owner or admin role; see Members & roles for what each role can do.
curl -X PATCH https://api.infro.io/v1/projects/proj_9m4kQx \
-H "Authorization: Bearer $INFRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"allowed_models": [
"anthropic/claude-sonnet-5",
"openai/gpt-5.1",
"openai/whisper-v3-turbo",
"bfl/*"
]
}'{
"id": "proj_9m4kQx",
"name": "production",
"allowed_models": [
"anthropic/claude-sonnet-5",
"openai/gpt-5.1",
"openai/whisper-v3-turbo",
"bfl/*"
],
"updated_at": "2026-08-24T09:14:02Z"
}The console equivalent is the project's Models tab at console.infro.io — the same list, edited with a catalog picker, with the same effect. To clear a policy, PATCH "allowed_models": [] or clear the list in the console; the project immediately returns to the full catalog.
The refusal
A request for a model outside the allowlist is refused with HTTP 403 in the standard error envelope: type is permission_denied — the same type every 403 carries — and code is model_not_allowed, the stable string to branch on.
{
"error": {
"message": "Model \"google/gemini-3-pro\" is not in the allowlist for project \"production\".",
"type": "permission_denied",
"code": "model_not_allowed"
}
}- The check runs before provider selection: no provider is contacted, no tokens are consumed, nothing is charged.
- It is deterministic — the same request fails the same way until the policy changes. Exclude it from automatic retries, like every other
4xxin the retry rules. - Branch on
error.code, noterror.message— the wording can change, the code will not. - The check applies with BYOK too: your own provider key does not bypass the project's policy.
Fallbacks and routing
Fallback models are checked against the allowlist as well. An entry in your fallbacks array that falls outside the policy is skipped — the chain moves to the next entry without trying it. If the primary model itself is disallowed, the request is refused with 403 immediately: fallbacks exist to survive outages, not to route around policy. Chain mechanics are covered in Failover & fallbacks.
A skipped fallback is silent at request time. If every entry in a chain sits outside the project's allowlist, the route has no model-level resilience left — and you find out during an outage. Validate fallback chains against the project policy when you deploy, and again after any allowlist change.
Routing is unaffected. The allowlist governs which models may serve; routing governs which provider serves an allowed model. The allowlist check runs first, then the router scores providers as usual — routing.policy, routing.providers, and routing.regions all behave exactly as documented.
What teams use it for
- Procurement-approved models. Legal or security cleared specific vendors — an allowlist of
anthropic/*andopenai/*makes the clearance enforceable at the gateway instead of aspirational in a wiki. - EU-only model sets. A project pinned to the EU routing zone usually pairs the pin with an allowlist of models actually hosted in EU datacenters, so requests never fail
503for want of an EU deployment. - Cost discipline. Keep video generation out of development projects — leave
kuaishou/kling-2.5off the dev allowlist and cap the rest with spend limits. The two compose: allowlists bound what can run, spend limits bound what it can cost. - Blast-radius control. A key leaked from a locked-down project can only call the models that project allows — one more bound on the damage, alongside the per-key spend limit from Authentication.
Propagation and the audit log
Changes take effect within seconds, on every key in the project, with no key rotation and no redeploy. A request already past the allowlist check completes normally; the next request sees the new policy. Enforcement is entirely gateway-side — there is nothing to invalidate in your clients.
Every change lands in the audit log as a policy.updated event with the actor, the UTC timestamp, and the before and after lists in detail. "Who allowed that model, and when" is one GET /v1/org/audit away, retained for 12 months.