remover.dev

A familiar request, so the move can stay small.

remove.bg’s self-serve API shuts down on 1 December 2026 at 09:00 CET. If your code already speaks that request shape, remover.dev is its own product and the move can stay small.

Create a key
  1. Create a key. Create an API key on the pricing page. A new email receives 5 test credits that do not expire.
  2. Send the request here. Use https://remover.dev where the client currently uses https://api.remove.bg. The header is still X-Api-Key, and the image is still image_file or image_url.
  3. Read the bytes. A successful response is the image, not JSON. Errors are JSON with errors[].code. GET /v1.0/account returns the Ruby gem shape.

What 200 images a month costs

PathThis monthCode change
remover.dev API plan$20Familiar request
remover.dev annual$16Familiar request
remover.dev packs only$16Familiar request
remove.bg, as published$40Shuts down 1 Dec 2026

The API plan includes 1,000 full-resolution images. Images above that are priced as a credit-pack top-up, which never expires. The annual row is the yearly price divided by 12, plus the same top-up. remove.bg uses $0.20 per image, a mid published subscription rate. Their rates ran about $0.14–$1.00. Leonardo.Ai speaks a different API, so moving there means a larger rewrite.

curl
curl -H "X-Api-Key: $REMOVER_API_KEY" \
  -F "image_file=@image.png" \
  -F "size=auto" \
  -o no-bg.png \
  https://remover.dev/v1.0/removebg
Node
import { readFile, writeFile } from "node:fs/promises";

const body = new FormData();
body.set("image_file", new Blob([await readFile("image.png")]), "image.png");
body.set("size", "auto");
const response = await fetch("https://remover.dev/v1.0/removebg", {
  method: "POST",
  headers: { "X-Api-Key": process.env.REMOVER_API_KEY },
  body,
});
if (!response.ok) throw new Error(await response.text());
await writeFile("no-bg.png", Buffer.from(await response.arrayBuffer()));
Python
import os, requests

response = requests.post(
    "https://remover.dev/v1.0/removebg",
    headers={"X-Api-Key": os.environ["REMOVER_API_KEY"]},
    files={"image_file": open("image.png", "rb")},
    data={"size": "auto"},
)
response.raise_for_status()
open("no-bg.png", "wb").write(response.content)
Ruby gem
connection = RemoveBg::HttpConnection.build("https://remover.dev")
client = RemoveBg::ApiClient.new(connection: connection)
client.remove_from_file(
  "image.png",
  RemoveBg::RequestOptions.new(api_key: ENV["REMOVER_API_KEY"], size: "auto")
).save("no-bg.png")
PHP
$request = curl_init("https://remover.dev/v1.0/removebg");
curl_setopt_array($request, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["X-Api-Key: " . getenv("REMOVER_API_KEY")],
  CURLOPT_POSTFIELDS => ["image_file" => new CURLFile("image.png"), "size" => "auto"],
]);
file_put_contents("no-bg.png", curl_exec($request));
WordPress / WooCommerce
// The official remove.bg plugin always calls api.remove.bg.
// If your own plugin or theme posts the image, this is the endpoint:
$endpoint = "https://remover.dev/v1.0/removebg";
$request = wp_remote_post($endpoint, [
  "headers" => ["X-Api-Key" => getenv("REMOVER_API_KEY")],
  "body" => ["image_url" => $product_image_url, "size" => "auto"],
]);
Shopify
# The remove.bg Shopify app cannot point at another host.
# Call the HTTP API from a custom app with the same POST body.
curl -H "X-Api-Key: $REMOVER_API_KEY" \
  -F "image_url=$PRODUCT_IMAGE_URL" \
  -F "size=auto" \
  -o no-bg.png \
  https://remover.dev/v1.0/removebg

Account JSON matches the Ruby gem: credits.total, subscription, payg, and enterprise, plus api.free_calls and api.sizes. credits.payg is purchased credits and the signup grant. credits.subscription is the current monthly allowance. credits.total is the sum. enterprise is 0. free_calls is 0 because signup credits are prepaid balance, not a monthly counter.

Field reference/Buy credits

What do I change in existing code?

Mostly the host. POST /v1.0/removebg, the X-Api-Key header, and the common parameters are familiar on purpose, so the move can stay small. Snippets for curl, Node, Python, PHP, the Ruby gem, WordPress, and Shopify are on this page.

Do credits expire?

Purchased packs and the 5 signup credits do not expire. API plan credits reset each cycle. The plan is 1,000 images a month at $20, or $192 a year.

What happens when many requests arrive at once?

They are processed one at a time, in arrival order, and each still returns the image in the same response. A request that cannot start within about 10 seconds gets 503 with a Retry-After header and a JSON error with code service_unavailable. It is not charged. Retry after that many seconds, with the same Idempotency-Key if you send one.

Will the cutout match what we had before?

The request shape is familiar. The model is U²-NetP, a compatibility matte, so the result will differ on some images. type is echoed and does not switch models. Shadows and semitransparency are accepted and ignored.