modelschemas
Live AI model schema service. Per-endpoint request/response JSON Schemas and
model metadata for 30+ monitored providers (OpenAI, Anthropic, Gemini, xAI
Grok, Mistral, Groq, DeepSeek, and more — GET /v1/providers for the full
roster), refreshed automatically: model lists every 15 minutes, full OpenAPI
spec syncs daily. Responses are JSON unless noted (text/typescript,
application/openapi+json).
Why use this
- Discover which models exist right now, across providers, by activity
(chat, image, video, audio, embeddings, moderation, world, decision). Grain=provider
catalogs (Grok, OpenAI, …) set
activityon each row andschemaEndpointIdpointing at the shared generation route (v1/images/generations,images/generations, …).pricingis a RateCard (or null when no price is stored). List rows carry a summary:{currency, per: 'token', inputPerMillion, outputPerMillion, tiered?}at the base rate, or{currency, per: 'second' | 'character' | 'image' | …}for a card billed by unit.currencyis ISO 4217 (mostly USD; nothing is converted, so compare only like with like);?pricing=1returns the full card./v1/statuscounts livepricedmodels per provider and scorescompleteness(the share of chat facts filled;scoreis null with no chat models). A provider there carriesdocsFailing,priceClearsRefused,updateStorm, orstaleProbeswhile its stored docs facts or prices may be stale, one poll rewrote most of its live rows, or a probe record is older than 90 days. A model row'srequiredRequestHeaderslists client-supplied connect headers.trainsOnRequestData: truemeans that id's own source says it trains on request data. - Fetch a self-contained JSON Schema (refs bundled under $defs) for any
provider generation endpoint — request (input) and response (output).
A listed model rawId also works as
{endpointId}: it aliases onto that route and pins the requestmodelfield to the one id. - Validate a payload server-side before spending tokens on a provider call.
- Estimate the cost of a call from the stored rate card, in the card's
currency (
POST /v1/estimate). - Poll /v1/changes (or subscribe via webhooks) to hear about new models and API revisions. A catalog.shape_changed change means the model row itself changed shape (payload.version, payload.notes): re-read openapi.json. /v1 changes are otherwise additive; ignore keys you do not know.
Quickstart (no auth needed for reads)
- GET /v1 — endpoint index.
- GET /v1/models?activity=chat — cross-provider catalog of chat models. GET /v1/providers/{provider} — one provider's status, counts, and live models per activity.
- GET /v1/schemas — system-wide index: every provider's activities and endpoint ids in one response (all schemas on the system).
- GET /v1/schemas/anthropic — activities + endpoint ids for one provider.
- GET /v1/schemas/anthropic/chat/{endpointId}?kind=input — the JSON Schema
for a request body (endpoint ids contain slashes; URL-encode them).
Grain=provider models also accept the raw id:
/v1/schemas/grok/image/grok-imagine-image-2.0?kind=input. - GET /v1/openapi/{provider} — generation-only OpenAPI (servers, auth, paths). FAL is one queue document: the model id is the endpoint_id path parameter (x-modelschemas-encode: raw — do not percent-encode slashes). Bare, the bodies are untyped; ?activity= inlines each model's own body schema (up to 1024 models); ?model= is that one model's paths. Reactor publishes POST /tokens only. Model commands are input_/output_ components tagged x-modelschemas-transport: realtime, not HTTP paths. A filter that matches none: 400 spec_requires_selector. HTTP only (no MCP tool).
- POST /v1/validate {"provider","endpointId","payload"} — check a payload.
- POST /v1/estimate {"provider","model","request"?,"usage"?} — {amount, currency} for a call from the stored rate card. Missing levers → 422; no card → 404 unknown_pricing. See "Estimate usage" below.
- GET /v1/changes?since= — what changed.
TypeScript types
Add ?format=types to a schema read
(GET /v1/schemas/{provider}/{activity}/{endpointId}) to get a self-contained
TypeScript module instead of JSON: the schema as a pure const plus generated
interfaces (text/typescript, zero imports, tree-shakeable, same ETag
discipline). ?optional=undefined widens optional properties to
T | undefined for exactOptionalPropertyTypes consumers; default is
foo?: T. A request model field is the live catalog union plus
ListedModelId<'provider'> (still branded when the catalog is empty).
Minted by listModels / listProviderModels / getModel (or
asListedModelId). Arbitrary string values do not assign.
Hypermedia (HAL, extended)
Every JSON read response carries _links: HAL link objects extended with
method, contentType, and an inline example (a resolvable URL for
GETs, a request body for POSTs) so you can follow the API without consulting
docs. Templated hrefs (RFC 6570) set "templated": true and always include
an example. Start at GET /v1 and follow _links.
Long-polling
No sleep tool? Add ?wait=30 (seconds, cap 60, 30s form accepted) to
GET /v1/changes or GET /v1/status: the request holds until new data lands or
the window expires, then returns whatever is current. One request, one
rate-limit token.
Caching
Catalog and current schema reads (/v1/models, /v1/providers, /v1/schemas,
/v1/openapi/{provider}) send Cache-Control: public, max-age=900 (the
15-minute model poll) and are edge-cached. A schema read with
?version=<content hash> is immutable and cached for a year. Responses also
carry ETag (content hash), Last-Modified, X-Fetched-At and X-Stale-At (unix
epoch seconds). Send If-None-Match to get 304s. /v1/changes and
/v1/status are not edge-cached. A response served from the edge does not
run the worker, so it does not count toward the rate limit, with or without
Authorization. Only cache misses are counted.
Auth (optional — unlocks higher rate limits + webhooks)
- Agent-auth protocol: discovery at /.well-known/agent-configuration, register at POST /api/auth/agent/register, then execute capabilities with short-lived JWTs.
- Simple alternative: POST /v1/agents/register-key { "name" } returns an API key once; send it as Authorization: Bearer .
Machine-readable spec
GET /openapi.json — OpenAPI 3.1 for this service; every operation has an operationId. GET /skill — installable agent skill (SKILL.md) teaching this full workflow.
Estimate usage
usage on POST /v1/estimate takes one of two shapes. A payload that
mixes them gets 422 mixed_usage.
- The provider's own usage object, as the API returned it: OpenAI
Responses or Chat Completions
usage, Anthropicusage, or GeminiusageMetadata. The service maps it to card levers. - Card levers. Their counts do not overlap:
input_tokensexcludes the tokens incache_read_tokens,cache_write_tokens(5-minute writes) andcache_write_1h_tokens. A card can also readreasoning_tokens,audio_tokens,image_tokensorweb_searches; a count in one of these is not also ininput_tokensoroutput_tokens. The model'spricing.inputs(GET /v1/models/{provider}/{id}) lists the levers its card reads. A zero card lever the card does not read is dropped. A non-zero one is 422unknown_usage_key.
Reasoning, audio, image and video counts move to their own lever only
when the card reads that lever. Otherwise they stay in the total, because
the source bills them at that rate. Example: gpt-5 usage
{"input_tokens":12000,"input_tokens_details":{"cached_tokens":4000},"output_tokens":800}
prices 8000 input, 4000 cached and 800 output tokens.
Errors
All errors are JSON: { "error": { "code", "message" } }. Messages include remedies (e.g. valid provider ids on a 404).