Developers · v1

API reference.

One endpoint takes a photograph and returns a PNG with the background gone. Everything else on this page is the detail around that call: what it accepts, what comes back, and what to do when it fails.

Base URL
https://api.qikkstools.com/v1
Auth
Authorization: Bearer <key>

01

Overview #

The API is one POST away from working. Send an image, get back a PNG with an alpha channel, keep the original. Requests are HTTPS only, responses are JSON, and status codes mean what they mean everywhere else.

curl -X POST "https://api.qikkstools.com/v1/remove-background" \
  -H "Authorization: Bearer $API_KEY" \
  -F "image=@product.jpg" \
  -o product.png
HTTP/1.1 200 OK
Content-Type: image/png

<binary PNG, alpha channel intact>
returns product.png · alpha

What it accepts #

Input JPEG, PNG or WebP
Output PNG with transparency, or WebP on request
Max file 25 MB per image
Max batch 20 images, 100 MB in total per request
Transport HTTPS, multipart/form-data in, JSON or binary out

How long it takes #

Treat it as asynchronous

A call is seconds, not milliseconds — it is model time, and a cold worker is slower than a warm one. Put it behind a queue or a background job. A page render that waits on this is a page render that times out.

02

Authentication #

Every request carries a bearer key in the header. There is no session, no signature, and nothing to refresh.

Request headers
Authorization: Bearer YOUR_API_KEY
Accept: image/png

Getting a key #

Keys are issued with a Pro or Enterprise plan. Tell us the volume you expect and we will set one up — there is no self-serve key page yet, and this page will say so until there is.

Keeping it secret #

Server side only

The key spends your plan's allowance, so it belongs in an environment variable on your server — never in a browser bundle, a mobile app, or a repository. If one leaks, ask for a replacement and the old key stops working.

03

Remove background #

POST /v1/remove-background

One image in, one cutout out. The response is the PNG itself by default; ask for JSON with Accept: application/json and you get a URL that stays valid for ten minutes.

Parameters #

Field Type Default Notes
image file required JPEG, PNG or WebP, up to 25 MB
format string png png or webp. Both keep the alpha channel
quality integer 85 1–100. Ignored for PNG, which is lossless
crop boolean false Trim the canvas to the subject's bounds
curl -X POST "https://api.qikkstools.com/v1/remove-background" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -F "image=@/path/to/product.jpg" \
  -F "format=png" \
  -F "quality=90" \
  -F "crop=true"
{
  "success": true,
  "data": {
    "result_url": "https://cdn.qikkstools.com/processed/abc123.png",
    "original_size": { "width": 1024, "height": 768 },
    "processed_size": { "width": 812, "height": 740 },
    "processing_time": 2.34,
    "credits_used": 1
  }
}
returns abc123.png · alpha

Result URLs expire — download the file, do not hotlink it.

04

Batch process #

POST /v1/batch-process

Up to 20 images and 100 MB in one request. The call returns a job immediately rather than holding the connection open for a minute; poll the status URL or give us a webhook. A nightly run over the day's uploads is the cheapest shape this API has, and the only one with nothing user-facing to break.

Parameters #

Field Type Default Notes
images[] file[] required 1–20 files. A batch that exceeds either cap is refused whole
webhook_url string POSTed the finished job. Must be HTTPS
format string png Applied to every image in the batch
curl -X POST "https://api.qikkstools.com/v1/batch-process" \
  -H "Authorization: Bearer $API_KEY" \
  -F "images[]=@image1.jpg" \
  -F "images[]=@image2.jpg" \
  -F "images[]=@image3.jpg" \
  -F "webhook_url=https://your-site.com/hooks/cutouts"
{
  "success": true,
  "data": {
    "job_id": "batch_abc123def456",
    "total_images": 3,
    "status_url": "https://api.qikkstools.com/v1/jobs/batch_abc123def456"
  }
}
returns job · 3 queued

A batch costs one call per image

Twenty images spend twenty removals against your plan, the same as twenty single calls. A batch that does not fit in what is left is refused whole, with the number that would fit — processing three of twenty and dropping the rest is a failure you would only find when you opened the archive.

05

Job status #

GET /v1/jobs/{job_id}

Where a batch has got to. Poll it every few seconds, not every few hundred milliseconds — polling counts against your rate limit and the work is measured in seconds per image.

curl "https://api.qikkstools.com/v1/jobs/batch_abc123def456" \
  -H "Authorization: Bearer $API_KEY"
{
  "success": true,
  "data": {
    "job_id": "batch_abc123def456",
    "status": "completed",
    "progress": { "total": 3, "completed": 2, "failed": 1 },
    "results": [
      {
        "filename": "image1.jpg",
        "status": "success",
        "result_url": "https://cdn.qikkstools.com/processed/result1.png"
      },
      {
        "filename": "image3.jpg",
        "status": "failed",
        "error": "UNSUPPORTED_FORMAT"
      }
    ]
  }
}
every failure is named 2 done · 1 failed
queued Accepted, nothing started
processing progress moves while this holds
completed Every image finished, some possibly failed — check the counts
failed The job itself could not run. Nothing was spent

06

Rate limits #

Your plan sets the ceiling, and the pricing page states the numbers — they are not repeated here, because two places to state one figure is one place to get it wrong. What matters in code is that every response tells you where you stand.

Headers on every response #

X-RateLimit-Limit Calls allowed in the current window
X-RateLimit-Remaining Calls left in it
X-RateLimit-Reset Unix time the window rolls over
Retry-After Seconds to wait. Sent with a 429 only

Backing off #

Retry 429 and 5xx, nothing else

Wait Retry-After if it is there, otherwise double the delay each attempt and give up after five. Retrying a 400 sends the same broken image again and spends the same allowance on the same answer.

07

Errors #

Standard status codes, and a body that names the failure in a string you can branch on rather than a sentence you would have to parse.

Status codes #

200 The cutout, or the job
400 Missing or malformed field
401 Key absent, wrong, or revoked
413 Over 25 MB, or the batch over 100 MB
415 Not a JPEG, PNG or WebP
429 Allowance spent. Read Retry-After
5xx Ours. Retry, then check status

The body #

415 Unsupported Media Type
{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_FORMAT",
    "message": "Unsupported image format",
    "details": "Send JPEG, PNG or WebP"
  }
}

Keep the original

Never overwrite the source file with the result. The cut is reproducible; the photograph is not.

08

Recipes #

There is no SDK to install, which also means there is no SDK to upgrade. These are complete, in the standard HTTP client of each language.

import os
import requests

API = "https://api.qikkstools.com/v1/remove-background"


def remove_background(path, out):
    """Write the cutout to `out`. Leaves `path` untouched."""
    with open(path, "rb") as image:
        response = requests.post(
            API,
            headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
            files={"image": image},
            data={"format": "png", "crop": "true"},
            timeout=120,          # model time, not network time
        )

    response.raise_for_status()   # 4xx will not fix itself on retry
    with open(out, "wb") as handle:
        handle.write(response.content)
    return out


remove_background("product.jpg", "product.png")
import { readFile, writeFile } from 'node:fs/promises';

const API = 'https://api.qikkstools.com/v1/remove-background';

// Writes the cutout beside the original; the original is never touched.
export async function removeBackground(path, out) {
  const form = new FormData();
  form.append('image', new Blob([await readFile(path)]), path);
  form.append('format', 'png');
  form.append('crop', 'true');

  const response = await fetch(API, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.API_KEY}` },
    body: form,
  });

  if (!response.ok) {
    const { error } = await response.json();
    throw new Error(`${response.status} ${error?.code ?? 'unknown'}`);
  }

  await writeFile(out, Buffer.from(await response.arrayBuffer()));
  return out;
}
#!/usr/bin/env bash
set -euo pipefail

# Writes product.png next to product.jpg, and fails loudly if the API does.
curl --fail-with-body -X POST \
  "https://api.qikkstools.com/v1/remove-background" \
  -H "Authorization: Bearer ${API_KEY}" \
  -F "image=@product.jpg" \
  -F "format=png" \
  -F "crop=true" \
  -o product.png

echo "wrote product.png"