When you process a handful of car photos, polling an image processing API is fine. But when you are cleaning an entire dealership inventory — hundreds or thousands of vehicle images — polling becomes wasteful and slow. That is where async image processing and webhooks come in. This deep dive explains how to build a scalable, event-driven integration with the AutoBackgrounding car background removal API.
Synchronous vs asynchronous processing
A synchronous request blocks until the background removal is finished and returns the result in the same HTTP response. That is convenient for a single, small image where a user is actively waiting. But full-resolution vehicle photos take real processing time, and holding a connection open for every image does not scale.
With asynchronous processing, you submit a car photo, immediately get back a job ID, and the vehicle image API does the work in the background. You then learn the result either by polling the job or — better — by receiving a webhook.
Polling vs webhooks
Both approaches tell you when a car photo is done, but they scale very differently:
| Aspect | Polling | Webhooks |
|---|---|---|
| Extra requests | Many (repeated status checks) | None — the API calls you |
| Latency to result | Up to one poll interval | Near-instant |
| Best for | Small interactive jobs | Bulk and background processing |
| Infra needed | None | A public HTTPS endpoint |
Registering a webhook
You can attach a webhook URL per request, or configure a default endpoint for your account. Passing it per job gives you the most flexibility when routing events to different services:
curl -X POST https:"tok-comment">//api.autobackgrounding.com/v1/images/process \
-H "Authorization: Bearer $AUTOBG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https:">//example.com/lot/vin123-front.jpg",
"background": "white_studio",
"webhook_url": "https:">//yourapp.com/webhooks/autobg"
}'The webhook payload
When a vehicle photo finishes processing, the background removal API POSTs a JSON event to your endpoint. A completed event looks like this:
{
"event": "image.completed",
"job_id": "job_9f8c2a1b",
"status": "completed",
"created_at": "2026-07-05T12:00:00Z",
"completed_at": "2026-07-05T12:00:04Z",
"input_url": "https:">//example.com/lot/vin123-front.jpg",
"output_url": "https:">//cdn.autobackgrounding.com/out/job_9f8c2a1b.png",
"metadata": {
"vin": "1FTFW1E50NF...",
"background": "white_studio"
}
}The metadata object echoes back any custom fields you sent when submitting the job — a great place to stash the VIN or your internal photo ID so you can match the result to the right vehicle.
Verifying webhook signatures
Because your webhook endpoint is public, you must verify that each request genuinely came from the image API and was not spoofed. Every delivery includes an X-AutoBG-Signature header — an HMAC-SHA256 of the raw body using your webhook secret. Recompute and compare it in constant time:
import crypto from "node:crypto"
import express from "express"
const app = express()
const WEBHOOK_SECRET = process.env.AUTOBG_WEBHOOK_SECRET
"tok-comment">// Use the raw body so the signature matches exactly
app.post("/webhooks/autobg", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.header("X-AutoBG-Signature") || ""
const expected = crypto.createHmac("sha256", WEBHOOK_SECRET).update(req.body).digest("hex")
const valid =
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
if (!valid) return res.status(401).send("Invalid signature")
const event = JSON.parse(req.body.toString())
handleEvent(event) "tok-comment">// process the completed car photo
res.status(200).send("ok")
})Idempotency and retries
The async image API retries webhook deliveries if your endpoint is slow or returns an error, so the same image.completed event can arrive more than once. Make your handler idempotent by tracking processed job IDs:
const processed = new Set() "tok-comment">// use a database in production
function handleEvent(event) {
"tok-comment">// Skip if we have already handled this car photo job
if (processed.has(event.job_id)) return
processed.add(event.job_id)
if (event.event === "image.completed") {
saveCleanPhoto(event.metadata.vin, event.output_url)
} else if (event.event === "image.failed") {
flagForReview(event.job_id, event.error)
}
}A few rules keep your webhook integration healthy: respond with a 200 quickly (do heavy work in a queue), always verify the signature, and treat delivery as at-least-once. Combined with the async batch endpoint, webhooks let you process an entire inventory efficiently with the bulk vehicle image processing API. Ready to build? See live endpoints and per-image pricing on the API pricing & docs page.