API reference
Convert images from your own app
A small REST API to turn any image into a pixel-perfect SVG (plus PNG/WebP at every size) without opening the studio. Upload an image, poll until it is ready, download the result. Everything the web app does under the hood, driven by your code.
Plan
Business
Quota
5000 / month
Auth
API key
Format
REST · JSON
Base URL
https://rgpixel.com/api/v1Authentication
Every request carries your API key as a Bearer token. Generate one on your account page — it is shown once, starts with fk_, and can be rotated any time (rotating does not reset your monthly usage). Keep it secret; it is the only thing standing between a caller and your quota.
Authorization: Bearer fk_YOUR_KEYA missing or unknown key returns 401. A valid key whose plan no longer includes API access returns 403 — access follows the live plan, so a lapsed subscription loses the API immediately.
Start a conversion
Send the image as multipart/form-data. Returns immediately with an uploadId and a queued status — the conversion runs in the background. This is the only call that spends quota (one call per conversion). A missing file returns 400 and is not charged.
Form fields
filefilerequiredThe image to convert (PNG, JP, WebP, …). Its longest side is capped at your plan maximum (4096 px on Business); larger images are downscaled, never upscaled.
removeBackgroundbooleanPass "true" to strip the background to real transparency before vectorizing. Omit for images that already have clean alpha.
curl -X POST https://rgpixel.com/api/v1/convert \
-H "Authorization: Bearer fk_YOUR_KEY" \
-F "file=@logo.png" \
-F "removeBackground=true"
# → { "uploadId": "u_abc123", "status": "queued" }Check status & list files
Poll this until status is done. Polling is free — it never spends quota. When done, engine.variants[] lists every file produced; each entry’s path is what you pass to the download endpoint.
curl "https://rgpixel.com/api/v1/convert?id=u_abc123" \
-H "Authorization: Bearer fk_YOUR_KEY"
# → {
# "uploadId": "u_abc123",
# "status": "done",
# "engine": {
# "status": "done",
# "imageKind": "flat",
# "variants": [
# { "kind": "svg-exact", "path": "vector/u_abc123.exact.svg",
# "mimeType": "image/svg+xml", "bytes": 11234 },
# { "kind": "png", "path": "512x512/u_abc123_512.png",
# "sizePx": 512, "mimeType": "image/png", "bytes": 8765 }
# ]
# }
# }Each variant has a kind (e.g. svg-exact — the lossless, pixel-perfect SVG; svg-traced — a small scalable trace; and png/webp at each sizePx), a path, its mimeType and bytes.
Download a result file
Stream any file from variants[] by its path. Free (no quota). Returns the raw bytes with the right Content-Type; supports Range requests. Returns 409 if the conversion is not done yet, and 404 for a path that isn’t in the manifest.
# Use a "path" from engine.variants[] above
curl "https://rgpixel.com/api/v1/convert/u_abc123/file/vector/u_abc123.exact.svg" \
-H "Authorization: Bearer fk_YOUR_KEY" \
-o logo.svgFull example (Node.js)
The whole flow — upload, poll, download the exact SVG — with no dependencies.
import { readFile, writeFile } from "node:fs/promises";
const KEY = process.env.RGPIXEL_API_KEY;
const BASE = "https://rgpixel.com/api/v1/convert";
const headers = { Authorization: `Bearer ${KEY}` };
// 1 — start the conversion
const form = new FormData();
form.set("file", new Blob([await readFile("logo.png")]), "logo.png");
const start = await fetch(BASE, { method: "POST", headers, body: form });
const { uploadId } = await start.json();
// 2 — poll until it is done (or failed)
let engine;
for (;;) {
const res = await fetch(`${BASE}?id=${uploadId}`, { headers });
const data = await res.json();
if (data.status === "done") { engine = data.engine; break; }
if (data.status === "failed") throw new Error("conversion failed");
await new Promise((r) => setTimeout(r, 1500));
}
// 3 — download the exact SVG
const svg = engine.variants.find((v) => v.kind === "svg-exact");
const file = await fetch(`${BASE}/${uploadId}/file/${svg.path}`, { headers });
await writeFile("logo.svg", Buffer.from(await file.arrayBuffer()));Quota & rate limits
Monthly quota
5000 conversions per calendar month (UTC). Only POST /convert counts; status polls and downloads are free. The counter resets on the 1st and lives on your account, so rotating your key does not reset it.
Burst limit
Up to 30 requests per 10 seconds per key. Over that returns 429 with a Retry-After header — back off and retry.
Exhausted quota
Once you reach 5000 for the month, POST /convert returns 429 ("Monthly API quota exceeded") until the next month. Upgrade or wait for the reset.
Errors
Errors are JSON with an error message and the matching HTTP status.
| Status | When | Meaning |
|---|---|---|
| 400 | POST | No file in the request. Not charged. |
| 401 | any | Missing or unknown API key. |
| 403 | any | Your plan does not include API access. |
| 404 | GET file | Upload isn’t yours, or the path isn’t a real variant. |
| 409 | GET file | The conversion isn’t done yet — keep polling status. |
| 429 | POST | Monthly quota reached, or too many requests too fast. |
| 502 | POST | The conversion couldn’t be started. Not charged — retry. |
Ready to build?
The API ships with the Business plan. Grab a key and make your first call in a minute.
