Aller au contenu
Liens Courts, Résilients et SouverainsLCRS
Menu

Documentation de l'API

API REST de lcrs.fr pour créer et gérer les liens courts d'un workspace, sur le domaine du service ou sur un domaine personnalisé, obtenir leurs QR codes et lire leurs statistiques.

Version 1.5.0 · Description OpenAPI 3.1 : /api/v1/openapi.yaml

Créer une clé

Dans le dashboard, ouvrez le workspace, puis « Clés API » (réservé aux propriétaires et administrateurs, adresse e-mail confirmée). Donnez un nom à la clé, choisissez sa portée (lecture et écriture, ou lecture seule), puis copiez la clé affichée : elle ne sera plus jamais affichée. Une clé se révoque depuis le même écran.

Authentification

Clé API du workspace dans l'en-tête Authorization: Bearer <clé> uniquement. Une clé se crée dans le dashboard (« Clés API » du workspace) et ne s'affiche qu'une fois. Clé absente, invalide ou révoquée : 401 unauthenticated. Après 100 échecs d'authentification en 15 minutes depuis une même adresse IP : 429 rate_limited, même pour une clé valide, jusqu'à la fin de la fenêtre. Plusieurs intégrations qui partagent une adresse IP de sortie (plateforme d'automatisation, NAT d'entreprise, CI) partagent donc ce compteur : une intégration doit cesser ses appels après un 401 au lieu de réessayer, et une clé révoquée doit être retirée de toutes les intégrations qui l'utilisent. La clé ne doit jamais figurer dans l'URL : en paramètre de requête, elle est refusée (401 ; 422 unknown_field si une clé valide est aussi présentée dans l'en-tête) et peut rester dans les journaux d'accès des intermédiaires (proxy, serveur web).

Format des clés

lcrs_<identifiant>_<secret>. lcrs_ est le préfixe du service ; l'identifiant de clé (8 caractères, non secret) apparaît dans created_by.key_prefix et dans le dashboard sous la forme lcrs_<identifiant>…. Une règle gitleaks fournie par lcrs.fr, reproduite en entier dans la documentation publique /docs/api (section « Format des clés »), détecte les clés publiées par erreur.

Pour détecter une clé publiée par erreur, ajoutez cette règle à la configuration gitleaks de vos dépôts :

.gitleaks.toml
# Règle gitleaks de détection des clés API lcrs.fr (FR-003).
#
# Une clé a la forme lcrs_<identifiant>_<secret> : le préfixe du service « lcrs_ », un
# identifiant de clé de 8 caractères et un secret de 44 caractères, tous deux dans l'alphabet
# base58. Ajoutez ce bloc à la configuration gitleaks de votre projet (fichier .gitleaks.toml,
# avec [extend] useDefault = true pour garder les règles par défaut).

[[rules]]
id = "lcrs-api-key"
description = "Clé API lcrs.fr : révoquez-la dans « Clés API » du workspace, puis créez-en une autre."
regex = '''lcrs_[1-9A-HJ-NP-Za-km-z]{8}_[1-9A-HJ-NP-Za-km-z]{44}'''
keywords = ["lcrs_"]
tags = ["key", "lcrs"]

Portée

Une clé read_only ne peut que lire ; toute écriture rend 403 insufficient_scope. L'existence du lien est contrôlée avant la portée : une écriture visant un lien introuvable rend 404 quelle que soit la portée de la clé.

Format

JSON en UTF-8, champs en snake_case, dates ISO 8601 en UTC, identifiants publics préfixés (lnk_, dom_). Corps des requêtes POST et PATCH en Content-Type: application/json (paramètre charset=utf-8 accepté, casse indifférente ; type absent ou autre : 400 invalid_content_type), objet JSON de 16 Kio au plus (au-delà : 413 payload_too_large). Un corps envoyé avec GET ou DELETE est ignoré jusqu'à 1 Mio ; au-delà de 1 Mio, quelle que soit l'opération, le serveur web refuse la requête (413 payload_too_large, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id).

Erreurs

{"error": {"code", "message", "details"?, "request_id"?}} ; code stable (anglais), message en français. Une erreur du client ne rend jamais de 5xx : une requête que le serveur ne peut pas interpréter (en-tête d'hôte invalide…) rend 400 bad_request.

CodeStatutSens
unauthenticated401Clé absente, invalide ou révoquée.
insufficient_scope403Écriture avec une clé en lecture seule.
workspace_pending_deletion403Workspace en attente de suppression.
not_found404Lien ou chemin introuvable.
invalid_json400Corps qui n'est pas un objet JSON valide.
invalid_content_type400Content-Type absent ou autre que JSON.
bad_request400Requête que le serveur ne peut pas interpréter.
method_not_allowed405Méthode non prévue pour ce chemin.
payload_too_large413Corps de plus de 16 Kio (1 Mio au serveur web).
validation_failed422Valeurs invalides, un détail par champ.
unknown_field422Champ ou paramètre non prévu.
slug_taken409Slug déjà pris ; un slug libre est proposé.
link_state_conflict409Changement impossible dans l'état actuel du lien.
link_blocked409Lien bloqué pour destination dangereuse : pas de QR code (1.3.0).
idempotency_key_reused409Même Idempotency-Key, corps différent.
idempotency_in_progress409Première requête de même Idempotency-Key encore en cours.
plan_feature_unavailable403Fonctionnalité non comprise dans l'offre du titulaire (statistiques) ; voir `details`.
quota_exceeded429Limite de l'offre atteinte (liens, tags par lien, ou clics du mois pour les statistiques) ; voir `details.quota`. Ne pas réessayer avant `Retry-After` s'il est présent.
rate_limited429Limite de débit dépassée ; voir Retry-After.
creation_limit_reached429Plafond de créations du compte sur 24 heures atteint ; voir `details.retry_at` et Retry-After (1.5.0).
account_suspended403Compte du créateur de la clé suspendu par l'équipe lcrs.fr (1.5.0).
workspace_suspended403Workspace suspendu par l'équipe lcrs.fr (1.5.0).
internal_error500Erreur du service, avec request_id.
service_unavailable503Service momentanément indisponible.

Pagination

page (≥ 1, défaut 1), per_page (1 à 100, défaut 20) ; hors bornes : 422.

Limite de débit

Par clé, selon l'offre du titulaire du workspace (Free 60 requêtes par minute, Starter 300, Pro et Business 1 200). En-têtes X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset ; dépassement : 429 rate_limited avec Retry-After. Ces trois en-têtes sont présents sur toute réponse à une requête authentifiée, succès ou erreur (absents seulement en 401, sur le 429 des échecs d'authentification par IP et sur les 404 et 405 de chemin ou de méthode inconnus, rendus avant l'authentification) : la limite de débit est toujours bornée.

Chemins et méthodes

Un chemin inconnu sous /api/v1/, barre oblique finale comprise (/links/ : aucune redirection), rend 404 not_found ; une méthode non prévue pour un chemin existant (PUT, OPTIONS…) rend 405 method_not_allowed, au format d'erreur standard. Ces deux réponses sont rendues avant toute vérification de la clé, qu'une clé soit présentée ou non : sans en-têtes X-RateLimit-*, sans consommer de limite de débit ni compter comme une utilisation de la clé.

Paramètres de requête

Chaque opération n'accepte que les paramètres qu'elle documente (listLinks : page, per_page, q, status, slug, tag, has_tags, untagged, domain ; listTags : page, per_page, key ; getAnalytics : period, from, to, tag, link, country, device, referrer, group_by, sort, page, per_page ; listDomains : page, per_page ; getLinkQrCode : format, size ; les autres : aucun). Tout autre paramètre (per-page, limit…) rend 422 unknown_field, avec le nom du paramètre dans details, comme un champ inconnu du corps : une faute de frappe n'est jamais ignorée. Une pagination ou un filtre invalides, ou un lien introuvable, sont signalés en premier.

Création rejouable

En-tête facultatif Idempotency-Key sur la création (24 h).

Tags

Paires clé/valeur libres portées par un lien ({"campaign": "black-friday"}). Clé de 1 à 32 caractères (lettres minuscules non accentuées, chiffres, -, _, commençant par une lettre ; une clé envoyée avec des majuscules est enregistrée en minuscules) ; valeur de 1 à 100 caractères Unicode (points de code), espaces de bord retirés, casse conservée et significative, sans caractère de contrôle, retour à la ligne, séparateur de ligne ou de paragraphe (U+2028, U+2029) ni contrôle du sens d'écriture (U+202A à U+202E, U+2066 à U+2069). Nombre de tags par lien limité par l'offre du titulaire (Free 1, Starter, Pro et Business 20 ; au-delà : 429 quota_exceeded, details.quota à max_tags_per_link). Chaque clic garde une copie des tags du lien à l'instant de la redirection : modifier les tags ne change jamais les clics passés. Les tags sont copiés sur chaque clic et conservés avec l'historique : n'y placez pas de données personnelles (adresse e-mail, nom d'un particulier). Envoyez les caractères non ASCII en UTF-8 tels quels : échappés en \uXXXX, 20 valeurs longues peuvent dépasser la limite de 16 Kio du corps.

Statistiques

getAnalytics, à partir de l'offre Starter (Free : 403 plan_feature_unavailable). Clics hors robots, jours et heures selon l'heure de Paris, tags pris à l'instant de chaque clic. Suspendues (429 quota_exceeded, details.quota à max_clicks_per_month) quand la consommation du mois du titulaire dépasse la limite de son offre, jusqu'au 1er du mois suivant.

Compteur des liens (1.2.0)

click_count et last_clicked_at d'un lien ne comptent plus les clics de robots, comme les statistiques. Recalculés une fois à la mise en service de la 1.2.0, ils ont pu baisser pour les liens qui avaient reçu des clics de robots (aperçus des messageries et réseaux sociaux) ; ils ne baissent plus ensuite, purge comprise.

Domaines (1.3.0)

Un lien est servi sur le domaine du service (lcrs.fr) ou sur un domaine personnalisé du titulaire du workspace (go.acme.fr). Les domaines s'ajoutent, se vérifient et se suppriment dans le dashboard (« Mon compte », réservé au titulaire) ; l'API les liste en lecture (listDomains). À la création, domain (identifiant dom_… ou nom) choisit le domaine ; sans domain, le domaine par défaut du workspace est utilisé. Seul un domaine active peut recevoir un lien. Un slug est unique sur son domaine : promo peut exister sur lcrs.fr et sur go.acme.fr. short_url est toujours l'adresse complète, sur le domaine du lien, en forme ASCII (https://liens.xn--caf-dma.fr/promo).

QR codes (1.3.0)

getLinkQrCode rend l'image (PNG ou SVG) du QR code de l'URL courte d'un lien ; chaque scan passe par la redirection et compte comme un clic.

Aperçus sociaux (1.4.0)

Collé sur un réseau social ou une messagerie (LinkedIn, Facebook, X, Slack, WhatsApp…), un lien actif est présenté par une carte que lcrs.fr construit à partir des informations publiées par sa destination (titre, description, image recadrée), avec la mention « via lcrs.fr » sur l'offre Free ; les offres payantes peuvent la retirer dans les réglages du workspace. Le champ preview d'un lien, en lecture seule, décrit cette carte. Elle ne se personnalise pas. Les passages des robots des réseaux ne comptent jamais comme des clics.

Anti-abus (1.5.0)

Un lien peut être checking (en vérification : sa destination est analysée avant qu'il ne redirige, quelques secondes, pour un compte récent) ou under_review (en examen par l'équipe lcrs.fr) ; ni l'un ni l'autre ne redirige. Une destination refusée par lcrs.fr est rejetée à la création (422, destination_refused) ; un compte récent a un plafond de créations sur 24 heures (429 creation_limit_reached, avec Retry-After) ; les clés d'un compte ou d'un workspace suspendu sont refusées (403 account_suspended, workspace_suspended). Les mesures sont expliquées et contestables dans le dashboard.

Opérations

Lister les tags du workspace

GET /api/v1/tags

Couples clé et valeur portés par les liens non supprimés du workspace de la clé, avec le nombre de liens qui portent chacun. Rien n'est à déclarer : un couple apparaît dès qu'un lien le porte et disparaît quand plus aucun ne le porte. Ordre : clés par ordre alphabétique, puis valeurs par nombre de liens décroissant, puis par ordre alphabétique. Permis aux clés read_only. Pour obtenir les liens d'un couple : listLinks avec tag[<clé>]=<valeur>. Cas limites : key invalide → 422 ; per_page=500 → 422 ; workspace sans tag → liste vide.

Paramètres

  • page (requête) : Numéro de page, à partir de 1 ; hors bornes ou non numérique → 422. Exemple : 1.
  • per_page (requête) : Taille de page, de 1 à 100 ; hors bornes ou non numérique → 422. Exemple : 20.
  • key (requête) : Limite la liste aux valeurs d'une clé (normalisée en minuscules). Exemple : campaign.

Exemple de requête

curl "https://lcrs.fr/api/v1/tags?page=1&per_page=20" \
  -H "Authorization: Bearer lcrs_7Qk2Ab9x_…"

Réponse 200

Page de couples clé et valeur.

{
    "data": [
        {
            "key": "campaign",
            "value": "black-friday",
            "link_count": 12
        },
        {
            "key": "campaign",
            "value": "summer-sale",
            "link_count": 3
        },
        {
            "key": "channel",
            "value": "Email",
            "link_count": 8
        },
        {
            "key": "channel",
            "value": "email",
            "link_count": 5
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 20,
        "total": 4
    }
}

Erreurs

400
Requête rejetée par le serveur avant son traitement, par exemple un en-tête d'hôte invalide (bad_request, message générique).
Requête rejetée avant son traitement (en-tête d'hôte invalide…)
{
    "error": {
        "code": "bad_request",
        "message": "La requête n'a pas pu être interprétée."
    }
}
401
Clé absente, invalide ou révoquée.
Clé absente, invalide ou placée dans l'URL
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
Clé révoquée (même réponse que toute autre clé refusée)
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
403
Workspace en attente de suppression (workspace_pending_deletion), compte du créateur de la clé ou workspace suspendu (account_suspended, workspace_suspended, 1.5.0) ; une lecture ne reçoit jamais insufficient_scope.
Workspace en attente de suppression
{
    "error": {
        "code": "workspace_pending_deletion",
        "message": "Ce workspace est en attente de suppression : ses clés API sont suspendues jusqu'à sa restauration."
    }
}
Compte du créateur de la clé suspendu (1.5.0)
{
    "error": {
        "code": "account_suspended",
        "message": "Le compte qui a créé cette clé est suspendu par l'équipe lcrs.fr : la clé est refusée tant que la suspension dure."
    }
}
Workspace suspendu (1.5.0)
{
    "error": {
        "code": "workspace_suspended",
        "message": "Ce workspace est suspendu par l'équipe lcrs.fr : ses clés API sont refusées tant que la suspension dure."
    }
}
413
Corps de requête de plus de 16 Kio (payload_too_large). Au-delà de 1 Mio, quelle que soit l'opération, la réponse vient du serveur web, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id.
Corps de plus de 16 Kio
{
    "error": {
        "code": "payload_too_large",
        "message": "Le corps de la requête dépasse 16 Kio."
    }
}
422
Pagination ou clé invalides (validation_failed), paramètre non prévu (unknown_field).
Clé mal formée
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "key",
                "code": "tag_key_invalid",
                "message": "Une clé compte de 1 à 32 caractères : lettres non accentuées, chiffres, tiret et underscore, en commençant par une lettre."
            }
        ]
    }
}
Pagination hors bornes (per_page=500)
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "per_page",
                "code": "out_of_range",
                "message": "La taille de page doit être comprise entre 1 et 100."
            }
        ]
    }
}
429
Limite de débit (rate_limited, en-tête Retry-After) : par clé, ou après 100 échecs d'authentification en 15 minutes depuis une même IP.
Limite de débit de la clé dépassée (en-tête Retry-After)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 12 secondes."
    }
}
Trop d'échecs d'authentification depuis cette adresse IP (sans en-têtes X-RateLimit)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 540 secondes."
    }
}
500
Erreur serveur (internal_error), avec l'identifiant de corrélation request_id, aussi rendu dans l'en-tête X-Request-Id.
Erreur serveur, avec l'identifiant de corrélation
{
    "error": {
        "code": "internal_error",
        "message": "Une erreur interne est survenue. Communiquez cet identifiant au support.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}
503
Service momentanément indisponible (service_unavailable), avec request_id ; réessayer plus tard. Si l'application ne répond pas (arrêt, saturation, délai dépassé), la réponse vient du serveur web, au même format, avec request_id et X-Request-Id, sans en-têtes X-RateLimit-*.
Service momentanément indisponible
{
    "error": {
        "code": "service_unavailable",
        "message": "Le service est momentanément indisponible. Réessayez dans quelques instants.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}

Lire les statistiques du workspace

GET /api/v1/analytics

Clics du workspace de la clé sur une période, éventuellement filtrés et regroupés. Les chiffres sont ceux du tableau de bord pour la même période et les mêmes filtres. - Clics comptés : les clics des robots d'aperçu (messageries, réseaux sociaux) ne sont jamais comptés ; leur nombre est rendu à part (bot_clicks). - Fuseau : jours et heures découpés selon l'heure de Paris (Europe/Paris), pour tous les workspaces. Un jour est rendu en date calendaire AAAA-MM-JJ de Paris ; une heure, par l'instant UTC de son début (le jour du retour à l'heure d'hiver compte 25 heures). period donne les deux formes : jours de Paris (from, to) et instants UTC (start, end). - Période : period (défaut 30d, ou 7d quand l'historique de l'offre compte moins de 30 jours), ou from et to (jours de Paris, to inclus, 366 jours au plus), dans l'historique de l'offre du titulaire (Free 30 jours, Starter 365, Pro et Business sans limite). 24h : les 24 heures pleines qui précèdent l'heure en cours, et l'heure en cours (25 lignes avec group_by=hour). 7d, 30d, 90d et 12m : 7, 30, 90 et 365 jours de Paris, aujourd'hui inclus (12m compte toujours 365 jours, année bissextile comprise). - Tags : les filtres et le regroupement tag:<clé> portent sur les tags du lien à l'instant de chaque clic, jamais sur ses tags actuels. value: null regroupe les clics dont l'instantané ne portait pas la clé. - Sans group_by : total (AnalyticsSummary). Avec group_by : collection paginée (AnalyticsCollection), chaque jour ou heure de la période présent même à 0. - Accès : offre Starter et au-delà (sinon 403 plan_feature_unavailable) ; clés de toute portée. Quand la consommation du mois du titulaire dépasse la limite de son offre, les statistiques sont suspendues jusqu'au 1er du mois suivant : 429 quota_exceeded (details.quota à max_clicks_per_month, Retry-After jusqu'au 1er du mois à 0 h, heure de Paris). Les liens continuent de rediriger et les clics d'être comptés. - Ordre des contrôles : paramètres (422, lien d'un autre workspace → 404, puis paramètre non prévu → 422 unknown_field, comme pour les autres opérations), puis offre (403 plan_feature_unavailable), puis quota du mois (429 quota_exceeded). Une clé Free dont le quota est dépassé reçoit donc 403 ; un filtre mal formé donne 422 même en Free. Cas limites : from avant l'historique de l'offre → 422 period_out_of_history ; group_by=hour sur une période qui commence plus de 30 jours avant aujourd'hui (au-delà des 31 derniers jours, aujourd'hui compris) → 422 hour_period_too_old ; group_by=day avec period=24h → 422 invalid_group_by (deux jours de Paris incomplets : regrouper par heure) ; country=ZZ (code hors ISO 3166-1) ou device=bot → 422 invalid_choice ; tag[campaign] répété → 422 tag_filter_conflict ; link mal formé → 422 invalid_id, plus de 20 liens → 422 too_many_links, lien d'un autre workspace → 404 ; sort, page ou per_page sans group_by → 422 not_applicable ; page ou per_page hors bornes → 422 out_of_range ; avec device, bot_clicks vaut toujours 0 ; workspace sans clic → clicks: 0, jours à 0.

Paramètres

  • period (requête) : Période nommée ; exclusive avec from / to. Par défaut 30d, ou 7d quand l'historique de l'offre compte moins de 30 jours (il en compte toujours au moins 7) : une demande sans période n'est jamais refusée pour l'historique. Exemple : 30d.
  • from (requête) : Premier jour (Paris), avec to. Exemple : 2026-09-01.
  • to (requête) : Dernier jour inclus (Paris), au plus aujourd'hui, avec from. Exemple : 2026-09-30.
  • tag (requête) : Filtres de tags tag[<clé>]=<valeur> (1 à 5, une valeur par clé, combinés en ET), sur l'instantané des tags de chaque clic. Exemple : { "campaign": "black-friday", "channel": "email" }.
  • link (requête) : Liens du workspace (lnk_…, 1 à 20, séparés par des virgules), supprimés compris. Identifiant mal formé → 422 invalid_id ; plus de 20 liens → 422 too_many_links ; lien inconnu ou d'un autre workspace → 404. Exemple : lnk_4Vq9cE2mK7pW3xT8yR1nB,lnk_9Hd2Lm5Qx8Wz3Ty6Rc1Pv.
  • country (requête) : Pays (code ISO 3166-1 alpha-2 attribué), ou XX pour inconnu ; tout autre code → 422 invalid_choice. Exemple : FR.
  • device (requête) : Type d'appareil ; bot → 422 invalid_choice (les robots ne sont jamais comptés). Exemple : mobile.
  • referrer (requête) : Domaine d'origine tel qu'enregistré (t.co, www.google.com), ou (direct) pour les clics sans origine. Exemple : t.co.
  • group_by (requête) : Regroupement : day (refusé avec period=24h), hour (31 derniers jours, aujourd'hui compris), link, country, device, referrer, ou tag:<clé>. La clé est ramenée en minuscules, comme celle des filtres tag[<clé>] (tag:Campaign équivaut à tag:campaign). Exemple : tag:campaign.
  • sort (requête) : Ordre des lignes (avec group_by). Pour link, country, device, referrer et tag:<clé> : -clicks (défaut), clicks, label, -label ; time et -time y sont refusés (422 invalid_sort). Pour day et hour, toujours chronologique : time (défaut) ou -time ; clicks, -clicks, label et -label y sont refusés (422 invalid_sort). Par nombre de clics (clicks comme -clicks), les ex aequo sont départagés par libellé croissant. Par libellé : le libellé du tableau de bord, et non value (nom français du pays, « Inconnu » pour XX ; appareil en français ; titre du lien, à défaut son lien court ; hôte ; valeur du tag), dans l'ordre alphabétique sans casse ni accents, valeurs null, XX (pays) et unknown (appareil) en fin de liste avec label comme avec -label. À libellé égal (deux liens de même titre, Email et email), départage final par value comparée octet par octet, dans le sens du libellé (croissant, sauf avec -label) : l'ordre est unique et stable d'une page à l'autre. Sans group_by → 422 not_applicable. Exemple : group_by=country&sort=label rend DE (Allemagne), BE (Belgique), FR (France). Exemple : label.
  • page (requête) : Numéro de page, à partir de 1 ; hors bornes ou non numérique → 422. Exemple : 1.
  • per_page (requête) : Taille de page, de 1 à 100 ; hors bornes ou non numérique → 422. Exemple : 20.

Exemple de requête

curl "https://lcrs.fr/api/v1/analytics?page=1&per_page=20" \
  -H "Authorization: Bearer lcrs_7Qk2Ab9x_…"

Réponse 200

Total de la période (sans `group_by`) ou page de lignes (avec `group_by`).

Erreurs

400
Requête rejetée par le serveur avant son traitement, par exemple un en-tête d'hôte invalide (bad_request, message générique).
Requête rejetée avant son traitement (en-tête d'hôte invalide…)
{
    "error": {
        "code": "bad_request",
        "message": "La requête n'a pas pu être interprétée."
    }
}
401
Clé absente, invalide ou révoquée.
Clé absente, invalide ou placée dans l'URL
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
Clé révoquée (même réponse que toute autre clé refusée)
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
403
Offre sans statistiques par l'API (plan_feature_unavailable) ou workspace en attente de suppression (workspace_pending_deletion).
Offre Free
{
    "error": {
        "code": "plan_feature_unavailable",
        "message": "Votre offre Free ne comprend pas l'API des statistiques. Passez à l'offre Starter pour y accéder.",
        "details": {
            "feature": "analytics_api",
            "upgrade_plan": "Starter"
        }
    }
}
Workspace en attente de suppression
{
    "error": {
        "code": "workspace_pending_deletion",
        "message": "Ce workspace est en attente de suppression : ses clés API sont suspendues jusqu'à sa restauration."
    }
}
404
Lien inconnu, supprimé ou d'un autre workspace ; ou domaine désigné (domain, id d'un domaine) inconnu, d'un autre titulaire ou retiré.
Lien inconnu, supprimé ou d'un autre workspace
{
    "error": {
        "code": "not_found",
        "message": "Lien introuvable."
    }
}
Domaine inconnu ou d'un autre titulaire
{
    "error": {
        "code": "not_found",
        "message": "Domaine introuvable."
    }
}
413
Corps de requête de plus de 16 Kio (payload_too_large). Au-delà de 1 Mio, quelle que soit l'opération, la réponse vient du serveur web, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id.
Corps de plus de 16 Kio
{
    "error": {
        "code": "payload_too_large",
        "message": "Le corps de la requête dépasse 16 Kio."
    }
}
422
Période, filtre, regroupement, tri ou pagination invalides (validation_failed, un détail par paramètre), paramètre non prévu (unknown_field).
Début avant l'historique de l'offre
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "from",
                "code": "period_out_of_history",
                "message": "Votre offre Starter conserve 365 jours d'historique : choisissez un début à partir du 2025-10-08."
            }
        ]
    }
}
Regroupement par heure au-delà des 31 derniers jours
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "group_by",
                "code": "hour_period_too_old",
                "message": "Le regroupement par heure couvre les 31 derniers jours, aujourd'hui compris : choisissez un début à partir du 2026-09-07."
            }
        ]
    }
}
Pagination sans regroupement
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "page",
                "code": "not_applicable",
                "message": "La pagination ne s'applique qu'avec group_by."
            }
        ]
    }
}
period avec from et to
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "period",
                "code": "invalid_period",
                "message": "Indiquez soit period, soit from et to."
            }
        ]
    }
}
Même clé de tag deux fois
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "tag",
                "code": "tag_filter_conflict",
                "message": "Le filtre sur la clé campaign figure deux fois."
            }
        ]
    }
}
Regroupement inconnu
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "group_by",
                "code": "invalid_group_by",
                "message": "Regroupement inconnu : day, hour, link, country, device, referrer ou tag:<clé>."
            }
        ]
    }
}
Pays inconnu
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "country",
                "code": "invalid_choice",
                "message": "Pays inconnu : code ISO 3166-1 alpha-2 (FR, BE…) ou XX."
            }
        ]
    }
}
Tri par clics sur un regroupement par jour
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "sort",
                "code": "invalid_sort",
                "message": "Un regroupement par jour ou par heure se trie par date : time ou -time."
            }
        ]
    }
}
Plus de 20 liens dans le filtre link
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "link",
                "code": "too_many_links",
                "message": "Indiquez 20 liens au plus."
            }
        ]
    }
}
Identifiant de lien mal formé dans le filtre link
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "link",
                "code": "invalid_id",
                "message": "L'identifiant doit être de la forme lnk_…."
            }
        ]
    }
}
429
Statistiques suspendues pour le mois (quota_exceeded, details.quota à max_clicks_per_month, Retry-After jusqu'au 1er du mois suivant à 0 h, heure de Paris) ou limite de débit (rate_limited, Retry-After).
Clics du mois au-delà de la limite de l'offre
{
    "error": {
        "code": "quota_exceeded",
        "message": "Limite de 100 000 clics du mois de l'offre Starter dépassée : statistiques suspendues jusqu'au 1er novembre. Passez à l'offre Pro pour continuer à les suivre.",
        "details": {
            "quota": "max_clicks_per_month",
            "limit": 100000,
            "upgrade_plan": "Pro"
        }
    }
}
Limite de débit de la clé dépassée (en-tête Retry-After)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 12 secondes."
    }
}
500
Erreur serveur (internal_error), avec l'identifiant de corrélation request_id, aussi rendu dans l'en-tête X-Request-Id.
Erreur serveur, avec l'identifiant de corrélation
{
    "error": {
        "code": "internal_error",
        "message": "Une erreur interne est survenue. Communiquez cet identifiant au support.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}
503
Service momentanément indisponible (service_unavailable), avec request_id ; réessayer plus tard. Si l'application ne répond pas (arrêt, saturation, délai dépassé), la réponse vient du serveur web, au même format, avec request_id et X-Request-Id, sans en-têtes X-RateLimit-*.
Service momentanément indisponible
{
    "error": {
        "code": "service_unavailable",
        "message": "Le service est momentanément indisponible. Réessayez dans quelques instants.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}

Obtenir le QR code d'un lien

GET /api/v1/links/{id}/qr-code

Image du QR code de l'URL courte du lien (short_url, sans paramètre), niveau de correction M, noir sur blanc, marge d'au moins 4 modules. Le code reste valable tant que le lien garde son domaine et son slug : changer la destination ne le change pas. Toute portée de clé. Réponse mise en cache 5 minutes par le client (ETag, 304 sur If-None-Match). Cas limites : lien désactivé, expiré ou en attente → 200 (le code mène à une page introuvable tant que le lien ne redirige pas) ; lien bloqué → 409 link_blocked ; size avec format=svg → 422 (not_applicable) ; size hors de la liste, ou trop petite pour garder 4 pixels par module avec l'URL de ce lien (URL très longue) → 422 (invalid_choice, le message donne la plus petite taille permise) ; sans size, 512, ou la plus petite taille permise si 512 ne l'est pas. Représentation binaire admise par la constitution 1.5.0 (principe I) : sous-ressource unique, au singulier, erreurs au format JSON standard.

Paramètres

  • id (chemin, obligatoire) : Identifiant public du lien (lnk_…). Mal formé → 422 ; inconnu, supprimé ou d'un autre workspace → 404. Exemple : lnk_1CfhK2qKFyECr9Rx5oPk7i.
  • format (requête) : Format de l'image. Exemple : svg.
  • size (requête) : Côté de l'image PNG en pixels. Sans size : 512, ou la plus petite taille permise si 512 ne garde pas 4 pixels par module pour l'URL de ce lien. Exemple : 1024.

Exemple de requête

curl "https://lcrs.fr/api/v1/links/lnk_1CfhK2qKFyECr9Rx5oPk7i/qr-code" \
  -H "Authorization: Bearer lcrs_7Qk2Ab9x_…"

Réponse 200

Image du QR code.

Type de contenu : image/png ou image/svg+xml.

Réponse 304

Image inchangée (If-None-Match).

Erreurs

400
Requête rejetée par le serveur avant son traitement, par exemple un en-tête d'hôte invalide (bad_request, message générique).
Requête rejetée avant son traitement (en-tête d'hôte invalide…)
{
    "error": {
        "code": "bad_request",
        "message": "La requête n'a pas pu être interprétée."
    }
}
401
Clé absente, invalide ou révoquée.
Clé absente, invalide ou placée dans l'URL
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
Clé révoquée (même réponse que toute autre clé refusée)
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
403
Workspace en attente de suppression (workspace_pending_deletion), compte du créateur de la clé ou workspace suspendu (account_suspended, workspace_suspended, 1.5.0) ; une lecture ne reçoit jamais insufficient_scope.
Workspace en attente de suppression
{
    "error": {
        "code": "workspace_pending_deletion",
        "message": "Ce workspace est en attente de suppression : ses clés API sont suspendues jusqu'à sa restauration."
    }
}
Compte du créateur de la clé suspendu (1.5.0)
{
    "error": {
        "code": "account_suspended",
        "message": "Le compte qui a créé cette clé est suspendu par l'équipe lcrs.fr : la clé est refusée tant que la suspension dure."
    }
}
Workspace suspendu (1.5.0)
{
    "error": {
        "code": "workspace_suspended",
        "message": "Ce workspace est suspendu par l'équipe lcrs.fr : ses clés API sont refusées tant que la suspension dure."
    }
}
404
Lien inconnu, supprimé ou d'un autre workspace ; ou domaine désigné (domain, id d'un domaine) inconnu, d'un autre titulaire ou retiré.
Lien inconnu, supprimé ou d'un autre workspace
{
    "error": {
        "code": "not_found",
        "message": "Lien introuvable."
    }
}
Domaine inconnu ou d'un autre titulaire
{
    "error": {
        "code": "not_found",
        "message": "Domaine introuvable."
    }
}
409
Lien bloqué pour destination dangereuse (link_blocked).
Lien bloqué
{
    "error": {
        "code": "link_blocked",
        "message": "Ce lien est bloqué pour raison de sécurité : son QR code n'est pas disponible."
    }
}
413
Corps de requête de plus de 16 Kio (payload_too_large). Au-delà de 1 Mio, quelle que soit l'opération, la réponse vient du serveur web, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id.
Corps de plus de 16 Kio
{
    "error": {
        "code": "payload_too_large",
        "message": "Le corps de la requête dépasse 16 Kio."
    }
}
422
Identifiant mal formé, format ou size invalides (validation_failed), ou paramètre non prévu (unknown_field).
Taille hors de la liste
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "size",
                "code": "invalid_choice",
                "message": "Choisissez 256, 512, 1024 ou 2048."
            }
        ]
    }
}
Taille trop petite pour l'URL de ce lien
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "size",
                "code": "invalid_choice",
                "message": "Pour ce lien, choisissez au moins 512."
            }
        ]
    }
}
Taille avec le format SVG
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "size",
                "code": "not_applicable",
                "message": "La taille ne s'applique qu'au format PNG."
            }
        ]
    }
}
429
Limite de débit (rate_limited, en-tête Retry-After) : par clé, ou après 100 échecs d'authentification en 15 minutes depuis une même IP.
Limite de débit de la clé dépassée (en-tête Retry-After)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 12 secondes."
    }
}
Trop d'échecs d'authentification depuis cette adresse IP (sans en-têtes X-RateLimit)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 540 secondes."
    }
}
500
Erreur serveur (internal_error), avec l'identifiant de corrélation request_id, aussi rendu dans l'en-tête X-Request-Id.
Erreur serveur, avec l'identifiant de corrélation
{
    "error": {
        "code": "internal_error",
        "message": "Une erreur interne est survenue. Communiquez cet identifiant au support.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}
503
Service momentanément indisponible (service_unavailable), avec request_id ; réessayer plus tard. Si l'application ne répond pas (arrêt, saturation, délai dépassé), la réponse vient du serveur web, au même format, avec request_id et X-Request-Id, sans en-têtes X-RateLimit-*.
Service momentanément indisponible
{
    "error": {
        "code": "service_unavailable",
        "message": "Le service est momentanément indisponible. Réessayez dans quelques instants.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}

Lister les domaines utilisables par le workspace

GET /api/v1/domains

Le domaine du service (lcrs.fr, toujours en tête) puis les domaines non retirés du titulaire du workspace, par nom. Seuls les domaines active acceptent de nouveaux liens ; un domaine verification_lost redirige encore pendant son délai de grâce. Les demandes en attente de vérification, la preuve de possession et l'adresse de racine ne sont pas exposées : la gestion des domaines se fait dans le dashboard du titulaire. Cas limites : per_page=500 ou page=0 → 422 ; paramètre non prévu → 422 unknown_field.

Paramètres

  • page (requête) : Numéro de page, à partir de 1 ; hors bornes ou non numérique → 422. Exemple : 1.
  • per_page (requête) : Taille de page, de 1 à 100 ; hors bornes ou non numérique → 422. Exemple : 20.

Exemple de requête

curl "https://lcrs.fr/api/v1/domains?page=1&per_page=20" \
  -H "Authorization: Bearer lcrs_7Qk2Ab9x_…"

Réponse 200

Page de domaines.

{
    "data": [
        {
            "id": "dom_1CfhJmHgRwcnJGYzZgkkcf",
            "name": "lcrs.fr",
            "display_name": "lcrs.fr",
            "status": "active",
            "is_service_domain": true,
            "is_workspace_default": false,
            "created_at": "2026-10-03T00:00:00Z"
        },
        {
            "id": "dom_1CfhK2qKFyECr9Rx5oPk7j",
            "name": "go.acme.fr",
            "display_name": "go.acme.fr",
            "status": "active",
            "is_service_domain": false,
            "is_workspace_default": true,
            "created_at": "2026-10-11T09:12:00Z"
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 20,
        "total": 2
    }
}

Erreurs

400
Requête rejetée par le serveur avant son traitement, par exemple un en-tête d'hôte invalide (bad_request, message générique).
Requête rejetée avant son traitement (en-tête d'hôte invalide…)
{
    "error": {
        "code": "bad_request",
        "message": "La requête n'a pas pu être interprétée."
    }
}
401
Clé absente, invalide ou révoquée.
Clé absente, invalide ou placée dans l'URL
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
Clé révoquée (même réponse que toute autre clé refusée)
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
403
Workspace en attente de suppression (workspace_pending_deletion), compte du créateur de la clé ou workspace suspendu (account_suspended, workspace_suspended, 1.5.0) ; une lecture ne reçoit jamais insufficient_scope.
Workspace en attente de suppression
{
    "error": {
        "code": "workspace_pending_deletion",
        "message": "Ce workspace est en attente de suppression : ses clés API sont suspendues jusqu'à sa restauration."
    }
}
Compte du créateur de la clé suspendu (1.5.0)
{
    "error": {
        "code": "account_suspended",
        "message": "Le compte qui a créé cette clé est suspendu par l'équipe lcrs.fr : la clé est refusée tant que la suspension dure."
    }
}
Workspace suspendu (1.5.0)
{
    "error": {
        "code": "workspace_suspended",
        "message": "Ce workspace est suspendu par l'équipe lcrs.fr : ses clés API sont refusées tant que la suspension dure."
    }
}
413
Corps de requête de plus de 16 Kio (payload_too_large). Au-delà de 1 Mio, quelle que soit l'opération, la réponse vient du serveur web, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id.
Corps de plus de 16 Kio
{
    "error": {
        "code": "payload_too_large",
        "message": "Le corps de la requête dépasse 16 Kio."
    }
}
422
Pagination ou filtre invalides (validation_failed, un détail par paramètre), paramètre non prévu (unknown_field).
Pagination hors bornes (per_page=500)
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "per_page",
                "code": "out_of_range",
                "message": "La taille de page doit être comprise entre 1 et 100."
            }
        ]
    }
}
Statut de filtre inconnu
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "status",
                "code": "invalid_choice",
                "message": "Statut inconnu."
            }
        ]
    }
}
Filtre slug mal formé
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "slug",
                "code": "slug_invalid",
                "message": "Le slug compte de 3 à 64 caractères : lettres non accentuées, chiffres, tiret et underscore."
            }
        ]
    }
}
Paramètre de requête non prévu (per-page)
{
    "error": {
        "code": "unknown_field",
        "message": "La requête contient un champ ou un paramètre inconnu.",
        "details": [
            {
                "field": "per-page",
                "code": "unknown_field",
                "message": "Ce champ ou paramètre n'est pas prévu par cette opération."
            }
        ]
    }
}
Plus de 5 filtres de tags
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "tag",
                "code": "too_many_tag_filters",
                "message": "Filtrez sur 5 clés de tags au plus."
            }
        ]
    }
}
untagged avec un autre filtre de tag
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "untagged",
                "code": "tag_filter_conflict",
                "message": "Le filtre untagged ne se combine pas avec un autre filtre de tag."
            }
        ]
    }
}
429
Limite de débit (rate_limited, en-tête Retry-After) : par clé, ou après 100 échecs d'authentification en 15 minutes depuis une même IP.
Limite de débit de la clé dépassée (en-tête Retry-After)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 12 secondes."
    }
}
Trop d'échecs d'authentification depuis cette adresse IP (sans en-têtes X-RateLimit)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 540 secondes."
    }
}
500
Erreur serveur (internal_error), avec l'identifiant de corrélation request_id, aussi rendu dans l'en-tête X-Request-Id.
Erreur serveur, avec l'identifiant de corrélation
{
    "error": {
        "code": "internal_error",
        "message": "Une erreur interne est survenue. Communiquez cet identifiant au support.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}
503
Service momentanément indisponible (service_unavailable), avec request_id ; réessayer plus tard. Si l'application ne répond pas (arrêt, saturation, délai dépassé), la réponse vient du serveur web, au même format, avec request_id et X-Request-Id, sans en-têtes X-RateLimit-*.
Service momentanément indisponible
{
    "error": {
        "code": "service_unavailable",
        "message": "Le service est momentanément indisponible. Réessayez dans quelques instants.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}

Lire un domaine

GET /api/v1/domains/{id}

Un domaine utilisable par le workspace de la clé : le domaine du service, ou un domaine non retiré du titulaire du workspace. Mêmes champs que dans listDomains. Cas limites : identifiant mal formé (dom-…, lnk_…) → 422 ; domaine inconnu, retiré, d'un autre titulaire, ou demande d'ajout encore en attente (elle n'a pas d'identifiant dom_) → 404 ; paramètre de requête → 422 unknown_field. Un lien resté sur le domaine d'un ancien titulaire du workspace expose domain.id, mais getDomain sur cet identifiant rend 404 : ce domaine n'est plus utilisable par le workspace.

Paramètres

  • id (chemin, obligatoire) : Identifiant public du domaine (dom_…). Mal formé → 422 ; inconnu, retiré ou d'un autre titulaire → 404. Exemple : dom_1CfhK2qKFyECr9Rx5oPk7j.

Exemple de requête

curl "https://lcrs.fr/api/v1/domains/dom_1CfhK2qKFyECr9Rx5oPk7j" \
  -H "Authorization: Bearer lcrs_7Qk2Ab9x_…"

Réponse 200

Le domaine.

{
    "id": "dom_1CfhK2qKFyECr9Rx5oPk7j",
    "name": "liens.xn--caf-dma.fr",
    "display_name": "liens.café.fr",
    "status": "verification_lost",
    "is_service_domain": false,
    "is_workspace_default": false,
    "created_at": "2026-10-11T09:12:00Z"
}

Erreurs

400
Requête rejetée par le serveur avant son traitement, par exemple un en-tête d'hôte invalide (bad_request, message générique).
Requête rejetée avant son traitement (en-tête d'hôte invalide…)
{
    "error": {
        "code": "bad_request",
        "message": "La requête n'a pas pu être interprétée."
    }
}
401
Clé absente, invalide ou révoquée.
Clé absente, invalide ou placée dans l'URL
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
Clé révoquée (même réponse que toute autre clé refusée)
{
    "error": {
        "code": "unauthenticated",
        "message": "Clé API absente, invalide ou révoquée."
    }
}
403
Workspace en attente de suppression (workspace_pending_deletion), compte du créateur de la clé ou workspace suspendu (account_suspended, workspace_suspended, 1.5.0) ; une lecture ne reçoit jamais insufficient_scope.
Workspace en attente de suppression
{
    "error": {
        "code": "workspace_pending_deletion",
        "message": "Ce workspace est en attente de suppression : ses clés API sont suspendues jusqu'à sa restauration."
    }
}
Compte du créateur de la clé suspendu (1.5.0)
{
    "error": {
        "code": "account_suspended",
        "message": "Le compte qui a créé cette clé est suspendu par l'équipe lcrs.fr : la clé est refusée tant que la suspension dure."
    }
}
Workspace suspendu (1.5.0)
{
    "error": {
        "code": "workspace_suspended",
        "message": "Ce workspace est suspendu par l'équipe lcrs.fr : ses clés API sont refusées tant que la suspension dure."
    }
}
404
Lien inconnu, supprimé ou d'un autre workspace ; ou domaine désigné (domain, id d'un domaine) inconnu, d'un autre titulaire ou retiré.
Lien inconnu, supprimé ou d'un autre workspace
{
    "error": {
        "code": "not_found",
        "message": "Lien introuvable."
    }
}
Domaine inconnu ou d'un autre titulaire
{
    "error": {
        "code": "not_found",
        "message": "Domaine introuvable."
    }
}
413
Corps de requête de plus de 16 Kio (payload_too_large). Au-delà de 1 Mio, quelle que soit l'opération, la réponse vient du serveur web, au même format, sans en-têtes X-RateLimit-* ni X-Request-Id.
Corps de plus de 16 Kio
{
    "error": {
        "code": "payload_too_large",
        "message": "Le corps de la requête dépasse 16 Kio."
    }
}
422
Identifiant de domaine mal formé (validation_failed) ou paramètre de requête non prévu (unknown_field).
Identifiant de domaine mal formé (getDomain)
{
    "error": {
        "code": "validation_failed",
        "message": "La requête contient des valeurs invalides.",
        "details": [
            {
                "field": "id",
                "code": "invalid_id",
                "message": "L'identifiant doit être de la forme dom_…."
            }
        ]
    }
}
Paramètre de requête non prévu (per-page)
{
    "error": {
        "code": "unknown_field",
        "message": "La requête contient un champ ou un paramètre inconnu.",
        "details": [
            {
                "field": "per-page",
                "code": "unknown_field",
                "message": "Ce champ ou paramètre n'est pas prévu par cette opération."
            }
        ]
    }
}
429
Limite de débit (rate_limited, en-tête Retry-After) : par clé, ou après 100 échecs d'authentification en 15 minutes depuis une même IP.
Limite de débit de la clé dépassée (en-tête Retry-After)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 12 secondes."
    }
}
Trop d'échecs d'authentification depuis cette adresse IP (sans en-têtes X-RateLimit)
{
    "error": {
        "code": "rate_limited",
        "message": "Trop de requêtes : réessayez dans 540 secondes."
    }
}
500
Erreur serveur (internal_error), avec l'identifiant de corrélation request_id, aussi rendu dans l'en-tête X-Request-Id.
Erreur serveur, avec l'identifiant de corrélation
{
    "error": {
        "code": "internal_error",
        "message": "Une erreur interne est survenue. Communiquez cet identifiant au support.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}
503
Service momentanément indisponible (service_unavailable), avec request_id ; réessayer plus tard. Si l'application ne répond pas (arrêt, saturation, délai dépassé), la réponse vient du serveur web, au même format, avec request_id et X-Request-Id, sans en-têtes X-RateLimit-*.
Service momentanément indisponible
{
    "error": {
        "code": "service_unavailable",
        "message": "Le service est momentanément indisponible. Réessayez dans quelques instants.",
        "request_id": "0192f1c4-7b3a-7e21-9c55-3f0e8d2a6b41"
    }
}