La forma más fácil y rápida de explorar la API es usando Swagger UI:
🌐 URL: http://localhost:4300/api-docs
Swagger proporciona:
- ✅ Documentación interactiva completa
- ✅ Prueba de endpoints en tiempo real
- ✅ Esquemas de datos con ejemplos
- ✅ Autenticación integrada
- ✅ Respuestas en vivo
📖 Ver guía completa de Swagger
- ✅ Generación de enlaces cortos con códigos personalizados o aleatorios
- ✅ Reserva de enlaces sin URL (para QR codes impresos)
- ✅ Gestión de estados (ACTIVO, RESERVADO, DESHABILITADO, EXPIRADO)
- ✅ Redirección pública optimizada sin autenticación
- ✅ Métricas de uso (clics, última visita)
- ✅ Auditoría completa de cambios
- ✅ Autenticación segura (API Key + Bearer Token)
- ✅ Organización flexible por proyectos, módulos y etiquetas
Todos los endpoints de gestión requieren autenticación:
X-API-Key: dev-key-123Authorization: Bearer dev-token-123Configuración: Las claves se definen en el archivo .env:
API_KEYS=dev-key-123,prod-key-456
BEARER_TOKENS=dev-token-123,prod-token-456http://localhost:4300
| Método | Endpoint | Descripción |
|---|---|---|
POST |
/v1/short-links |
Crear enlace corto |
GET |
/v1/short-links |
Listar enlaces con filtros |
GET |
/v1/short-links/{id} |
Obtener enlace por ID |
PATCH |
/v1/short-links/{id} |
Actualizar enlace |
| Método | Endpoint | Descripción |
|---|---|---|
GET |
/r/{codigo} |
Redirigir a URL destino |
| Método | Endpoint | Descripción |
|---|---|---|
GET |
/ |
Info del servicio |
GET |
/health |
Health check |
GET |
/api-docs |
Documentación Swagger |
curl -X POST http://localhost:4300/v1/short-links \
-H "X-API-Key: dev-key-123" \
-H "Content-Type: application/json" \
-d '{
"proyecto": "Marketing",
"creado_por": "admin",
"url_destino": "https://example.com/promo"
}'Respuesta (201):
{
"code": 201,
"message": "Enlace corto creado exitosamente",
"data": {
"id": 1,
"codigo": "a1b2c3",
"url_corta": "http://localhost:4300/r/a1b2c3",
"url_destino": "https://example.com/promo",
"estado": "ACTIVO",
"proyecto": "Marketing",
"total_clicks": 0,
"fecha_creacion": "2025-11-27T12:00:00Z"
}
}curl -X POST http://localhost:4300/v1/short-links \
-H "X-API-Key: dev-key-123" \
-H "Content-Type: application/json" \
-d '{
"proyecto": "Eventos",
"creado_por": "admin"
}'Nota: Sin url_destino, el enlace queda en estado RESERVADO_SIN_DESTINO.
curl -X GET "http://localhost:4300/v1/short-links?proyecto=Marketing&estado=ACTIVO" \
-H "X-API-Key: dev-key-123"curl -X PATCH http://localhost:4300/v1/short-links/1 \
-H "X-API-Key: dev-key-123" \
-H "Content-Type: application/json" \
-d '{
"url_destino": "https://example.com/evento-2025",
"estado": "ACTIVO",
"actualizado_por": "admin"
}'http://localhost:4300/r/a1b2c3
Comportamiento:
- ACTIVO → HTTP 302 a URL destino + incrementa contador
- RESERVADO → Muestra página genérica
- DESHABILITADO/EXPIRADO → HTTP 410 (Gone)
| Estado | Código | Comportamiento |
|---|---|---|
RESERVADO_SIN_DESTINO |
🟡 | Muestra página reservada |
ACTIVO |
🟢 | Redirige a URL destino |
DESHABILITADO |
🔴 | Error 410 (Gone) |
EXPIRADO |
⚫ | Error 410 (Gone) |
| Parámetro | Tipo | Descripción | Ejemplo |
|---|---|---|---|
proyecto |
string | Filtrar por proyecto | ?proyecto=Marketing |
estado |
enum | Filtrar por estado | ?estado=ACTIVO |
modulo |
string | Filtrar por módulo | ?modulo=Campañas |
etiquetas |
string | Filtrar por etiquetas (CSV) | ?etiquetas=promo,2025 |
fecha_creacion_desde |
date | Desde fecha (YYYY-MM-DD) | ?fecha_creacion_desde=2025-01-01 |
fecha_creacion_hasta |
date | Hasta fecha (YYYY-MM-DD) | ?fecha_creacion_hasta=2025-12-31 |
{
id: number; // ID auto-increment
codigo: string; // Código único (6-8 caracteres)
url_corta: string; // URL completa del enlace corto
url_destino: string | null; // URL destino (null si reservado)
estado: ShortLinkStatus; // Estado actual
proyecto: string; // Proyecto origen (requerido)
modulo?: string; // Módulo (opcional)
etiquetas?: string[]; // Tags de categorización
fecha_creacion: Date; // Timestamp de creación
fecha_ultima_actualizacion: Date; // Timestamp última modificación
creado_por: string; // Usuario creador
actualizado_por: string; // Usuario última actualización
historial_cambios: AuditEntry[]; // Auditoría completa
total_clicks: number; // Contador de visitas
fecha_ultimo_click: Date | null; // Última visita registrada
}{
proyecto: string; // ✅ Requerido
creado_por: string; // ✅ Requerido
codigo?: string; // Opcional (se genera si no se proporciona)
url_destino?: string; // Opcional (null = reservado)
modulo?: string; // Opcional
etiquetas?: string[]; // Opcional
}{
actualizado_por: string; // ✅ Requerido
url_destino?: string; // Opcional
estado?: ShortLinkStatus; // Opcional
modulo?: string; // Opcional
etiquetas?: string[]; // Opcional
}| Tipo | Límite | Endpoints |
|---|---|---|
| Lectura | 300 req/min | GET /v1/short-links, GET /v1/short-links/{id} |
| Escritura | 100 req/min | POST /v1/short-links |
| Actualización | 30 req/min | PATCH /v1/short-links/{id} |
| Redirección | Sin límite | GET /r/{codigo} |
| Código | Significado | Cuándo ocurre |
|---|---|---|
200 |
OK | Operación exitosa (GET, PATCH) |
201 |
Created | Enlace creado exitosamente |
302 |
Found | Redirección exitosa |
400 |
Bad Request | Error de validación |
401 |
Unauthorized | Falta autenticación |
403 |
Forbidden | Autenticación inválida |
404 |
Not Found | Recurso no encontrado |
409 |
Conflict | Código duplicado |
410 |
Gone | Enlace deshabilitado/expirado |
500 |
Internal Error | Error del servidor |
- Swagger UI Interactivo - Documentación completa con pruebas en vivo
- Guía de Swagger - Cómo usar la documentación interactiva
- Base de Datos (TypeORM) - Entidades, repositorios y migraciones
- Guía de Testing - Colección de pruebas con ejemplos
- Despliegue en Producción - Guía completa de despliegue
- Guía para Desarrolladores (AGENTS.md) - Arquitectura y estándares
💡 Tip: Para explorar la API de forma interactiva, usa Swagger UI en lugar de leer esta documentación completa. Es más rápido y te permite probar los endpoints directamente.
🌐 Accede ahora: http://localhost:4300/api-docs
#### Campos
| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| proyecto | string | ✅ Sí | Proyecto origen del enlace |
| creado_por | string | ✅ Sí | Usuario/sistema que crea el enlace |
| codigo | string | ❌ No | Código personalizado (si no se proporciona, se genera automáticamente) |
| url_destino | string | ❌ No | URL de destino (si no se proporciona, queda como RESERVADO) |
| modulo | string | ❌ No | Módulo del proyecto |
| etiquetas | string[] | ❌ No | Etiquetas de campaña/canal |
#### Response (201)
```json
{
"code": 201,
"message": "Enlace corto creado exitosamente",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "promo2025",
"url_corta": "https://lnk.simpledatacorp.com/promo2025",
"url_destino": "https://www.ejemplo.com/promocion",
"estado": "ACTIVO",
"proyecto": "marketing-2025",
"modulo": "campanas",
"etiquetas": ["promocion", "verano", "descuento"],
"fecha_creacion": "2025-01-15T10:00:00.000Z",
"fecha_ultima_actualizacion": "2025-01-15T10:00:00.000Z",
"total_clicks": 0,
"fecha_ultimo_click": null
}
}
GET /v1/short-links/:id
Obtiene los detalles de un enlace específico.
{
"code": 200,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "promo2025",
"url_corta": "https://lnk.simpledatacorp.com/promo2025",
"url_destino": "https://www.ejemplo.com/promocion",
"estado": "ACTIVO",
"proyecto": "marketing-2025",
"total_clicks": 150,
"fecha_ultimo_click": "2025-01-20T15:30:00.000Z"
}
}GET /v1/short-links
Lista y filtra enlaces según diversos criterios.
| Parámetro | Tipo | Descripción |
|---|---|---|
| proyecto | string | Filtrar por proyecto |
| estado | string | Filtrar por estado (ACTIVO, RESERVADO_SIN_DESTINO, etc.) |
| modulo | string | Filtrar por módulo |
| fecha_creacion_desde | date | Fecha mínima de creación |
| fecha_creacion_hasta | date | Fecha máxima de creación |
| etiquetas | string | Etiquetas separadas por comas |
GET /v1/short-links?proyecto=marketing-2025&estado=ACTIVO&etiquetas=promocion,verano
{
"code": 200,
"total": 2,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "promo2025",
"url_corta": "https://lnk.simpledatacorp.com/promo2025",
"url_destino": "https://www.ejemplo.com/promocion",
"estado": "ACTIVO",
"total_clicks": 150
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"codigo": "verano25",
"url_corta": "https://lnk.simpledatacorp.com/verano25",
"url_destino": "https://www.ejemplo.com/verano",
"estado": "ACTIVO",
"total_clicks": 89
}
]
}PATCH /v1/short-links/:id
Actualiza un enlace existente (URL destino, estado, etiquetas).
{
"actualizado_por": "usuario@empresa.com",
"url_destino": "https://www.ejemplo.com/nueva-promocion",
"estado": "ACTIVO",
"etiquetas": ["promocion", "invierno", "nuevo"]
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| actualizado_por | string | ✅ Sí | Usuario que actualiza |
| url_destino | string | ❌ No | Nueva URL de destino |
| estado | string | ❌ No | Nuevo estado |
| modulo | string | ❌ No | Actualizar módulo |
| etiquetas | string[] | ❌ No | Actualizar etiquetas |
{
"code": 200,
"message": "Enlace actualizado exitosamente",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"codigo": "promo2025",
"url_corta": "https://lnk.simpledatacorp.com/promo2025",
"url_destino": "https://www.ejemplo.com/nueva-promocion",
"estado": "ACTIVO",
"fecha_ultima_actualizacion": "2025-01-20T16:00:00.000Z"
}
}GET /r/:codigo
Endpoint público de redirección (NO requiere autenticación).
| Estado | Comportamiento |
|---|---|
| ACTIVO | Redirige a url_destino con HTTP 302 |
| RESERVADO_SIN_DESTINO | Redirige a página genérica configurada |
| DESHABILITADO | Muestra página de "Enlace deshabilitado" |
| EXPIRADO | Muestra página de "Enlace expirado" |
GET /r/promo2025
→ Redirige a: https://www.ejemplo.com/promocion
Nota: Este endpoint registra automáticamente:
- Incremento del contador de clics
- Fecha/hora del último acceso
| Estado | Descripción |
|---|---|
RESERVADO_SIN_DESTINO |
Enlace reservado sin URL de destino (para QR impresos) |
ACTIVO |
Enlace activo que redirige a su URL de destino |
DESHABILITADO |
Enlace deshabilitado, no redirige |
EXPIRADO |
Enlace que ha expirado, no redirige |
curl -X POST http://localhost:4100/v1/short-links \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
-d '{
"proyecto": "marketing-2025",
"creado_por": "admin@empresa.com",
"url_destino": "https://www.ejemplo.com/landing"
}'curl -X POST http://localhost:4100/v1/short-links \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
-d '{
"proyecto": "folletos-2025",
"creado_por": "admin@empresa.com",
"codigo": "folleto123"
}'curl -X PATCH http://localhost:4100/v1/short-links/550e8400-e29b-41d4-a716-446655440000 \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
-d '{
"actualizado_por": "admin@empresa.com",
"url_destino": "https://www.ejemplo.com/promocion-activa",
"estado": "ACTIVO"
}'curl -X PATCH http://localhost:4100/v1/short-links/550e8400-e29b-41d4-a716-446655440000 \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
-d '{
"actualizado_por": "admin@empresa.com",
"estado": "DESHABILITADO"
}'- Todos los endpoints administrativos requieren autenticación
- El endpoint de redirección es público para permitir acceso directo
- Las API Keys y tokens se configuran en variables de entorno
- Historial completo de auditoría de cambios
Para producción, actualiza estas variables:
SHORT_DOMAIN=https://lnk.simpledatacorp.com
RESERVED_LINK_URL=https://lnk.simpledatacorp.com/reserved
API_KEYS=key-produccion-segura-1,key-produccion-segura-2
BEARER_TOKENS=token-produccion-seguro-1
NODE_ENV=production- Almacenamiento: Actualmente en memoria (implementar base de datos para producción)
- Códigos cortos: Alfanuméricos, 4-20 caracteres
- Generación automática: 6 caracteres por defecto
- Redirección: HTTP 302 (temporal) para enlaces activos
- Performance: Endpoint de redirección optimizado para baja latencia
Ejecutar tests:
npm testPara soporte técnico o consultas, contactar a: dey.gordillo@simpledatacorp.com
UNLICENSED - Uso corporativo interno