Démarrer
L’adresse de base de l’API est :
https://qlynk.eu/api/v1 Trois étapes suffisent :
- 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.
- Envoyez la clé dans l’en-tête
Authorizationde chaque requête. - 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).
| Offre | Requêtes par jour |
|---|---|
| Gratuit | 50 |
| Pro | 10 000 |
Chaque réponse indique où vous en êtes :
X-RateLimit-Limit: votre quota quotidienX-RateLimit-Remaining: requêtes restantes aujourd’huiX-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
| Code | Signification |
|---|---|
| 200, 201 | Succès (201 pour une création) |
| 400 | Requê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. |
| 401 | Clé absente, invalide, révoquée, ou compte désactivé |
| 403 | Le 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) |
| 404 | Lien ou catégorie introuvable |
| 405 | Méthode non prise en charge sur cette adresse |
| 429 | Quota quotidien atteint (voir Retry-After) |
| 500 | Erreur de notre côté : réessayez, puis écrivez-nous |
| 503 | API désactivée temporairement |
Liens
Créer un lien
/urls| Champ | Description |
|---|---|
url (obligatoire) | Adresse de destination (http ou https) |
custom_code | Fin du lien souhaitée (offre Pro ; en Gratuit, réponse 403). Sinon, Qlynk en génère une. |
title, description | Texte libre (255 et 1 000 caractères au plus) |
is_indexed | Booléen, 1 par défaut |
category_id | Catégorie du lien (catégorie ou sous-catégorie) |
expires_at | Date 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
/urlscurl 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
/urls/{code}curl https://qlynk.eu/api/v1/urls/salon-26 \
-H "Authorization: Bearer VOTRE_CLE_API"
Modifier un lien
/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
/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
/categoriescurl 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
/categories/{id}/categories/categories/{id}/categories/{id}| Champ | Description |
|---|---|
name (obligatoire à la création) | Nom de la catégorie |
parent_id | Identifiant de la catégorie parente, ou null (premier niveau). Absent à la modification : inchangé. |
color | Couleur au format #RRGGBB |
icon | Nom d’icône (lettres minuscules, chiffres, tirets) |
position | Ordre 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
/stats/{code}Paramètre facultatif period :
1,7,30,365: les derniers jours correspondantsall: tout l’historique (valeur par défaut)- les anciennes valeurs
day,week,monthetyearrestent 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 } ]
}
} | Champ | Signification |
|---|---|
period_days | Nombre de jours réellement couverts (null pour tout l’historique) |
history_limited | true si la période demandée a été réduite par la limite de votre offre |
total_clicks, unique_visitors | Clics comptés et visiteurs uniques (sans les robots ni les doublons) |
app_opens | Clics qui ont ouvert directement une application |
qr_scans | Passages venus d’un QR code |
filtered_hits | Passages écartés du compte (robots, aperçus de messagerie, doublons…) |
last_click | Dernier clic, au format ISO 8601 avec le décalage de Paris (timezone) |
clicks_by_date | Clics 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é.