API del acortador de enlaces
Crea enlaces cortos de chu.es, cámbialos y consulta sus estadísticas desde tu web, tu tienda o tus scripts. API REST con respuestas en JSON y gratuita.
Primeros pasos
- Crea una cuenta gratis en chu.es (o entra con Google).
- En Mis enlaces → API, pulsa «Crear clave de API» y guárdala: solo se muestra una vez.
- Haz tu primera llamada:
curl -X POST https://chu.es/api/v1/links \
-H "Authorization: Bearer TU_CLAVE" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.ejemplo.com/una/direccion/larga"}' Respuesta (201 Created):
{
"data": {
"code": "k7mq2x",
"short_url": "https://chu.es/k7mq2x",
"url": "https://www.ejemplo.com/una/direccion/larga",
"title": null,
"active": true,
"status": "active",
"clicks": 0,
"created_at": "2026-10-11T23:50:00+02:00",
"last_click_at": null
},
"existing": false
}
Autenticación
Todas las peticiones llevan tu clave en la cabecera Authorization:
Authorization: Bearer chu_1a2b3c4d_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx También se acepta la cabecera X-API-Key. La URL base es https://chu.es/api/v1. Los cuerpos se envían en JSON (Content-Type: application/json) o como formulario. Trata la clave como una contraseña: no la pongas en código que se ejecute en el navegador de tus visitantes. Puedes revocarla y crear otra en cualquier momento desde el panel.
POST/links
Crea un enlace corto.
| Campo | Tipo | Descripción |
|---|---|---|
url | texto, obligatorio | Dirección de destino (http o https, máximo 2048 caracteres). Si no lleva esquema se entiende https. |
alias | texto, opcional | Nombre del enlace: chu.es/mi-oferta. De 3 a 50 caracteres: letras sin tilde, números y guiones. No distingue mayúsculas. |
title | texto, opcional | Título interno para reconocerlo en el panel (máximo 200 caracteres). |
Si ya habías acortado la misma dirección sin alias, se devuelve ese enlace con 200 y "existing": true en lugar de crear otro.
GET/links
Tus enlaces, del más reciente al más antiguo. Parámetros: page (desde 1), per_page (1–100, por defecto 50) y q (busca en código, destino y título).
curl "https://chu.es/api/v1/links?per_page=20&q=oferta" -H "Authorization: Bearer TU_CLAVE" Devuelve {"data": [ … ], "page": 1, "per_page": 20, "total": 3}.
GET/links/{code}
Datos de un enlace tuyo. clicks es el total histórico de clics de personas (sin bots).
PATCH/links/{code}
Cambia uno o varios campos: url (nuevo destino), title y active (false lo pausa; true lo reactiva). El código no cambia, así que los QR impresos siguen valiendo.
curl -X PATCH https://chu.es/api/v1/links/mi-oferta \
-H "Authorization: Bearer TU_CLAVE" -H "Content-Type: application/json" \
-d '{"url": "https://www.ejemplo.com/nueva-oferta", "active": true}'
DELETE/links/{code}
Borra el enlace y sus estadísticas. Responde 204 sin cuerpo. El código queda retirado para siempre: nadie podrá reutilizarlo.
GET/links/{code}/stats
Estadísticas de los últimos days días (1–400, por defecto 30). Solo cuenta personas: los bots y las vistas previas de redes sociales y apps de mensajería van aparte en bot_hits.
{
"data": {
"code": "mi-oferta",
"days": 30,
"clicks": 412,
"unique_visitors": 355,
"bot_hits": 61,
"total_clicks": 1290,
"by_day": [ {"date": "2026-09-12", "clicks": 8}, … ],
"countries": [ {"code": "ES", "name": "España", "clicks": 380}, … ],
"referrers": [ {"name": "instagram.com", "clicks": 120}, {"name": "Directo / sin procedencia", "clicks": 98}, … ],
"devices": [ {"name": "Móvil", "clicks": 301}, … ],
"browsers": [ {"name": "Chrome", "clicks": 190}, … ],
"os": [ {"name": "Android", "clicks": 170}, … ]
}
} unique_visitors cuenta personas distintas por día (no guardamos IPs: usamos un código anónimo que cambia cada día).
GET/me
Tu cuenta: email, plan y links_left_today (enlaces que aún puedes crear hoy; null = sin límite).
Errores y límites
Los errores responden con el código HTTP adecuado y este formato:
{
"error": {
"code": "alias_taken",
"message": "El alias «mi-oferta» ya está en uso. Elige otro."
}
} | HTTP | code | Cuándo |
|---|---|---|
| 400 | invalid_json | El cuerpo no es JSON válido. |
| 401 | unauthorized | Falta la clave o no es válida. |
| 403 | link_blocked | El enlace está desactivado por incumplir las condiciones de uso. |
| 404 | not_found | No existe ningún enlace tuyo con ese código, o la ruta no existe. |
| 409 | alias_taken | El alias ya está ocupado. |
| 422 | invalid_url · invalid_alias · blocked_destination · invalid_field | Dirección no válida o inaccesible, alias no válido o reservado, destino en una lista de sitios peligrosos, campo con valor incorrecto. |
| 429 | rate_limited · quota_exceeded | Más de 120 peticiones o 60 enlaces nuevos por minuto, o cupo diario agotado (200 enlaces al día en el plan gratuito). Mira la cabecera Retry-After. |
No se pueden acortar enlaces de otros acortadores, direcciones IP ni dominios que no resuelven o que figuran en listas de phishing y malware (Spamhaus DBL, SURBL, URIBL). Los enlaces deben cumplir el aviso legal y las condiciones de uso.
Ejemplos
PHP
<?php
$ch = curl_init('https://chu.es/api/v1/links');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CHU_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['url' => 'https://www.ejemplo.com/producto/123']),
]);
$res = json_decode(curl_exec($ch), true);
echo $res['data']['short_url']; Python
import os, requests
r = requests.post('https://chu.es/api/v1/links',
headers={'Authorization': f"Bearer {os.environ['CHU_API_KEY']}"},
json={'url': 'https://www.ejemplo.com/producto/123', 'alias': 'producto-123'})
r.raise_for_status()
print(r.json()['data']['short_url']) JavaScript (Node.js 18+)
const r = await fetch('https://chu.es/api/v1/links/producto-123/stats?days=7', {
headers: { Authorization: `Bearer ${process.env.CHU_API_KEY}` },
});
const { data } = await r.json();
console.log(data.clicks, 'clics esta semana');