REST API reference
Read-only JSON API over live pricing data. Base URL /api/v1. Works without a key on the anonymous tier; a free pr_live_ key raises the limits.
Base URL & conventions
Base URL: /api/v1 - all endpoints below are relative to it. Responses are application/json.
- All prices are decimal strings in USD per 1M tokens (unit usd_per_1m_tokens) - never floats.
- Model ids are stable slugs in the form provider:model-slug - the canonical id printed on each model card, in the CSV dump and in every feed (e.g. openai:openai-gpt-5-mini). The provider's own api id resolves too (openai:gpt-5-mini), as do renamed slugs, via aliases.
- Only published data is served; every price row carries last_verified_at and an is_stale flag.
- Every response is the same envelope: {schema_version, as_of, data, pagination, truncated, hint}. as_of is the timestamp of the last pipeline publish, not the HTTP response time.
- Pagination is keyset via an opaque cursor; changing filters between pages returns INVALID_CURSOR. There is no offset pagination.
- GET responses are cacheable (data changes only on publish runs).
{
"schema_version": "1",
"as_of": "2026-07-06T10:33:11Z",
"data": { ... },
"pagination": {"count": 20, "total_count": 336, "has_more": true, "next_cursor": "eyJz..."},
"truncated": false,
"hint": "optional next-step suggestion"
}Endpoints
GET /api/v1/models
MCP twin: priceradar_list_models
Search and filter models with current API prices. Paginated, sorted by the chosen key.
| Query parameters | Type | Default | Description |
|---|---|---|---|
| query | string | - | Free-text search over names, slugs and aliases. |
| provider | string | - | Provider slug (e.g. openai). Unknown slugs return did-you-mean suggestions. |
| modality | text | image | audio | video | - | Input modality filter. |
| status | active | deprecated | retired | all | active | Lifecycle status filter. |
| channel | official | openrouter | aws_bedrock | azure | vertex | together | fireworks | groq | novita | - | Price channel filter. |
| min_context | int ≥ 1 | - | Minimum context window, tokens. |
| max_input_price | decimal string | - | Maximum input price, USD per 1M tokens. |
| sort | price_input_asc | price_output_asc | price_blended_asc | context_desc | updated_desc | updated_desc | Sort key. Blended price = (3×input + output) / 4. |
| limit | int, 1-100 | 20 | Page size. |
| cursor | string | - | Opaque keyset cursor from pagination.next_cursor of the previous page. |
curl -s "https://techagent.net/api/v1/models?sort=price_blended_asc&min_context=200000&limit=10"
GET /api/v1/models/{model_id}
MCP twin: priceradar_get_model
One model's full card by stable id provider:model-slug: current prices across channels, context window, deprecation status. Unknown ids return did-you-mean suggestions.
| Query parameters | Type | Default | Description |
|---|---|---|---|
| include | CSV of pricing | deprecation | benchmarks | aliases | history_summary | - | Extra sections to include, comma-separated. |
curl -s "https://techagent.net/api/v1/models/openai:gpt-5-mini?include=pricing,history_summary"
GET /api/v1/models/{model_id}/history
MCP twin: priceradar_price_history
Published price-change events for one model over a date window (max 365 days per call).
| Query parameters | Type | Default | Description |
|---|---|---|---|
| component | input | output | cached_input | all | all | Price component. |
| channel | official | openrouter | aws_bedrock | azure | vertex | together | fireworks | groq | novita | - | Price channel filter. |
| since | date (ISO 8601) | - | Window start. The since..until window must not exceed 365 days. |
| until | date (ISO 8601) | - | Window end (defaults to today). |
| granularity | changes | daily | changes | changes returns only actual change events; daily returns a daily price series. |
| limit | int, 1-100 | 50 | Page size. |
| cursor | string | - | Opaque keyset cursor from pagination.next_cursor of the previous page. |
curl -s "https://techagent.net/api/v1/models/openai:gpt-5-mini/history?component=input&since=2026-01-01"
GET /api/v1/compare
MCP twin: priceradar_compare
Side-by-side comparison of 2-5 models: prices, context window, benchmark score and price per benchmark point.
| Query parameters | Type | Default | Description |
|---|---|---|---|
| ids | CSV of 2-5 model ids | - | Models to compare. Fails with suggestions if any id is unknown. |
| metrics | CSV of price_input | price_output | price_blended | context_window | benchmark_score | price_per_point | - | Metrics to include (default: all). |
| benchmark | string | aggregate | Benchmark used for score-based metrics. |
curl -s "https://techagent.net/api/v1/compare?ids=openai:gpt-5-mini,openai:gpt-5"
POST /api/v1/estimate
MCP twin: priceradar_estimate_cost
Estimate the monthly USD cost of a token workload. Pass a task preset or explicit token volumes per request; returns a per-model cost breakdown (the 10 cheapest active text models if model_ids is omitted). Assumptions are echoed back.
| JSON body | Type | Default | Description |
|---|---|---|---|
| requests_per_month | int ≥ 1 (required) | - | Workload volume. |
| preset | chatbot | summarization | extraction | coding_agent | translation | rag_qa | classification | - | Task preset with typical token volumes; alternative to explicit volumes. |
| input_tokens_per_request | int ≥ 1 | - | Explicit input volume per request. |
| output_tokens_per_request | int ≥ 1 | - | Explicit output volume per request. |
| cache_hit_rate | float 0-1 | 0 | Share of input tokens served from cache. |
| batch_share | float 0-1 | 0 | Share of traffic processed via batch pricing. |
| model_ids | array, ≤ 10 ids | - | Models to estimate for. |
curl -s -X POST "https://techagent.net/api/v1/estimate" -H "Content-Type: application/json" \
-d '{"requests_per_month": 100000, "preset": "chatbot", "model_ids": ["openai:gpt-5-mini"]}'GET /api/v1/changes
MCP twin: priceradar_recent_changes
Feed of published pricing and lifecycle events: price cuts and rises, deprecations, retirements, new models, limit changes. Newest first - same data as the public RSS/JSON change feed.
| Query parameters | Type | Default | Description |
|---|---|---|---|
| since | date (ISO 8601) | - | Window start. The since..until window must not exceed 365 days. |
| until | date (ISO 8601) | - | Window end (defaults to today). |
| event_type | price_change | price_change_scheduled | deprecation | retirement | model_launch | limit_change | all | all | Event type filter. |
| provider | string | - | Provider slug filter. |
| min_significance | int 0-100 | 0 | Minimum significance score. |
| limit | int, 1-100 | 20 | Page size. |
| cursor | string | - | Opaque keyset cursor from pagination.next_cursor of the previous page. |
curl -s "https://techagent.net/api/v1/changes?since=2026-06-01&min_significance=50"
GET /api/v1/health
Service liveness probe: no auth, not counted against quotas. Returns {status, db, as_of}; 503 when the database is unreachable.
curl -s "https://techagent.net/api/v1/health"
Authentication
- No key is required: without one, requests run on the Anonymous tier (per-IP quota).
- API keys look like pr_live_… and are passed in the X-API-Key header, as Authorization: Bearer pr_live_…, or as a ?key= query fallback (the query form ends up in access logs - prefer headers).
- One key works for both REST and MCP, and the quota is shared between the two channels.
- A key that is invalid or expired gets HTTP 401 (INVALID_API_KEY) on REST; on MCP the request silently falls back to the anonymous tier.
Rate limits & quotas
Every /api/v1 response (except /health) carries the rate-limit headers below. Quotas are shared between REST and MCP.
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Quota of your plan for the current window (requests). |
| X-RateLimit-Remaining | Requests left in the current window. |
| X-RateLimit-Reset | Unix time (seconds) when the quota refills completely. |
| Retry-After | Only on 429: seconds to wait before the next request. |
| Tier | Key | Quota | Rate |
|---|---|---|---|
| Anonymous | no key needed | 60 req/hour per IP | 2 req/s |
| Free key | pr_live_ (free, on request) | 1,000 req/day | 5 req/s |
Errors
Errors are actionable: HTTP status + a machine-readable object error {code, message, next_step}.
| Code | HTTP | When | Hint |
|---|---|---|---|
| MODEL_NOT_FOUND | 404 | model_id does not resolve via slug or aliases | Response includes did_you_mean suggestions; list valid ids via /api/v1/models?query=… |
| PROVIDER_NOT_FOUND | 404 | Unknown provider slug | Response includes did_you_mean; omit provider to see valid slugs. |
| NO_PRICE_DATA | 404 | Model exists but has no price rows for the requested channel/tier | Check the model card; try channel=official. |
| INVALID_CURSOR | 400 | Cursor is malformed or filters changed between pages | Restart the listing without the cursor. |
| WINDOW_TOO_LARGE | 400 | since..until window exceeds 365 days | Split the request into windows of at most 365 days. |
| INVALID_ARGUMENT | 400 | A value is outside its enum or range | The message names the parameter and the allowed values. |
| INVALID_API_KEY | 401 | A key was sent but is unknown or expired (REST only) | Request a new free key, or omit the key for the anonymous tier. |
| RATE_LIMITED | 429 | Plan quota or burst rate exceeded | Wait Retry-After seconds; a free key raises the limit. |
OpenAPI
A machine-readable OpenAPI 3 spec is generated automatically and served at /api/v1/openapi.json.