Skip to main content
unraster

DEVELOPERS / API v1

Images in. Editable files out.

Submit a conversion, follow its progress, and download SVG and PowerPoint files.

1. Create an API key

Sign in with Google and open API keys. Keep your key on your server and send it as a Bearer token. Reading tasks requires conversions:read; creating and deleting requires conversions:write. Keys share your account’s conversion credits.

2. Check credits

curl https://unraster.ai/v1/conversions/quote \
  -H "Authorization: Bearer $UNRASTER_API_KEY"

The response lists exact prices in prices: SVG costs 1 credit, PPTX costs 2 credits, and requesting both costs 3 credits. It also includes your integer available_credits, the upload limit, and supported outputs.

{"billing_version":"fixed-v1","prices":{"svg":1,"pptx":2},"available_credits":10,"reserved_credits":0,"max_upload_bytes":26214400,"outputs":["svg","pptx"]}

The exact price is reserved when you submit. Only requested outputs that are ready to download are charged; credits for unavailable outputs are released. Progress checks and downloads are free.

First PowerPoint free. A new API account’s first PowerPoint conversion is free: one per account and per Google sign-in, for requests with outputs=pptx only. While it is unused, the quote includes "agent_trial_pptx_remaining":1. The free task has "free_reason":"agent_trial" and no billing; you get the full PowerPoint file. If the conversion fails, or ends in needs_review without a ready PowerPoint, the free conversion stays available; if it ends in needs_review with a ready PowerPoint, you get that file and the free conversion is used. After it is used, each PowerPoint costs 2 credits.

3. Submit one image

Upload a static PNG, JPEG, or WebP, up to 25 MiB and 25 million pixels. Send outputs=svg, outputs=pptx, or outputs=svg,pptx. Generate a unique REQUEST_ID and retain it with your request.

curl https://unraster.ai/v1/conversions \
  -H "Authorization: Bearer $UNRASTER_API_KEY" \
  -H "Idempotency-Key: $REQUEST_ID" \
  -F "file=@slide.png" \
  -F "outputs=svg,pptx"

A new task returns HTTP 202. Save its ID.

{
  "id": "cnv_example", "status": "queued", "stage": null,
  "version_id": null, "error": null,
  "outputs": [
    { "format": "svg", "status": "pending" },
    { "format": "pptx", "status": "pending" }
  ]
}

If the connection fails, retry the same image and output selection with the same idempotency key. A changed request using that key returns HTTP 409. Do not generate another key just because a response was lost.

4. Check progress and download

curl https://unraster.ai/v1/conversions/$TASK_ID \
  -H "Authorization: Bearer $UNRASTER_API_KEY"
StatusWhat to do
queuedWaiting to start; check again shortly.
processingStill working; poll every few seconds.
completedDownload outputs whose status is ready.
needs_reviewDownload ready outputs; unavailable outputs are not charged.
failedReview your source. No unavailable output is charged.
deletedThis task is no longer available.

outputs is an array. Ready outputs contain a url and expires_at. Paid, settled results use a public link under https://files.unraster.ai that works without an API key for seven days after completion. Anyone holding that link can download the file, so keep it private. A relative URL is a short-lived account-authenticated download; resolve it against the API origin and send your Bearer key only to that origin. Fetch the task again to refresh a relative link. A seven-day public link cannot be extended by fetching the task again.

Deleting with DELETE /v1/conversions/{id} revokes its download links. Deleting a completed task does not refund a successful conversion.

5. Receive webhooks

Add a public HTTPS endpoint in Webhook settings. Save the signing secret when it appears; it is shown only once. Notifications include conversion.completed, conversion.failed, and conversion.needs_review.

Preserve the exact request body bytes. The webhook-id header identifies the event. The webhook-signature header has the form t=TIMESTAMP,v1=HEX_SIGNATURE.

HMAC-SHA256(
  hexDecode(signing_secret),
  timestamp + "." + webhook_id + "." + raw_body
)

Use a timing-safe signature comparison, reject timestamps outside a five-minute window, and verify the event ID matches the body. Deduplicate by event ID before applying your business action. Events can arrive repeatedly or out of order; query the current task for its latest status and download links. Return 2xx after durably accepting an event. Failed deliveries retry for a limited period, so retain polling as a recovery option.

6. Convert in batches

Convert many images with one batch and download the results as one zip. Subscribers can batch on every paid plan: up to 10 files on the $19.90/month plan, 50 on the $49.90/month plan and 100 on the $99.90/month plan (with priority). Through an API key, batches need a plan with API batch access (150 and 333). An account that has credits but no subscription can batch on the website, up to 10 files. Accounts with neither a subscription nor credits, and API keys without batch access, get 403 plan_required (max 0). A batch uses a single output, svg or pptx. Keys need conversions:write to create, upload, start and cancel, and conversions:read to read.

Endpoints

  • POST /v1/batchesDeclare the files and reserve credits. Needs Idempotency-Key.
  • PUT /v1/batches/{id}/files/{idx}Upload one file as multipart field file.
  • POST /v1/batches/{id}/startBegin conversion. Files not uploaded are released.
  • POST /v1/batches/{id}/cancelStop waiting files; running files are charged only if delivered.
  • GET /v1/batchesYour last 50 batches, newest first, under batches.
  • GET /v1/batches/{id}State, counts, credits and per-file status.
  • GET /v1/batches/{id}/archiveZip of every delivered file.

Flow

  1. Create the batch, declaring each file’s name, size and type. Save the returned id and each item’s idx.
  2. Upload each file to /files/{idx}.
  3. Start the batch.
  4. Poll GET /v1/batches/{id} every few seconds until finished_at is set, or wait for the batch.finished webhook.
  5. Download the zip from /archive. For a single file, use GET /v1/conversions/{task_id} with the task_id from the batch.
curl https://unraster.ai/v1/batches \
  -H "Authorization: Bearer $UNRASTER_API_KEY" \
  -H "Idempotency-Key: $REQUEST_ID" \
  -H "Content-Type: application/json" \
  -d '{"output":"svg","files":[
    {"name":"a.png","size":183204,"type":"image/png"},
    {"name":"b.jpg","size":96311,"type":"image/jpeg"}
  ]}'

A new batch returns HTTP 201 (200 if you repeat the same request with the same key).

{
  "id": "job_0b6f6c1e-5c1a-4a58-9d42-2f3f6e0a9a11",
  "state": "open",
  "item_limit": 50,
  "items": [
    { "idx": 0, "task_id": "cnv_example_0" },
    { "idx": 1, "task_id": "cnv_example_1" }
  ],
  "reserved_credits": 2
}

The rest of the flow:

BATCH=job_0b6f6c1e-5c1a-4a58-9d42-2f3f6e0a9a11

# Upload each file to its idx (PNG, JPEG or WebP)
curl -X PUT https://unraster.ai/v1/batches/$BATCH/files/0 \
  -H "Authorization: Bearer $UNRASTER_API_KEY" \
  -F "file=@a.png"
curl -X PUT https://unraster.ai/v1/batches/$BATCH/files/1 \
  -H "Authorization: Bearer $UNRASTER_API_KEY" \
  -F "file=@b.jpg"

# Start the batch; files not uploaded are released
curl -X POST https://unraster.ai/v1/batches/$BATCH/start \
  -H "Authorization: Bearer $UNRASTER_API_KEY"

# Poll until finished_at is set (after a cancel, files already converting still finish)
curl https://unraster.ai/v1/batches/$BATCH \
  -H "Authorization: Bearer $UNRASTER_API_KEY"

# Download every delivered file as one zip
curl -o results.zip https://unraster.ai/v1/batches/$BATCH/archive \
  -H "Authorization: Bearer $UNRASTER_API_KEY"

A batch has ended when finished_at is set. Its final state is completed (no file failed; files you never uploaded are simply not converted), partial, failed or cancelled. After a cancel the state reads cancelled at once, but files already converting still finish and are charged if delivered: wait for finished_at before reading charged_credits or downloading the archive. An open batch that you never start is closed after 24 hours and its credits are released.

{
  "id": "job_0b6f6c1e-5c1a-4a58-9d42-2f3f6e0a9a11",
  "output": "svg",
  "state": "partial",
  "counts": { "done": 1, "failed": 1, "running": 0, "waiting": 0, "cancelled": 0 },
  "charged_credits": 1,
  "reserved_credits": 0,
  "items": [
    { "idx": 0, "file_name": "a.png", "state": "done",
      "task_id": "cnv_example_0", "error_code": null, "credits": 1 },
    { "idx": 1, "file_name": "b.jpg", "state": "failed",
      "task_id": "cnv_example_1", "error_code": "conversion_failed", "credits": 0 }
  ],
  "item_count": 2,
  "created_at": "2026-11-08T10:00:00.000Z",
  "started_at": "2026-11-08T10:00:20.000Z",
  "finished_at": "2026-11-08T10:01:05.000Z"
}

Credits

Creating a batch reserves credits for every file at once. A subscriber pays 1 credit per SVG and 2 credits per PowerPoint; a credit-pack batch pays one credit more per file (2 per SVG, 3 per PowerPoint). If your balance does not cover the whole batch, the request returns 402 insufficient_credits and nothing is reserved. Only delivered files are charged. Failed, cancelled and never-uploaded files are released, not charged. Progress checks and downloads are free.

Limits

  • Files: PNG, JPEG or WebP, up to 20 MiB each.
  • Files per batch: 10 on the $19.90/month plan, 50 on the $49.90/month plan, 100 on the $99.90/month plan. Credit-pack accounts: 10 files per batch, on the website only.
  • Idempotency-Key is required when creating a batch. Retry a lost response with the same key.
  • Uploads: 240 per minute per account.
  • Delivered files are kept for seven days. After that, /archive returns 410 batch_expired. While the batch is still running it returns 409 batch_not_finished; if nothing was delivered it returns 404.

The zip

Each delivered file is named {idx}-{original name}.svg (or .pptx), with duplicate names made unique. Files that were not delivered are not included.

The batch.finished webhook

Once a batch reaches a final state, your enabled webhook endpoints receive batch.finished. It is sent once per batch, for batches created through the API. Signing, headers and retries work as in the previous section. The body has counts and charged credits but no download links; fetch the batch or the archive for those. Every file also sends its usual conversion.* event. Events may arrive in any order, so deduplicate by id. A batch that is cancelled or expires before any file starts sends no event.

{
  "id": "evt_job_0b6f6c1e-5c1a-4a58-9d42-2f3f6e0a9a11_finished",
  "type": "batch.finished",
  "created_at": "2026-11-08T10:01:05.000Z",
  "data": {
    "id": "job_0b6f6c1e-5c1a-4a58-9d42-2f3f6e0a9a11",
    "state": "partial",
    "output": "svg",
    "counts": { "done": 1, "failed": 1, "running": 0, "waiting": 0, "cancelled": 0 },
    "charged_credits": 1
  }
}

Handle errors

Errors use {"error": {"code": "…", "message": "…"}}. Branch on error.code.

  • 400 / 413 / 415: correct the request, file size, or format.
  • 401 / 403: check your key and permissions.
  • 402: insufficient available credits.
  • 404: the task or file is unavailable to this account.
  • 409: check for an idempotency conflict.
  • 429: respect Retry-After before retrying.
  • 503: retry later, preserving the original idempotency key.

Batch requests add these codes:

CodeHTTPMeaning
plan_required403Your plan has no batch API access. The body includes max.
job_too_large422More files than your plan allows. The body includes max and requested.
insufficient_credits402Not enough credits for the whole batch. The body includes required and available.
idempotency_key_required400Add an Idempotency-Key header to the create request.
idempotency_conflict409The key was already used with a different request.
invalid_request400Malformed or unexpected request body.
no_files_uploaded400Start was called before any file was uploaded. Upload at least one file, or cancel the batch to release the reserved credits.
file_already_uploaded409That index already holds a different file. Each index accepts one upload; the body includes idx.
conversion_not_found404No such batch for this key, or a file index outside the batch.
invalid_image400The file is not a single-frame PNG, JPEG or WebP, or the part’s Content-Type does not match the file. With curl, add the type: -F "file=@a.webp;type=image/webp".
unsupported_media_type415The request is not multipart/form-data.
upload_too_large413A file is over 20 MiB.
job_not_open409The batch was already started or closed; uploads are no longer accepted.
batch_not_finished409The archive is not ready; poll the batch until it finishes.
batch_expired410The seven-day delivery period has passed.
rate_limited429Too many requests. Wait for Retry-After.