Integrate Bolt.new with the Etsy Open API v3 by registering an app at developer.etsy.com, using the API key for read-only public data (shop listings, reviews) directly from your app, or implementing OAuth 2.0 with PKCE for write operations. Deployment is required before OAuth testing since the callback URL must be a publicly accessible HTTPS endpoint. Rate limit is 10,000 requests per day.
Building Etsy Shop Management and Storefront Features in Bolt.new
The Etsy Open API v3 is the developer interface for Etsy's handmade and vintage marketplace. For shop owners who want tools beyond what Etsy's native interface provides, the API enables custom dashboards that surface sales analytics, inventory management tools that bulk-update listing quantities, and integration with external systems like printing services or inventory management software.
Etsy's API has two access tiers. Read-only access to public shop data — listings, shop profiles, reviews, receipts for your own shop — requires only an API key appended to requests. No OAuth flow, no user login. This is the easiest path and works immediately in Bolt's development preview. Write access — creating listings, updating prices, managing inventory — requires OAuth 2.0 with the PKCE extension. Etsy enforces PKCE specifically, meaning you cannot use a simple client secret for the token exchange; you must generate a code verifier and code challenge pair.
The API rate limit is 10,000 requests per day per API key (not per token). This is a daily cap rather than a per-minute limit, which means bursting is allowed but you need to plan for daily budgets in high-volume scenarios. Etsy also enforces a secondary limit of 10 requests per second for individual endpoints, which rarely causes issues in normal usage patterns.
Integration method
Bolt generates the Etsy API integration code through conversation. Public Etsy data (shop listings, reviews, shop info) can be fetched directly with just an API key and works in Bolt's WebContainer preview. Write operations (creating or updating listings, managing orders) require OAuth 2.0 with PKCE, which in turn requires a deployed redirect URI — deploy to Netlify or Vercel before testing write flows. All API calls should go through server-side Next.js routes to keep the API key and OAuth tokens out of browser-accessible code.
Prerequisites
- An Etsy seller account (listings and shop management features require a seller account)
- An app registered at developer.etsy.com with an API key and OAuth credentials
- Your Etsy shop ID (visible in your Etsy shop URL: etsy.com/shop/YourShopName)
- For write operations: a deployed app on Netlify or Vercel with an HTTPS redirect URI registered in your Etsy app settings
- A Next.js project in Bolt.new (prompt 'Create a Next.js app' to scaffold one)
Step-by-step guide
Register an Etsy app and get your API key
Register an Etsy app and get your API key
Navigate to developer.etsy.com and click 'Register as a developer'. Sign in with your Etsy account. Complete the developer registration form — you need an Etsy seller account for full API access, but you can register as a developer with a buyer account for read-only testing. After registration, click 'Create App' and fill in the application details: name, website URL (your app's URL or a placeholder), and description. Etsy uses this information for their review process if your app ever exceeds the standard rate limits. You can use placeholder values for testing. Once created, your app shows the API Key (sometimes called the keystring) on the dashboard. This is a long alphanumeric string that you include in all API requests as the x-api-key header. For OAuth operations, you also need the Shared Secret (visible next to the API key). For OAuth redirect URIs, click 'Edit' on your app and add your callback URLs. For local testing, add http://localhost:3000/api/etsy/callback. For production, add https://your-app.netlify.app/api/etsy/callback. The redirect URI must match exactly what your OAuth flow sends — including protocol, domain, path, and any trailing slashes.
Create a Next.js app with Etsy API integration. Add ETSY_API_KEY and ETSY_SHARED_SECRET to .env.local. Create a /api/etsy/shop/[shopId] route that fetches public shop information from the Etsy Open API v3 using the API key as the x-api-key header. Return shop name, title, sale message, and listing count.
Paste this in Bolt.new chat
1// .env.local2ETSY_API_KEY=your_etsy_api_key_here3ETSY_SHARED_SECRET=your_etsy_shared_secret_here4ETSY_REDIRECT_URI=https://your-app.netlify.app/api/etsy/callbackPro tip: Etsy Open API v3 uses x-api-key as the header name for API key authentication, not Authorization. This is different from most other APIs — a common mistake when setting up the first request.
Expected result: Your Etsy app appears in the developer dashboard with an API key, and calling /api/etsy/shop/[shopId] returns JSON with the shop's public information.
Fetch public shop listings and reviews
Fetch public shop listings and reviews
With just the API key, you can access all public Etsy data without any OAuth flow. The Etsy v3 API base URL is https://openapi.etsy.com/v3. All public endpoints return JSON and require only the x-api-key header. To fetch listings for a shop, call GET /application/shops/{shop_id}/listings/active with query parameters: limit (max 100), offset for pagination, and sort_on (created, price, updated, score) with sort_order (asc or desc). The response includes an array of listing objects with listing_id, title, description, price, quantity, url, and images (array of image objects with full URL versions). For shop reviews, call GET /application/shops/{shop_id}/reviews. Reviews include rating, review (the text), and the listing title that was reviewed. Note that the reviewer's username is not returned in the public API for privacy reasons. The listing images require a separate call to GET /application/listings/{listing_id}/images to get the full image URLs with different resolution options. The thumbnail URL in the main listing response is sufficient for grid displays, but for product detail pages you want the full-size URLs from the images endpoint. All of these calls work perfectly from Bolt's WebContainer development preview since they are outbound HTTP requests with no OAuth requirement. You can build and test the entire read-only storefront without deploying.
Create an Etsy listings API route at /api/etsy/listings that accepts a shopId query parameter and fetches active listings from the Etsy API. Return title, price (amount and currency_code), main image URL (first image's url_570xN), listing URL, and quantity for each listing. Limit to 50 listings. Also create /api/etsy/reviews that fetches shop reviews with rating, review text, and listing title.
Paste this in Bolt.new chat
1// app/api/etsy/listings/route.ts2import { NextRequest, NextResponse } from 'next/server';34const ETSY_API = 'https://openapi.etsy.com/v3';5const API_KEY = process.env.ETSY_API_KEY;67export async function GET(request: NextRequest) {8 const { searchParams } = new URL(request.url);9 const shopId = searchParams.get('shopId');10 const limit = searchParams.get('limit') ?? '50';11 const offset = searchParams.get('offset') ?? '0';1213 if (!shopId) {14 return NextResponse.json({ error: 'shopId is required' }, { status: 400 });15 }1617 const response = await fetch(18 `${ETSY_API}/application/shops/${shopId}/listings/active?limit=${limit}&offset=${offset}&includes=Images`,19 { headers: { 'x-api-key': API_KEY! } }20 );2122 if (!response.ok) {23 const error = await response.json();24 return NextResponse.json({ error }, { status: response.status });25 }2627 const data = await response.json();2829 const listings = data.results.map((listing: Record<string, unknown>) => {30 const images = listing.images as Array<Record<string, string>> | undefined;31 return {32 id: listing.listing_id,33 title: listing.title,34 price: listing.price,35 quantity: listing.quantity,36 url: listing.url,37 imageUrl: images?.[0]?.url_570xN ?? null,38 };39 });4041 return NextResponse.json({42 listings,43 count: data.count,44 total: data.total_count ?? data.count,45 });46}Pro tip: Add ?includes=Images to listing requests to get image data in the same response, avoiding a separate images API call per listing. This halves your API request count for listing grids.
Expected result: Calling /api/etsy/listings?shopId=YourShopId returns an array of active listings with titles, prices, image URLs, and Etsy links. The storefront grid renders with real listing data.
Implement OAuth 2.0 PKCE for write operations
Implement OAuth 2.0 PKCE for write operations
Etsy requires OAuth 2.0 with PKCE (Proof Key for Code Exchange) for all write operations — creating listings, updating prices, managing orders. PKCE adds security by requiring a cryptographically generated code verifier and challenge, preventing authorization code interception attacks even without a client secret involved in the exchange. The PKCE flow works like this: before starting the OAuth redirect, your server generates a random 32-byte code verifier (base64url encoded) and a code challenge (SHA-256 hash of the verifier, base64url encoded). The code challenge is included in the authorization URL. When Etsy redirects back to your callback with the authorization code, you exchange the code using the original verifier — Etsy verifies the verifier matches the challenge to confirm the request is legitimate. Your authorization URL must include: response_type=code, client_id (your API key), redirect_uri, scope (the permissions you need — listings_r listings_w for listing read/write, transactions_r for orders), state (random value to prevent CSRF), and code_challenge plus code_challenge_method=S256. As with all OAuth flows, the callback URL must be a publicly accessible HTTPS endpoint. Etsy cannot redirect to the Bolt WebContainer preview URL. Deploy to Netlify or Vercel first, set ETSY_REDIRECT_URI to your deployed URL in the hosting platform's environment variables, and test the OAuth flow on the deployed site.
Add Etsy OAuth 2.0 PKCE authentication to my Next.js app. Create /api/etsy/authorize that generates a PKCE code verifier and challenge, stores the verifier in a server-side session or cookie, and redirects to Etsy's OAuth authorization URL with the correct scopes for reading and writing listings. Create /api/etsy/callback that exchanges the authorization code using the stored verifier and saves the access and refresh tokens.
Paste this in Bolt.new chat
1// app/api/etsy/authorize/route.ts2import { NextResponse } from 'next/server';3import crypto from 'crypto';4import { cookies } from 'next/headers';56function base64urlEncode(buffer: Buffer): string {7 return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');8}910export async function GET() {11 // Generate PKCE code verifier and challenge12 const codeVerifier = base64urlEncode(crypto.randomBytes(32));13 const codeChallenge = base64urlEncode(14 crypto.createHash('sha256').update(codeVerifier).digest()15 );16 const state = base64urlEncode(crypto.randomBytes(16));1718 // Store verifier and state in a cookie for the callback19 const cookieStore = await cookies();20 cookieStore.set('etsy_code_verifier', codeVerifier, { httpOnly: true, sameSite: 'lax' });21 cookieStore.set('etsy_state', state, { httpOnly: true, sameSite: 'lax' });2223 const authUrl = new URL('https://www.etsy.com/oauth/connect');24 authUrl.searchParams.set('response_type', 'code');25 authUrl.searchParams.set('redirect_uri', process.env.ETSY_REDIRECT_URI!);26 authUrl.searchParams.set('scope', 'listings_r listings_w transactions_r shops_r');27 authUrl.searchParams.set('client_id', process.env.ETSY_API_KEY!);28 authUrl.searchParams.set('state', state);29 authUrl.searchParams.set('code_challenge', codeChallenge);30 authUrl.searchParams.set('code_challenge_method', 'S256');3132 return NextResponse.redirect(authUrl.toString());33}3435// app/api/etsy/callback/route.ts36import { NextRequest, NextResponse } from 'next/server';37import { cookies } from 'next/headers';3839export async function GET(request: NextRequest) {40 const { searchParams } = new URL(request.url);41 const code = searchParams.get('code');42 const state = searchParams.get('state');4344 const cookieStore = await cookies();45 const storedState = cookieStore.get('etsy_state')?.value;46 const codeVerifier = cookieStore.get('etsy_code_verifier')?.value;4748 if (state !== storedState || !code || !codeVerifier) {49 return NextResponse.json({ error: 'Invalid OAuth state or missing parameters' }, { status: 400 });50 }5152 const tokenResponse = await fetch('https://api.etsy.com/v3/public/oauth/token', {53 method: 'POST',54 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },55 body: new URLSearchParams({56 grant_type: 'authorization_code',57 client_id: process.env.ETSY_API_KEY!,58 redirect_uri: process.env.ETSY_REDIRECT_URI!,59 code,60 code_verifier: codeVerifier,61 }).toString(),62 });6364 const tokens = await tokenResponse.json();65 // Store tokens in your database or session66 return NextResponse.json({ success: true, expiresIn: tokens.expires_in });67}Pro tip: Etsy access tokens expire after one hour. Store the refresh token (also returned in the token response) and use it with grant_type: 'refresh_token' to get a new access token without requiring the user to re-authorize.
Expected result: After deploying and visiting /api/etsy/authorize, you are redirected to Etsy's authorization page. After granting access, you are redirected to your callback URL and receive a JSON confirming the token exchange succeeded.
Common use cases
Custom Etsy storefront for a personal website
Display your Etsy shop listings on your own website with custom styling that matches your brand, rather than sending customers to Etsy's generic shop page. The listings link back to Etsy for purchase, keeping checkout on Etsy while the discovery experience is on your own domain.
Create a custom storefront page for my Etsy shop. Fetch all active listings from the Etsy API for shop ID [YOUR_SHOP_ID] using the API key. Display them in a 3-column masonry grid with the listing image, title, price, and a 'Shop Now' button that links to the Etsy listing URL. Include a loading skeleton while data fetches.
Copy this prompt to try it in Bolt.new
Etsy shop analytics dashboard
Build a custom analytics view showing your shop's sales by category, bestsellers by number of sales, average listing price, and new reviews this week. Etsy's native analytics are limited — a custom dashboard can combine data from multiple API endpoints in one view.
Build an Etsy shop analytics dashboard. Fetch shop stats, listing data with sales counts, and recent reviews from the Etsy API. Display: total active listings, total sales count, a bar chart of listings by category, the top 5 best-selling listings, and the 5 most recent reviews with star ratings.
Copy this prompt to try it in Bolt.new
Bulk listing price updater
Create a management tool that lets a shop owner load all their active listings, edit prices and quantities in a spreadsheet-like table, and save all changes in a single batch operation. This is dramatically faster than editing listings one by one in Etsy's interface.
Build a bulk listing editor for my Etsy shop. After OAuth login, fetch all active listings using the Etsy API and display them in an editable table with columns for title, price, and quantity. Allow editing multiple rows and save all changes with a single 'Save All Changes' button that calls the Etsy update listing API for each modified row.
Copy this prompt to try it in Bolt.new
Troubleshooting
API requests return 401 with 'Missing or invalid API key'
Cause: The x-api-key header is missing, misspelled, or contains an incorrect value. Note that Etsy uses x-api-key (lowercase with hyphens), not X-Api-Key or Authorization.
Solution: Verify the header name is exactly 'x-api-key' in your fetch call. Confirm the value in process.env.ETSY_API_KEY matches the API key shown on your developer.etsy.com app dashboard (not the shared secret — those are different values).
1// Correct header for Etsy API:2headers: { 'x-api-key': process.env.ETSY_API_KEY! }34// For OAuth-authenticated requests, use both:5headers: {6 'x-api-key': process.env.ETSY_API_KEY!,7 'Authorization': `Bearer ${accessToken}`,8}OAuth callback shows 'redirect_uri_mismatch' error from Etsy
Cause: The redirect_uri in the authorization request does not exactly match one of the URIs registered in your Etsy app settings. Etsy performs a strict string match.
Solution: Go to developer.etsy.com → your app → Callback URIs. Verify the URI matches exactly what ETSY_REDIRECT_URI contains in your environment variables. Check for http vs https, www vs no www, and trailing slashes. The URI in the code must be byte-for-byte identical to the registered URI.
OAuth flow works on deployed app but callback shows a blank page or redirects to Bolt's preview
Cause: ETSY_REDIRECT_URI in the hosting platform's environment variables is pointing to localhost:3000 or the Bolt preview URL instead of the deployed app's URL.
Solution: In your hosting platform (Netlify: Site settings → Environment variables, Vercel: Project settings → Environment variables), set ETSY_REDIRECT_URI to your deployed HTTPS URL (e.g., https://your-app.netlify.app/api/etsy/callback). Redeploy after updating environment variables for the change to take effect.
Best practices
- Use the API key for all read-only public data fetching — this is simpler than OAuth and works in development without deployment. Only implement OAuth when you need write access.
- Add ?includes=Images to listing requests to get image data in the same call, reducing total request count by half for listing-heavy pages and staying well under the 10,000 daily request limit.
- Store OAuth tokens in your database alongside expiry times. Etsy access tokens expire after 1 hour — implement token refresh using the stored refresh token before that expiry.
- Never expose your ETSY_API_KEY or ETSY_SHARED_SECRET in client-side components or NEXT_PUBLIC_ environment variables — even though the API key is technically just an identifier, exposing it allows others to make requests against your rate limit quota.
- Cache listing data on your server for 15-30 minutes to reduce API calls for public storefront pages — Etsy shop listings rarely change faster than that, and caching dramatically reduces your daily request budget usage.
- Implement pagination correctly: the total_count field in listing responses tells you the total number of active listings, and you need to loop through pages using the offset parameter to retrieve all of them for analytics use cases.
- When building a shop dashboard for public use, consider that Etsy's Terms of Service have restrictions on how API data can be displayed — review the Developer Terms at developer.etsy.com before launching a commercial product.
Alternatives
eBay's API covers a larger and more diverse marketplace than Etsy, making it a better choice if your sellers have both handmade and mass-produced inventory.
AliExpress API is appropriate for dropshipping and wholesale integrations targeting the Chinese manufacturing supply chain, unlike Etsy's handmade focus.
Printful integrates with Etsy for print-on-demand fulfillment and has its own API for order management, making it a complementary rather than alternative tool.
WooCommerce is better for sellers who want full control of their storefront without marketplace fees, using the WooCommerce REST API for the same listing and order management operations.
Frequently asked questions
Can I test the Etsy API integration in Bolt's preview without deploying?
Yes, for read-only operations. Fetching shop listings, reviews, and shop information requires only an API key and works in the Bolt WebContainer preview since these are outbound HTTP requests. The OAuth 2.0 flow for write operations requires a deployed HTTPS redirect URI — Etsy cannot redirect to the Bolt preview URL. Deploy to Netlify or Vercel before testing listing creation or updates.
Does Bolt.new have a native Etsy integration?
No. Etsy is not one of Bolt's native connectors. You integrate the Etsy Open API v3 by building Next.js API routes that call Etsy's endpoints. Bolt's AI can generate much of the integration code when you describe what shop management or storefront features you need.
What is the Etsy Open API daily rate limit?
The standard limit is 10,000 requests per day per API key. This resets at midnight UTC. For a typical shop dashboard app making a few dozen requests per session, this is very generous. If you are building a high-volume sync tool that processes thousands of listings, cache responses aggressively and consider requesting a rate limit increase through the Etsy developer portal.
Can I create Etsy listings through the API, or is that only possible through the Etsy website?
Yes, listing creation is supported through the POST /application/shops/{shop_id}/listings endpoint. However, it requires OAuth 2.0 authentication with the listings_w scope and the OAuth callback flow must be completed on a deployed app. New listings created via API are put in draft state by default — you must set state to 'active' in the request body or activate them through the Etsy seller dashboard.
Can I read another seller's listings and shop data with the Etsy API?
Yes, public shop data is accessible to anyone with a valid API key. You can fetch active listings, shop profiles, and published reviews for any public Etsy shop. Private data (draft listings, order details, financial information) requires OAuth authentication from the shop owner who controls that data.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation