Empezar
La dirección base de la API es:
https://qlynk.eu/api/v1 Bastan tres pasos:
- Inicia sesión y abre Claves API en tu área, luego crea una clave. Solo se muestra una vez: cópiala enseguida.
- Envía la clave en el encabezado
Authorizationde cada solicitud. - Las solicitudes con cuerpo (creación, modificación) envían JSON, con el encabezado
Content-Type: application/json.
curl https://qlynk.eu/api/v1/urls \
-H "Authorization: Bearer VOTRE_CLE_API" Autenticación
La API usa una clave personal enviada como token Bearer. Mantenla en secreto: da acceso a todos tus enlaces. Puedes revocarla en cualquier momento desde tu área, y el número de claves activas por cuenta es limitado.
Authorization: Bearer VOTRE_CLE_API Sin clave, con una clave mal formada, revocada o de una cuenta desactivada, la API responde 401.
Cuotas
El número de solicitudes por día depende de tu plan. El contador se reinicia a medianoche (hora de París).
| Plan | Solicitudes por día |
|---|---|
| Gratis | 50 |
| Pro | 10,000 |
Cada respuesta indica cómo vas:
X-RateLimit-Limit: tu cuota diariaX-RateLimit-Remaining: solicitudes restantes hoyX-RateLimit-Reset: momento de la renovación (marca de tiempo Unix)
Cuando se alcanza la cuota, la API responde 429 con el encabezado Retry-After (en segundos). Las solicitudes rechazadas no cuentan. Los límites del plan también se aplican a la API: por ejemplo, la creación de enlaces sigue el tope del plan Gratis (enlaces activos a la vez), y la elección del final del enlace (custom_code) y la fecha de caducidad están reservadas al plan Pro (respuesta 403).
Formato de las respuestas
Todas las respuestas son en JSON. En caso de éxito:
{
"success": true,
"data": { ... }
} En caso de error:
{
"success": false,
"error": "Enlace no encontrado"
} Códigos de error
| Código | Significado |
|---|---|
| 200, 201 | Éxito (201 para una creación) |
| 400 | Solicitud no válida: JSON mal formado, campo ausente o incorrecto (dirección no permitida, final de enlace ya en uso, período desconocido…). El mensaje indica qué corregir. |
| 401 | Clave ausente, no válida, revocada o cuenta desactivada |
| 403 | El enlace o la categoría no te pertenece, o la función no está incluida en tu plan (tope de enlaces del plan Gratis, final de enlace personalizado, fecha de caducidad) |
| 404 | Enlace o categoría no encontrado |
| 405 | Método no admitido en esta dirección |
| 429 | Cuota diaria alcanzada (consulta Retry-After) |
| 500 | Error por nuestra parte: inténtalo de nuevo y luego escríbenos |
| 503 | API desactivada temporalmente |
Enlaces
Crear un enlace
/urls| Campo | Descripción |
|---|---|
url (obligatorio) | Dirección de destino (http o https) |
custom_code | Final del enlace deseado (plan Pro; en Gratis, respuesta 403). Si no, Qlynk genera uno. |
title, description | Texto libre (255 y 1000 caracteres como máximo) |
is_indexed | Booleano, 1 por defecto |
category_id | Categoría del enlace (categoría o subcategoría) |
expires_at | Fecha de caducidad en formato AAAA-MM-DD, en el futuro (plan Pro). null para ninguna. |
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"
}
} El campo app indica el nombre de la aplicación que el enlace abre en el teléfono (por ejemplo «YouTube»), o null.
El campo status vale active o paused: un enlace en pausa (plan Gratis por encima del límite) ya no redirige y no cuenta entre los enlaces activos.
Listar tus enlaces
/urlscurl https://qlynk.eu/api/v1/urls \
-H "Authorization: Bearer VOTRE_CLE_API" La respuesta contiene total y el arreglo urls, del más reciente al más antiguo.
Para filtrar por categoría, añade ?category_id=12: obtendrás los enlaces de la categoría y de sus subcategorías. Añade &include_children=0 para la categoría sola, o usa ?category_id=none para los enlaces sin clasificar.
curl "https://qlynk.eu/api/v1/urls?category_id=3" \
-H "Authorization: Bearer VOTRE_CLE_API"
Leer un enlace
/urls/{code}curl https://qlynk.eu/api/v1/urls/salon-26 \
-H "Authorization: Bearer VOTRE_CLE_API"
Modificar un enlace
/urls/{code}Envía solo los campos que quieras cambiar (los mismos que para la creación): los demás permanecen igual. Cambiar custom_code cambia la dirección corta (solo plan Pro).
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"}'
Eliminar un enlace
/urls/{code}La eliminación es definitiva: el enlace corto deja de funcionar y sus estadísticas se borran.
curl -X DELETE https://qlynk.eu/api/v1/urls/salon-26 \
-H "Authorization: Bearer VOTRE_CLE_API" Categorías
Una categoría puede tener una categoría padre mediante el campo parent_id. Solo hay un nivel de subcategorías: la categoría padre debe ser una categoría de primer nivel que te pertenezca. parent_id vale null para una categoría de primer nivel.
Listar tus categorías
/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" }
]
}
}
Leer, crear, modificar, eliminar
/categories/{id}/categories/categories/{id}/categories/{id}| Campo | Descripción |
|---|---|
name (obligatorio al crear) | Nombre de la categoría |
parent_id | Identificador de la categoría padre, o null (primer nivel). Si se omite al modificar: sin cambios. |
color | Color en formato #RRGGBB |
icon | Nombre de icono (letras minúsculas, números, guiones) |
position | Orden de visualización |
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"}' Un error 400 explica los casos rechazados: padre no encontrado, categoría que sería su propia padre, subcategoría que contendría otra subcategoría, categoría que ya tiene subcategorías y que se quisiera colocar bajo otra.
Al eliminar, los enlaces se conservan (pasan a «Sin clasificar») y las subcategorías se convierten en categorías de primer nivel.
Estadísticas
/stats/{code}Parámetro opcional period:
1,7,30,365: los últimos días correspondientesall: todo el historial (valor por defecto)- los valores antiguos
day,week,monthyyearsiguen aceptándose
Con el plan Gratis, el historial está limitado a 30 días. Si pides un período más largo, la API lo reduce a ese límite y el campo history_limited vale true. El plan Pro no tiene límite.
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 } ]
}
} | Campo | Significado |
|---|---|
period_days | Número de días realmente cubiertos (null para todo el historial) |
history_limited | true si el período solicitado se ha reducido por el límite de tu plan |
total_clicks, unique_visitors | Clics contados y visitantes únicos (sin robots ni duplicados) |
app_opens | Clics que abrieron directamente una aplicación |
qr_scans | Visitas procedentes de un código QR |
filtered_hits | Visitas excluidas del recuento (robots, vistas previas de mensajería, duplicados…) |
last_click | Último clic, en formato ISO 8601 con el desfase de París (timezone) |
clicks_by_date | Clics por día (hora de París), del más reciente al más antiguo, sin los días sin clics |
Nunca se proporcionan las direcciones IP. Consulta la política de privacidad.