API para desarrolladores

Documentación de la API

Crea enlaces protegidos, consulta analíticas respetuosas con la privacidad y registra conversiones desde tu producto.

01

Haz tu primera solicitud

La API es de servidor a servidor. Nunca expongas un token en JavaScript del navegador ni en un paquete móvil público.

  1. 1Activa Pro o BusinessEl acceso a la API está habilitado en planes de pago compatibles y durante la prueba Pro.
  2. 2Crea un token con permisos limitadosElige solo los permisos que necesita tu integración en la consola para desarrolladores.
  3. 3Envíalo mediante HTTPSAuthorization: Bearer 4ul_live_…
  4. 4Guárdalo como una contraseñaEl token completo se muestra una sola vez. Revócalo de inmediato si puede haberse expuesto.
curl "https://4ul.ink/api/v1/links?per_page=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
02

Referencia de endpoints

El acceso a cada objeto está limitado al workspace asignado al token.

MétodoRutaPermisoResultado
GET/api/v1/linkslinks:readEnlaces paginados
POST/api/v1/linkslinks:writeCrea un enlace protegido
PATCH/api/v1/links/{id}links:writeActualiza los campos enviados
DELETE/api/v1/links/{id}links:writeDesactiva sin borrar analíticas
GET/api/v1/links/{id}/analyticsanalytics:readAnalítica agregada
POST/api/v1/conversionslinks:writeRegistra un evento atribuido
GET/api/v1/domainsdomains:readDominios personalizados
POST/api/v1/domainsdomains:writeConectar un dominio
POST/api/v1/domains/{id}/verifydomains:writeVerificar DNS
DELETE/api/v1/domains/{id}domains:writeEliminar
GET/api/v1/webhookswebhooks:readEndpoints de webhook
POST/api/v1/webhookswebhooks:writeAñadir endpoint
PATCH/api/v1/webhooks/{id}webhooks:writeActualiza los campos enviados
POST/api/v1/webhooks/{id}/testwebhooks:writeEnviar prueba
POST/api/v1/webhooks/{id}/rotate-secretwebhooks:writeRotar secreto
DELETE/api/v1/webhooks/{id}webhooks:writeEliminar
03

Solicitudes y respuestas

Los nombres de los campos coinciden con la API v1 activa.

POST

Crear un enlace

links:write
{
    "destination_url": "https://example.com",
    "slug": "launch",
    "title": "Launch article"
}
destination_url
URL público HTTP o HTTPS obligatorio.
title
Opcional, hasta 190 caracteres.
slug
Alias personalizado opcional, de 3 a 80 caracteres.
201

Respuesta del enlace

application/json
{
  "data": {
    "id": 123,
    "slug": "launch",
    "short_url": "https://4ul.ink/launch",
    "destination_url": "https://example.com/article",
    "title": "Launch article",
    "click_count": 0,
    "is_active": true,
    "created_at": "2026-07-25 12:00:00"
  }
}
GET

Listar enlaces

?page=1&per_page=25
{
  "data": [{ "id": 123, "slug": "launch", "is_active": true }],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 1,
    "total_pages": 1
  }
}

per_page acepta de 1 a 100. Los objetos de enlace usan la estructura completa mostrada arriba.

GET

Leer analíticas

analytics:read
/api/v1/links/123/analytics?period=custom
  &from=2026-07-01
  &to=2026-07-20

Los periodos son 7, 30, 90 o custom. La respuesta incluye resumen, comparaciones, calidad del tráfico, conversiones, series diarias, audiencias y patrones horarios, nunca IP sin procesar.

PATCH

Actualizar un enlace

/api/v1/links/123
{
  "destination_url": "https://example.com/new",
  "title": "New title",
  "slug": "new-alias",
  "is_active": true
}

Solo cambian los campos enviados. Cambiar el destino pone en cola un nuevo análisis de Nova Shield.

POST

Registrar una conversión

/api/v1/conversions
{
  "click_token": "4ul_click_…",
  "event": "sale",
  "external_id": "order_1042",
  "amount": 49.00,
  "currency": "USD"
}

Los eventos son lead, sale o refund. Un evento externo duplicado devuelve HTTP 409 y nunca se cuenta dos veces.

Permisos del token

links:read
lista enlaces.
links:write
crea, actualiza y desactiva enlaces, y registra conversiones.
analytics:read
lee analíticas de enlaces.
domains:read / domains:write
Dominios personalizados
webhooks:read / webhooks:write
Webhooks firmados

Límites de solicitudes

Cada token permite 120 solicitudes por minuto más la cuota mensual del workspace. Analytics tiene un límite adicional de 60 por minuto. HTTP 429 incluye Retry-After y RateLimit. Los redireccionamientos siguen funcionando.

Idempotencia

Al crear enlaces, envía un Idempotency-Key de 8 a 128 caracteres imprimibles. La clave dura 24 horas en el workspace. Un reintento idéntico reproduce la respuesta; otros datos con la misma clave devuelven HTTP 409.

HTTP

Errores

Los errores usan un único formato JSON. Estados comunes: 400 JSON no válido, 401 token no válido, 403 sin permiso o plan, 404 no encontrado, 409 conflicto, 413 cuerpo demasiado grande, 415 tipo incorrecto, 422 validación y 429 límite.

{
  "error": "destination_url must be a valid public HTTP or HTTPS URL.",
  "code": "invalid_destination",
  "field": "destination_url",
  "request_id": "req_7fd9c0c8d821e84b3d69d171",
  "error_details": {
    "code": "invalid_destination",
    "message": "destination_url must be a valid public HTTP or HTTPS URL.",
    "field": "destination_url",
    "request_id": "req_7fd9c0c8d821e84b3d69d171"
  }
}
HMAC

Verifica cada webhook

Los eventos incluyen link.created, link.updated, link.disabled, link.clicked, conversion.created, shield.status_changed y endpoint.test. La entrega automática reintenta hasta cinco veces.

Los webhooks de disponibilidad usan shield.availability_changed e incluyen transiciones y diagnósticos HTTP limitados sin URL de destino.

Cabeceras de entrega

X-4ulink-Event: conversion.created
X-4ulink-Delivery: EVENT_UUID
X-4ulink-Timestamp: UNIX_TIMESTAMP
X-4ulink-Signature: sha256=HEX_HMAC

Verificación en PHP

$raw = file_get_contents('php://input');
$signed = $timestamp . '.' . $raw;
$expected = 'sha256=' . hash_hmac('sha256', $signed, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit;
}

Usa el cuerpo sin procesar, compara firmas en tiempo constante, rechaza marcas de tiempo de más de cinco minutos y guarda X-4ulink-Delivery para reintentos idempotentes. El endpoint debe usar HTTPS público en el puerto 443.