Models & Pricing API
A public, anonymous aggregation endpoint for the model catalog and published prices, following the OpenRouter Providers specification — ready to be crawled programmatically by third-party price aggregators or clients.
Overview
/v1/models/pricing is a public, anonymous aggregation endpoint that outputs all models currently available on the platform together with their published prices. The response follows the OpenRouter Providers specification and can be consumed programmatically by any third-party platform or client.
This endpoint is the "published price" entry point and carries no user identity. The prices returned are the final transaction prices (USD) of the default group (default), consistent with anonymous crawling scenarios. The actual prices paid by logged-in users include user group and tier discount contexts — please refer to the console pricing page.
Use Cases
| Scenario | Description |
|---|---|
| Third-party price aggregation | Price aggregators crawling the platform's model catalog and published prices |
| Client display | Third-party apps, bots, and SDKs displaying the available model list |
| Monitoring & alerting | Monitoring changes to the platform's models / prices |
Endpoint Definition
| Item | Value |
|---|---|
| URL | https://api.calgine.com.cn/v1/models/pricing |
| Method | GET |
| Auth | None (public, anonymous) |
| Rate Limit | Strict per-IP rate limit |
| Caching | 60-second server-side cache; response includes Cache-Control: public, max-age=60 |
Request Examples
curl https://api.calgine.com.cn/v1/models/pricingimport requests
resp = requests.get("https://api.calgine.com.cn/v1/models/pricing", timeout=10)
data = resp.json()["data"]
for m in data[:3]:
print(m["id"], m["pricing"])const resp = await fetch("https://api.calgine.com.cn/v1/models/pricing");
const { data } = await resp.json();
console.log(data.slice(0, 3).map((m) => ({ id: m.id, pricing: m.pricing })));package main
import (
"encoding/json"
"net/http"
)
type ModelEntry struct {
ID string `json:"id"`
Name string `json:"name"`
Pricing map[string]interface{} `json:"pricing"`
}
func main() {
resp, _ := http.Get("https://api.calgine.com.cn/v1/models/pricing")
defer resp.Body.Close()
var body struct{ Data []ModelEntry }
_ = json.NewDecoder(resp.Body).Decode(&body)
_ = body
}Response Structure
The top-level structure is always wrapped in a data array:
{
"data": [
{
"id": "gpt-4o",
"name": "GPT-4o",
"created": 1715558400,
"input_modalities": ["text", "image"],
"output_modalities": ["text"],
"quantization": "unknown",
"context_length": 128000,
"max_output_length": 16384,
"pricing": {
"prompt": "0.0000025",
"completion": "0.00001",
"request": "0",
"image": "0",
"input_cache_read": "0.00000125"
},
"supported_sampling_parameters": [
"temperature", "top_p", "frequency_penalty", "presence_penalty",
"stop", "seed", "max_tokens", "logit_bias", "response_format",
"tools", "tool_choice", "parallel_tool_calls", "logprobs", "top_logprobs"
],
"supported_features": ["tools", "json_mode", "structured_outputs", "logprobs"]
}
]
}Top-Level Fields
| Field | Type | Description |
|---|---|---|
data | Array<Model> | Array of model entries; an empty array means no models are currently published |
Model Object Fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✅ | Unique model identifier; use this value when calling /v1/chat/completions |
name | string | ✅ | Display name (e.g., GPT-4o); falls back to id when not configured |
created | int64 | ✅ | Model release time (Unix seconds) |
input_modalities | string[] | ✅ | Supported input modalities; includes at least text |
output_modalities | string[] | ✅ | Supported output modalities; includes at least text |
quantization | string | ✅ | Quantization method (fp16 / fp8 / bf16 / int8 / unknown) |
context_length | int | ✅ | Maximum context window in tokens |
max_output_length | int | ✅ | Maximum output tokens per response |
pricing | Pricing | ✅ | Pricing object, see below |
pricing_tiers | Pricing[] | Tiered pricing array (at most 1 element, only output when a threshold is explicitly marked) | |
supported_sampling_parameters | string[] | ✅ | Supported sampling parameters (e.g., temperature, top_p) |
supported_features | string[] | ✅ | Supported feature enums (see the table below) |
deprecation_date | string | Planned deprecation date (ISO 8601, YYYY-MM-DD) | |
hugging_face_id | string | Hugging Face repository ID for open-source models |
Pricing Object Fields
All prices are expressed as USD strings. Token-based fields use USD / token; flat-fee field units are listed in the description column.
| Field | Type | Required | Unit | Description |
|---|---|---|---|---|
prompt | string | ✅ | USD / input token | Input token unit price |
completion | string | ✅ | USD / output token | Output token unit price |
request | string | ✅ | USD / request | Fixed fee per request (for per-request models) |
image | string | ✅ | USD / image | Image generation unit price (per image) |
audio | string | USD / audio | Audio generation unit price (per segment) | |
video | string | USD / video | Video generation unit price (per segment) | |
web_search | string | USD / query | Built-in web search tool call unit price | |
internal_reasoning | string | USD / reasoning token | Reasoning token unit price (o1 / Claude thinking series) | |
input_cache_read | string | USD / token | Cache hit read unit price | |
input_cache_write | string | USD / token | Cache write unit price (most expensive window published) | |
min_context | int | tokens | Only used by pricing_tiers elements; marks the minimum context length that triggers this pricing tier |
- Missing fields may be returned as
"0"(the four base fieldsprompt/completion/request/imageare always present) or omitted entirely (optional fields) "0"can mean either "free" or "this dimension is not supported by the model" — please evaluate together withsupported_featuresandsupported_sampling_parameters
supported_features Enum
| Value | Meaning |
|---|---|
tools | Supports tool calling (Function Calling) |
reasoning | Supports reasoning process (reasoning_content / thinking) |
json_mode | Supports JSON mode output |
structured_outputs | Supports structured outputs (Schema constrained) |
logprobs | Supports returning token log probabilities |
web_search | Supports the built-in web search tool |
Mapping of the Three Billing Modes
The platform supports three billing modes (see Pricing), all of which map onto OpenRouter specification fields:
| Internal Billing Mode | Output Fields | Description |
|---|---|---|
| Per Token | prompt / completion / internal_reasoning / input_cache_read / input_cache_write / web_search | Text, Embedding, and similar models; token unit prices are converted from "USD / million tokens" to "USD / token" |
| Per Request | image / video / audio / request | Routed automatically by unit type: image generation → image, video generation → video, music/speech → audio, everything else → request |
| Per Second | request / video / audio | Converted to a "published price per request" using a typical use-case duration (e.g., 30 seconds); actual billing remains real seconds × unit price, so reconciliation never drifts |
Price Calculation
Published price formula:
final_usd = base_price × group_ratio × currency_factor- base_price: The official price configured in the backend
- group_ratio: The group multiplier of the default group (
default) - currency_factor: If the base is configured in CNY, it is converted to USD at the exchange rate; if configured in USD, it remains unchanged
- Not included: Reseller markups, user tier discounts, user-specific multipliers, time-of-day multipliers, or runtime dynamic factors
The actual amount paid by logged-in users may differ from the published price: users in other groups, with tier discounts, or accessing via a reseller domain will see different prices. Anonymous crawling only reflects the platform's base published price.
Tiered Pricing
Some models have different unit prices in different context-length ranges (e.g., the Gemini Pro series charges more at long-context tiers). The "high tier" prices of such models are output via the pricing_tiers array:
{
"id": "gemini-2.5-pro",
"pricing": {
"prompt": "0.00000125",
"completion": "0.00001",
"request": "0",
"image": "0"
},
"pricing_tiers": [
{
"min_context": 200000,
"prompt": "0.0000025",
"completion": "0.000015",
"request": "0",
"image": "0"
}
]
}pricingis the base tier (the one with the lowest threshold)pricing_tiers[i]is the high tier; it applies when the request's total input tokens ≥min_context- At most 1 high tier is currently returned
Tier Dimension
Threshold matching is based on "total input tokens", including cache and multimodal content: plain text input, text cache (cache_read / cache_create), and image/audio/video input along with their cache reads all count toward the total.
Matching Rules
Matching proceeds from large to small: among the tiers satisfying total >= min, the one with the largest threshold is selected, and the entire request is billed at the matched tier's unit price (consistent with official providers — not progressive). If no tier is matched, the base tier applies.
Data Updates & Caching
| Dimension | Description |
|---|---|
| Server-side cache | 60-second in-process cache; model/price changes take effect within at most 1 minute |
| Client-side cache | Response includes Cache-Control: public, max-age=60, safe for CDNs and browsers to cache for 1 minute |
| Recommended crawl frequency | ≥ once every 5 minutes; high-frequency crawling will be rate-limited |
Differences from Other Endpoints
| Endpoint | Purpose | Auth |
|---|---|---|
/v1/models/pricing | This endpoint: published prices (OpenRouter spec) | Public |
/v1/models | OpenAI SDK-compatible model ID list | Token required |
| Console pricing page | Front-end price display (with user context) | Login required |
FAQ
Why are the returned prices different from what I actually pay?
The published price is the final transaction price of the "default group" in anonymous scenarios. If you belong to another group, have tier discounts, or access via a reseller domain, your actual payment will differ. After logging in, please refer to the prices shown on the console pricing page.
Why are some fields "0"?
"0" can mean either "free" or "this dimension is not supported by the model". Please evaluate model capabilities together with supported_features and supported_sampling_parameters — do not infer feature support from pricing fields alone.
How are per-second models (TTS / video) converted?
The OpenRouter specification does not support a per_second field, so the platform converts per-second price × seconds into the published request / video / audio fields using a "typical use-case duration" (30 seconds by default). Actual billing is always real seconds × unit price — nothing is overcharged or undercharged due to the conversion.
Is there a crawl frequency limit?
The endpoint enforces a strict per-IP rate limit. We recommend crawling no more than once every 5 minutes and using the Cache-Control: max-age=60 response header for client-side caching.
Can I filter by vendor / modality?
The endpoint currently does not support filter parameters and always returns all models in normal status. Clients can filter the data array themselves by fields such as supported_features / input_modalities.