Skip to main content
RapidDev - Software Development Agency

How to Automate Etsy Inventory Management Using the API

Use the Etsy v3 API to update listing quantities automatically. Listen for order.paid webhooks to decrement stock after each sale, and use PUT /listings/{listing_id}/inventory to sync quantities from your master inventory source. This prevents overselling and eliminates manual stock updates.

Need help automating? Talk to an expert
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate6 min read45–60 minutesEtsyLast updated May 2026RapidDev Engineering Team
TL;DR

Use the Etsy v3 API to update listing quantities automatically. Listen for order.paid webhooks to decrement stock after each sale, and use PUT /listings/{listing_id}/inventory to sync quantities from your master inventory source. This prevents overselling and eliminates manual stock updates.

Quick facts about this guide
FactValue
PlatformEtsy
Auth methodOAuth 2.0 with mandatory PKCE
Rate limits10 req/sec, 10,000 req/day (new apps: 5/sec, 5,000/day)
DifficultyIntermediate
Time required45–60 minutes
Last updatedMay 2026

API Quick Reference

Auth

OAuth 2.0 with mandatory PKCE

Rate limit

10 req/sec, 10,000 req/day (new apps: 5/sec, 5,000/day)

Format

JSON

SDK

REST only

API overview

Base URLhttps://openapi.etsy.com/v3/application

Authentication

Every Etsy v3 API request requires both Authorization: Bearer {access_token} and x-api-key: {keystring} headers. Access tokens expire in 1 hour. Refresh tokens are valid for 90 days and rotate on each use. Store the latest refresh token after every refresh call.

Key endpoints

GET/listings/{listing_id}/inventory

Returns current inventory for a listing, including quantity, SKU, and price for each product variant. Use this before updating to read current state.

ParameterTypeRequiredDescription
optional
optional
PUT/listings/{listing_id}/inventory

Replaces the entire inventory for a listing. You must send ALL products and their offerings — partial updates are not supported. Read current inventory first, modify quantities, then PUT the full object.

ParameterTypeRequiredDescription
optional
optional
optional
optional
optional
GET/listings/{listing_id}

Returns listing state, including quantity and state (active/inactive). A listing with quantity=0 automatically moves to inactive state.

ParameterTypeRequiredDescription
optional
GET/shops/{shop_id}/listings/active

Returns all active listings for the shop. Use for full catalog inventory sync when initializing your local inventory database.

ParameterTypeRequiredDescription
optional
optional
optional

Step-by-step automation

1

Build a Local Inventory Map from All Active Listings

Initialize your inventory database by fetching all active listings and their current stock levels. Store listing_id, sku, and quantity locally so you can track changes without re-fetching every time.

request.sh
1# Fetch all active listings (paginated)
2curl -X GET "https://openapi.etsy.com/v3/application/shops/$SHOP_ID/listings/active?limit=100" \
3 -H "Authorization: Bearer $ETSY_ACCESS_TOKEN" \
4 -H "x-api-key: $ETSY_KEYSTRING"
5
6# Get inventory for a specific listing
7curl -X GET "https://openapi.etsy.com/v3/application/listings/$LISTING_ID/inventory" \
8 -H "Authorization: Bearer $ETSY_ACCESS_TOKEN" \
9 -H "x-api-key: $ETSY_KEYSTRING"
2

Decrement Stock on Order.paid Webhook

When an order.paid webhook fires, fetch the receipt to get purchased listing IDs and quantities, then update each affected listing's inventory by decrementing the sold quantity. The PUT /inventory endpoint requires sending the full products array — read first, modify, then PUT.

request.sh
1# First GET current inventory, then PUT updated inventory
2# GET
3curl -X GET "https://openapi.etsy.com/v3/application/listings/$LISTING_ID/inventory" \
4 -H "Authorization: Bearer $ETSY_ACCESS_TOKEN" \
5 -H "x-api-key: $ETSY_KEYSTRING"
6
7# PUT with decremented quantity
8curl -X PUT "https://openapi.etsy.com/v3/application/listings/$LISTING_ID/inventory" \
9 -H "Authorization: Bearer $ETSY_ACCESS_TOKEN" \
10 -H "x-api-key: $ETSY_KEYSTRING" \
11 -H "Content-Type: application/json" \
12 -d '{
13 "products": [{
14 "product_id": 1234,
15 "sku": "MUG-BLUE-SM",
16 "offerings": [{
17 "offering_id": 5678,
18 "quantity": 12,
19 "is_enabled": true,
20 "price": {"amount": 2999, "divisor": 100, "currency_code": "USD"}
21 }]
22 }]
23 }'
3

Sync Inventory from External Source (Warehouse or Spreadsheet)

For multi-channel sellers, sync Etsy quantities from a master inventory source. Map your SKUs to Etsy listing IDs, then push updated quantities via the inventory PUT endpoint. Run this on a schedule (every 15-30 minutes or after each warehouse update).

request.sh
1# Sync a batch of listings from a JSON file
2# inventory-updates.json: [{"listing_id": 9876, "new_quantity": 25}, ...]
3cat inventory-updates.json | python3 -c "
4import sys, json, subprocess, os
5updates = json.load(sys.stdin)
6for item in updates:
7 print(f'Updating listing {item[\"listing_id\"]} to qty {item[\"new_quantity\"]}')"
4

Monitor for Zero-Stock Listings and Re-enable When Restocked

Etsy automatically deactivates listings when quantity hits 0. When you restock, you must explicitly set quantity > 0 AND is_enabled=true in the PUT request. Build a polling job to check for deactivated listings that have been restocked.

request.sh
1# Get inactive listings that need to be re-enabled
2curl -X GET "https://openapi.etsy.com/v3/application/shops/$SHOP_ID/listings?state=inactive&limit=100" \
3 -H "Authorization: Bearer $ETSY_ACCESS_TOKEN" \
4 -H "x-api-key: $ETSY_KEYSTRING"

Complete working code

Complete Etsy inventory automation: webhook listener to decrement on sale + scheduled sync from a master inventory source (JSON file or database).

Error handling

Cause

The PUT /inventory endpoint is a full replacement — if you omit any product or offering from the products array, those variants are deleted.

Fix

Always GET the current inventory first, modify only the quantity/is_enabled fields you intend to change, and PUT back the complete products array unchanged except for your modifications. Never construct the products array from scratch without reading first.

Cause

For large catalog syncs with hundreds of listings, the 1-hour access token can expire before the job finishes.

Fix

Implement per-request token refresh check. Before each API call, compare the current time to token_expiry - 60 seconds and refresh if needed. This is critical for any sync job that runs longer than 50 minutes.

Cause

Etsy automatically sets state=inactive when quantity hits 0. Simply updating quantity back to > 0 via PUT inventory re-enables the offerings, but you must explicitly set is_enabled=true.

Fix

When restocking a listing, set both quantity = new_stock AND is_enabled = true in the PUT request. The listing state will revert to active automatically once inventory has enabled offerings with quantity > 0.

Cause

Each listing requires 2 API calls (GET + PUT), so syncing 100 listings = 200 calls. At 10/sec that's 20 seconds minimum, but add processing time and you can easily spike above the limit.

Fix

Add 200ms minimum delay between each listing update (GET + PUT pair). This reduces throughput to ~5 listings/sec, keeping you well under the 10 req/sec limit.

Cause

If an order.paid webhook fires while your scheduled inventory sync is running, two processes may read the same inventory and apply conflicting writes.

Fix

Use a distributed lock (Redis SETNX or database row lock) before reading/writing inventory for a listing. Alternatively, serialize all inventory writes through a single queue.

Rate limits & throttling

Security checklist

  • Store ETSY_KEYSTRING and tokens in environment variables — never in source code or version control
  • Verify webhook signatures using HMAC-SHA256 and constant-time comparison before processing any inventory change
  • Use express.raw() for webhook endpoints to preserve raw body for signature verification
  • Save the rotated refresh token after every OAuth token refresh
  • Use minimum required scopes: listings_r, listings_w, transactions_r
  • Implement a distributed lock before inventory read-modify-write operations to prevent race conditions
  • Log all inventory changes with timestamps and receipt IDs for audit trail

Automation use cases

Multi-Channel Inventory Sync

Keep Etsy in sync with your Shopify, Amazon, or WooCommerce stores. After each sale on any channel, push the updated master quantity to all channels via their respective APIs.

Oversell Prevention

Decrement Etsy inventory immediately on order.paid webhook — before the order is even fulfilled — to prevent selling items you don't have in stock.

Restock Alert and Auto-Reactivation

When new inventory arrives and your warehouse system is updated, automatically push the new quantities to Etsy and re-enable any listings that were deactivated due to zero stock.

Low Stock Warning

After each inventory update, check if any listing quantity drops below a threshold (e.g., 3 units) and send a Slack or email alert to trigger a reorder.

No-code alternatives

Don't want to write code? These platforms can automate the same workflows visually.

Zapier

Zapier's Etsy integration can trigger on new orders, but updating listing inventory requires the HTTP action to call the Etsy API directly. Complex for multi-step read-modify-write inventory updates.

Pros
    Cons

      Make (Integromat)

      More suitable than Zapier for multi-step inventory operations. Can chain GET inventory → modify → PUT with the HTTP module. Supports error handling and retries.

      Pros
        Cons

          n8n

          Self-hosted n8n with HTTP Request nodes can handle the full read-modify-write inventory pattern. Code nodes allow custom logic for multi-channel sync and SKU mapping.

          Pros
            Cons

              Best practices

              • Always GET inventory before PUT — never construct the products array from scratch as you'll delete unlisted variants
              • Implement distributed locking for inventory writes to prevent race conditions when webhooks fire during batch syncs
              • Add a 200ms delay between each listing update pair (GET+PUT) to stay within rate limits during bulk operations
              • Cache Etsy listing IDs mapped to your SKUs locally to avoid extra API calls on every update
              • Set is_enabled=true explicitly when restocking a listing that went to zero — setting quantity alone may not re-enable offerings
              • Log every inventory change with receipt_id, listing_id, old_quantity, new_quantity, and timestamp for debugging
              • Implement a polling fallback for the order.paid webhook — run a scheduled job every 30 minutes to catch any missed webhook events
              • Test your sync logic with a single test listing before running a full catalog sync

              Ask AI to help

              Copy one of these prompts to get a personalized, working implementation.

              ChatGPT / Claude Prompt

              Help me build a Node.js inventory sync system for Etsy that: (1) listens for order.paid webhooks (verify signature with HMAC-SHA256 on raw body), (2) for each order, fetches receipt details to get listing IDs and quantities sold, (3) for each listing, calls GET /listings/{listing_id}/inventory, decrements the quantity sold, and PUTs the full modified products array back — IMPORTANT: the PUT requires the complete products array, not just the changed offering, (4) handles 429 rate limits with 200ms delays. Include both Authorization: Bearer and x-api-key headers. Access tokens expire in 1 hour so include automatic refresh.

              Lovable / V0 Prompt

              Build me an Etsy inventory management dashboard that: (1) shows all active listings with current stock levels fetched from GET /shops/{shop_id}/listings/active, (2) has an inline edit field to update quantity for each listing, (3) when quantity is changed, calls GET /listings/{listing_id}/inventory then PUT with the full modified products array (required by Etsy), (4) shows a warning badge on listings with quantity < 5. Use Supabase to store the listing inventory data and the Etsy OAuth tokens. Include both Authorization: Bearer and x-api-key headers on every API call.

              Frequently asked questions

              Does the PUT inventory endpoint support partial updates — can I just change one variant's quantity?

              No. The PUT /listings/{listing_id}/inventory endpoint is a full replacement. You must include ALL products and their offerings in the request body. If you omit a product or offering, it is deleted. Always GET the current inventory first, modify only the fields you need to change, and PUT the complete object back.

              What happens to a listing when inventory hits zero?

              Etsy automatically sets the listing to inactive state when quantity reaches 0. The listing disappears from search results and shop pages. To reactivate it when you restock, PUT the inventory with quantity > 0 AND is_enabled=true. The listing returns to active state automatically.

              Can I sync inventory by SKU instead of listing_id?

              Etsy's API uses listing_id as the primary identifier. SKUs are stored within the products array of each listing's inventory. You'll need to maintain a local SKU-to-listing_id mapping table. Build this mapping during initial setup by fetching all listings and their inventory.

              Is there a way to lock a listing to prevent overselling during high-traffic periods?

              Etsy doesn't have a reservation or lock concept. The most reliable oversell prevention is to use the order.paid webhook to decrement inventory immediately after each sale — before fulfillment — and to use a distributed lock in your own system when updating inventory to prevent concurrent write conflicts.

              How many API calls does a full inventory sync cost?

              Each listing requires 2 API calls: GET inventory + PUT inventory. For a 100-listing shop, that's 200 calls per full sync cycle. With the 10,000/day limit, you can run about 50 full syncs per day. In practice, use webhook-driven updates for real-time accuracy and full syncs less frequently (every few hours).

              Can RapidDev help me build multi-channel inventory sync across Etsy, Shopify, and Amazon?

              Yes. RapidDev can design and build a centralized inventory hub that syncs stock levels across Etsy, Shopify, Amazon, and other platforms in real time, preventing overselling across all channels simultaneously.

              What scopes do I need to request for inventory management?

              You need listings_r and listings_w to read and write listing inventory. If you're using webhooks triggered by orders, you also need transactions_r. Request the minimum scopes needed — avoid requesting write scopes for workflows that only read data.

              RapidDev

              Need this automated?

              Our team has built 600+ apps with API automations. We can build this for you.

              Book a free consultation
              Matt Graham

              Written by

              Matt Graham · CEO & Founder, RapidDev

              1,000+ client projects delivered. Columbia University & Harvard Business School alumnus, U.S. Navy veteran. About the author →

              Want this built for you?

              We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

              Get a fixed-price quote

              We put the rapid in RapidDev

              Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.