Create LLM Provider
Endpoint
POST /apiops/projects/{projectName}/llm-providers/{providerName}/
Authentication
Requires a Personal API Access Token.
Header
Authorization: Bearer YOUR_TOKEN
Request
Headers
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer {token} | Yes |
| Content-Type | application/json | Yes |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| projectName | string | Yes | Project name |
| providerName | string | Yes | LLM provider name (must match the name field in the body) |
Query Parameters
None
Request Body
The body is the LLM provider object. A "_class": "llm" field is not required; if you send it, it is ignored.
Full JSON Body Example
{
"_class": "llm",
"name": "deepseek-primary",
"description": "DeepSeek production provider",
"enabled": true,
"providerType": "DEEPSEEK",
"endpoint": "https://api.deepseek.com/v1",
"apiVersion": "v1",
"authScheme": "BEARER",
"authHeaderName": "Authorization",
"credentialSource": "GATEWAY",
"apiKeyLocation": "HEADER",
"apiKeyPrefix": null,
"allowClientOverride": false,
"apiKey": "sk-your-deepseek-api-key",
"onlyListedModels": false,
"deploymentType": "CLOUD",
"supportedModels": [
{
"modelId": "deepseek-chat",
"displayName": "DeepSeek Chat",
"contextWindow": 64000,
"maxOutputTokens": 8192,
"pricePerMillionInput": 0.27,
"pricePerMillionOutput": 1.10,
"capabilities": ["chat", "function_calling"],
"modality": "TEXT",
"enabled": true,
"aclEnabled": false,
"aclEntries": []
}
],
"metadata": [
{
"key": "team",
"value": "platform",
"secret": false
}
]
}
Request Body Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| _class | string | No | - | Not required. Ignored when sent |
| name | string | Yes | - | Provider name; must match providerName in the path (case-insensitive) |
| description | string | No | - | Free-text description |
| enabled | boolean | No | true | Whether the provider is active |
| providerType | string | No | - | Provider type enum constant (OPENAI, ANTHROPIC, AZURE_OPENAI, BEDROCK, VERTEX, COHERE, MISTRAL, DEEPSEEK, GROQ, MOONSHOT, ZHIPU, QWEN_DASHSCOPE, XAI, GOOGLE_AI_STUDIO, TOGETHER, FIREWORKS, CEREBRAS, HUGGINGFACE, OPENROUTER, PERPLEXITY, NVIDIA_NIM, VLLM, OLLAMA, CUSTOM_OPENAI_COMPAT, VOYAGE, TYPESAFE, TEI, OTHER) |
| endpoint | string | No | provider default | Base API URL; auto-filled from providerType when blank. Required for TEI (no default endpoint); TYPESAFE defaults to https://api.typesafe.ai/v1 |
| apiVersion | string | No | provider default | Provider API version; auto-filled from providerType when blank |
| organizationId | string | No | - | Organization identifier (OpenAI org-...) |
| authScheme | string | No | provider default | Auth scheme enum constant (BEARER, API_KEY_HEADER, BASIC, AWS_SIGV4, OAUTH2, NONE, CUSTOM); auto-filled from providerType when null |
| authHeaderName | string | No | provider default | Credential header name; auto-filled from providerType when blank |
| apiKey | string | No | - | Primary auth secret (Bearer token, api-key). Encrypted at rest; never returned |
| apiSecret | string | No | - | Secondary auth secret (e.g. AWS SigV4 secretKey). Encrypted at rest; never returned |
| region | string | No | - | Region (e.g. Bedrock AWS region) |
| serviceAccountJson | string | No | - | GCP Vertex service-account JSON blob. Encrypted at rest; never returned |
| supportedModels | array | No | - | The models of the provider (see fields below) |
| coldStartRetryEnabled | boolean | No | - | Deprecated, has no effect. Still accepted in the request body for compatibility; the value is ignored |
| onlyListedModels | boolean | No | false | When true, the gateway refuses a model ID that is not in supportedModels (HTTP 403). true with an empty supportedModels list is rejected with 400. |
| deploymentType | string | No | auto | Deployment type enum constant (CLOUD, ON_PREM, OTHER). A report-only label (Cloud / On-Premises / Other breakdown in AI usage reports); it never changes routing. When null it is auto-filled: OTHER for providerType OTHER (custom provider), ON_PREM for self-hosted types (VLLM, OLLAMA, CUSTOM_OPENAI_COMPAT, TEI), CLOUD otherwise. An explicit value is kept |
| metadata | array | No | - | Custom key/value metadata entries (see fields below) |
endpoint and apiVersion runtime semanticsendpoint takes the base address only (e.g. https://api.deepseek.com/v1) — the request path
(/chat/completions, /embeddings, /audio/transcriptions, /audio/speech, /images/generations,
/responses) is appended automatically based on the request type. Putting a path in endpoint
produces a broken URL at request time; to set a custom path, use a
providerType: OTHER connection with its own path fields. A query string embedded in
endpoint is not lost, but it is relocated to the end of the resolved address, after the appended path.
apiVersion only reaches the request URL for AZURE_OPENAI connections, where it is added as an
api-version query parameter (skipped if one is already present). For ANTHROPIC it is sent as the
anthropic-version header instead and never touches the URL. Bedrock and Vertex build their address
entirely in provider-specific code, so apiVersion has no effect on either.
See Query Strings and API Versioning in the Final URL for the full behavior.
wireProtocol and the six default*Path fields are the provider type's own, unless you set them on
the connection. You can write them through this endpoint. A body that omits them, or sends a blank path,
keeps the stored values. If the body changes providerType, the stored values are not kept and the new
type's own apply. For a vendor outside the provider type list, use providerType: OTHER and set the
protocol and paths on the connection.
Paths support Apinizer variable resolution (${env.name}, #{contextVar}), resolved at request time
against the effective URL endpoint + path.
Supported Model Fields
Each supportedModels row is one model of the provider.
| Field | Type | Required | Description |
|---|---|---|---|
| modelId | string | Yes | Model identifier (e.g. deepseek-chat) |
| displayName | string | No | Human-readable model name |
| contextWindow | integer | No | Maximum context window in tokens |
| maxOutputTokens | integer | No | Maximum output tokens |
| pricePerMillionInput | number | No | USD per 1M input tokens |
| pricePerMillionOutput | number | No | USD per 1M output tokens |
| pricePerMillionCached | number | No | USD per 1M cached input tokens |
| pricePerMillionCacheWrite | number | No | USD per 1M cache-write tokens (flat rate). A matching row in cacheWritePricesByTtl overrides this for its TTL |
| cacheWritePricesByTtl | array | No | Cache-write price per TTL — see Cache-Write Price Fields |
| contextTierPrices | array | No | Long-context price tiers — see Context-Tier Price Fields |
| serviceTierPrices | array | No | Provider service-tier price multipliers — see Service-Tier Price Fields |
| pricePerImage | number | No | USD per generated image |
| pricePerAudioMinute | number | No | USD per minute of audio (STT) |
| pricePerCharacterTts | number | No | USD per input character (TTS) |
| capabilities | array[string] | No | Capability tags, normalized on save — see Capabilities Normalization |
| modality | string | No | Modality enum constant (TEXT, VISION, AUDIO, EMBEDDING, RERANK, MULTIMODAL, IMAGE) |
| enabled | boolean | No | false makes the gateway refuse the model with 403 and leave it out of GET /v1/models |
| aclEnabled | boolean | No | true limits the callers of the model to the subjects in aclEntries |
| aclEntries | array | No | Consumers, applications and organizations allowed to call the model — see Model Access Control Fields |
Cache-Write Price (cacheWritePricesByTtl) Fields
One row per cache TTL the provider bills separately for (e.g. Anthropic prices a 5-minute cache
write at 1.25× input and a 1-hour cache write at 2× input). A row overrides
pricePerMillionCacheWrite for usage that reports that TTL.
| Field | Type | Required | Description |
|---|---|---|---|
| ttl | string | Yes | Short TTL label as the provider reports it — typically "5m" or "1h" |
| pricePerMillion | number | Yes | USD per 1M cache-write tokens at this TTL |
"cacheWritePricesByTtl": [
{ "ttl": "5m", "pricePerMillion": 3.75 },
{ "ttl": "1h", "pricePerMillion": 6.00 }
]
Context-Tier Price (contextTierPrices) Fields
Long-context pricing: above aboveTokens prompt tokens, the whole request is priced at
inputFactor × the input price and outputFactor × the output price. When several tiers match,
the one with the highest aboveTokens threshold wins.
| Field | Type | Required | Description |
|---|---|---|---|
| aboveTokens | integer | Yes | Prompt-token threshold (input + cached + cache-write). The tier applies strictly above this value |
| inputFactor | number | Yes | Multiplier applied to the input price for the whole request |
| outputFactor | number | Yes | Multiplier applied to the output price for the whole request |
"contextTierPrices": [
{ "aboveTokens": 200000, "inputFactor": 2.0, "outputFactor": 1.5 }
]
Service-Tier Price (serviceTierPrices) Fields
The gateway applies the row whose tier matches the service_tier value the provider echoed in
the response usage (e.g. OpenAI's flex / priority, or a request routed through a Batch API).
| Field | Type | Required | Description |
|---|---|---|---|
| tier | string | Yes | Service tier enum constant: BATCH, PRIORITY, FLEX or CUSTOM |
| name | string | No | Provider-reported tier value to match, used only when tier is CUSTOM (e.g. "scale"); ignored for the fixed tiers |
| inputFactor | number | Yes | Multiplier applied to the input price when the provider echoes this tier |
| outputFactor | number | Yes | Multiplier applied to the output price when the provider echoes this tier |
"serviceTierPrices": [
{ "tier": "BATCH", "name": null, "inputFactor": 0.5, "outputFactor": 0.5 },
{ "tier": "PRIORITY", "name": null, "inputFactor": 2.0, "outputFactor": 2.0 }
]
Model Access Control (aclEntries) Fields
One row per consumer, application or organization that may call the model. The rows apply only when
aclEnabled is true. Whoever may edit the provider may edit the access control of its models.
| Field | Type | Required | Description |
|---|---|---|---|
| subjectType | string | Yes | Kind of the subject: consumer, application or organization |
| subjectId | string | No* | Identifier of the subject. If sent, it wins over subjectName |
| subjectName | string | No* | Name of the subject: consumer username, application name or organization name. Used when subjectId is not sent |
| organizationId | string | No | Identifier of the organization of the subject |
| organizationName | string | No | Name of the organization of the subject |
"aclEnabled": true,
"aclEntries": [
{ "subjectType": "ORGANIZATION", "subjectId": "64f0c0ffee", "subjectName": "Payments", "organizationId": null, "organizationName": null }
]
* Send subjectId or subjectName. A name is looked up in the project of the provider, then in the admin project. A name that finds nobody returns 400 Bad Request. A name that matches more than one subject returns 400 Bad Request too, and the message asks you to send the subject id. One match in the project of the provider wins over matches in the admin project. Two matches in the project of the provider are ambiguous. When the project of the provider has no match, several matches in the admin project are ambiguous. Send subjectId in these cases.
Capabilities Normalization
capabilities is normalized on every save. The stored value never contains a legacy spelling.
Known keys (the values capabilities normalizes to): function_calling, vision,
prompt_caching, reasoning, structured_output, streaming, web_search.
Aliases collapsed to a known key: tools, tool_use, tool_calling, function-calling →
function_calling; image_input, multimodal_input → vision; caching → prompt_caching;
json_mode, json_schema, response_schema → structured_output; search → web_search.
Dropped as modality noise (already implied by the modality field, so it carries no extra
information): chat, completion, text, embedding, embeddings, code.
Unknown values are lower-cased, converted to snake_case, and kept as a custom tag.
For example, a request body sending "capabilities": ["chat", "tool_use", "json_mode"] is stored
as ["function_calling", "structured_output"] — chat is dropped and both remaining values
collapse to their canonical key.
A model without a price counts as 0 in cost reports. A USD limit does not meter such a model.
Metadata Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Metadata key |
| value | string | No | Metadata value; encrypted at rest when secret is true |
| secret | boolean | No | Whether the value is a secret (nulled in read responses) |
Notes
namemust matchproviderNamein the path (case-insensitive), otherwise a400 Bad Requestis returned- Fields left blank (
endpoint,apiVersion,authScheme,authHeaderName,deploymentType) are auto-filled from the selectedproviderType