|
| 1 | +--- |
| 2 | +hidden: true |
| 3 | +icon: list-tree |
| 4 | +--- |
| 5 | + |
| 6 | +# Model Catalogue API |
| 7 | + |
| 8 | +## List models |
| 9 | + |
| 10 | +`GET /v1/models` returns the live catalogue. It is the machine-readable source for which models exist, what they are called, what they can do, and what they cost — use it instead of scraping the model pages. |
| 11 | + |
| 12 | +By default each entry carries only its identity. Pricing, modalities and capabilities are opt-in, so the default response stays small: |
| 13 | + |
| 14 | +```bash |
| 15 | +curl https://api.aimlapi.com/v1/models |
| 16 | +``` |
| 17 | + |
| 18 | +```json |
| 19 | +{ |
| 20 | + "object": "list", |
| 21 | + "data": [ |
| 22 | + { |
| 23 | + "id": "deepgram/aura-2", |
| 24 | + "aliases": ["aura-2", "aura-2-helena-en", "deepgram/aura-2-helena-en"], |
| 25 | + "type": "internal/text-to-speech", |
| 26 | + "info": { "name": "Aura-2", "developer": "Deepgram" }, |
| 27 | + "tags": ["playground:tts"] |
| 28 | + } |
| 29 | + ] |
| 30 | +} |
| 31 | +``` |
| 32 | + |
| 33 | +{% openapi-operation spec="models-catalogue" path="/v1/models" method="get" %} |
| 34 | +[Broken link](/broken/openapi/models-catalogue) |
| 35 | +{% endopenapi-operation %} |
| 36 | + |
| 37 | +## Asking for more per model |
| 38 | + |
| 39 | +`include` attaches optional sections. Combine them freely, comma-separated: |
| 40 | + |
| 41 | +```bash |
| 42 | +curl 'https://api.aimlapi.com/v1/models?include=pricing' |
| 43 | +curl 'https://api.aimlapi.com/v1/models?include=pricing,capabilities' |
| 44 | +curl 'https://api.aimlapi.com/v1/models?include=all' |
| 45 | +``` |
| 46 | + |
| 47 | +| Value | Adds | |
| 48 | +| -------------- | --------------------------------------------------- | |
| 49 | +| `pricing` | the `pricing` block — rates, units, price bands | |
| 50 | +| `modalities` | which input and output modalities the model handles | |
| 51 | +| `capabilities` | declared capabilities, e.g. `image_to_video` | |
| 52 | +| `all` | every section. `?details=true` is a synonym | |
| 53 | + |
| 54 | +Unknown values are ignored rather than rejected, so a typo returns a valid response with that section missing. |
| 55 | + |
| 56 | +## Filtering |
| 57 | + |
| 58 | +Every filter below narrows _which models_ come back. They are independent of `include`, so you can filter on capabilities without asking for the capabilities section. |
| 59 | + |
| 60 | +| Parameter | Keeps models that… | |
| 61 | +| ------------------- | -------------------------------------------- | |
| 62 | +| `id` | match this id **or carry it as an alias** | |
| 63 | +| `type` | are served through this endpoint type | |
| 64 | +| `tags` | carry this tag, e.g. `playground:video` | |
| 65 | +| `modalities` | have it among input **or** output modalities | |
| 66 | +| `input_modalities` | accept this input modality | |
| 67 | +| `output_modalities` | produce this output modality | |
| 68 | +| `capabilities` | declare this capability | |
| 69 | + |
| 70 | +Rules that apply to all of them: |
| 71 | + |
| 72 | +* **Several values, one parameter — OR.** `?capabilities=text_to_video,image_to_video` returns models that do either. |
| 73 | +* **Several parameters — AND.** `?output_modalities=video&capabilities=audio_generation` returns models that do both. |
| 74 | +* Values are **case-insensitive**, and may be given comma-separated (`?tags=a,b`) or repeated (`?tags=a&tags=b`). Both forms merge. |
| 75 | +* An omitted parameter filters nothing. |
| 76 | + |
| 77 | +```bash |
| 78 | +# every model that turns an image into video |
| 79 | +curl 'https://api.aimlapi.com/v1/models?capabilities=image_to_video' |
| 80 | + |
| 81 | +# what one specific model costs — a few kilobytes instead of the whole catalogue |
| 82 | +curl 'https://api.aimlapi.com/v1/models?id=deepgram/aura-2&include=pricing' |
| 83 | +``` |
| 84 | + |
| 85 | +## Checking whether a model is still available |
| 86 | + |
| 87 | +Match against **`id` and `aliases` together**. A model may be published under a canonical id while the name you integrated against lives on as an alias — the alias keeps working, but it is not the `id` any more, so an `id`-only comparison reports a live model as gone. |
| 88 | + |
| 89 | +```js |
| 90 | +const res = await fetch('https://api.aimlapi.com/v1/models'); |
| 91 | +const { data } = await res.json(); |
| 92 | + |
| 93 | +const byName = new Map(); |
| 94 | +for (const model of data) { |
| 95 | + byName.set(model.id, model.id); |
| 96 | + for (const alias of model.aliases ?? []) byName.set(alias, model.id); |
| 97 | +} |
| 98 | + |
| 99 | +const canonical = byName.get(myModelId); // undefined ⇒ genuinely unavailable |
| 100 | +``` |
| 101 | +
|
| 102 | +The same map de-duplicates your list: two names resolving to one canonical id are one model, not two. |
| 103 | +
|
| 104 | +## Reading prices |
| 105 | +
|
| 106 | +With `?include=pricing`, each model carries a `pricing` block. Read `kind` first: |
| 107 | +
|
| 108 | +| `kind` | What it means | |
| 109 | +| ---------- | ------------------------------------------------------------------------------------------------------------ | |
| 110 | +| `fixed` | one rate per unit, in `units[]` | |
| 111 | +| `variants` | the rate depends on request parameters — `dimensions` names them, `variants[]` quotes a rate per combination | |
| 112 | +| `variable` | the rate cannot be quoted ahead of the request | |
| 113 | +
|
| 114 | +**Always read `per` together with `price`.** `price` is the charge for `per` units, and `per` is not the same across models — `1000000` for most token rates, `1000` for some, `1` for per-second and per-megapixel rates. Comparing bare `price` values across models compares different bases and will be wrong by orders of magnitude. |
| 115 | +
|
| 116 | +```json |
| 117 | +{ |
| 118 | + "kind": "variants", |
| 119 | + "dimensions": ["resolution"], |
| 120 | + "variants": [ |
| 121 | + { "when": { "resolution": "720p" }, "price": 0.39, "unit": "second", "per": 1 }, |
| 122 | + { "when": { "resolution": "1080p" }, "price": 0.65, "unit": "second", "per": 1 } |
| 123 | + ] |
| 124 | +} |
| 125 | +``` |
| 126 | +
|
| 127 | +Here a 5-second 1080p generation costs `0.65 × 5 = $3.25`. |
| 128 | +
|
| 129 | +Prices are in USD and are what you are charged. |
| 130 | +
|
| 131 | +## Caching |
| 132 | +
|
| 133 | +Responses carry an `ETag`. Send it back as `If-None-Match` and you get `304 Not Modified` with an empty body when nothing changed: |
| 134 | +
|
| 135 | +```bash |
| 136 | +curl -I 'https://api.aimlapi.com/v1/models?include=pricing' |
| 137 | +# etag: W/"1440a0-uH6NONsG/9An5njw3kqMcYY5k8w" |
| 138 | + |
| 139 | +curl -H 'If-None-Match: W/"1440a0-uH6NONsG/9An5njw3kqMcYY5k8w"' \ |
| 140 | + 'https://api.aimlapi.com/v1/models?include=pricing' |
| 141 | +# 304 |
| 142 | +``` |
| 143 | +
|
| 144 | +The ETag covers the whole response, so it changes on any catalogue edit — a new model or a reworded description, not only a price change. Treat it as "something moved, re-read and diff", not as a price-change feed. |
0 commit comments