API

Bulk Background Removal via API: Async Jobs, Batches of 50 and Webhooks

September 6, 20267 min readBy BG Clear Editorial

One image is a curl command. Ten thousand product images is a queueing problem: rate limits, images over the sync size cap, results that expire, a script that dies at image 6,000 and does not know where it was. This guide is the production pattern for the bgclear API — batch submission, callbacks, back-pressure and exact credit accounting — with code you can paste into a worker.

In this guide

Sync vs jobs: which to use for bulk

POST /api/v1/remove is synchronous: the response is the image, within 30 seconds, for images up to 4 megapixels at full size. It is perfect for interactive uploads. For bulk it has two costs: your worker is blocked while each image processes, and anything over 4 MP is rejected.

POST /api/v1/jobs queues the image and returns 202 {"job_id": …, "status": "queued"} immediately. Jobs take images up to 50 MP, run on the GPU queue in order, and can notify you when done. POST /api/v1/jobs/batch submits up to 50 images in one JSON request. Both share the sync endpoint's parameters (size, format, bg_color, crop). For catalogues, use batch.

Submitting a catalogue 50 at a time

Batch is JSON-only: an images array of objects each carrying an image_url (or image_file_b64), plus top-level parameters that apply to every image. Store the returned job ids against your SKUs — that mapping is what lets you resume after a crash.

import csv, requests, itertools

API = "https://www.bgclear.ai/api/v1"
H = {"Authorization": "Bearer bgc_live_YOUR_KEY", "X-Callback-Url": "https://yourapp.com/hooks/bgclear"}

def chunks(it, n):
    it = iter(it)
    while batch := list(itertools.islice(it, n)):
        yield batch

rows = list(csv.DictReader(open("catalogue.csv")))      # columns: sku, image_url
for batch in chunks(rows, 50):
    r = requests.post(f"{API}/jobs/batch", headers=H, json={
        "size": "full", "format": "webp", "bg_color": "ffffff",
        "images": [{"image_url": row["image_url"]} for row in batch],
    })
    if r.status_code == 503:                            # queue full — back off
        import time; time.sleep(int(r.headers.get("Retry-After", 30))); continue
    r.raise_for_status()
    for row, job_id in zip(batch, r.json()["job_ids"]):
        save_mapping(row["sku"], job_id)               # your DB

Order is preserved: job_ids[i] corresponds to images[i]. Each image URL is fetched server-side with a 25 MB limit; private-network URLs are refused, so use signed public URLs for S3 or GCS.

Callbacks instead of polling

Send an X-Callback-Url header with the batch (or single job) request and the API POSTs a JSON body to it when each job finishes — job_id, status (done or failed), the result url on success and error on failure. Callbacks are signed with an HMAC header so you can reject forged requests; the docs show the verification snippet.

// Express receiver
app.post("/hooks/bgclear", express.json(), async (req, res) => {
  const { job_id, status, url, error } = req.body;
  res.sendStatus(200);                       // ack first, work after
  const sku = await skuForJob(job_id);
  if (status === "done") {
    const bytes = Buffer.from(await (await fetch(url)).arrayBuffer());
    await uploadToCdn(`${sku}.webp`, bytes); // result URLs expire after 24 h
  } else {
    await markFailed(sku, error);            // failed jobs are not charged
  }
});

Ack with a 2xx immediately and do the download afterwards; a slow handler is the usual reason callbacks look "lost". If you cannot expose a URL, poll GET /api/v1/jobs/{id} every few seconds — but poll only jobs still in queued or processing.

Back-pressure: 429, 503 and the 24-hour window

Three limits shape a bulk run. The per-key rate limit is 60 requests a minute — batch calls count as one request, which is why 50-image batches matter. The GPU queue has a depth cap; when it is full you get 503 gpu_unavailable with a Retry-After header — sleep and resubmit that batch, nothing was queued or charged. And result files are kept for 24 hours, so download promptly; the callback pattern above does this by design.

A 10,000-image catalogue is 200 batch requests, comfortably inside the rate limit; throughput is then set by queue depth and image size rather than by your client.

Credit accounting you can reconcile

Each full-resolution job costs one credit, charged when the job succeeds — never on failure, never on a rejected submission. The job status response includes credits_charged and credits_remaining; GET /api/v1/usage lists charges by day for your finance export. Before a large run, check GET /api/v1/account for the balance and buy a pack sized to the whole catalogue: credits never expire, so over-buying costs nothing. Preview-size jobs (size=preview, ≤800 px) are free and are a good dry run for a new supplier feed.

Frequently asked questions

How many images can I process per hour?

Submission is limited to 60 requests a minute per key, i.e. up to 3,000 images a minute via 50-image batches. Actual throughput is governed by the shared GPU queue; large runs are best submitted with callbacks and left to drain.

Can I upload files in a batch, or only URLs?

Batch is JSON: image_url or base64 image_file_b64 per item. For local files, either host them at signed URLs or submit single multipart jobs to /api/v1/jobs.

What happens if my callback endpoint is down?

Poll GET /api/v1/jobs/{id} for any job whose callback you did not receive; the status and result URL stay available for 24 hours.

Is batch available on RapidAPI?

No — RapidAPI bills per request, so batch is only available with a direct bgclear key. Single jobs and sync calls work on both.

Ship it with the bgclear API

remove.bg-compatible endpoints, credits from $9 for 100 images, no subscription. Pay, get a key, make your first call in under two minutes.

Get API credits →

Tools for this guide

Background Removal API Free

background removal api free

Batch Background Remover Free

batch background remover free

Cheapest Background Remover API

cheapest background remover api

Keep reading

API

Remove Image Backgrounds in Python with an API (requests, 20 Lines)

A complete Python walkthrough: single image, URL input, JSON responses, a folder script with safe retries, and async jobs for large files — no ML libraries, just requests.

API

Remove Image Backgrounds in Node.js with fetch and FormData (No SDK)

Node 18+ built-in fetch, a file upload, a URL input, an Express proxy endpoint so your browser never sees the key, and retries that cannot double-charge.

API

Automate Background Removal in n8n, Zapier and Make (No Code)

Exact node-by-node settings to remove backgrounds inside an automation: HTTP Request node in n8n, Webhooks by Zapier, and Make's HTTP module — then send the cutout to Drive, Shopify or Airtable.

API

remove.bg Is Shutting Down on 1 December 2026: Migrate Your API Integration in 10 Minutes

remove.bg's standalone site and API close on 1 Dec 2026 (9:00 CET) as it folds into Canva's Leonardo.Ai, and unused credits expire the same day. A field-by-field migration to a drop-in compatible API, with code.