Documentation

API

API publique en lecture seule : récupérez le CSS de repli et les métriques calibrées de chaque police de la base, en JSON ou en CSS.

Vue d'ensemble

L'API expose, en lecture seule, chaque police de la base avec ses métriques calibrées et le CSS de repli correspondant. Elle est conçue pour être appelée directement depuis un site tiers, un script de build ou un plugin de CMS.

  • URL de base : https://nmfs.agencewebperformance.fr/api/v1
  • Aucune authentification, aucune clé, aucun quota déclaré. Les réponses sont mises en cache en amont (voir Cache), ce qui absorbe les appels répétés.
  • Destinée aux projets en développement, pas à la production. Récupérez le CSS au moment du build ou côté serveur, et intégrez-le dans votre propre feuille de styles. Ne référencez jamais une URL de l'API depuis un site en ligne : ce n'est pas un CDN, et rien ne garantit sa disponibilité ni sa latence pour vos visiteurs.
  • Pas de CORS. Le navigateur d'un visiteur d'un site tiers ne peut pas lire ces réponses. Les usages prévus — script de build, plugin de CMS côté serveur, curl — n'en ont pas besoin.
  • Seules les polices publiées et publiques sont exposées. Les polices privées et les soumissions en attente renvoient un 404 indiscernable d'un identifiant inexistant — impossible d'en déduire l'existence.
  • Aucune donnée interne ne sort : ni chemin de fichier, ni adresse e-mail, ni le fichier de police lui-même.

Points d'entrée

Méthode et cheminRenvoieType
GET /api/v1/fontsListe paginée des policesapplication/json
GET /api/v1/fonts/{id}Métadonnées, métriques et CSS d'une policeapplication/json
GET /api/v1/fonts/{id}/cssLe CSS seul, à copier dans votre projettext/plain

Seuls GET et HEAD sont acceptés. Une autre méthode sur un chemin connu renvoie 405 ; un chemin inconnu sous /api renvoie 404, toujours en JSON.

Lister les polices

GET https://nmfs.agencewebperformance.fr/api/v1/fonts?stack=serif&per_page=25
ParamètreValeursEffet
qtexte libreFiltre les polices dont le nom contient ce texte.
stacksans ou serifNe garde que ce stack de repli. Toute autre valeur est ignorée.
slugslug exact, ex. poppinsCorrespondance exacte. Un slug n'étant pas garanti unique, la réponse reste une liste (0 à n éléments) et n'est pas paginée.
pageentier ≥ 1Page demandée. Défaut 1.
per_page1 à 100Taille de page. Défaut 50, plafonnée à 100.

Les polices sont triées par nom, sans tenir compte de la casse. Chaque élément porte les liens vers sa fiche JSON, son CSS et sa page dans l'outil :

{
  "data": [
    {
      "id": 1,
      "name": "Poppins",
      "slug": "poppins",
      "stack": "sans",
      "updated_at": "2026-05-12T15:33:02+00:00",
      "links": {
        "self": "https://nmfs.agencewebperformance.fr/api/v1/fonts/1",
        "css":  "https://nmfs.agencewebperformance.fr/api/v1/fonts/1/css",
        "html": "https://nmfs.agencewebperformance.fr/font/1"
      }
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 81, "total_pages": 2 }
}

Une police en détail

GET https://nmfs.agencewebperformance.fr/api/v1/fonts/1

La fiche regroupe tout ce qu'il faut pour intégrer la police sans repasser par l'outil. Les métriques sont données par cible — la police système que chaque repli vise réellement — plutôt que par numéro d'emplacement :

{
  "id": 1,
  "name": "Poppins",
  "slug": "poppins",
  "stack": "sans",
  "contributor": "Eroan",
  "created_at": "2026-04-30T09:17:41+00:00",
  "updated_at": "2026-05-12T15:33:02+00:00",
  "fallbacks": {
    "android": {
      "font": "Roboto",
      "size_adjust": 112.54,
      "ascent_override": 97.24,
      "descent_override": 35.78,
      "line_gap_override": null
    },
    "desktop": {
      "font": "Arial",
      "size_adjust": 113,
      "ascent_override": 96,
      "descent_override": 34.2,
      "line_gap_override": null
    }
  },
  "font_family": "'Poppins', 'Poppins-fallback', sans-serif",
  "css": "/* Android fallback (Roboto) — declared FIRST */\n@font-face { … }\n\nbody { font-family: … }",
  "links": { "self": "…", "css": "…", "html": "…" }
}
ChampContenu
stacksans (Arial + Roboto) ou serif (Times New Roman + Noto Serif).
fallbacks.desktopRepli pour Windows, macOS et iOS. C'est la face déclarée en dernier dans le CSS, donc prioritaire quand les deux polices système sont présentes.
fallbacks.androidRepli pour Android, où la police desktop n'existe pas. Déclarée en premier.
*.size_adjustPourcentage, toujours renseigné (100 = inchangé).
*.ascent_override, descent_override, line_gap_overridePourcentage, ou null quand le descripteur vaut normal et n'est pas émis dans le CSS.
font_familyLa pile font-family seule, pour l'appliquer au sélecteur de votre choix.
cssL'exemple d'intégration complet, identique à celui de la page de la police : les deux @font-face (une famille de repli, deux faces) et la déclaration sur body.
contributorNom d'affichage du dernier contributeur, ou null.
created_at, updated_atISO 8601, avec décalage horaire du serveur.

Le CSS seul

GET https://nmfs.agencewebperformance.fr/api/v1/fonts/1/css

Renvoie les règles @font-face précédées d'un en-tête de provenance, pour les récupérer sans analyser de JSON — typiquement depuis un script de build :

curl -s https://nmfs.agencewebperformance.fr/api/v1/fonts/1/css >> src/styles/fonts.css

Ce point d'entrée n'est pas une feuille de style, et ne peut pas en être une. Il est servi en text/plain avec X-Content-Type-Options: nosniff : aucun navigateur moderne ne l'applique via <link rel="stylesheet">. Mieux, quand le navigateur annonce lui-même une destination style (Sec-Fetch-Dest: style), la requête est refusée en 403 avec un message explicite. L'API existe pour alimenter vos projets, pas pour que vos visiteurs en dépendent à chaque chargement de page.

Le CSS est identique à celui affiché sur la page de la police : les deux @font-face, puis une déclaration body { font-family: … }. Cette dernière est un exemple d'intégration — adaptez le sélecteur à votre projet (html, .site, un composant…) ; la valeur seule est aussi fournie dans le champ font_family de la fiche JSON :

body { font-family: 'Poppins', 'Poppins-fallback', sans-serif; }

Le CSS reproduit la pile de la police telle qu'elle a été calibrée dans l'outil. Si vous réorganisez ces règles, conservez l'ordre : la face desktop doit rester déclarée en dernier.

Cache et requêtes conditionnelles

Toutes les réponses portent Cache-Control: public, max-age=3600 et un ETag qui change dès que la fiche est ré-enregistrée. Tout cache intermédiaire ou client HTTP qui respecte ces en-têtes peut donc les conserver une heure sans nous solliciter.

Pour revalider sans re-télécharger, renvoyez l'ETag reçu : la réponse est un 304 Not Modified sans corps si rien n'a changé.

GET /api/v1/fonts/1/css
If-None-Match: "c8cf8315612e57dc9057159925c729d7"

HTTP/1.1 304 Not Modified

Aucun cookie n'est posé par l'API — c'est ce qui rend le cache partagé possible.

Erreurs

Les erreurs sont toujours en JSON, y compris sur le point d'entrée CSS :

HTTP/1.1 404 Not Found
{ "error": "not_found" }
StatutCas
404Identifiant inexistant, police privée, soumission en attente de validation, ou chemin inconnu. Les trois premiers cas sont volontairement indiscernables.
403Tentative de chargement du point d'entrée CSS comme feuille de style (Sec-Fetch-Dest: style) — { "error": "stylesheet_hotlink_forbidden" }.
405Méthode autre que GET / HEAD sur un chemin connu.
500Erreur interne — { "error": "internal_error" }. Le détail n'est jamais exposé.

Un paramètre de filtre invalide n'est pas une erreur : il est ignoré (stack) ou ramené dans les bornes (per_page).

Stabilité

Le préfixe /v1 est un engagement : les champs documentés ici ne seront ni renommés ni supprimés dans cette version. Des champs pourront être ajoutés — écrivez vos clients pour qu'ils ignorent ce qu'ils ne connaissent pas. Un changement incompatible passera par un /v2, en laissant /v1 en service.

Les identifiants numériques sont stables dans le temps. Les slugs sont dérivés du nom de la police et peuvent changer si celle-ci est renommée ; préférez l'identifiant pour référencer une police durablement.

Skill pour Claude et IA génératives

Ce bloc est un mode d'emploi condensé de l'API, rédigé pour un assistant. Copiez-le dans les instructions d'un projet Claude, un fichier SKILL.md, un CLAUDE.md ou le prompt système de l'outil de votre choix : l'assistant saura alors chercher une police dans la base, récupérer son CSS et l'intégrer correctement — sans inventer de métriques.

# No More Font Shift — skill API

## Ce que c'est
No More Font Shift maintient une base de polices web avec, pour chacune, un CSS de repli calibré : deux @font-face (size-adjust, ascent-override, descent-override, line-gap-override) qui éliminent le décalage de mise en page (CLS) pendant le chargement de la police. L'API est publique, en lecture seule, sans clé, en JSON ou en CSS.

Base : https://nmfs.agencewebperformance.fr/api/v1

## Quand l'utiliser
- L'utilisateur veut supprimer le CLS causé par une police web.
- Il cite une police (Poppins, Inter, Lora…) : cherche-la ICI avant de calculer des métriques toi-même.

## Commandes
1. Trouver une police   GET /fonts?q=poppins      (ou ?slug=poppins pour une correspondance exacte)
2. Lire sa fiche        GET /fonts/{id}           → fallbacks.desktop, fallbacks.android, font_family, css
3. Récupérer le CSS     GET /fonts/{id}/css       (text/css, @font-face uniquement)

## Comment livrer le résultat
- Insère le contenu de `css` dans la feuille de styles DU PROJET. Ne référence JAMAIS une URL de l'API depuis un site en production : ce n'est pas un CDN, le CSS est servi en text/plain et un chargement en feuille de style est refusé (403).
- Le CSS se termine par un exemple `body { font-family: … }` : adapte ce sélecteur au projet (`font_family` donne la pile seule).
- Ne réordonne JAMAIS les deux @font-face : la face desktop doit rester déclarée en dernier (la dernière l'emporte).
- Si la recherche renvoie une liste vide, dis-le à l'utilisateur et propose l'outil (https://nmfs.agencewebperformance.fr) : n'invente pas de valeurs.

## Règles
- Uniquement GET. Réponses cacheables (ETag, max-age 3600). Aucune authentification.
- Pas de CORS : appelle l'API au build ou côté serveur, jamais depuis le navigateur d'un visiteur.
- 404 = identifiant inexistant OU police privée : n'en déduis pas l'existence.
- Champs stables en v1 ; ignore ceux que tu ne connais pas.

Documentation complète : https://nmfs.agencewebperformance.fr/docs/api

Le skill renvoie vers cette page pour tout ce qu'il ne couvre pas. Il évolue avec l'API : recopiez-le après une mise à jour majeure.