Documentación de la API

Crea tus enlaces, organízalos en categorías y consulta tus estadísticas desde tus propias herramientas.

Empezar

La dirección base de la API es:

https://qlynk.eu/api/v1

Bastan tres pasos:

  1. Inicia sesión y abre Claves API en tu área, luego crea una clave. Solo se muestra una vez: cópiala enseguida.
  2. Envía la clave en el encabezado Authorization de cada solicitud.
  3. 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).

PlanSolicitudes por día
Gratis50
Pro10,000

Cada respuesta indica cómo vas:

  • X-RateLimit-Limit: tu cuota diaria
  • X-RateLimit-Remaining: solicitudes restantes hoy
  • X-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ódigoSignificado
200, 201Éxito (201 para una creación)
400Solicitud 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.
401Clave ausente, no válida, revocada o cuenta desactivada
403El 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)
404Enlace o categoría no encontrado
405Método no admitido en esta dirección
429Cuota diaria alcanzada (consulta Retry-After)
500Error por nuestra parte: inténtalo de nuevo y luego escríbenos
503API desactivada temporalmente

Enlaces

Crear un enlace

POST/urls
CampoDescripción
url (obligatorio)Dirección de destino (http o https)
custom_codeFinal del enlace deseado (plan Pro; en Gratis, respuesta 403). Si no, Qlynk genera uno.
title, descriptionTexto libre (255 y 1000 caracteres como máximo)
is_indexedBooleano, 1 por defecto
category_idCategoría del enlace (categoría o subcategoría)
expires_atFecha 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

GET/urls
curl 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

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

Modificar un enlace

PUT/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

DELETE/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

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" }
    ]
  }
}

Leer, crear, modificar, eliminar

GET/categories/{id}
POST/categories
PUT/categories/{id}
DELETE/categories/{id}
CampoDescripción
name (obligatorio al crear)Nombre de la categoría
parent_idIdentificador de la categoría padre, o null (primer nivel). Si se omite al modificar: sin cambios.
colorColor en formato #RRGGBB
iconNombre de icono (letras minúsculas, números, guiones)
positionOrden 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

GET/stats/{code}

Parámetro opcional period:

  • 1, 7, 30, 365: los últimos días correspondientes
  • all: todo el historial (valor por defecto)
  • los valores antiguos day, week, month y year siguen 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 } ]
  }
}
CampoSignificado
period_daysNúmero de días realmente cubiertos (null para todo el historial)
history_limitedtrue si el período solicitado se ha reducido por el límite de tu plan
total_clicks, unique_visitorsClics contados y visitantes únicos (sin robots ni duplicados)
app_opensClics que abrieron directamente una aplicación
qr_scansVisitas procedentes de un código QR
filtered_hitsVisitas 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_dateClics 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.