DEV Community

a353551071
a353551071

Posted on

Migrating off the remove.bg API: a field-by-field compatibility audit

TL;DR The remove.bg standalone site — and its self-serve API — retires on 1 December 2026, 9:00 CET. The official landing spot for API users, Leonardo.Ai, is a capable platform but not a drop-in replacement: it means async jobs, polling loops, presigned S3 URLs and JSON image payloads where you currently have one synchronous function call. This post is the field-by-field audit I did while wiring up a drop-in endpoint, condensed into the two tables I wish someone had already published: which request parameters behave identically, which are silently ignored, and what your error handling actually depends on. Everything here is checkable in about five minutes with curl — including against my own endpoint.


The deadline, in the official words

From remove.bg's own API page: "The standalone website will no longer be available from 1 December 2026 at 9:00am CET." The banner on the same page points self-serve API users to Leonardo.Ai (both are part of Canva). Enterprise customers are unaffected — their contracts hold. Unused prepaid credits expire that morning.

So if you're on the self-serve API, you have a real decision to make before December 1, and the rest of this post is about making it with evidence instead of vibes.

Why the "official path" is a rewrite, not a swap

To be fair up front: Leonardo.Ai is a legitimate platform, and pointing existing users somewhere is more than many sunset notices offer. But "our API is moving" and "port your integration to our generation platform" are very different sentences. The Leonardo integration model looks like this:

Leonardo.Ai (official path) Drop-in replacement (what this post audits)
Call pattern Async: submit → job_id → write a polling loop Synchronous: one request, PNG bytes come back
Image transfer Presigned S3 URLs, or JSON with base64 / image URL multipart file, base64 string, or image URL — as before
Billing Token cost varies with output resolution, hard to pre-estimate One credit per image, disclosed in a response header
Code changes Queueing, polling, a new error taxonomy Change the base URL
Output Generation-pipeline artifacts Raw 32-bit RGBA PNG stream

If your current integration is "POST an image, get a PNG" — which is what the vast majority of remove.bg integrations are — the Leonardo path means replacing a function call with an async client. That is a weekend, not a line.

Pit 1: half the parameters are accepted — and do nothing

The first trap in any compatibility claim is the NO-OP parameter: a field the new endpoint accepts without error but doesn't act on. This is worse than a 400, because your happy-path test passes, your staging run passes, and the difference only shows up when someone asks why the thumbnails are full-resolution.

Here is the full audit table for the drop-in endpoint I run, published in full rather than summarized — the ignored rows are exactly as important as the supported ones:

Parameter / behavior Status Notes
image_file ✅ FULL SUPPORT multipart/form-data upload, identical
image_file_b64 ✅ FULL SUPPORT base64 string; data-URI prefix tolerated
image_url ✅ FULL SUPPORT http/https, public hosts only (SSRF-guarded), ≤ 30 MB
size ⚠️ ACCEPTED · NO-OP output is always full resolution
type ⚠️ ACCEPTED · NO-OP one general model handles all subjects
format ⚠️ ACCEPTED · NO-OP output is always RGBA PNG
bg_color / bg_image_file / bg_image_b64 / bg_image_url ❌ NOT SUPPORTED silently ignored — composite client-side (snippet below)
crop / crop_margin / scale / roi / position ❌ NOT SUPPORTED silently ignored — full uncropped foreground returned
X-Api-Key header ✅ FULL SUPPORT same auth header, same semantics
Binary PNG response body ✅ FULL SUPPORT raw image/png bytes streamed
X-Width / X-Height / X-Credits-Charged / X-Processing-Time-Ms ✅ FULL SUPPORT same header names, same meaning
GET /v1.0/account ✅ FULL SUPPORT same credits JSON structure
Error body {"errors":[{title,detail,code}]} ✅ SAME SHAPE semantic codes mapped below

The transferable lesson: audit parameters, don't probe them. A parameter that doesn't error is not a parameter that works. Whatever endpoint you land on — official or third-party — demand this table, or build it yourself in an afternoon.

Pit 2: your error handling is coupled to the error body shape

Most remove.bg integrations don't parse error bodies; they branch on the HTTP status and maybe surface detail to logs. The shape to preserve is:

{ "errors": [ { "title": "...", "detail": "...", "code": "..." } ] }
Enter fullscreen mode Exit fullscreen mode

If the shape changes — error vs errors, nested vs flat — every retry branch and alert rule that touches the body goes quiet at once. Here's the full error mapping for the endpoint I audited:

HTTP code Meaning remove.bg equivalent
400 invalid_request missing/invalid image payload, bad image_url 400 · missing/invalid parameters
402 insufficient_credits credit balance exhausted 402 · credits exhausted
403 invalid_api_key unknown or revoked key 403 · invalid API key
429 rate_limit_exceeded 10 req/min demo · 60 req/min registered 429 · rate limit exceeded
5xx error processing failure — retry with backoff 5xx · internal error

One deliberate choice worth copying: keep retry logic keyed on the HTTP status, and treat code as informational. Status codes survived the migration; your assumption that a specific code string did is what breaks pipelines.

Pit 3: response headers are a free acceptance test

The four X- headers are the cheapest migration QA you will ever get:

  • X-Width / X-Height — assert on these in your smoke test. If your old endpoint respected size and the new one doesn't, this assertion fails in CI, not in a customer Slack thread.
  • X-Credits-Charged — reconcile billing per request. This is how you catch "this parameter used to be free" surprises before they become an invoice conversation.
  • X-Processing-Time-Ms — server-disclosed timing. Our endpoint runs CPU inference (isnet-general-use) and a typical photo takes ~4–5 seconds; we'd rather print the number than promise an SLA we don't have.

Ten lines of test code against these headers catches every silent behavioral drift in Pit 1. Write them once, run them against old and new endpoints side by side.

Pit 4: don't trust "compatible" claims — including this one

Five minutes, one command:

curl -s -D headers.txt -o out.png \
  -H "X-Api-Key: $KEY" \
  -F "image_file=@photo.jpg" \
  https://backgroundremoverapi.com/v1.0/removebg

grep -i "^x-" headers.txt
Enter fullscreen mode Exit fullscreen mode

Then check the output is a real cutout, not an error page that happens to be 3 MB:

from PIL import Image
im = Image.open("out.png")
print(im.mode, im.size)   # expect RGBA, original dimensions
Enter fullscreen mode Exit fullscreen mode

If you rely on server-side background compositing, note that bg_color is in the NOT SUPPORTED rows — do it client-side instead:

from PIL import Image
fg = Image.open("out.png").convert("RGBA")
bg = Image.new("RGBA", fg.size, "#00FF00")   # your old bg_color
bg.alpha_composite(fg)
bg.convert("RGB").save("final.jpg")
Enter fullscreen mode Exit fullscreen mode

Run this against any candidate endpoint, ours included. A compatibility claim you can't verify with curl in five minutes is a landing page, not a spec.

The honest fine print

Migration decisions run on the limitations, so here they are without adjectives:

  • CPU inference (isnet-general-use), ~4–5 s per image. No "sub-second" claims.
  • Self-hosted behind Cloudflare, no SLA — there's a public status page instead of an uptime promise.
  • Always full-resolution RGBA PNG (size / format are no-ops, see Pit 1).
  • No server-side background compositing — bg_color and friends are client-side jobs.
  • Rate limits: 10 req/min on the demo key, 60 req/min registered.

If any of those are dealbreakers, better to know in October than on November 30.

One more thing about "alternatives" roundups

Most articles rounding up remove.bg alternatives are about consumer tools, which is fine — but at least one well-ranking post states in its own text: "There is no Backgroundless API." If what you actually need is an endpoint your code talks to, verify that before you budget the migration weekend. The drop-in lane is genuinely narrow, which is exactly why this audit exists.

If you want to skip the audit

We run the drop-in endpoint this post audits at backgroundremoverapi.com: same auth header, same three input channels, binary PNG out, same-shaped errors, and the four X- headers for reconciliation. The playground takes your key and fires one live request with every response header on display; the migration guide walks the 60-second base-URL switch; the API docs mirror the tables above.

Pricing is prepaid credit packs — $9 / 1,000, $29 / 5,000, $79 / 20,000, credits never expire — instead of a subscription. That's 0.9¢ per image, versus a ~8.1¢/image effective rate on remove.bg's $99/mo plan at the time of writing. New accounts include 100 free credits, and if you're migrating: email support@backgroundremoverapi.com from your registered address with a screenshot of your remove.bg dashboard, and we'll top up 500 extra credits.


remove.bg is a trademark of its respective owner, referenced here nominatively to identify the interface being replaced. This post and its author are not affiliated with, endorsed by, or sponsored by remove.bg, Canva, or Leonardo.Ai.

Top comments (0)