Optimización de Imágenes

Descargar tipos de TypeScript

SDK

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.

typescript
	# Solo este servicio
	npm install @ircg/ios
	# O el meta-paquete
	npm install @ircg/sdk

Uso 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.

typescript
	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:

typescript
	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.

typescript
	// 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étodoRutaDescripción
POST/api/v1/imagesSubir una imagen.
GET/api/v1/imagesListar imágenes.
GET/api/v1/images/:imageIdConsultar los metadatos de una imagen.
POST/api/v1/images/:imageId/signFirmar una URL de imagen.
DELETE/api/v1/images/:imageIdEliminar una imagen.

Subir Imagen POST

typescript
	// 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ámetroTipoValores permitidosPor defectoDescripción
fieldsstringArreglo JSON de nombres de camposTodos los campos

Especifica qué campos incluir en la respuesta. Campos disponibles: imageId, name, requireSignedURLs, createdAt, requests, currentVariants, placeholderBase64.

currentVariants enumera los nombres, dimensiones y URLs disponibles. placeholderBase64 contiene una imagen de baja resolución generada con la variante placeholder (32x32); puedes guardarla con los datos de la imagen y mostrarla mientras carga la imagen definitiva.

Ejemplo: ?fields=["imageId","name","currentVariants"]

Cuerpo

CampoTipoRequeridoPor defectoDescripción
imageFile-El archivo de imagen a subir y optimizar.
requireSignedURLsbooleanNo-Si la imagen requiere URLs firmadas para acceso. Default: false

Respuestas

Listar Imágenes GET

typescript
	// 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ámetroTipoValores permitidosPor defectoDescripción
fieldsstringArreglo JSON de nombres de camposTodos los campos

Campos disponibles: imageId, name, requireSignedURLs, createdAt y requests.

amountnumber1 - 10050Útil para la paginación.
pagenumber1 - 999991Útil para la paginación.
ascendingboolean

true

false

falseOrdena la lista tomando en cuenta la fecha de creación (createdAt).

Respuestas

Consultar metadatos por ID GET

typescript
	// 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

SegmentoTipoDescripción
imageIdstringEl identificador único de la imagen.

Parámetros opcionales

https://ircg.dev/api/v1/images/:imageId?fields=["imageId","name","currentVariants"]

ParámetroTipoValores permitidosPor defectoDescripción
fieldsstringArreglo JSON de nombres de camposTodos los campos

Especifica qué campos incluir en la respuesta. Campos disponibles: imageId, name, requireSignedURLs, createdAt, requests, currentVariants, placeholderBase64.

currentVariants enumera los nombres, dimensiones y URLs disponibles. placeholderBase64 contiene una imagen de baja resolución generada con la variante placeholder (32x32); puedes guardarla con los datos de la imagen y mostrarla mientras carga la imagen definitiva.

Ejemplo: ?fields=["imageId","name","requests","currentVariants"]

Respuestas

Firmar Imagen POST

typescript
	// 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

SegmentoTipoDescripción
imageIdstringEl 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ámetroTipoValores permitidosPor defectoDescripción
variantstringoriginal, thumbnail, etc.originalLa variante de la imagen a firmar.
fieldsstringArreglo JSON de nombres de camposTodos los campos

Especifica qué campos incluir en la respuesta. Campos disponibles: sig, exp, signedUrl, imageId y requests.

Ejemplo: ?fields=["sig","exp","signedUrl"]

reuseSignaturebooleantrue, falsefalseCuando es true, la API intentará reutilizar una firma generada recientemente para el mismo imageId + variant.

Respuestas

Eliminar Imagen DELETE

typescript
	// 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

SegmentoTipoDescripción
imageIdstringEl 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>.

typescript
	// 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, GET y HEAD responden 429 con Retry-After: 60.

Reportar abuso