cd /news/artificial-intelligence/building-an-ai-clothes-changer-provi… · home topics artificial-intelligence article
[ARTICLE · art-30723] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Building an AI Clothes Changer: provider abstraction, async jobs, and a credit system that won't lose money

A developer launched Dressora, an AI clothes changer for virtual try-on, and detailed the backend architecture behind it. The system uses a provider abstraction to swap AI services easily, async job handling with webhook callbacks and re-upload to R2 storage, and a credit system with freeze/settle/release logic to prevent double-charging. The project is live at aiclotheschanger.me.

read2 min views1 publishedJun 17, 2026

I recently launched Dressora, an AI clothes changer that swaps outfits onto a single photo for virtual try-on. The product side is fun, but the parts I actually sweated over were the boring backend bits: orchestrating multiple AI providers, handling long-running generation jobs, and building a credit system that never double-charges or loses money. Here's what I learned.

AI providers change pricing, rate limits, and quality constantly. Hardcoding one is a trap. I put everything behind a small factory:

const provider = getProvider("evolink");
const task = await provider.createTask({ prompt, aspectRatio });

Each provider implements the same interface (createTask

, handleCallback

, status mapping). Swapping or adding a provider is a new file, not a refactor. When one provider had an outage, switching the default was a one-line env change.

AI generation takes 10s–minutes. Blocking a request is a non-starter. The flow:

generate()

— create a DB record, handleCallback()

— download the result, re-upload to R2, mark complete, The frontend just polls a lightweight status endpoint. The webhook is the source of truth.

A gotcha: always re-upload the provider's output to your own storage. Provider URLs expire. Down and pushing to R2 on completion saved me from dead links later.

Money + concurrency + async failures = the scariest combination. The pattern that worked: freeze → settle / release.

freeze(credits)

— move credits to a "held" statesettle()

— actually consume themrelease()

— give them back

freeze  -> hold created, balance reserved
settle  -> hold consumed (success)
release -> hold returned (failure)

This way a failed generation never costs the user, and a user can't fire 10 concurrent jobs with credits for one. I also did FIFO consumption across credit packages so credits with the nearest expiry get used first — fairer for users and simpler for accounting.

If you want to see the end result, it's live at aiclotheschanger.me. Happy to answer questions about the architecture in the comments.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @dressora 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/building-an-ai-cloth…] indexed:0 read:2min 2026-06-17 ·