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>
- Plan
- Pro and Enterprise →
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
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.
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 #
/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"
Result URLs expire — download the file, do not hotlink it.
04
Batch process #
/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"
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 #
/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"
| 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 #
{
"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")