Optimización de Imágenes
Descargar tipos de TypeScriptSDK
Además de la API REST, el SDK oficial para TypeScript y JavaScript gestiona la autenticación, las solicitudes multipart y el filtrado de campos de las imágenes. Úsalo desde tu servidor para no exponer la API key.
Instalación
Instala el SDK de optimización de imágenes desde npm. Puedes usar @ircg/ios para este servicio o @ircg/sdk para todos los servicios de IRCG.
# Solo este servicio
npm install @ircg/ios
# O el meta-paquete
npm install @ircg/sdkUso básico
Usa IOSClient directamente en el backend de tu proyecto. Si la imagen proviene de un formulario web, ejecuta el siguiente manejador después de recibir la solicitud del navegador. Los métodos seguros devuelven error en vez de lanzar una excepción.
import { IOSClient } from '@ircg/ios'
// Ejecuta este manejador después de que el navegador envíe el formulario a tu servidor.
export async function handleImageUpload(request: Request, apiKey: string): Promise {
const formData = await request.formData()
const image = formData.get('image')
if (!image || typeof image === 'string') {
return Response.json({ error: 'Selecciona una imagen' }, { status: 400 })
}
const ios = new IOSClient({ apiKey })
const { optimizedImage, error } = await ios.upload({
image,
requireSignedURLs: false,
fields: ['imageId'],
})
if (error) {
const status = typeof error.status === 'number' && error.status >= 400 && error.status <= 599 ? error.status : 502
return Response.json({ error: error.message }, { status })
}
return Response.json({
imageId: optimizedImage.imageId,
imageUrl: ios.getImageUrl(optimizedImage.imageId, 'product'),
})
} Para procesos del backend en los que la imagen ya existe en el sistema de archivos —por ejemplo, una tarea programada o un proceso por lotes— puedes leerla directamente:
import { File } from 'node:buffer'
import { readFile } from 'node:fs/promises'
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const image = new File([await readFile('./product.jpg')], 'product.jpg', { type: 'image/jpeg' })
const ios = new IOSClient({ apiKey, lang: 'es' })
const { optimizedImage, error } = await ios.upload({ image, requireSignedURLs: false, fields: ['imageId', 'currentVariants'] })
if (error) throw new Error(error.message)
// Usa el nombre o las dimensiones de una variante configurada.
console.log(ios.getImageUrl(optimizedImage.imageId, '500x500'))Dry run
Configura dryRun: true para recibir respuestas sintéticas tipadas sin realizar solicitudes
HTTP ni consumir créditos. Todas las operaciones remotas se simulan; las listas regresan vacías y no se conserva estado
entre llamadas.
// server.ts
import { File } from 'node:buffer'
import { readFile } from 'node:fs/promises'
import { IOSClient } from '@ircg/ios'
// Simula la optimización sin realizar solicitudes HTTP ni consumir créditos.
const image = new File([await readFile('./product.jpg')], 'product.jpg', { type: 'image/jpeg' })
const ios = new IOSClient({ apiKey: 'unused', dryRun: true, lang: 'es' })
const { optimizedImage, error } = await ios.upload({ image, fields: ['imageId', 'currentVariants'] })
if (error) throw new Error(error.message)
console.log(optimizedImage.imageId) // "dry-run-image"API REST
| Método | Ruta | Descripción |
|---|---|---|
| POST | /api/v1/images | Subir una imagen. |
| GET | /api/v1/images | Listar imágenes. |
| GET | /api/v1/images/:imageId | Consultar los metadatos de una imagen. |
| POST | /api/v1/images/:imageId/sign | Firmar una URL de imagen. |
| DELETE | /api/v1/images/:imageId | Eliminar una imagen. |
Subir Imagen POST
// server.ts
import { File } from 'node:buffer'
import { readFile } from 'node:fs/promises'
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const ios = new IOSClient({ apiKey, lang: 'es' })
const imageFile = new File([await readFile('./product.jpg')], 'product.jpg', { type: 'image/jpeg' })
// SDK
const { optimizedImage: sdkImage, error } = await ios.upload({
image: imageFile,
requireSignedURLs: false,
fields: ['imageId', 'name', 'requireSignedURLs', 'currentVariants'],
})
if (error) throw new Error(error.message)
console.log(sdkImage.imageId)
// REST: envía el mismo archivo como multipart/form-data
const formData = new FormData()
formData.append('image', imageFile)
formData.append('requireSignedURLs', 'false')
const fieldsQuery = encodeURIComponent(JSON.stringify(["imageId", "name", "requireSignedURLs", "currentVariants"]))
const response = await fetch('https://ircg.dev/api/v1/images?fields=' + fieldsQuery, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}`, 'Accept-Language': 'es' },
body: formData,
})
if (!response.ok) throw new Error(`Upload failed: ${response.status}`)
const { optimizedImage: restImage } = await response.json()
console.log(restImage.imageId)Parámetros opcionales
https://ircg.dev/api/v1/images?fields=["imageId","name","requireSignedURLs","currentVariants"]
| Parámetro | Tipo | Valores permitidos | Por defecto | Descripción |
|---|---|---|---|---|
| fields | string | Arreglo JSON de nombres de campos | Todos los campos | Especifica qué campos incluir en la respuesta. Campos disponibles:
Ejemplo: |
Cuerpo
| Campo | Tipo | Requerido | Por defecto | Descripción |
|---|---|---|---|---|
| image | File | Sí | - | El archivo de imagen a subir y optimizar. |
| requireSignedURLs | boolean | No | - | Si la imagen requiere URLs firmadas para acceso. Default: false |
Respuestas
Listar Imágenes GET
// server.ts
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const ios = new IOSClient({ apiKey, lang: 'es' })
// SDK
const {
optimizedImages: sdkImages,
totalAmount: sdkTotalAmount,
error,
} = await ios.getAll({
page: 1,
amount: 50,
fields: ['imageId', 'name', 'requireSignedURLs', 'requests'],
})
if (error) throw new Error(error.message)
console.log(sdkImages, sdkTotalAmount)
// REST
const fieldsQuery = encodeURIComponent(JSON.stringify(["imageId", "name", "requireSignedURLs", "requests"]))
const response = await fetch('https://ircg.dev/api/v1/images?fields=' + fieldsQuery, {
headers: { Authorization: `Bearer ${apiKey}`, 'Accept-Language': 'es' },
})
if (!response.ok) throw new Error(`List failed: ${response.status}`)
const { optimizedImages: restImages, totalAmount: restTotalAmount } = await response.json()
console.log(restImages, restTotalAmount)Parámetros opcionales
https://ircg.dev/api/v1/images?fields=["imageId","name","requests"]&amount=100&page=3&ascending=true
| Parámetro | Tipo | Valores permitidos | Por defecto | Descripción |
|---|---|---|---|---|
| fields | string | Arreglo JSON de nombres de campos | Todos los campos | Campos disponibles: |
| amount | number | 1 - 100 | 50 | Útil para la paginación. |
| page | number | 1 - 99999 | 1 | Útil para la paginación. |
| ascending | boolean | true false | false | Ordena la lista tomando en cuenta la fecha de creación (createdAt). |
Respuestas
Consultar metadatos por ID GET
// server.ts
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const ios = new IOSClient({ apiKey, lang: 'es' })
const imageId = 'd290f1ee-6c54-4b01-90e6-d701748f0851'
// SDK
const { optimizedImage: sdkImage, error } = await ios.getById({
imageId,
fields: ['imageId', 'name', 'requireSignedURLs', 'currentVariants'],
})
if (error) throw new Error(error.message)
console.log(sdkImage)
// REST
const fieldsQuery = encodeURIComponent(JSON.stringify(["imageId", "name", "requireSignedURLs", "currentVariants"]))
const response = await fetch(`https://ircg.dev/api/v1/images/${imageId}?fields=${fieldsQuery}`, {
headers: { Authorization: `Bearer ${apiKey}`, 'Accept-Language': 'es' },
})
if (!response.ok) throw new Error(`Read failed: ${response.status}`)
const { optimizedImage: restImage } = await response.json()
console.log(restImage)Segmento de ruta
https://ircg.dev/api/v1/images/:imageId
| Segmento | Tipo | Descripción |
|---|---|---|
| imageId | string | El identificador único de la imagen. |
Parámetros opcionales
https://ircg.dev/api/v1/images/:imageId?fields=["imageId","name","currentVariants"]
| Parámetro | Tipo | Valores permitidos | Por defecto | Descripción |
|---|---|---|---|---|
| fields | string | Arreglo JSON de nombres de campos | Todos los campos | Especifica qué campos incluir en la respuesta. Campos disponibles:
Ejemplo: |
Respuestas
Firmar Imagen POST
// server.ts
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const ios = new IOSClient({ apiKey, lang: 'es' })
const imageId = 'd290f1ee-6c54-4b01-90e6-d701748f0851'
const variant = '500x500' // También puedes usar el nombre de la variante.
// SDK
const { optimizedImage: sdkImage, error } = await ios.signImage({
imageId,
variant,
reuseSignature: true,
fields: ['sig', 'exp', 'imageId', 'signedUrl', 'requests'],
})
if (error) throw new Error(error.message)
console.log(sdkImage.signedUrl)
// REST: codifica los valores que forman parte de la consulta
const fieldsQuery = encodeURIComponent(JSON.stringify(["sig", "exp", "imageId", "signedUrl", "requests"]))
const response = await fetch(
`https://ircg.dev/api/v1/images/${imageId}/sign?variant=${encodeURIComponent(variant)}&fields=${fieldsQuery}&reuseSignature=true`,
{
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}`, 'Accept-Language': 'es' },
},
)
if (!response.ok) throw new Error(`Signing failed: ${response.status}`)
const { optimizedImage: restImage } = await response.json()
console.log(restImage.signedUrl)El parámetro variant acepta el nombre configurado, como product, o dimensiones en formato ancho×alto, como 500x500.
Segmento de ruta
https://ircg.dev/api/v1/images/:imageId/sign
| Segmento | Tipo | Descripción |
|---|---|---|
| imageId | string | El identificador único de la imagen. |
Parámetros opcionales
https://ircg.dev/api/v1/images/:imageId/sign?variant=original&fields=["sig","exp","signedUrl"]&reuseSignature=true
Cuando reuseSignature=true, el servidor puede reutilizar una URL firmada cacheada para el mismo imageId + variant. Las firmas cacheadas se guardan por ~58 minutos (la firma subyacente expira después de ~60 minutos).
| Parámetro | Tipo | Valores permitidos | Por defecto | Descripción |
|---|---|---|---|---|
| variant | string | original, thumbnail, etc. | original | La variante de la imagen a firmar. |
| fields | string | Arreglo JSON de nombres de campos | Todos los campos | Especifica qué campos incluir en la respuesta. Campos disponibles: Ejemplo: |
| reuseSignature | boolean | true, false | false | Cuando es true, la API intentará reutilizar una firma generada recientemente para el mismo imageId + variant. |
Respuestas
Eliminar Imagen DELETE
// server.ts / server.js
import { IOSClient } from '@ircg/ios'
const apiKey = process.env.IRCG_IOS_API_KEY
if (!apiKey) throw new Error('Configura IRCG_IOS_API_KEY en el servidor')
const ios = new IOSClient({ apiKey, lang: 'es' })
const imageId = 'd290f1ee-6c54-4b01-90e6-d701748f0851'
// SDK
const { success, error } = await ios.delete({ imageId })
if (error) throw new Error(error.message)
console.log(success)
// REST
const response = await fetch(`https://ircg.dev/api/v1/images/${imageId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}`, 'Accept-Language': 'es' },
})
if (!response.ok) throw new Error(`Delete failed: ${response.status}`)
console.log(response.status)Segmento de ruta
https://ircg.dev/api/v1/images/:imageId
| Segmento | Tipo | Descripción |
|---|---|---|
| imageId | string | El identificador único de la imagen a eliminar. |
Respuestas
Variantes disponibles
El acordeón muestra el nombre y las dimensiones exactas de cada variante configurada. Usa cualquiera de los dos valores como argumento variant en getImageUrl() y signImage(). Solo se aceptan las dimensiones mostradas; no se generan tamaños arbitrarios.
Cargando variantes…
Mostrar una imagen
La operación GET /api/v1/images/:imageId devuelve metadatos en JSON; no devuelve los bytes de la imagen. Para mostrar una imagen pública, construye su URL de entrega con el imageId y una variante, y úsala como src de <img>.
// server.ts / server.js
const mediaOrigin = 'https://media.ircg.dev'
const imageId = 'd290f1ee-6c54-4b01-90e6-d701748f0851'
const variant = 'product'
const imageUrl = `${mediaOrigin}/i/${imageId}/${variant}`
// Incluye imageUrl en la respuesta del servidor; el frontend decide cómo mostrarla.
console.log(imageUrl)Este acceso directo solo aplica a imágenes cargadas con requireSignedURLs: false. Para una imagen privada, llama a signImage() desde tu servidor y usa la signedUrl devuelta como src; nunca expongas tu API key en el navegador.
Límites y costos
- Cada imagen cargada admite PNG, JPEG, GIF, WebP o SVG y un tamaño máximo de 10 MB.
- Se cobran 5 créditos por cada imagen activa en cada ciclo de facturación y 1 crédito por cada imagen servida, sin importar la variante o el tamaño de la respuesta.
- Generar o reutilizar una firma de URL no consume créditos.
- Los SVG conservan las mismas rutas de variantes y el mismo cobro por solicitud. Se entrega la salida sanitizada; las variantes SVG no se redimensionan aunque la ruta indique un tamaño.
- La API autenticada tiene un límite predeterminado de 600 solicitudes por 60 segundos y 15,000 por 3,600 segundos por API key; ambas ventanas se aplican de forma independiente. Puedes solicitar cambios a esos límites desde el panel.
- La entrega de imágenes tiene límites independientes y no consume el cupo de la API key:
3,000 solicitudes por 60 segundos por organización y dirección cliente, 30,000 por imagen y 60,000 por
organización. Son aproximados por ubicación de entrega; al alcanzarlos,
GETyHEADresponden429conRetry-After: 60.