Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ curl https://models.dev/api.json

Use the **Model ID** field to do a lookup on any model; it's the identifier used by [AI SDK](https://ai-sdk.dev/).

The API also provides several specialized endpoints for faster access:

| Endpoint | Description |
|---|---|
| `/api/models.json` | Lightweight index of all model IDs with capabilities and provider list |
| `/api/{provider}.json` | Full data for a single provider (e.g., `/api/anthropic.json`) |
| `/api/providers.json` | Lightweight list of all providers with name, model count, and docs link |
| `/api/schema.json` | JSON Schema describing the full data shape |

```bash
# Find which providers offer a specific model
curl https://models.dev/api/models.json | jq '."claude-sonnet-4-5".providers'

# Get full pricing for one provider
curl https://models.dev/api/anthropic.json
```

### Logos

Provider logos are available as SVG files:
Expand Down
9 changes: 9 additions & 0 deletions packages/function/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ export default {

if (url.pathname === "/api.json") {
url.pathname = "/_api.json";
} else if (url.pathname === "/api/models.json") {
url.pathname = "/_api/models.json";
} else if (url.pathname === "/api/schema.json") {
url.pathname = "/_api/schema.json";
} else if (url.pathname === "/api/providers.json") {
url.pathname = "/_api/providers.json";
} else if (url.pathname.match(/^\/api\/[a-z0-9][a-z0-9._-]+\.json$/)) {
const providerId = url.pathname.replace("/api/", "").replace(".json", "");
url.pathname = `/_api/${providerId}.json`;
} else if (
url.pathname === "/" ||
url.pathname === "/index.html" ||
Expand Down
152 changes: 152 additions & 0 deletions packages/web/script/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,155 @@ await Bun.write("./dist/api.json", JSON.stringify(Providers));

await $`mv ./dist/index.html ./dist/_index.html`;
await $`mv ./dist/api.json ./dist/_api.json`;

// Build per-provider API files
await fs.mkdir("./dist/_api", { recursive: true });
const providerEntries = Object.entries(Providers);
for (const [providerId, provider] of providerEntries) {
await Bun.write(
`./dist/_api/${providerId}.json`,
JSON.stringify({ [providerId]: provider }),
);
}

// Build model index: model ID → { providers[], capabilities }
const modelIndex: Record<
string,
{
name: string;
providers: string[];
tool_call: boolean;
reasoning: boolean;
modalities: { input: string[]; output: string[] };
open_weights: boolean;
structured_output?: boolean;
}
> = {};
for (const [providerId, provider] of providerEntries) {
for (const [modelId, model] of Object.entries(provider.models)) {
if (!modelIndex[modelId]) {
modelIndex[modelId] = {
name: model.name,
providers: [],
tool_call: model.tool_call,
reasoning: model.reasoning,
modalities: model.modalities,
open_weights: model.open_weights,
structured_output: model.structured_output,
};
}
// sanity check: conflicting capabilities across providers
const entry = modelIndex[modelId];
if (entry.name !== model.name) {
console.warn(
`Model name mismatch for "${modelId}": "${entry.name}" vs "${model.name}" (${providerId})`,
);
}
entry.providers.push(providerId);
}
}
await Bun.write("./dist/_api/models.json", JSON.stringify(modelIndex));

// Build JSON Schema for the full API shape
const providerNames = providerEntries
.sort(([, a], [, b]) => a.name.localeCompare(b.name))
.map(([id]) => id);

const schema = {
$schema: "https://json-schema.org/draft/2020-12/schema",
$id: "https://models.dev/api/schema.json",
title: "Models.dev",
description: "Open-source database of AI model specifications and pricing",
type: "object",
additionalProperties: {
$ref: "#/$defs/Provider",
},
$defs: {
Provider: {
type: "object",
properties: {
id: { type: "string", enum: providerNames },
name: { type: "string" },
env: { type: "array", items: { type: "string" } },
npm: { type: "string" },
api: { type: "string" },
doc: { type: "string", format: "uri" },
models: {
type: "object",
additionalProperties: { $ref: "#/$defs/Model" },
},
},
required: ["id", "name", "env", "npm", "doc", "models"],
},
Model: {
type: "object",
properties: {
id: { type: "string" },
name: { type: "string" },
family: { type: "string" },
attachment: { type: "boolean" },
reasoning: { type: "boolean" },
tool_call: { type: "boolean" },
structured_output: { type: "boolean" },
temperature: { type: "boolean" },
open_weights: { type: "boolean" },
release_date: { type: "string" },
last_updated: { type: "string" },
knowledge: { type: "string" },
modalities: {
type: "object",
properties: {
input: {
type: "array",
items: { type: "string", enum: ["text", "audio", "image", "video", "pdf"] },
},
output: {
type: "array",
items: { type: "string", enum: ["text", "audio", "image", "video", "pdf"] },
},
},
},
cost: { $ref: "#/$defs/Cost" },
limit: { $ref: "#/$defs/Limit" },
status: { type: "string", enum: ["alpha", "beta", "deprecated"] },
},
required: ["id", "name", "modalities", "limit"],
},
Cost: {
type: "object",
properties: {
input: { type: "number" },
output: { type: "number" },
reasoning: { type: "number" },
cache_read: { type: "number" },
cache_write: { type: "number" },
input_audio: { type: "number" },
output_audio: { type: "number" },
context_over_200k: { $ref: "#/$defs/Cost" },
},
},
Limit: {
type: "object",
properties: {
context: { type: "integer" },
input: { type: "integer" },
output: { type: "integer" },
},
required: ["context", "output"],
},
},
};
await Bun.write("./dist/_api/schema.json", JSON.stringify(schema, null, 2));

// Build provider list: lightweight index of all providers
const providerList = providerEntries
.sort(([, a], [, b]) => a.name.localeCompare(b.name))
.map(([id, provider]) => ({
id,
name: provider.name,
doc: provider.doc,
model_count: Object.keys(provider.models).length,
npm: provider.npm,
api: provider.api,
}));
await Bun.write("./dist/_api/providers.json", JSON.stringify(providerList));
48 changes: 48 additions & 0 deletions packages/web/src/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,54 @@ export const Rendered = renderToString(
</a>
.
</p>
<h3>Model Index</h3>
<p>
Lightweight index of all model IDs with their capabilities and which
providers offer each model. Useful for finding which providers carry a
model without downloading the full dataset.
</p>
<div class="code-block">
<code>
curl{" "}
<a href="/api/models.json">https://models.dev/api/models.json</a>
{" | jq '.\"claude-sonnet-4-5\".providers'"}
</code>
</div>
<h3>Per-Provider</h3>
<p>
Full data for a single provider. Replace <code>{`{provider}`}</code>{" "}
with the <b>Provider ID</b>.
</p>
<div class="code-block">
<code>
curl{" "}
<a href="/api/anthropic.json">
https://models.dev/api/anthropic.json
</a>
</code>
</div>
<h3>Providers</h3>
<p>
Lightweight list of all providers with their display name, model
count, and documentation link. Useful for finding the right{" "}
<b>Provider ID</b>.
</p>
<div class="code-block">
<code>
curl{" "}
<a href="/api/providers.json">
https://models.dev/api/providers.json
</a>
</code>
</div>
<h3>Schema</h3>
<p>JSON Schema describing the full API data shape.</p>
<div class="code-block">
<code>
curl{" "}
<a href="/api/schema.json">https://models.dev/api/schema.json</a>
</code>
</div>
<h2>Logos</h2>
<p>
Provider logos are available at <code>/logos/{`{provider}`}.svg</code>{" "}
Expand Down
Loading