API de jpg.now
Convierte imágenes y documentos mediante programación. Un endpoint REST envía un archivo, otro lo consulta y otro descarga el resultado; no hay SDK que instalar ni nada que configurar más allá de una clave de API.
Cómo funciona
La conversión es asíncrona, porque un archivo RAW grande tarda más de lo que debería durar una solicitud HTTP. Cada conversión consta de tres pasos:
- Enviar —
POST /api/v1/convertcon el archivo y un convertidorslug. Devuelve202y unjob_idde inmediato. - Consultar —
GET /api/v1/jobs/{job_id}hasta questatusseacompletedofailed. La mayoría de las conversiones terminan en menos de un segundo; consulta aproximadamente una vez por segundo. - Descargar —
GETeldownload_urldel trabajo completado.
Cada conversión enviada cuesta créditos: 1 normalmente, 2 para formatos que requieren mucha CPU. Consulta Créditos y precios.
Autenticación
Pasa tu clave de API en el encabezado X-Api-Key en cada solicitud. Las claves se crean en tu página Panel → Acceso a la API y se muestran una sola vez, al crearlas; solo almacenamos un hash, por lo que una clave perdida debe regenerarse en lugar de recuperarse. Regenerarla invalida la clave anterior de inmediato.
X-Api-Key: jpgnow_your_key_here
Las solicitudes sin una clave válida devuelven 401 y nunca se cobran.
URL base
https://jpg.now — todos los endpoints a continuación son relativos a esta. Solo HTTPS.
Inicio rápido
Una conversión completa, en el lenguaje de tu elección.
# 1. Submit
curl -X POST https://jpg.now/api/v1/convert \
-H "X-Api-Key: $API_KEY" \
-F "[email protected]" \
-F "slug=png-to-jpg"
# -> {"job_id":"abc123","status":"queued","credits_charged":1,"credits_remaining":999}
# 2. Poll until it is done
curl https://jpg.now/api/v1/jobs/abc123 -H "X-Api-Key: $API_KEY"
# -> {"status":"completed","download_url":"/download/abc123"}
# 3. Download
curl -L https://jpg.now/download/abc123 -o converted.jpg
import os, time, requests
BASE = "https://jpg.now"
HEAD = {"X-Api-Key": os.environ["API_KEY"]}
# 1. Submit
with open("photo.png", "rb") as fh:
r = requests.post(f"{BASE}/api/v1/convert", headers=HEAD,
files={"file": fh}, data={"slug": "png-to-jpg"})
r.raise_for_status()
job_id = r.json()["job_id"]
# 2. Poll. Give up eventually rather than looping forever on a stuck job.
for _ in range(120):
job = requests.get(f"{BASE}/api/v1/jobs/{job_id}", headers=HEAD).json()
if job["status"] in ("completed", "failed"):
break
time.sleep(1)
else:
raise TimeoutError(job_id)
if job["status"] == "failed":
raise RuntimeError(job.get("error", "conversion failed"))
# 3. Download
out = requests.get(BASE + job["download_url"], headers=HEAD)
open("converted.jpg", "wb").write(out.content)
import fs from "node:fs";
const BASE = "https://jpg.now";
const HEAD = { "X-Api-Key": process.env.API_KEY };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// 1. Submit
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("photo.png")]), "photo.png");
form.append("slug", "png-to-jpg");
const res = await fetch(`${BASE}/api/v1/convert`, {
method: "POST", headers: HEAD, body: form,
});
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error}`);
const { job_id } = await res.json();
// 2. Poll, with a ceiling so a stuck job cannot hang the process
let job;
for (let i = 0; i < 120; i++) {
job = await (await fetch(`${BASE}/api/v1/jobs/${job_id}`, { headers: HEAD })).json();
if (job.status === "completed" || job.status === "failed") break;
await sleep(1000);
}
if (job.status !== "completed") throw new Error(job.error ?? "conversion failed");
// 3. Download
const file = await fetch(BASE + job.download_url, { headers: HEAD });
fs.writeFileSync("converted.jpg", Buffer.from(await file.arrayBuffer()));
La lista completa de slugs de convertidores está en la página de formatos compatibles.
Endpoints
POST/api/v1/convert
Envía un archivo para convertir. Envíalo como multipart/form-data.
| Campo | Obligatorio | Descripción |
|---|---|---|
file | Sí | El archivo a convertir |
slug | Sí | ID del convertidor - Ej. jpg-to-png |
quality | No | Calidad de salida 10–100 (predeterminado 90) |
width / height | No | Redimensionar la salida en píxeles |
Devuelve 202 con {"job_id": "…", "status": "queued", "poll_url": "/api/v1/jobs/…"}
GET/api/v1/jobs/{job_id}
Consulta el estado del trabajo. Cuando status es "completed", se incluye un download_url.
GET/download/{job_id}
Descarga el archivo convertido. Devuelve el binario directamente.
GET/api/v1/usage
Tu límite y consumo actuales, para que una integración pueda reducir la velocidad antes de llegar al tope en lugar de descubrirlo al fallar. Devuelve quota_used, quota_included, quota_remaining y resets_at.
Límites de tasa y cuota
Se aplican dos límites separados. El límite de tasa es un tope de ráfaga por minuto; superarlo devuelve 429 y puedes reintentar poco después. La cuota mensual es tu asignación incluida; agotarla devuelve 402 hasta que el período se reinicie.
Las solicitudes que exceden la cuota son rechazadas, no facturadas — no hay cargo por exceso, por lo que un script descontrolado no puede generar una factura sorpresa. Las solicitudes que rechazamos (401, 429, 402) no cuentan contra tu asignación.
Cada llamada, aceptada o rechazada, aparece en tu panel de uso con su código de estado y resultado.
Créditos y precios
La API funciona con créditos. Un crédito es una conversión. Los formatos que requieren mucha CPU — archivos RAW de cámara, rasterización de PDF y vectores, PSD, TIFF — cuestan 2 créditos, porque requieren varias veces la CPU de una transcodificación normal. Todo lo demás cuesta 1.
| Conversión | Costo | Ejemplos |
|---|---|---|
| Estándar | 1 crédito | jpg-to-png, png-to-jpg, jpg-to-webp, compresión, redimensionado |
| Alto consumo de CPU | 2 créditos | raw-to-jpg, pdf-to-jpg, psd-to-jpg, svg-to-jpg, jpg-to-pdf, jpg-to-tiff |
Solo se cobra el trabajo que realmente encolamos. Las solicitudes que rechazamos — una clave incorrecta, un límite de tasa, un convertidor desconocido — no cuestan nada, y si tomamos un crédito y luego no logramos encolar el trabajo, se reembolsa automáticamente.
Dos formas de comprar
Los créditos se pueden comprar directamente u otorgarse mensualmente mediante una suscripción:
- Único — comprados una vez, nunca caducan. Ideal para volumen irregular o impredecible.
- Suscripción mensual — 30% más barato por crédito, pero los créditos no utilizados se reinician en cada renovación en lugar de acumularse. Ideal para volumen constante.
Puedes tener ambos. Los créditos de suscripción se gastan primero, por lo que los que compraste directamente nunca se pierden con una renovación.
| Créditos | Único | Mensual | Por crédito (mensual) | |
|---|---|---|---|---|
| 1,000 | $12.00 | $8.40/mes | $0.0084 | Comprar → |
| 5,000 | $60.00 | $42.00/mes | $0.0084 | Comprar → |
| 25,000 | $300.00 | $210.00/mes | $0.0084 | Comprar → |
| 100,000 | $1200.00 | $840.00/mes | $0.0084 | Comprar → |
Se puede comprar cualquier cantidad desde 500 créditos en el panel de API. Los suscriptores de Premium y Premium Plus tienen acceso a la API sin costo de crédito alguno.
Errores
| Estado | Significado | Qué hacer |
|---|---|---|
400 | Solicitud incorrecta — slug desconocido, archivo faltante o un archivo que no podemos aceptar | Corrige la solicitud; no se cobró nada |
401 | X-Api-Key faltante o no válido | Verifica el encabezado y que la clave no haya sido revocada |
402 | Sin créditos | Recarga; la respuesta indica cuántas necesitaba la llamada |
403 | La cuenta no puede usar la API | Crea una clave y compra créditos |
404 | Trabajo no encontrado, o no es tuyo | Revisa el job_id |
429 | Límite de velocidad excedido | Reduce la velocidad e inténtalo de nuevo; tu límite está en /api/v1/usage |
503 | No pudimos encolar el trabajo | Inténtalo de nuevo en breve; el crédito fue reembolsado |