Quick start
BASE=https://tinymodels.co
# what is in the catalogue
curl -s "$BASE/api/models" | jq '.total, .models[].slug'
# the video models only
curl -s "$BASE/api/models?task=video-classification" | jq '.models[].slug'
# everything you need to fetch and verify one model
curl -s "$BASE/api/models/all-minilm-l6-v2" | jq '{sha256, download_filename, download_url}'
GET /api/models
Lists the catalogue. Every parameter is optional and they combine:
| parameter | values | meaning |
|---|---|---|
| q | any text | Substring match, case-insensitive, across the name, the one-line summary and the whole model card. |
| task | task slug | Exact match, e.g. text-generation, video-classification. Browse the catalogue for the full list. |
| format | format slug | Exact match, e.g. safetensors, gguf, mlx. |
| licence | licence slug | Exact match, e.g. apache-2.0, mit, cc-by-nc-4.0. |
| size | under-100mb · 100mb-500mb · 500mb-1gb · over-1gb | A range on the file size, not an exact value. |
| sort | recency · downloads · size-asc · size-desc | Defaults to recency. |
| limit | 1–100 | Default 24, clamped at 100. |
| offset | 0 and up | For paging. `total` in the response tells you how many there are. |
The response wraps the rows with the query that produced them:
{
"total": 12, // matching the filters, ignoring limit and offset
"limit": 24,
"offset": 0,
"sort": "recency",
"models": [ … ]
}
GET /api/models/<slug>
A single model object, unwrapped:
{
"slug": "all-minilm-l6-v2",
"name": "sentence-transformers/all-MiniLM-L6-v2",
"summary": "The 22M-parameter sentence embedder that quietly powers a large share of local search.",
"task": "sentence-similarity",
"format": "safetensors",
"parameters": 22713728,
"file": { "name": "model.safetensors", "bytes": 90868376 },
"download_filename": "all-MiniLM-L6-v2.safetensors",
"licence": "apache-2.0",
"upstream": {
"repo": "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2",
"path": "model.safetensors"
},
"sha256": "53aa51172d142c89d9012cce15ae4d6cc0ca6895895114379cacb4fab128d9db",
"sha256_source": "upstream",
"mirrored_locally": false,
"download_url": "…/models/all-minilm-l6-v2/download",
"page_url": "…/models/all-minilm-l6-v2",
"checksum_url": "…/models/all-minilm-l6-v2/checksum",
"downloads": 2,
"added_at": "2026-08-03T20:14:21.719Z",
"source": "seed",
"bench": [
{
"metric": "Encoding speed",
"value": 14200,
"unit": "sentences/s",
"hardware": "NVIDIA V100 GPU",
"source": "https://www.sbert.net/docs/sentence_transformer/pretrained_models.html",
"note": "the sentence-transformers model table's own definition of its speed column"
}
]
}
The fields:
| field | values | meaning |
|---|---|---|
| slug | string | Stable identifier, used in every URL for this model. |
| name | string | org/model, as the publisher writes it. |
| summary | string | One line. May be empty. |
| task | string | What the model does. |
| format | string | safetensors, gguf, mlx, onnx, pytorch… |
| parameters | number | null | Parameter count, or null if the publisher does not state one. |
| file | { name, bytes } | The publisher's own filename and the exact size in bytes. |
| download_filename | string | What the file saves as. Differs from file.name when the publisher's name is generic, so several models can share a folder. |
| licence | string | As the publisher declares it. Check it — some are non-commercial. |
| upstream | { repo, path } | null | Where the bytes actually come from. |
| sha256 | 64 hex chars | The digest to verify against. |
| sha256_source | upstream · local | `upstream` means the publisher's own record of that file (Hugging Face's LFS object id). `local` means this hub computed it from bytes it stored. |
| mirrored_locally | boolean | Whether this hub holds the bytes. Always false for the curated catalogue. |
| download_url | string | The stable download URL. Absolute, so it is copy-pasteable. |
| page_url | string | The model page. |
| checksum_url | string | The checksum page. |
| downloads | number | Times the hub served a download response for it. |
| bench | array | Benchmark figures: `{ metric, value, unit, hardware, source, note?, measured?, short? }`. Entries with `measured: true` were run by this hub on its own machine — the first is always milliseconds for one fixed input, which is what the catalogue column shows, and the second is the peak memory that run needed; `short` is the label the row uses. The rest are published results quoted from the source link. `hardware` is null when a source does not say what it ran on. Nothing is ever estimated: a figure is published, measured, or absent. |
| added_at | ISO 8601 | When the entry was added to the catalogue. |
| source | seed | How the row got here. `seed` is the curated catalogue. |
GET /health
Enough to check the service is alive and see what it is serving:
{
"ok": true,
"models": 12,
"described_bytes": 5993076446,
"port": 8080,
"uptime_seconds": 849
}
Downloading and verifying from a script
Two endpoints do the work, and neither is JSON:
- GET /models/<slug>/download — answers 302 to the publisher, with x-checksum-sha256 and a content-disposition naming the file
- GET /models/<slug>/checksum — the digest as the default HTML page, ?format=txt for a sha256sum-compatible line, or ?format=json for { slug, file, upstream_file, bytes, sha256, sha256_source, download_url }
SLUG=all-minilm-l6-v2 curl -sL -o "$SLUG.safetensors" "$BASE/models/$SLUG/download" curl -s "$BASE/models/$SLUG/checksum?format=txt" | shasum -a 256 -c -
Note that the digest header rides on the 302: a client that follows redirects never sees it. Take the expected digest from the API or the checksum endpoint and compare it yourself, as above. Verifying a download goes through this properly, including what a matching digest does and does not prove.
Writes
There are none. There is no upload endpoint, no authentication and no state a request can change. GET /upload, POST /upload and POST /api/upload all answer 404, and the proof run asserts that.