← Back to Blog
5 min read

Four Marketplaces, One Card, Zero Oversells

AutomationE-commerceAISupabase

I sell trading cards. A lot of them are one-of-a-kind—a specific graded card, a specific serial number. And I sell them on four marketplaces at once: eBay, TCGplayer, Whatnot, and Loupe.

Do the math on that. The moment a card sells on one platform, it's still listed on three others. Someone buys it there, and now you're refunding a sale, eating fees, and apologizing to a customer for selling them something you don't have. Every oversell costs money and reputation.

The Problem Nobody Warns You About

The obvious answer is "use the APIs." Here's the thing: half these platforms don't have one. eBay has a real API. TCGplayer has no seller API at all. Loupe has no public API—listings go through a third-party tool. Whatnot sales show up as... emails.

So the textbook architecture—webhooks everywhere, real-time events, everything reacts instantly—was never on the table. I had to build sync for platforms that actively don't participate in it.

One Source of Truth

Everything starts with a single database that knows the state of every card: what I paid for it, where it's listed, whether it's sold. Every channel is a projection of that database. No channel is ever authoritative—the database is.

When a sale happens anywhere, one operation records it: cost basis, sale price, fees, channel. And then it delists that card everywhere else. Atomically. That's the whole game.

No API? Drive the Browser

For platforms without an API, I automated the same portal a human would use. A headless browser logs in, exports inventory, uploads zero-quantity files for sold items, and publishes them. Sales notifications get parsed straight out of Gmail—an AI model reads the receipt emails and extracts what sold, for how much, with what fees.

Is that elegant? No. Does it work every single day? Yes. When a platform gives you nothing, you use what they gave the humans.

Boring Beats Clever

My favorite part of the system is also the dumbest: a reconciliation job that runs every few minutes and enforces exactly one rule—a card may only be listed on a secondary marketplace if it still has an active primary listing. That's it. Anything that fails the test gets delisted.

I tried cleverer designs first. Real-time pipelines, event chains, syncing state between platforms directly. Every clever version had a failure mode where things silently drifted. The boring loop can't drift—it re-derives the correct state from scratch every time it runs. If it crashes, the next run fixes everything.

Self-Healing or It Doesn't Ship

Twenty years of infrastructure taught me this: the system that pages you at 2am is the system you built to need you. So every job here assumes failure. Browser session died? Relaunch it. Transient error? Retry once, silently. Real problem? Alert me—but only after it fails twice in a row, so a blip never wakes anyone up.

The Result

Thousands of cards, four channels, effectively zero oversells. Listing a card went from minutes of data entry to seconds—I take a photo, AI reads the card, and a finished listing goes up. The same database runs the storefront, the accounting sync, and the live break reservations.

It's a one-person business that behaves like it has an ops team. The ops team is a database, a pile of cron jobs, and one rule enforced relentlessly.