Documentation de l’API

Créez vos liens, rangez-les dans des catégories et lisez vos statistiques depuis vos propres outils.

Démarrer

L’adresse de base de l’API est :

https://qlynk.eu/api/v1

Trois étapes suffisent :

  1. Connectez-vous et ouvrez Clés API dans votre espace, puis créez une clé. Elle n’est affichée qu’une fois : copiez-la tout de suite.
  2. Envoyez la clé dans l’en-tête Authorization de chaque requête.
  3. Les requêtes avec un corps (création, modification) envoient du JSON, avec l’en-tête Content-Type: application/json.
curl https://qlynk.eu/api/v1/urls \
  -H "Authorization: Bearer VOTRE_CLE_API"

Authentification

L’API utilise une clé personnelle transmise en jeton Bearer. Gardez-la secrète : elle donne accès à tous vos liens. Vous pouvez la révoquer à tout moment depuis votre espace, et le nombre de clés actives par compte est limité.

Authorization: Bearer VOTRE_CLE_API

Sans clé, avec une clé mal formée, révoquée ou d’un compte désactivé, l’API répond 401.

Quotas

Le nombre de requêtes par jour dépend de votre offre. Le compteur repart à zéro à minuit (heure de Paris).

OffreRequêtes par jour
Gratuit50
Pro10 000

Chaque réponse indique où vous en êtes :

  • X-RateLimit-Limit : votre quota quotidien
  • X-RateLimit-Remaining : requêtes restantes aujourd’hui
  • X-RateLimit-Reset : moment du renouvellement (horodatage Unix)

Quand le quota est atteint, l’API répond 429 avec l’en-tête Retry-After (en secondes). Les requêtes refusées ne comptent pas. Les limites de l’offre s’appliquent aussi à l’API : par exemple, la création de liens suit le plafond de l’offre Gratuit (liens actifs à la fois), et le choix de la fin du lien (custom_code) comme la date d’expiration sont réservés à l’offre Pro (réponse 403).

Format des réponses

Toutes les réponses sont en JSON. En cas de succès :

{
  "success": true,
  "data": { ... }
}

En cas d’erreur :

{
  "success": false,
  "error": "Lien non trouvé"
}

Codes d’erreur

CodeSignification
200, 201Succès (201 pour une création)
400Requête invalide : JSON mal formé, champ manquant ou incorrect (adresse non autorisée, fin de lien déjà prise, période inconnue…). Le message dit quoi corriger.
401Clé absente, invalide, révoquée, ou compte désactivé
403Le lien ou la catégorie ne vous appartient pas, ou la fonction n’est pas dans votre offre (plafond de liens de l’offre Gratuit, fin de lien choisie, date d’expiration)
404Lien ou catégorie introuvable
405Méthode non prise en charge sur cette adresse
429Quota quotidien atteint (voir Retry-After)
500Erreur de notre côté : réessayez, puis écrivez-nous
503API désactivée temporairement

Liens

Créer un lien

POST/urls
ChampDescription
url (obligatoire)Adresse de destination (http ou https)
custom_codeFin du lien souhaitée (offre Pro ; en Gratuit, réponse 403). Sinon, Qlynk en génère une.
title, descriptionTexte libre (255 et 1 000 caractères au plus)
is_indexedBooléen, 1 par défaut
category_idCatégorie du lien (catégorie ou sous-catégorie)
expires_atDate d’expiration au format AAAA-MM-JJ, dans le futur (offre Pro). null pour aucune.
curl -X POST https://qlynk.eu/api/v1/urls \
  -H "Authorization: Bearer VOTRE_CLE_API" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.exemple.com/evenements/salon-2026",
    "custom_code": "salon-26",
    "title": "Salon des entrepreneurs",
    "category_id": 12
  }'
{
  "success": true,
  "data": {
    "short_code": "salon-26",
    "short_url": "https://qlynk.eu/salon-26",
    "original_url": "https://www.exemple.com/evenements/salon-2026",
    "title": "Salon des entrepreneurs",
    "description": "",
    "is_indexed": 1,
    "category_id": 12,
    "status": "active",
    "paused_at": null,
    "expires_at": null,
    "app": null,
    "created_at": "2026-10-17 14:32:08"
  }
}

Le champ app donne le nom de l’application que le lien ouvre sur téléphone (par exemple « YouTube »), ou null.

Le champ status vaut active ou paused : un lien mis en pause (offre Gratuit au-delà de la limite) ne redirige plus et ne compte pas dans les liens actifs.

Lister vos liens

GET/urls
curl https://qlynk.eu/api/v1/urls \
  -H "Authorization: Bearer VOTRE_CLE_API"

La réponse contient total et le tableau urls, du plus récent au plus ancien.

Pour filtrer par catégorie, ajoutez ?category_id=12 : vous obtenez les liens de la catégorie et de ses sous-catégories. Ajoutez &include_children=0 pour la catégorie seule, ou utilisez ?category_id=none pour les liens non classés.

curl "https://qlynk.eu/api/v1/urls?category_id=3" \
  -H "Authorization: Bearer VOTRE_CLE_API"

Lire un lien

GET/urls/{code}
curl https://qlynk.eu/api/v1/urls/salon-26 \
  -H "Authorization: Bearer VOTRE_CLE_API"

Modifier un lien

PUT/urls/{code}

Envoyez seulement les champs à changer (les mêmes que pour la création) : les autres restent identiques. Changer custom_code change l’adresse courte (offre Pro seulement).

curl -X PUT https://qlynk.eu/api/v1/urls/salon-26 \
  -H "Authorization: Bearer VOTRE_CLE_API" \
  -H "Content-Type: application/json" \
  -d '{"title": "Salon 2026, programme", "expires_at": "2026-12-31"}'

Supprimer un lien

DELETE/urls/{code}

La suppression est définitive : le lien court cesse de fonctionner et ses statistiques sont effacées.

curl -X DELETE https://qlynk.eu/api/v1/urls/salon-26 \
  -H "Authorization: Bearer VOTRE_CLE_API"

Catégories

Une catégorie peut avoir une catégorie parente grâce au champ parent_id. Il n’y a qu’un seul niveau de sous-catégories : la parente doit être une catégorie de premier niveau, qui vous appartient. parent_id vaut null pour une catégorie de premier niveau.

Lister vos catégories

GET/categories
curl https://qlynk.eu/api/v1/categories \
  -H "Authorization: Bearer VOTRE_CLE_API"
{
  "success": true,
  "data": {
    "total": 2,
    "categories": [
      { "id": 3, "parent_id": null, "name": "Paperasse Zéro", "color": "#E4572E",
        "icon": "folder", "position": 0, "link_count": 1,
        "created_at": "2026-09-02 10:15:00", "updated_at": "2026-09-02 10:15:00" },
      { "id": 4, "parent_id": 3, "name": "Indy", "color": "#2E86AB",
        "icon": "folder", "position": 0, "link_count": 4,
        "created_at": "2026-09-02 10:16:00", "updated_at": "2026-09-02 10:16:00" }
    ]
  }
}

Lire, créer, modifier, supprimer

GET/categories/{id}
POST/categories
PUT/categories/{id}
DELETE/categories/{id}
ChampDescription
name (obligatoire à la création)Nom de la catégorie
parent_idIdentifiant de la catégorie parente, ou null (premier niveau). Absent à la modification : inchangé.
colorCouleur au format #RRGGBB
iconNom d’icône (lettres minuscules, chiffres, tirets)
positionOrdre d’affichage
curl -X POST https://qlynk.eu/api/v1/categories \
  -H "Authorization: Bearer VOTRE_CLE_API" \
  -H "Content-Type: application/json" \
  -d '{"name": "Tiime", "parent_id": 3, "color": "#2E86AB"}'

Une erreur 400 explique les cas refusés : parente introuvable, catégorie qui serait sa propre parente, sous-catégorie qui contiendrait une autre sous-catégorie, catégorie qui a déjà des sous-catégories et que l’on voudrait ranger sous une autre.

À la suppression, les liens sont conservés (ils passent en « Non classés ») et les sous-catégories deviennent des catégories de premier niveau.

Statistiques

GET/stats/{code}

Paramètre facultatif period :

  • 1, 7, 30, 365 : les derniers jours correspondants
  • all : tout l’historique (valeur par défaut)
  • les anciennes valeurs day, week, month et year restent acceptées

Avec l’offre Gratuit, l’historique est limité à 30 jours. Si vous demandez une période plus longue, l’API la ramène à cette limite et le champ history_limited vaut true. L’offre Pro n’a pas de limite.

curl "https://qlynk.eu/api/v1/stats/salon-26?period=30" \
  -H "Authorization: Bearer VOTRE_CLE_API"
{
  "success": true,
  "data": {
    "short_code": "salon-26",
    "period": "30",
    "period_days": 30,
    "history_limited": false,
    "timezone": "Europe/Paris",
    "total_clicks": 412,
    "unique_visitors": 351,
    "app_opens": 96,
    "qr_scans": 111,
    "filtered_hits": 38,
    "last_click": "2026-10-17T14:02:11+02:00",
    "clicks_by_date": [ { "date": "2026-10-17", "clicks": 52 } ],
    "devices": { "mobile": 280, "tablet": 14, "desktop": 118 },
    "top_countries": [ { "country": "France", "code": "FR", "clicks": 375 } ],
    "top_browsers": [ { "browser": "Safari", "clicks": 190 } ],
    "top_os": [ { "os": "iOS", "clicks": 201 } ],
    "top_referrers": [ { "domain": "linkedin.com", "clicks": 64 } ]
  }
}
ChampSignification
period_daysNombre de jours réellement couverts (null pour tout l’historique)
history_limitedtrue si la période demandée a été réduite par la limite de votre offre
total_clicks, unique_visitorsClics comptés et visiteurs uniques (sans les robots ni les doublons)
app_opensClics qui ont ouvert directement une application
qr_scansPassages venus d’un QR code
filtered_hitsPassages écartés du compte (robots, aperçus de messagerie, doublons…)
last_clickDernier clic, au format ISO 8601 avec le décalage de Paris (timezone)
clicks_by_dateClics par jour (heure de Paris), du plus récent au plus ancien, jours sans clic omis

Les adresses IP ne sont jamais fournies. Voir la politique de confidentialité.