JSON API
Plain static JSON files served from CloudFront. CORS is enabled (Access-Control-Allow-Origin: *). Refreshed by the collector Lambda 4× daily; CloudFront cache TTL is 5 minutes.
/api/models.json
Full normalized list, one entry per (provider, model). Each entry has a canonicalId you can use to join across providers.
Array<{
canonicalId: string,
provider: "bedrock" | "vertex" | "openrouter",
providerModelId: string,
displayName: string,
family: string,
publisher?: string,
modality?: string[],
contextWindow?: number,
pricingStatus: "known" | "unknown",
pricingInputPer1M?: number,
pricingOutputPer1M?: number,
pricingCurrency?: "USD",
available: boolean,
region?: string,
firstSeenAt: string,
lastSeenAt: string
}>/api/models-by-provider.json
Same data, pre-grouped by provider. Faster than filtering models.json yourself.
{
bedrock: Model[],
vertex: Model[],
openrouter: Model[]
}/api/models-by-family.json
Same data, pre-grouped by detected family (claude, gemini, qwen, deepseek, kimi, …). Use the family key "other" for long-tail models that don't match a known family.
{
claude: Model[],
gemini: Model[],
qwen: Model[],
/* … */
}/api/diff-latest.json
Models added/removed since the previous run. Available after Phase 6 lands.
{
added: Model[],
removed: Model[],
since: string // ISO timestamp
}/api/meta.json
Collection metadata.
{
lastRun: string, // ISO timestamp
counts: { bedrock, vertex, openrouter, total },
schemaVersion: "1"
}Examples
# every Claude model and where it is
curl -s https://models.apresai.dev/api/models.json \
| jq '.[] | select(.family == "claude") | {provider, providerModelId, in: .pricingInputPer1M}'
# everything currently on Bedrock
curl -s https://models.apresai.dev/api/models-by-provider.json | jq .bedrock
# is "kimi-k2" available anywhere right now?
curl -s https://models.apresai.dev/api/models.json \
| jq '[.[] | select(.canonicalId | test("kimi-k2"))] | map(.provider) | unique'