🚀 Inicio rápido
Cinco pasos con curl: token, subida, URL firmada, una variante y un listado paginado.
| Método | Ruta | Scope | Qué hace |
|---|---|---|---|
| POST | /api/v1/auth/token | — | Cambia la API key por un JWT |
| POST | /api/v1/assets | asset:write | Sube un fichero |
| GET | /api/v1/assets/{id} | asset:read | Detalle con URLs firmadas |
| POST | /api/v1/assets/{id}/variants | variant:write | Genera variantes |
| GET | /api/v1/assets | asset:read | Lista paginada |
Necesitas una API key con los scopes asset:read, asset:write y variant:write.
Los ejemplos usan https://limbo.lefebvre.es; cambia el host por el de tu entorno.
1. Pedir el token
Desde tu servidor, con la pk_ y el sk_ de la key:
curl -X POST https://limbo.lefebvre.es/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"public_key": "pk_...", "api_key": "sk_..."}'
# Respuesta (recortada)
{ "success": true, "data": { "token": "eyJhbGciOi...", "token_type": "Bearer", "expires_in": 3600, "scopes": ["asset:read", "asset:write", "variant:write"] } }
Guarda el token en una variable: export JWT=eyJhbGciOi.... Detalles en Autenticación.
2. Subir una imagen
Multipart con el fichero en file; folder y tags (separados por comas) son opcionales.
Idempotency-Key permite repetir la petición sin crear un duplicado.
curl -i -X POST https://limbo.lefebvre.es/api/v1/assets \
-H "Authorization: Bearer $JWT" \
-H "Idempotency-Key: 5d1e9a7c-3b42-4f0e-a6c8-2f7b1d9e4a10" \
-F "file=@portada.jpg" \
-F "folder=campana-otono" \
-F "tags=portada,otono"
# HTTP/1.1 201 Created
# Location: /api/v1/assets/3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1
{
"success": true,
"data": {
"id": "3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1",
"filename": "portada.jpg",
"mime_type": "image/jpeg",
"width": 1920,
"height": 1080,
"status": "active",
"url": "https://limbo.lefebvre.es/media/mi-portal/portada.webp?a=Zk3xT...",
"format": "webp",
"permanent": true,
"folder": { "id": "...", "slug": "campana-otono", "name": "campana-otono" },
"tags": ["portada", "otono"]
}
}
Si reintentas con la misma clave y el mismo fichero recibes el mismo 201 con Idempotent-Replayed: true.
3. Leer el asset: URL firmada
curl https://limbo.lefebvre.es/api/v1/assets/3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1 \
-H "Authorization: Bearer $JWT"
# Respuesta (recortada)
{
"success": true,
"data": {
"id": "3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1",
"filename": "portada.jpg",
"url": "https://limbo.lefebvre.es/media/mi-portal/portada.webp?a=Zk3xT...",
"url_original": "https://limbo.lefebvre.es/media/mi-portal/portada.jpg?a=Qm81B...",
"permanent": true,
"expires_at": null,
"tags": ["portada", "otono"],
"variants": []
}
}
Las URLs de /media/…?a= llevan un token firmado y, por defecto, no caducan (permanent: true, expires_at: null).
Si necesitas que caduquen, pide el asset con ?url_expires=3600 (segundos). Se sirven sin Authorization, así que la URL puede ir directamente en un <img>; no intentes recomponerla a mano.
4. Generar una variante
variants es una lista de especificaciones (name, width y height obligatorios).
Por defecto la generación es asíncrona (202, estado queued); con "async": false se hace en la misma
petición y responde 201.
curl -X POST https://limbo.lefebvre.es/api/v1/assets/3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1/variants \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"async": false, "variants": [{"name": "card", "width": 400, "height": 300, "format": "webp"}]}'
# HTTP/1.1 201 Created
{
"success": true,
"data": {
"asset_id": "3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1",
"variants_requested": 1,
"processing_mode": "sync",
"variants": [
{ "name": "card", "status": "completed", "size": "400x300", "format": "webp", "file_size": 18234, "url": "https://limbo.lefebvre.es/media/mi-portal/variants/portada_card_400_300.webp?a=Hd7pL..." }
]
}
}
5. Listar con paginación
curl "https://limbo.lefebvre.es/api/v1/assets?page=1&per_page=20" \
-H "Authorization: Bearer $JWT"
# Respuesta (recortada)
{
"success": true,
"data": [
{ "id": "3f1c9a52-7d0e-4b8a-9c11-0a52e6d4b7f1", "filename": "portada.jpg", "variants_count": 1, "tags": ["portada", "otono"] }
],
"meta": {
"pagination": { "current_page": 1, "total_pages": 1, "total_items": 1, "items_per_page": 20, "has_next_page": false, "has_prev_page": false }
}
}
Errores frecuentes
| Estado | Causa en este recorrido |
|---|---|
| 401 | El JWT falta o ha caducado: pide otro |
| 403 | La key no tiene el scope del paso (asset:write, variant:write…) |
| 422 | Falta file, un campo es inválido, o reutilizaste una Idempotency-Key con otro cuerpo |
| 429 | Más de 600 peticiones por minuto; espera Retry-After segundos |
Qué más puedes hacer: Assets, Variantes. Los schemas completos están en la referencia OpenAPI.