MétodoRutaScopeQué hace
POST/api/v1/auth/token—Cambia la API key por un JWT
POST/api/v1/assetsasset:writeSube un fichero
GET/api/v1/assets/{id}asset:readDetalle con URLs firmadas
POST/api/v1/assets/{id}/variantsvariant:writeGenera variantes
GET/api/v1/assetsasset:readLista 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
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
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
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
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
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

EstadoCausa en este recorrido
401El JWT falta o ha caducado: pide otro
403La key no tiene el scope del paso (asset:write, variant:write…)
422Falta file, un campo es inválido, o reutilizaste una Idempotency-Key con otro cuerpo
429Má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.