Back to portfolio
ENESFRPT
Engineering

How I Built a Full ERP That Runs a Multi-Marketplace E-Commerce Operation

18 min read · 2026

One engineer. A full custom platform. 12 marketplace accounts. ~100 orders/day. 5 employees using it daily. This is the complete technical story of how I designed, built, and operated the entire production platform behind REUSALIA — from the first Selenium bot to a full ERP with reverse-engineered APIs, AI pipelines, and physical hardware integration.

The Problem: Running a Real Business on Manual Processes

In April 2023, I founded REUSALIA — an e-commerce company that buys Amazon liquidation pallets, processes the inventory, and resells individual items across multiple marketplaces (Wallapop, eBay, PortalHero). The business model is simple. The operations behind it are not.

Every pallet that arrives contains 50-200 mixed items. Each item needs to be inspected, photographed, categorized, priced, listed on multiple platforms, tracked through sales, packaged, and shipped. Multiply that by thousands of SKUs across 12 marketplace accounts, and you start to see the scale of the problem.

When I started, everything was manual. Listing a single item on Wallapop took 5-10 minutes of typing. Orders came in through multiple accounts and had to be checked one by one. Inventory was tracked in Google Sheets. There was no system — just a person with a laptop and a warehouse.

Three years later, the entire operation runs on a platform I built from scratch: a FastAPI backend with 25+ database models, a custom Retool ERP with 10+ operational modules, reverse-engineered marketplace APIs, AI-powered product enrichment, and a custom hardware bridge that connects cloud interfaces to physical label printers. This is the story of how it evolved.

Phase 1: The Selenium Era (2023)

The first technical problem I solved was the most painful one: publishing listings on Wallapop.

Wallapop has no bulk publishing API. No CSV import. No way to list products at scale. Every listing had to be created manually through their web interface — fill in the title, description, category, price, upload photos, set location, confirm. At 5-10 minutes per item, listing a catalog of 500-600 items was a full-time job.

So I built a Selenium bot that automated the entire flow. It opened a browser, navigated to the listing form, filled in every field, uploaded images, and submitted. Each listing took about 1 minute (slowed down intentionally to avoid detection).

But 1 minute per item across 600 items is still 10 hours. And I needed to re-list every 3 days to maintain marketplace positioning. So I scaled the only way I could: horizontally, across physical machines.

I set up 5-6 PCs, connected to each one remotely via AnyDesk, and launched multiple bot instances per machine. Each instance used different cookies and user agents. This way, I could publish my entire catalog in about an hour. Every 3 days, I'd spend an hour managing the distributed bot fleet.

It was ugly. It was fragile. It worked.

What I Learned

Phase 2: Reverse Engineering Wallapop's Private API (2023-2024)

As the business grew, so did the operational complexity. We went from 10 orders a day to nearly 100. From 1 Wallapop account to 12. The Selenium approach couldn't scale anymore — not for publishing, and definitely not for order management.

The problem was that Wallapop is a closed ecosystem. No public API. No documentation. No third-party integrations. Everything happens inside their app and website. For most people, that's a wall. For me, it was an invitation.

I started intercepting network traffic. Every action I performed on the website — browsing listings, checking orders, reading chats — I captured the HTTP request, studied the headers, decoded the payloads, and mapped the response structures.

The Discovery Process

Reverse engineering a private API is detective work:

  1. Capture — Use browser DevTools to intercept every request during a session
  2. Classify — Group requests by endpoint pattern and HTTP method
  3. Decode — Analyze request headers (especially authorization), query parameters, and response JSON structures
  4. Cross-reference — Compare responses from different accounts to identify what's user-specific vs. universal
  5. Replicate — Build a Python client that can authenticate and make the same requests outside the browser
  6. Iterate — When Wallapop changes their API (which they do), update the client

Over 5 major versions of the extractor codebase, I mapped their authentication system (cookie-based with bearer tokens), their order management endpoints, their chat API, and their listing metadata system. The result: 2,100+ lines of production Python code that can:

The multi-account architecture was the hardest part. Each account has its own authentication lifecycle: cookies expire, tokens need refreshing, sessions get invalidated. I built a centralized auth manager that stores credentials in PostgreSQL, automatically refreshes tokens across sessions, and provides clean authentication contexts to every extractor.

Nobody else has built this. There are tools like PortalHero for bulk publishing, but nothing for extraction. Our extractors are unique — and they're what makes it possible to run a 12-account operation with a team of 5 instead of a much larger manual operations team.

Phase 3: The Core Platform — FastAPI + PostgreSQL (2024-2025)

With the extractors feeding data reliably, I needed somewhere for that data to live and something to do with it. Google Sheets wasn't going to cut it anymore (that's a whole other story).

I designed the core platform around three principles:

  1. Single source of truth — Every piece of data lives in PostgreSQL. No spreadsheets, no local files, no "I'll update it later"
  2. API-first — Every operation goes through the FastAPI backend. The custom ERP frontend built on Retool, the extractors, the sync engines — all talk to the same API
  3. Operational automation — If a human does something more than twice, it should be automated

Database Design

The PostgreSQL schema has 25+ models with 35+ migrations, covering:

I use SQLModel (SQLAlchemy + Pydantic) for the ORM layer, which gives me type-safe models that work both for database operations and API serialization. Alembic handles migrations, and I've never had to roll one back in production.

API Architecture

The FastAPI backend exposes ~60 endpoints covering CRUD operations, business logic, and integrations. Key design decisions:

Phase 4: The ERP — Retool Frontend (2025)

A database and API are useless if your team can't interact with them. I needed an interface that 6 non-technical employees could use daily — for everything from processing incoming pallets to shipping orders to tracking incidents.

I chose Retool because it let me build a complex, multi-module ERP frontend in weeks instead of months. The result: a custom ERP with 10+ operational modules:

The key challenge with Retool was making it feel native. Default Retool apps look like admin panels. I invested significant effort in custom CSS, conditional rendering, and UX flows that feel intuitive to warehouse workers who've never used enterprise software.

Phase 5: AI Product Enrichment Pipeline

One of the most time-consuming parts of the business is product listing creation. Each item needs:

Writing these manually for thousands of SKUs is insane. At ~15 minutes per item, that's 40+ hours per week just on descriptions. So I built an AI pipeline:

  1. Amazon Scraper — Identifies products from our pallet inventory on Amazon.es, extracts titles, descriptions, features, images, and pricing. Anti-detection with UA rotation and request throttling to avoid blocks
  2. GPT Enrichment — Feeds scraped data into GPT-4 with structured prompts. The model categorizes items, generates marketplace-specific titles (Wallapop style is very different from eBay style), writes descriptions, and suggests pricing
  3. Image Pipeline — Downloads product images, applies anti-duplicate transforms (OpenCV) to avoid marketplace duplicate-image filters, resizes and compresses for optimal upload
  4. Listing Sync — Pushes enriched data to each marketplace with format-specific adaptations

The pipeline runs autonomously. I feed it a batch of new items, and hours later I have fully enriched listings ready for publication across all marketplaces. What used to take a full-time employee's entire week now runs in the background while we process the next pallet.

Phase 6: The Cloud-Local Bridge (The Hardest Problem)

Here's a problem nobody talks about in architecture blogs: how do you print a physical shipping label from a cloud UI?

Our custom ERP frontend runs on Retool Cloud. Our label printer is a Brother QL-700 connected via USB to a warehouse PC. There's no cloud-native path between the two. I needed to bridge the gap without requiring the warehouse team to switch between applications.

The solution is what I call the Command Bridge Pattern:

  1. The Retool UI writes a command record to PostgreSQL (e.g., "print label for order #1234")
  2. A local Python daemon on the warehouse PC polls for new commands every few seconds
  3. When it finds one, it acquires an exclusive database lock, processes the command (generates and prints the label), and marks it complete
  4. The Retool UI sees the status update and reflects it to the user

The tricky part is reliability. What if the local daemon crashes? What if two instances run simultaneously? I implemented:

This pattern now handles not just label printing but any operation that requires local hardware interaction from a cloud interface.

Phase 7: Multi-Marketplace Sync

With inventory in PostgreSQL, listings enriched by AI, and orders flowing through the extractors, the final piece was keeping everything synchronized across marketplaces.

The sync engine maintains PostgreSQL as the single source of truth and pushes formatted data to each platform:

When an item sells on one platform, the sync engine pulls it from the others within minutes. When I update a price in the ERP, it propagates everywhere. When new inventory arrives, listings go to all marketplaces simultaneously.

The Full Architecture

Zooming out, the complete system looks like this:


Data Sources          Processing Layer        Core              Outputs
─────────────         ────────────────        ────              ───────
Wallapop API ──┐                           ┌──────────┐
eBay API ──────┤      FastAPI Backend       │PostgreSQL│ Custom ERP Frontend
Amazon Scraper ┤──→   ( extractors )   ──→  │25+ models│──→ (   Retool ERP    )
PortalHero ────┤      ThreadPoolExecutor    │35+ migr. │      10+ modules
Google Drive ──┘      OpenAI GPT-4          └──────────┘
                                                │
                                      Command Bridge Pattern
                                      (excl. lock + heartbeat)
                                                │
                                         Local Hardware
                                      (Brother QL-700 printer)

Every component talks to the same API. Every piece of data lives in the same database. Every operation is logged, tracked, and recoverable.

Scale & Impact

Here's what this system handles in production, daily:

MetricValue
Orders processed/day~100+
Active marketplace accounts12
Team members using ERP daily6
Marketplaces synced3 (Wallapop, eBay, PortalHero)
Manual order processing replaced~5h/day
Manual listing creation replaced~40h/week
Marketplace APIs reverse-engineeredWallapop, eBay
ERP modules (Retool)10+
Database models25+
Database migrations35+
Extractor versions (Wallapop)5 major

This is not a demo project. This is a production system that handles real inventory, real money, and real customer operations. Every day. Built and maintained by one engineer.

What I'd Do Differently

Three years of iteration teaches you a lot about your own mistakes:

The Takeaway

Building a production ERP as a solo engineer while running the business it's designed to automate is a unique engineering challenge. You're simultaneously the architect, the developer, the DBA, the QA, the DevOps engineer, and the product manager — plus the CEO, the warehouse manager, and the customer support lead.

The technical work is the easy part. The hard part is:

I wouldn't trade it for anything. This is what real engineering looks like — not perfect code, but code that solves real problems for real people, every single day.

The platform components are open-source: github.com/AspiranteD/AspiranteD