Presets API
Create, list, update, and delete reusable preset configurations.
Presets are reusable configuration bundles that store a default model, system prompt, sampling parameters, and provider routing rules. Reference a preset in any inference request with the @preset/<slug> model syntax.
/api/v1/presetsAuthenticate with a Management key (ak_…) carrying read:presets (read routes) or write:presets (write routes), or a signed-in dashboard session. An LLM key (sk-ar-…) is not accepted. See Management API Keys.
Request
POST /api/v1/presets creates a preset in the authenticated workspace:
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | Unique identifier. Lowercase alphanumeric and hyphens (/^[a-z0-9][a-z0-9-]*$/). Unique per workspace. |
name | string | Yes | Display name. Must not be empty. |
description | string | null | No | Optional description. |
config | object | Yes | Preset configuration. See PresetConfig fields. |
Other routes
| Method & path | Purpose |
|---|---|
GET /api/v1/presets | List all presets in the workspace, newest first. |
GET /api/v1/presets/{slug} | Return a single preset by slug (404 if none). |
PATCH /api/v1/presets/{slug} | Partial update — only included fields change. |
DELETE /api/v1/presets/{slug} | Delete a preset by slug (404 if none). |
PATCH update behavior: name is updated if provided and non-empty; description is tri-state (omit to keep, null to clear, string to set); config is shallow-merged so existing keys not in the patch are preserved.
PresetConfig fields
All fields are optional. When a preset is referenced in a request, these values serve as defaults the request can override.
| Field | Type | Description |
|---|---|---|
model | string | Default model (e.g. "z-ai/glm-4.7-flash") |
models | string[] | Fallback model list, tried in order if the primary is unavailable. |
system | string | System prompt, prepended as a {role: "system"} message when the request has none. |
temperature | number | Sampling temperature (0–2) |
max_tokens | number | Maximum tokens in the response |
max_completion_tokens | number | Maximum completion tokens (newer OpenAI parameter) |
top_p | number | Nucleus sampling threshold |
top_k | number | Top-K sampling |
frequency_penalty | number | Frequency penalty (-2 to 2) |
presence_penalty | number | Presence penalty (-2 to 2) |
repetition_penalty | number | Repetition penalty |
stop | string | string[] | Stop sequences |
seed | number | Reproducibility seed |
response_format | object | Response format (e.g. { "type": "json_object" }) |
tools | array | Tool definitions |
tool_choice | string | object | Tool selection strategy |
provider | object | Provider routing rules (sort, only, ignore, allow_fallbacks, etc.) |
reasoning | object | Reasoning config (effort, max_tokens, exclude) |
stream_options | object | Streaming options (e.g. { "include_usage": true }) |
Reasoning on anyrouter/* routes
The built-in anyrouter/auto, anyrouter/free, anyrouter/cowork, anyrouter/hermes, and anyrouter/latest ids are routing presets, not fixed models. They do not add a synthetic reasoning level list. The rules below describe explicit request controls on these built-in routes; a custom preset's stored reasoning object is not a promise that every endpoint will merge it:
- Chat-style requests use flat
reasoning_effort. Responses uses the nestedreasoning.effortform, withreasoning.enabled: falseas the endpoint-specific disable form. For flat Chat and converted Messages,noneis a disable sentinel, not an effort tier. - Messages requests use
thinking.type(enabled/disabled); native Anthropic routes receive the body unchanged. When Messages is converted to a non-native upstream,enabledmaps to flathighanddisabledmaps tonone;thinking.budget_tokensis not carried into that flat field. - For flat
reasoning_effortpaths (including the converted Messages form), before each upstream attempt AnyRouter clamps the requested effort against the selected concrete model's declared levels, using a route-specific level override when one exists. It prefers the nearest lower supported level and falls back to the model default for an unknown tier. An omitted effort stays omitted; the declareddefaultis a clamp fallback, not automatic injection. A branch's levels never leak into the next fallback branch.noneremains a disable sentinel and is never clamped on these flat paths. - If a resolved branch has no declared effort enum, AnyRouter does not invent one and forwards the caller's flat value unchanged. For a selected route, its per-upstream
supported_parametersis the authority; the top-level model list is a model-level/legacy projection, not a promise shared by every fallback. - Preset-level
require_paramsis forwarded as a hard candidate constraint on paths that support preset candidate selection. Preset, key, and request provider lists are unioned at the preference layer, but provider/key requirements are not a universal hard filter on every concrete dispatch. Built-in virtual resolution uses tool-related entries in the list (and request tools) to require tool-capable members; it does not turn every arbitrary parameter into a capability guarantee. provider.require_parameters: trueis a separate strict model-level check over the request body. It also has no effect when the model has no declaredsupported_parameterslist. Ordinary body-inferred parameters such astools,tool_choice, andresponse_formatuse the softer candidate-reorder/strip path. If a route has no declared support list, the current router treats support as unknown/permissive rather than claiming universal support.- Routing floors merge deliberately:
min_contexttakes the stricter (higher) value, keyignoreis unioned, and key/requestonlylists intersect. The top-level presetrequire_paramsis the legacy alias forprovider.require_params;min_contextis likewise accepted at the top level. - A normal fallback chain may still try a different resolved model after an upstream failure. Reasoning clamping is recalculated for that attempt; it is not a promise that every model in the chain has identical effort levels.
These rules describe the current router. They do not claim that every provider supports a toggle, a reasoning token budget, or interleaved thinking. Interleaved thinking is a provider beta request (anthropic-beta: interleaved-thinking-2025-05-14), not a preset/model guarantee; use the model response's declared fields and the endpoint-specific parameters instead.
Response
GET /api/v1/presets returns a list envelope; a single preset record looks like:
{
"id": "preset_abc123",
"object": "preset",
"slug": "code-reviewer",
"name": "Code Reviewer",
"description": "Strict senior-engineer review focused on bugs, security, and clarity.",
"config": {
"model": "anthropic/claude-sonnet-4",
"system": "You are a senior code reviewer...",
"temperature": 0.2,
"max_tokens": 4096
},
"created_at": "2026-03-01T12:00:00.000Z",
"updated_at": "2026-03-01T12:00:00.000Z"
}
DELETE /api/v1/presets/{slug} returns:
{
"deleted": true,
"slug": "code-reviewer"
}
Examples
curl -X POST https://anyrouter.dev/api/v1/presets \
-H "Authorization: Bearer ak_your-management-key" \
-H "Content-Type: application/json" \
-d '{
"slug": "code-reviewer",
"name": "Code Reviewer",
"description": "Strict senior-engineer review focused on bugs, security, and clarity.",
"config": {
"model": "anthropic/claude-sonnet-4",
"system": "You are a senior code reviewer. Focus on bugs, security issues, and clarity.",
"temperature": 0.2,
"max_tokens": 4096
}
}'
import httpx
httpx.post(
"https://anyrouter.dev/api/v1/presets",
headers={"Authorization": "Bearer ak_your-management-key"},
json={
"slug": "code-reviewer",
"name": "Code Reviewer",
"config": {
"model": "anthropic/claude-sonnet-4",
"system": "You are a senior code reviewer.",
"temperature": 0.2,
"max_tokens": 4096,
},
},
)
await fetch("https://anyrouter.dev/api/v1/presets", {
method: "POST",
headers: {
Authorization: "Bearer ak_your-management-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
slug: "code-reviewer",
name: "Code Reviewer",
config: {
model: "anthropic/claude-sonnet-4",
system: "You are a senior code reviewer.",
temperature: 0.2,
max_tokens: 4096,
},
}),
})
Once created, use it in any inference request by setting model to @preset/code-reviewer.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_slug | Slug doesn't match the required pattern. |
| 400 | name_required | Name is empty or missing. |
| 400 | config_required | Config is missing or not an object. |
| 401 | — | Missing or invalid credential. |
| 403 | — | Key lacks the required read:presets / write:presets scope. |
| 409 | duplicate_slug | A preset with this slug already exists in the workspace. |
Related
- Management API Keys — the
ak_…keys and scopes used here - Presets — the feature overview and dashboard flow
- Provider Routing — the
providerconfig block explained