software-engineering 6 min read

Speccing a Shopify app for a friend: Etsy-to-Shopify inventory sync

A friend needed a Shopify app that keeps stock in sync with Etsy. Before any code, I wrote him a spec to hand to a developer: scope, diagrams and a 70-hour initial estimate.

A friend of mine is starting his first venture, and one piece of it is a Shopify app that keeps inventory in sync with Etsy. Guess who’s writing the spec? 🙋‍♂️

He’ll be handing the build to a developer, and before anyone agrees to a timeline I wanted a written definition of the app that everyone is looking at. So I spent this Sunday afternoon writing one in my notes: scope, diagrams, phases, an initial estimate, and a few notes for the hand-off. This post is that doc, minus the private bits.

Who it’s for

Shopify merchants who also sell on Etsy. They have the same products listed in two places and want the stock levels to match, so they don’t sell something on one store that already sold out on the other.

Scope: core vs optional

I split the scope into two buckets. The core is what the estimate covers:

  • Inventory sync: periodically fetch active listings and inventory levels from Etsy, and update product inventory in Shopify from that data.
  • Order sync: periodically fetch order details from Etsy and surface them inside the app on Shopify.
  • User interface: connect the Shopify and Etsy accounts, configure the sync (frequency, specific products), and view logs and the status of each sync.

Then there’s the optional bucket, for things that sound small in a conversation but really aren’t:

  • Bidirectional sync: update Etsy inventory based on changes in Shopify.
  • Reviews sync: pull customer reviews from Etsy and surface them in the app on Shopify.

Bidirectional sync is the bigger of the two. One-way sync has a single source of truth. Once both sides can write, you need conflict resolution and a clear answer to “which number wins?”. So it stays optional, and its first step is literally “investigate feasibility and API limitations”.

The architecture

I drew two diagrams. The first is the high-level shape: the Shopify app UI or a scheduler triggers a sync, the sync talks to the Shopify API and the Etsy API, results go to a database, and anything that fails lands in an error log.

A hand-drawn style architecture diagram: inside a "User Interaction" box, the Shopify App UI points to Trigger Sync, which talks both ways with the Shopify API and the Etsy API. A Scheduler in a "Sync Process" box also triggers the sync. Trigger Sync writes to a Database in a "Data Flow" box, and the sync and both APIs send failures to an Error Log in an "Error Handling" box The high-level architecture I sketched for the spec.

The second is the flow from the merchant’s side. They log in to Shopify and open the app, log in to Etsy, and grant permissions on both, which gives the app an API key or access token for each store. After that the backend takes over. A periodic sync task triggers an inventory sync, which fetches inventory from Etsy and from Shopify and transforms the data for Shopify. If the product is found, update its inventory in Shopify. If there’s no match, create a new product first, then update it. Finally, update the UI with the sync status.

A hand-drawn style flowchart: a user at a laptop logs in to Shopify and opens the app, then logs in to Etsy. Each side has a "grant permissions" step that stores an API key or access token. In the App Backend box, a Periodic Sync Task triggers Inventory Sync, which fetches inventory from Etsy and Shopify, then Transform Data for Shopify. If found, Update Inventory in Shopify; if no match, Create new product and then update. The last step is Update UI with Sync status The user flow, from connecting both stores to the sync status showing up in the app.

My guess is that the “if no match” branch is where most of the pain will be. Fetching from two APIs is straightforward. Matching products and variants across two platforms? That’s the part I expect to eat the hours.

Phases and hours

I broke the build into four phases and put hours against each.

API integration (~15 hours). OAuth 2.0 on both sides. On Shopify, API calls to read and update product inventory, plus webhooks to listen for inventory changes (optional). On Etsy, API calls to fetch active listings and inventory levels, and a look at whether we can write inventory back, for the bidirectional option later.

Backend (~25 hours). This is the biggest chunk:

  • Database models for product IDs, titles, variants and whatever else we need from both platforms, with tables for Products, Inventory Levels and Sync Logs.
  • The sync logic itself: fetch from Etsy, update Shopify, handle the data mapping, and resolve inventory discrepancies on its own.
  • A scheduler, like a cron job, to trigger the periodic sync.
  • Error handling and logging.

Frontend (~20 hours). A UI for connecting accounts, configuring the sync and monitoring its status, built in React. My friend’s side already provided mockups of the screens, so this phase works from those instead of starting from a blank page. They’re their designs, so they stay out of this post.

Deployment and testing (~10 hours). Deploy the backend somewhere reliable, define a testing strategy for the sync, and test properly before submitting the app to the Shopify App Store.

Add it up and you get 15 + 25 + 20 + 10 = 70 hours. Right under that number, I wrote: “This is a very optimistic estimate”. And it leaves out the time a developer who hasn’t built a Shopify app before will need to skill up.

The MVP target is about four weeks from the start. That can be beaten if the optimistic path holds, but for someone’s first app of this kind it might spill over, or it might not. No way to tell yet. A deadline still helps though.

A few calls I made up front

The scheduler is cron for now, with events as the goal. A cron-style job is the simplest thing that works, but my note right next to it says we should definitely look into event-based sync if possible. With a periodic sync, stock can be stale for up to one interval, and that’s the window where a shop can oversell. That’s also why Shopify inventory webhooks show up in the API phase as optional.

Alerts have to fire before customers notice anything. If a sync job dies quietly, the merchant finds out when a customer buys something that’s no longer in stock. So the spec says the app needs alerts and alarms that page someone way before a customer even notices, on top of the logs.

For hosting, I’m leaning towards AWS Lambda over EC2. A sync job wakes up, does its work and goes back to sleep, and Lambda’s free tier includes a million requests a month, so it should cost less than an EC2 instance sitting idle between syncs. I marked this “yet to explore further” though.

For testing, the build will need a couple of test tenants (test stores) to make sure the sync doesn’t break. I marked that one optional, something to scale up later.

Notes for the hand-off

The last section of the doc is about how the work should run once a developer picks it up. With a friend’s project, it’s very tempting to leave all of this vague. Don’t.

  • For accountability: a quick daily sync of about 10 minutes, a weekly sync of about 45 minutes, and a bi-weekly one of about 90 minutes if needed.
  • Development starts in a private repo, since the whole Shopify app development environment, AWS test accounts and so on need setting up first. Once my friend’s side has its own AWS accounts and GitHub set up, there’s a migration path to theirs before production.

The template, if you’re writing a spec to hand off

Stripped of the Shopify and Etsy specifics, the doc has this shape:

  1. Who it’s for, in one sentence.
  2. Core scope and optional scope, kept apart.
  3. An architecture diagram and a user-flow diagram.
  4. Phases with hours, and an honest label on how confident the total is.
  5. The calls you’ve already made (scheduler vs events, hosting, alerting, testing) and the ones still open.
  6. How the hand-off runs: syncs, where the code lives and how it moves to the owner.

Each of these answers a question that would otherwise come up halfway through the build, when it’s a lot more awkward to discuss.

Leave a comment

Keep reading