Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with Etsy API

To integrate Replit with Etsy API, register an app on the Etsy developer portal, implement OAuth 2.0 PKCE flow from your Replit server, store credentials in Replit Secrets (lock icon 🔒), and call the Etsy Open API v3 endpoints for listings, shops, and receipts. Etsy uses OAuth 2.0 with PKCE (no client secret) for all operations that require seller authorization. Use an Autoscale deployment for the OAuth callback handler.

What you'll learn

  • How to register an Etsy developer app and configure the OAuth redirect URI for Replit
  • How to implement OAuth 2.0 PKCE flow from a Node.js or Python server running on Replit
  • How to read Etsy listings, shop data, and order receipts with the Open API v3
  • How to store and refresh Etsy OAuth tokens securely in Replit Secrets
  • The difference between API key access (public data) and OAuth access (seller operations)
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read30 minutesE-commerceMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with Etsy API, register an app on the Etsy developer portal, implement OAuth 2.0 PKCE flow from your Replit server, store credentials in Replit Secrets (lock icon 🔒), and call the Etsy Open API v3 endpoints for listings, shops, and receipts. Etsy uses OAuth 2.0 with PKCE (no client secret) for all operations that require seller authorization. Use an Autoscale deployment for the OAuth callback handler.

Etsy API Integration from Replit: Listings, Shops, and Orders

Etsy's Open API v3 is the access point for the handmade marketplace's data: shop listings with photos and pricing, order receipts, shipping profiles, and seller analytics. For app builders, the Etsy API enables custom seller dashboards, inventory sync tools, order management automation, and listing analytics beyond what Etsy's native tools provide. With millions of active sellers, Etsy integrations are in demand for e-commerce tooling.

Etsy uses OAuth 2.0 with PKCE exclusively for API v3. Unlike older OAuth 2.0 implementations with client secrets, PKCE uses a cryptographically random code verifier generated per-request — there is no static secret to store or protect. Your Replit app generates a code verifier (random string), derives a code challenge from it (SHA256 hash), sends the challenge to Etsy's auth endpoint, and then proves ownership by sending the original verifier during the token exchange. This design is specifically intended for public clients and server-side apps that cannot safely store a secret.

Public data — listing search, shop info, listing photos — can be accessed with just your API key (x-api-key header) without OAuth. This is useful for marketplace search features or displaying Etsy shop data on a website. Seller-specific operations like reading private orders, updating listings, or accessing financial data all require a user OAuth token with appropriate scopes.

Integration method

Standard API Integration

Etsy Open API v3 uses OAuth 2.0 with PKCE (Proof Key for Code Exchange) — there is no client secret involved. Your Replit server generates a code verifier and challenge, redirects the seller to Etsy's authorization page, handles the OAuth callback to exchange the code for an access token, and stores the token for subsequent API calls. Public data (listing search, shop info) can be accessed with just an API key. Seller-specific operations (orders, inventory updates) require a user access token obtained through the PKCE flow.

Prerequisites

  • A Replit account with a Node.js or Python Repl ready
  • An Etsy seller account (required to access seller API features)
  • An Etsy developer account at developers.etsy.com
  • An Etsy app registered with OAuth redirect URI pointing to your Replit app URL

Step-by-step guide

1

Register an Etsy Developer App

Navigate to developers.etsy.com and sign in with your Etsy account. If you do not have a developer account, you will be prompted to create one — this requires agreeing to the developer terms of service. Click 'Create a New App' and fill in the required fields: App Name (your integration's name), App Description (what the app does), and how you plan to use the API. Under the OAuth configuration section, add a Redirect URI. This must be the URL of your Replit app's callback endpoint — for example, https://yourapp.yourusername.repl.co/auth/callback. For development, you can use your Replit dev URL. For production, use your deployed Autoscale URL or custom domain. Etsy only redirects to pre-registered redirect URIs, so you must update this when your URL changes. After creating the app, you will see your Keystring (this is your API key / client ID). The Keystring is not secret — it identifies your app. You will include it in API requests as the x-api-key header for public endpoints. Etsy Open API v3 does NOT have a client secret — the PKCE flow is used instead, so you only have a Keystring. Note your Keystring and the authorized scopes you will need. Common scopes are: listings_r (read listings), listings_w (write listings), transactions_r (read orders), shops_r (read shop data). Request only the scopes your app needs.

Pro tip: Etsy apps go through a review process before receiving production access to all API scopes. During development, your app has limited quota. Register as early as possible and apply for production access when your integration is ready, as review can take several days.

Expected result: An Etsy developer app exists with your Replit URL as the redirect URI. You have your app's Keystring (API key / client ID).

2

Store Etsy Credentials in Replit Secrets

Click the lock icon (🔒) in the left Replit sidebar to open the Secrets pane. Add the following secrets: ETSY_CLIENT_ID: your app's Keystring (the API key from the developer portal — this identifies your app). ETSY_REDIRECT_URI: the full redirect URI you registered (e.g., https://yourapp.yourusername.repl.co/auth/callback). This must match exactly what you registered on the developer portal. ETSY_SCOPES: space-separated list of scopes your app needs (e.g., listings_r transactions_r shops_r). When you complete the OAuth flow and receive tokens, also store them in Secrets: ETSY_ACCESS_TOKEN: the OAuth access token received after PKCE authorization. ETSY_REFRESH_TOKEN: the refresh token (if your app type supports offline access). For a production multi-user app, you would store tokens in a database keyed by user ID rather than as environment variables. For a single-seller tool, storing the token in Secrets is fine. The access token expires after 3600 seconds (1 hour). Your code must handle token expiry by catching 401 responses and refreshing the token automatically.

check-etsy-secrets.js
1// check-etsy-secrets.js
2const required = ['ETSY_CLIENT_ID', 'ETSY_REDIRECT_URI', 'ETSY_SCOPES'];
3for (const key of required) {
4 if (!process.env[key]) {
5 throw new Error(`Missing secret: ${key}. Set it in Replit Secrets (lock icon 🔒).`);
6 }
7}
8console.log('Etsy config OK.');
9console.log('Client ID:', process.env.ETSY_CLIENT_ID);
10console.log('Scopes:', process.env.ETSY_SCOPES);

Pro tip: The ETSY_CLIENT_ID (Keystring) is not truly secret — it is sent in URLs and headers and visible to users. However, storing it in Secrets alongside sensitive tokens ensures consistent configuration management and allows you to rotate it if needed.

Expected result: ETSY_CLIENT_ID, ETSY_REDIRECT_URI, and ETSY_SCOPES appear in Replit Secrets. The check script prints the client ID and scopes without errors.

3

Implement OAuth 2.0 PKCE Authorization Flow (Node.js)

Install dependencies in the Shell tab: npm install axios express crypto-js. The PKCE flow has three steps: generate a code verifier + challenge, redirect the user to Etsy's authorization page, and exchange the returned code for access tokens. Step 1 — Generate PKCE values: create a random 43-128 character code verifier (alphanumeric + -._~), then generate a code challenge by taking the SHA256 hash of the verifier and base64url-encoding the result. Store the code verifier in the session (or a server-side cache) — you will need it in step 3. Step 2 — Authorization redirect: build the Etsy authorization URL with query parameters: client_id (your Keystring), redirect_uri, response_type=code, scope (space-separated), state (random nonce for CSRF protection), and code_challenge + code_challenge_method=S256. Redirect the user to this URL. Step 3 — Token exchange: when Etsy redirects to your callback with a code parameter, call Etsy's token endpoint (POST https://api.etsy.com/v3/public/oauth/token) with grant_type=authorization_code, client_id, redirect_uri, code, and code_verifier. Etsy returns an access_token and refresh_token. Store these securely. For public data endpoints (no OAuth required), include x-api-key: {ETSY_CLIENT_ID} in request headers. For seller endpoints, include Authorization: Bearer {access_token} instead.

etsy.js
1// etsy.js — Etsy OAuth 2.0 PKCE + API integration for Node.js on Replit
2const express = require('express');
3const axios = require('axios');
4const crypto = require('crypto');
5
6const app = express();
7app.use(express.json());
8
9const CLIENT_ID = process.env.ETSY_CLIENT_ID;
10const REDIRECT_URI = process.env.ETSY_REDIRECT_URI;
11const SCOPES = process.env.ETSY_SCOPES || 'listings_r transactions_r shops_r';
12
13// In-memory store for PKCE verifiers (use Redis/DB in production)
14const pkceStore = {};
15
16function generateCodeVerifier() {
17 return crypto.randomBytes(32).toString('base64url');
18}
19
20function generateCodeChallenge(verifier) {
21 return crypto.createHash('sha256').update(verifier).digest('base64url');
22}
23
24// Step 1: Start OAuth — generate PKCE and redirect to Etsy
25app.get('/auth/login', (req, res) => {
26 const codeVerifier = generateCodeVerifier();
27 const codeChallenge = generateCodeChallenge(codeVerifier);
28 const state = crypto.randomBytes(16).toString('hex');
29
30 // Store verifier for later (use session store in production)
31 pkceStore[state] = codeVerifier;
32
33 const params = new URLSearchParams({
34 response_type: 'code',
35 redirect_uri: REDIRECT_URI,
36 scope: SCOPES,
37 client_id: CLIENT_ID,
38 state,
39 code_challenge: codeChallenge,
40 code_challenge_method: 'S256'
41 });
42
43 res.redirect(`https://www.etsy.com/oauth/connect?${params}`);
44});
45
46// Step 2: OAuth callback — exchange code for tokens
47app.get('/auth/callback', async (req, res) => {
48 const { code, state } = req.query;
49 const codeVerifier = pkceStore[state];
50
51 if (!codeVerifier) return res.status(400).send('Invalid state parameter');
52 delete pkceStore[state];
53
54 try {
55 const tokenResponse = await axios.post('https://api.etsy.com/v3/public/oauth/token', {
56 grant_type: 'authorization_code',
57 client_id: CLIENT_ID,
58 redirect_uri: REDIRECT_URI,
59 code,
60 code_verifier: codeVerifier
61 });
62
63 const { access_token, refresh_token, expires_in } = tokenResponse.data;
64 // In production: store tokens securely in database
65 // For single-user tool: update ETSY_ACCESS_TOKEN in Secrets manually
66 console.log('OAuth complete. Access token expires in:', expires_in, 'seconds');
67 res.json({ success: true, expires_in });
68 } catch (err) {
69 res.status(500).json({ error: err.response?.data || err.message });
70 }
71});
72
73// Get current user's shop info (requires OAuth token)
74app.get('/api/shop', async (req, res) => {
75 const token = process.env.ETSY_ACCESS_TOKEN;
76 try {
77 const response = await axios.get('https://openapi.etsy.com/v3/application/users/me/shops', {
78 headers: { 'Authorization': `Bearer ${token}`, 'x-api-key': CLIENT_ID }
79 });
80 res.json(response.data);
81 } catch (err) {
82 res.status(err.response?.status || 500).json({ error: err.response?.data || err.message });
83 }
84});
85
86// Search public listings by keyword (API key only, no OAuth needed)
87app.get('/api/listings/search', async (req, res) => {
88 const { keywords, limit = 25 } = req.query;
89 try {
90 const response = await axios.get('https://openapi.etsy.com/v3/application/listings/active', {
91 headers: { 'x-api-key': CLIENT_ID },
92 params: { keywords, limit }
93 });
94 res.json(response.data);
95 } catch (err) {
96 res.status(err.response?.status || 500).json({ error: err.response?.data || err.message });
97 }
98});
99
100app.listen(3000, '0.0.0.0', () => console.log('Etsy server running on port 3000'));

Pro tip: The pkceStore in the example uses an in-memory object. In production or multi-instance deployments, store PKCE verifiers in a database or Redis keyed by the state parameter. Memory-stored verifiers are lost on server restart.

Expected result: Navigating to /auth/login redirects to Etsy's authorization page. After the seller authorizes, /auth/callback exchanges the code for tokens. GET /api/listings/search returns Etsy listings matching the keyword.

4

Python Integration for Etsy API

For Python Replit projects, install requests and flask: pip install requests flask. The PKCE flow works the same way as Node.js — generate the code verifier and challenge using Python's hashlib and base64 modules, redirect to Etsy's authorization URL, and exchange the code at the token endpoint. Python's standard library has all the cryptographic primitives you need: secrets.token_urlsafe() for the code verifier, hashlib.sha256() for the challenge, and base64.urlsafe_b64encode() for base64url encoding. Note that base64url encoding must not have padding characters — use .rstrip('=') to remove them. For Etsy API calls after OAuth, use requests.Session() with the Authorization header set. The access token expires in 3600 seconds. Implement a refresh token flow: when you receive a 401 response, call the token endpoint with grant_type=refresh_token, your CLIENT_ID, and the stored refresh_token to get a new access token. For a single-seller tool deployed on Replit, run the OAuth flow once, copy the access_token and refresh_token from the logs or response, and store them in Replit Secrets. Add automatic refresh logic so the token renews without manual intervention.

etsy_api.py
1# etsy_api.py Etsy Open API v3 with OAuth 2.0 PKCE for Python on Replit
2import os
3import hashlib
4import base64
5import secrets
6import requests
7from flask import Flask, request, redirect, jsonify, session
8
9app = Flask(__name__)
10app.secret_key = secrets.token_hex(32) # Set SECRET_KEY in Secrets for production
11
12CLIENT_ID = os.environ['ETSY_CLIENT_ID']
13REDIRECT_URI = os.environ['ETSY_REDIRECT_URI']
14SCOPES = os.environ.get('ETSY_SCOPES', 'listings_r transactions_r shops_r')
15
16def generate_pkce():
17 """Generate PKCE code verifier and S256 challenge."""
18 verifier = secrets.token_urlsafe(43)
19 challenge = base64.urlsafe_b64encode(
20 hashlib.sha256(verifier.encode()).digest()
21 ).rstrip(b'=').decode()
22 return verifier, challenge
23
24@app.route('/auth/login')
25def login():
26 verifier, challenge = generate_pkce()
27 state = secrets.token_hex(16)
28 session['pkce_verifier'] = verifier
29 session['oauth_state'] = state
30
31 params = {
32 'response_type': 'code',
33 'redirect_uri': REDIRECT_URI,
34 'scope': SCOPES,
35 'client_id': CLIENT_ID,
36 'state': state,
37 'code_challenge': challenge,
38 'code_challenge_method': 'S256'
39 }
40 auth_url = 'https://www.etsy.com/oauth/connect?' + '&'.join(f'{k}={v}' for k, v in params.items())
41 return redirect(auth_url)
42
43@app.route('/auth/callback')
44def callback():
45 code = request.args.get('code')
46 state = request.args.get('state')
47
48 if state != session.get('oauth_state'):
49 return 'Invalid state', 400
50
51 verifier = session.pop('pkce_verifier', None)
52 if not verifier:
53 return 'Missing PKCE verifier', 400
54
55 response = requests.post('https://api.etsy.com/v3/public/oauth/token', json={
56 'grant_type': 'authorization_code',
57 'client_id': CLIENT_ID,
58 'redirect_uri': REDIRECT_URI,
59 'code': code,
60 'code_verifier': verifier
61 })
62
63 if not response.ok:
64 return jsonify({'error': response.json()}), response.status_code
65
66 tokens = response.json()
67 # Store tokens securely update Secrets or save to database
68 print('Access token received, expires in:', tokens['expires_in'], 'seconds')
69 return jsonify({'success': True, 'expires_in': tokens['expires_in']})
70
71@app.route('/api/receipts')
72def get_receipts():
73 """Get shop orders (requires OAuth token with transactions_r scope)."""
74 token = os.environ.get('ETSY_ACCESS_TOKEN')
75 if not token:
76 return jsonify({'error': 'ETSY_ACCESS_TOKEN not set — run OAuth flow first'}), 401
77
78 # First get shop ID
79 me_resp = requests.get(
80 'https://openapi.etsy.com/v3/application/users/me/shops',
81 headers={'Authorization': f'Bearer {token}', 'x-api-key': CLIENT_ID}
82 )
83 if not me_resp.ok:
84 return jsonify({'error': 'Failed to get shop info'}), me_resp.status_code
85
86 shop_id = me_resp.json()['shop_id']
87 receipts_resp = requests.get(
88 f'https://openapi.etsy.com/v3/application/shops/{shop_id}/receipts',
89 headers={'Authorization': f'Bearer {token}', 'x-api-key': CLIENT_ID},
90 params={'limit': 25, 'was_paid': True}
91 )
92 return jsonify(receipts_resp.json())
93
94if __name__ == '__main__':
95 app.run(host='0.0.0.0', port=3000)

Pro tip: The base64url encoding for the PKCE challenge must strip padding characters ('='). Python's base64.urlsafe_b64encode() adds padding by default — call .rstrip(b'=') on the result before using it as the code_challenge parameter.

Expected result: Visiting /auth/login redirects to Etsy's OAuth page. After authorization, /auth/callback exchanges the code for tokens. GET /api/receipts returns the shop's paid orders.

Common use cases

Seller Order Management Dashboard

Build a custom order management tool that pulls Etsy receipts (orders) into a unified dashboard alongside orders from other platforms. Track fulfillment status, customer information, and shipping details. Post shipping tracking numbers back to Etsy when orders ship.

Replit Prompt

Build an Express app with Etsy OAuth PKCE login, a dashboard showing open orders with buyer details, and an endpoint to mark orders as shipped with a tracking number.

Copy this prompt to try it in Replit

Listing Inventory Sync

Sync Etsy listing quantities with an external inventory system. When stock is updated in your warehouse or spreadsheet, automatically update the corresponding Etsy listing quantity via the API. Prevent overselling on Etsy when items are sold on other platforms.

Replit Prompt

Create an endpoint that accepts a listing ID and new quantity, updates the listing inventory quantity on Etsy via the API, and returns the updated listing details.

Copy this prompt to try it in Replit

Shop Analytics Aggregator

Pull Etsy shop stats — views, favorites, sales counts — and combine them with revenue data from order receipts to build custom analytics reports. Generate weekly summaries or trend charts that Etsy's native analytics does not provide.

Replit Prompt

Build a Python script that fetches all Etsy receipts from the past 30 days, calculates total revenue by listing category, and outputs a summary report with top-selling items.

Copy this prompt to try it in Replit

Troubleshooting

invalid_grant error during token exchange in the OAuth callback

Cause: The PKCE code verifier was lost between the login and callback requests (e.g., server restarted between steps, in-memory store cleared), or the authorization code has expired (codes expire after a few minutes), or the redirect_uri in the token request does not exactly match the one used in the authorization request.

Solution: Ensure the code verifier is persisted across the redirect (use a database-backed session rather than in-memory storage). Verify that REDIRECT_URI is identical in both the login redirect and the token exchange call — even a trailing slash difference will cause this error. Complete the OAuth flow quickly after starting it.

401 Unauthorized after OAuth completes — API calls fail

Cause: The access token has expired (Etsy tokens expire after 1 hour), the token was stored incorrectly in Secrets with extra whitespace, or the token was issued with insufficient scopes for the endpoint you are calling.

Solution: Check when the token was issued and whether 3600 seconds have passed. Implement a refresh flow using the refresh_token. Also verify the token's scopes match what the endpoint requires — for example, reading orders requires transactions_r scope.

typescript
1// Refresh access token
2async function refreshToken(refreshToken) {
3 const response = await axios.post('https://api.etsy.com/v3/public/oauth/token', {
4 grant_type: 'refresh_token',
5 client_id: CLIENT_ID,
6 refresh_token: refreshToken
7 });
8 return response.data.access_token;
9}

redirect_uri_mismatch error when starting OAuth flow

Cause: The ETSY_REDIRECT_URI in Replit Secrets does not exactly match the redirect URI registered in the Etsy developer portal. This includes differences in http vs https, trailing slashes, or path differences.

Solution: Log into the Etsy developer portal and copy the exact registered redirect URI. Update ETSY_REDIRECT_URI in Replit Secrets to match character-for-character. For Replit Autoscale deployments, the URL format is https://{repl-name}.{username}.repl.co/auth/callback.

typescript
1// Debug redirect URI mismatch
2console.log('Redirect URI:', JSON.stringify(process.env.ETSY_REDIRECT_URI));

scope error — endpoint requires scope that was not requested

Cause: The OAuth flow was completed without requesting the necessary scope. For example, reading order receipts requires transactions_r but only listings_r was requested.

Solution: Update ETSY_SCOPES in Replit Secrets to include all required scopes (space-separated), then re-run the OAuth flow. The user must re-authorize with the new scopes. Etsy scope list: listings_r, listings_w, listings_d, transactions_r, transactions_w, billing_r, profile_r, profile_w, email_r, shops_rw, favorites_rw, feedback_r, recommended_listings_r.

Best practices

  • Store ETSY_CLIENT_ID, ETSY_REDIRECT_URI, ETSY_SCOPES, and obtained tokens in Replit Secrets (lock icon 🔒) — never hardcode them
  • Use server-side session storage (database or Redis) to persist PKCE verifiers across the OAuth redirect flow — in-memory storage is lost on server restart
  • Request only the minimum Etsy scopes your app needs — this makes the OAuth consent screen less alarming to users and limits API exposure
  • Implement automatic token refresh logic — Etsy access tokens expire after 1 hour; catch 401 responses and use the refresh_token to get a new access_token
  • Validate the OAuth state parameter in your callback to prevent CSRF attacks — reject callbacks where the state does not match what you generated
  • For public listing search that does not need seller data, use API key auth (x-api-key header) only — save OAuth flow for features that truly need seller account access
  • Apply for production API access on the Etsy developer portal early — rate limits and feature availability differ between development and production apps
  • Deploy with Autoscale on Replit for OAuth callback handlers and on-demand API endpoints; use Reserved VM only for continuous background sync jobs

Alternatives

Frequently asked questions

How do I connect Replit to Etsy API?

Register an app at developers.etsy.com to get your API Keystring, implement OAuth 2.0 PKCE in your Replit server to obtain seller access tokens, store the client ID and tokens in Replit Secrets (lock icon 🔒), and call the Etsy Open API v3 endpoints at openapi.etsy.com/v3/application/.

Does Etsy API require a client secret?

No. Etsy Open API v3 uses OAuth 2.0 PKCE (Proof Key for Code Exchange), which does not use a client secret. Instead, your app generates a cryptographic code verifier per-request. You only need your app's Keystring (client ID), the OAuth code, and the code verifier to exchange for tokens — no stored client secret is involved.

How do I store my Etsy API key in Replit?

Click the lock icon (🔒) in the Replit sidebar and add ETSY_CLIENT_ID (your app's Keystring), ETSY_REDIRECT_URI (your OAuth callback URL), and ETSY_SCOPES. After completing the OAuth flow, also store ETSY_ACCESS_TOKEN and ETSY_REFRESH_TOKEN in Secrets. Access them in code with process.env.ETSY_CLIENT_ID (Node.js) or os.environ['ETSY_CLIENT_ID'] (Python).

Can I search Etsy listings without OAuth?

Yes. Public listing data — active listings, shop info, listing photos — can be accessed with just your API Keystring in the x-api-key header. OAuth is only required for seller-specific operations like reading orders, updating listings, or accessing financial data. For read-only marketplace search features, OAuth is not needed.

Why do Etsy access tokens expire so quickly?

Etsy access tokens expire after 3600 seconds (1 hour) for security. Etsy provides refresh tokens that allow you to get a new access token without requiring the user to re-authorize. Implement a refresh flow that catches 401 responses and calls the token endpoint with grant_type=refresh_token. Store the latest access token in your database or update Replit Secrets.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

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.