Base y formato de respuesta

Todos los endpoints de la v1 cuelgan del prefijo /api/v1/ (por ejemplo, https://limbo.lefebvre.es/api/v1/assets) y piden un token Authorization: Bearer, salvo POST /api/v1/auth/token y GET /api/v1/image-convert. Si vienes de la API anterior, empieza por Migrar a v1.

Una respuesta correcta lleva siempre success y data; meta solo aparece en los listados paginados:

JSON
{
  "success": true,
  "data": { "id": "3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1", "filename": "portada.jpg" }
}

Errores

Todo error de la v1 es application/problem+json (RFC 9457) con type, title, status, detail e instance. En algunos errores el prefijo de detail es un código de máquina (write_access_denied, folder_not_empty…): úsalo para decidir, no el texto completo. En los 5xx, detail es siempre An unexpected error occurred..

404
{
  "type": "https://limbo.lefebvre.es/problems/not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "Asset not found.",
  "instance": "/api/v1/assets/3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1"
}

El 422 de validación añade errors[] con el campo en snake_case:

422
{
  "type": "https://limbo.lefebvre.es/problems/validation-failed",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "The request contains invalid parameters.",
  "instance": "/api/v1/assets",
  "errors": [
    { "field": "per_page", "message": "This value should be between 1 and 100." }
  ]
}
Estado type (tras /problems/) Cuándo
400bad-requestJSON inválido, Idempotency-Key mal formada, combinación de filtros no permitida
401unauthorizedSin token, token inválido o caducado
403forbiddenFalta un scope, origen no permitido, escritura sobre un asset de otro portal
404not-foundNo existe, o no es legible para tu portal (no se distingue)
409conflictPetición idempotente aún en curso, carpeta no vacía
415unsupported-media-typeContent-Type que el endpoint no admite
422validation-failedCampos inválidos o Idempotency-Key reutilizada con otro cuerpo
429rate-limitedLímite de peticiones superado
500internal-errorFallo inesperado

Paginación

Los listados usan page (desde 1) y per_page (por defecto 20, máximo 100). Un valor fuera de rango es un 422; una página que no existe devuelve data vacío. La respuesta lleva meta.pagination:

JSON
"meta": {
  "pagination": {
    "current_page": 2,
    "total_pages": 3,
    "total_items": 45,
    "items_per_page": 20,
    "has_next_page": true,
    "has_prev_page": true
  }
}

Para recorrer un listado completo avanza page mientras has_next_page sea true. Puedes comprobar el comportamiento con GET /api/v1/ping?page=2&per_page=10, un catálogo fijo de 45 elementos.

Límite de peticiones

Cada portal puede hacer 600 peticiones por minuto (ventana deslizante). La petición de token tiene un límite aparte, de 120 por minuto e IP. Las respuestas llevan estas cabeceras:

CabeceraSignificado
X-RateLimit-LimitPeticiones permitidas en la ventana
X-RateLimit-RemainingPeticiones que te quedan
X-RateLimit-ResetTimestamp Unix del primer instante en que se aceptará la siguiente petición; si te quedan peticiones es «ahora»
Retry-AfterSegundos que esperar (de 1 a 60). Solo en el 429

Reintentos seguros: Idempotency-Key

En los POST de creación puedes enviar Idempotency-Key (1 a 255 caracteres ASCII imprimibles, sin espacios; un UUID sirve). La primera respuesta correcta se guarda 24 horas: si repites la petición con la misma clave y el mismo cuerpo recibes esa respuesta con Idempotent-Replayed: true y no se crea nada nuevo.

  • Misma clave con un cuerpo distinto: 422, sin errors[].
  • Misma clave mientras la primera petición sigue en curso: 409.
  • Si la primera petición falla (4xx o 5xx) no se guarda nada y puedes reintentar con la misma clave.
Rutas que admiten Idempotency-Key
POST /api/v1/assets
POST /api/v1/assets/{id}/variants y POST /api/v1/assets/{id}/variants/upload
POST /api/v1/folders
POST /api/v1/portals/me/presets/aspect y POST /api/v1/portals/me/presets/size
POST /api/v1/ai/generate y POST /api/v1/ai/video/generate
POST /api/v1/stock/download

CORS y rutas obsoletas

  • Desde un navegador, el Origin debe estar en los allowedOrigins del portal. Lo normal es que tu backend pida el token y el navegador solo reciba el JWT (Autenticación).
  • Las rutas de la API anterior siguen funcionando y responden con Deprecation: @<timestamp> y Link: <…>; rel="successor-version" apuntando a su sustituta. Llevan además Sunset: 2027-05-01, fecha a partir de la cual pueden retirarse; la retirada no es automática y la anuncia el equipo.

Mapa de la guía