Limbo como librería de imágenes (API)
Sube, transforma y sirve imágenes desde tu backend con la API REST v1 de Limbo. Esta página resume las reglas que comparten todos los endpoints.
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:
{
"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..
{
"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:
{
"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 |
|---|---|---|
| 400 | bad-request | JSON inválido, Idempotency-Key mal formada, combinación de filtros no permitida |
| 401 | unauthorized | Sin token, token inválido o caducado |
| 403 | forbidden | Falta un scope, origen no permitido, escritura sobre un asset de otro portal |
| 404 | not-found | No existe, o no es legible para tu portal (no se distingue) |
| 409 | conflict | Petición idempotente aún en curso, carpeta no vacía |
| 415 | unsupported-media-type | Content-Type que el endpoint no admite |
| 422 | validation-failed | Campos inválidos o Idempotency-Key reutilizada con otro cuerpo |
| 429 | rate-limited | Límite de peticiones superado |
| 500 | internal-error | Fallo 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:
"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:
| Cabecera | Significado |
|---|---|
X-RateLimit-Limit | Peticiones permitidas en la ventana |
X-RateLimit-Remaining | Peticiones que te quedan |
X-RateLimit-Reset | Timestamp Unix del primer instante en que se aceptará la siguiente petición; si te quedan peticiones es «ahora» |
Retry-After | Segundos 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
Origindebe estar en losallowedOriginsdel 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>yLink: <…>; rel="successor-version"apuntando a su sustituta. Llevan ademásSunset: 2027-05-01, fecha a partir de la cual pueden retirarse; la retirada no es automática y la anuncia el equipo.