API
Every feature of the site is a plain HTTP request. No key required for the public catalogue.
Stylesheet
Request a family and the weights you need. The response contains a single src per face, negotiated for the requesting browser.
<link rel="stylesheet" href="https://v2.fontapi.ir/css/inter:400,700">Several families, one stylesheet
Repeat family to load several families with one request and one <link>. Each takes the same weight syntax as the path form, and d and ur apply to all of them. A collection on this site builds exactly this URL. A custom family name (n) renames one family, so it is accepted only when a single family is requested.
<link rel="stylesheet" href="https://v2.fontapi.ir/css?family=inter:400,700&family=ibm-plex-serif:400&d=swap">
# and the structured equivalent:
curl "https://v2.fontapi.ir/json?family=inter:400,700&family=ibm-plex-serif:400"Weights and italics
Comma-separate weights. Suffix a weight with i for italic. A weight the family does not ship resolves by the CSS Fonts Level 4 matching rules rather than failing.
https://v2.fontapi.ir/css/ibm-plex-sans:400,400i,700Weight aliasing
Ask for a source weight but choose how it is labelled in the emitted CSS. Useful when your stylesheet expects font-weight: bold but the face you want is 600.
https://v2.fontapi.ir/css/ibm-plex-sans:600@bold
/* emits: font-weight: bold; using the 600 face */Custom family name
Serve a font under a different CSS family name, so you can swap the underlying face without touching your stylesheet.
https://v2.fontapi.ir/css/inter:400?n=Brand%20Sans
/* then: font-family: "Brand Sans", sans-serif; */font-display
Any value from the CSS enum: auto, block, swap, fallback, optional. Invalid values are rejected with 400 rather than silently ignored.
https://v2.fontapi.ir/css/inter:400?d=swapSubsetting
By default each script a family draws is a genuinely separate, smaller file with an accurate unicode-range, so the browser downloads only what your page text needs — Latin is typically under 10% of the full face. Every script Google Fonts defines a subset for is built, from latin and cyrillic-ext to devanagari, thai, ethiopic and math. Chinese, Japanese and Korean are cut into 120 slices ordered by how often each character is used, and whatever a family draws that no script file holds goes into other, so nothing the family covers is left out. Name the scripts you want with subset and the stylesheet carries only those; a CJK script name selects all of its slices.
/* automatic: one @font-face per file the family ships */
https://v2.fontapi.ir/css/inter:400
/* only the scripts you name */
https://v2.fontapi.ir/css/inter:400?subset=latin,latin-ext
/* every Japanese slice, and nothing else */
https://v2.fontapi.ir/css/noto-sans-jp:400?subset=japaneseunicode-range override
Request an exact range. If a pre-built subset matches it is served directly; if not, the nearest covering file is used and the JSON response reports subset_fallback so you always know whether you got byte-optimal output. ur and subset answer the same question in incompatible ways, so a request carrying both is rejected rather than silently resolved.
https://v2.fontapi.ir/css/inter:400?ur=U%2B0000-00FF
# check what actually happened:
curl "https://v2.fontapi.ir/json/inter:400?ur=U%2B0000-00FF" | jq .subset_fallbackhttp or https in font URLs
The font-file URLs in a response follow the scheme the request arrived on, so a page on plain HTTP is never handed https URLs and a page on HTTPS is never handed http ones the browser would block as mixed content. Override it with proto when you need the URLs pinned: https, http, or relative for scheme-relative //host URLs.
https://v2.fontapi.ir/css/inter:400 # follows the request
https://v2.fontapi.ir/css/inter:400?proto=https # always https://
https://v2.fontapi.ir/css/inter:400?proto=relative # //host/… , no schemeJSON
The same resolution as CSS, but structured — and unlike CSS it exposes the full format matrix plus the resolved user agent, so you can build your own @font-face rules and see why a format was chosen.
curl "https://v2.fontapi.ir/json/inter:400,700"Catalogue
Browse, search and filter the public library. No key required. A filter can repeat: several categories or languages list families in any of them, several scripts list only families that cover all of them. Each listing carries facet counts for its own filters — how many families each value would list if it were added — and every family carries sample: a sentence in its own language that it can set, which is what this site previews it in. sort=popular lists the families websites requested most in the last 30 days first, then the rest by name; each family's popularity field carries its rank, its requests and how many websites made them, and the listing's says how many families the ranking covers. With exactly one script filter, a family whose own sample is in another script also carries subset_sample: a sentence in the script asked for. /v1/suggest answers a search box as someone types — families whose name, designer or tags match, then designers and tags with how many families each has — ranked so that a name beginning with the text comes before one merely containing it; accents and letter variants such as Arabic and Persian yeh are folded, so either spelling finds both.
https://v2.fontapi.ir/v1/fonts?search=plex&language=en
https://v2.fontapi.ir/v1/fonts?category=serif&category=display
https://v2.fontapi.ir/v1/fonts?subset=latin&subset=greek
https://v2.fontapi.ir/v1/fonts?sort=popular&limit=10
https://v2.fontapi.ir/v1/fonts/inter
https://v2.fontapi.ir/v1/facets
https://v2.fontapi.ir/v1/suggest?q=vazGlyphs and languages
Every character a family draws, read from the fonts themselves, and every language it can set: a language is listed when every style maps every letter its orthography needs, judged against Google Fonts' language data. coverage is hexadecimal ranges; partial_styles names any style that lacks part of it. Each language carries its ISO 639 code, its ISO 15924 script and, for about four hundred, a sample sentence.
curl "https://v2.fontapi.ir/v1/fonts/inter/coverage" | jq '{count, coverage, languages: [.languages[].id][:5]}'Caching
Font files are immutable: every URL carries a version segment, so the bytes at a
given URL never change meaning and responses are served with max-age=31536000, immutable. Stylesheets use a
shorter window and are invalidated explicitly when a font is republished, rather than
waiting for a TTL to lapse. Byte-range and conditional requests are supported, so a
client on a poor connection can resume rather than restart.