To use the eBay Browse API with V0, generate your marketplace UI in V0, then create a Next.js API route at app/api/ebay/route.ts that authenticates with eBay's OAuth2 Client Credentials flow and proxies Browse API calls server-side. Store your eBay App ID and Client Secret in Vercel environment variables. V0 cannot call the eBay API directly from the browser due to CORS restrictions and credential exposure risks.
Building eBay Marketplace Features in Your V0 App
The eBay Browse API is one of the most useful e-commerce APIs available for building product discovery and price comparison tools. It gives you access to hundreds of millions of eBay listings including auction items, Buy It Now prices, seller ratings, item conditions, and shipping details — all through a clean REST interface. For V0 users, this means you can build a fully-featured product search and listing display without setting up any e-commerce infrastructure yourself.
The integration pattern is straightforward but has one important requirement that trips up many developers: eBay's API blocks direct browser-side requests with CORS restrictions, and more importantly, your API credentials should never appear in client-side JavaScript. This means all eBay API calls must go through a Next.js API route that runs server-side on Vercel. V0 generates the search interface and listing cards as React components, and those components call your Vercel serverless function which handles the eBay authentication and data fetching.
eBay uses OAuth2 with a Client Credentials grant for public Browse API access — you do not need a user to log in to eBay to search listings or fetch product details. The flow is: your server requests an access token using your App ID and Client Secret, then uses that token for Browse API calls. Tokens are valid for two hours, so a good optimization is to cache the token in memory (or Upstash Redis) to avoid an extra network round-trip on every search request. V0 cannot validate live eBay API connections in its preview sandbox, so you will deploy to Vercel and test from there.
Integration method
V0 generates your marketplace browsing UI while a Next.js API route handles eBay API authentication and data fetching server-side, keeping your Client Secret out of the browser. The API route obtains an OAuth2 application token from eBay, then proxies Browse API requests and returns formatted listing data to your V0 components. Since eBay's API blocks direct browser requests via CORS, all API calls must go through your server-side route.
Prerequisites
- A V0 account with a Next.js project generated at v0.dev
- An eBay Developer account at developer.ebay.com (free to create)
- An eBay application created in the Developer Portal to get your App ID (Client ID) and Client Secret
- A Vercel account with your V0 project deployed via GitHub
- Basic understanding of how search queries and REST API responses work
Step-by-step guide
Create an eBay Developer Application
Create an eBay Developer Application
Before writing any code, you need eBay API credentials. Go to developer.ebay.com and sign in with your eBay account (or create one — it is separate from a buyer/seller account). Navigate to the Application section and click 'Create Application'. Give it a name like 'My V0 App' and select 'Production' for the environment. You will also see a 'Sandbox' environment which is useful for development, but the Browse API works best testing against Production since Sandbox has limited listing data. After creating the application, eBay will show you three credentials: the App ID (also called Client ID), the Dev ID, and the Client Secret (also called Client Secret). For the Browse API with Client Credentials flow, you only need the App ID and Client Secret. Copy both of these values and keep them somewhere secure — you will add them to Vercel's environment variables in a later step. Important: eBay has two types of OAuth flows. The Client Credentials flow (what you will use here) requires only your App ID and Client Secret and is for accessing public data like listings — no user login needed. The Authorization Code flow is for accessing private user data like orders, which requires users to log in with their eBay account. For displaying and searching public listings, Client Credentials is simpler and sufficient. eBay also has rate limits: the Browse API allows 5,000 calls per day on the free Production tier. For a small app, this is plenty, but if you expect significant traffic you should implement token caching to avoid wasting calls on repeated token requests.
Pro tip: eBay's Developer Portal shows both Sandbox and Production credentials. Make sure you copy the Production credentials if you want to display real listings with actual prices.
Expected result: You have an eBay App ID (format: YourAppN-ame-PRD-xxxxxxxx-xxxxxxxx) and Client Secret copied and ready to add to Vercel.
Generate the Marketplace Search UI in V0
Generate the Marketplace Search UI in V0
Now use V0 to generate the front-end interface for your eBay integration. The key is to tell V0 exactly what API endpoints your components will call so it wires up the data fetching correctly. For an eBay listing display, you typically need two things: a search interface (input field and submit button) and a results display (cards or table rows with listing data). When prompting V0, be specific about the data fields you want to display. The eBay Browse API returns rich listing data including title, price (amount and currency), condition, image URL, item URL, seller username, and seller feedback score. Design your V0 component around the fields that matter for your use case. For a price comparison tool, price and condition are primary. For a buyer's tool, seller rating and shipping cost may matter more. The V0-generated component should make a GET or POST request to your Next.js API route at /api/ebay/search or similar. For search functionality, a GET request with a query string parameter like /api/ebay/search?q=vintage+camera is clean and easy to bookmark. V0 will generate a useEffect or event handler that fetches from this endpoint and updates component state with the results. Review the generated component's data handling. It should expect a response shape like { items: [{ title, price, imageUrl, itemUrl, condition, seller }] }. If V0 generates TypeScript interfaces for the response shape, that is excellent — it will help you match the API route's output to the component's expectations and catch mismatches early.
Create an eBay product search page. At the top, show a search input with a 'Search eBay' button. Below that, display search results as a responsive grid of cards. Each card shows a product image (use img with object-cover), product title (2-line truncation), price in bold, condition badge (New in green, Used in yellow), seller name, and a 'View on eBay' button linking to the item URL. Show a loading spinner during fetch. Fetch from GET /api/ebay/search?q={searchTerm} when the form is submitted.
Paste this in V0 chat
Pro tip: Ask V0 to add URL-based search state so the search query persists in the URL as a query parameter. This makes results shareable and preserves the search when users navigate back.
Expected result: V0 generates a polished search page with a form and listing cards. The component fetches from /api/ebay/search and maps the response to cards. It shows loading and empty states.
Create the eBay Authentication and Search API Route
Create the eBay Authentication and Search API Route
Now create the server-side API route that handles eBay authentication and search. The flow has two stages: first, obtain an OAuth token from eBay using your App ID and Client Secret; second, use that token to call the Browse API search endpoint. Create the file app/api/ebay/route.ts in your project. The eBay OAuth token endpoint is https://api.ebay.com/identity/v1/oauth2/token for Production. The token request uses HTTP Basic Auth with your App ID as the username and Client Secret as the password, encoded in Base64. The request body is a URL-encoded form: grant_type=client_credentials&scope=https://api.ebay.com/oauth/api_scope. Once you have the access token, call the Browse API search endpoint: https://api.ebay.com/buy/browse/v1/item_summary/search?q={query}&limit=20. The Authorization header must be Bearer {access_token}. The response contains an itemSummaries array with each listing's title, price, image, condition, and seller data. Token caching is important for performance and to stay within rate limits. In a serverless environment, you can use a module-level variable as a simple in-memory cache — it persists across requests within the same function instance. The token object should store the access_token string and an expiry timestamp. Before requesting a new token, check if the cached one is still valid (eBay tokens last 7,200 seconds, or two hours). For a more robust solution on high-traffic apps, store the token in Upstash Redis or Vercel Edge Config. The search response maps cleanly to your V0 component's expected data shape. Transform the eBay response fields (item.title, item.price.value, item.image.imageUrl, etc.) into the simpler shape your component expects. This transformation layer in the API route is valuable — it shields your frontend from eBay API changes and keeps your components clean.
Create a Next.js API route at app/api/ebay/route.ts that handles GET requests with a q query parameter. It should fetch an OAuth token from eBay using EBAY_CLIENT_ID and EBAY_CLIENT_SECRET environment variables with the Client Credentials flow, then call the eBay Browse API search endpoint with the query, and return an array of items with title, price, imageUrl, itemUrl, condition, and sellerName fields.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';23interface EbayTokenCache {4 token: string;5 expiresAt: number;6}78interface EbayItem {9 title: string;10 price: string;11 currency: string;12 imageUrl: string;13 itemUrl: string;14 condition: string;15 sellerName: string;16 feedbackScore: number;17}1819// Module-level token cache (persists across requests within same function instance)20let tokenCache: EbayTokenCache | null = null;2122async function getEbayToken(): Promise<string> {23 // Return cached token if still valid (with 5-minute buffer)24 if (tokenCache && Date.now() < tokenCache.expiresAt - 300_000) {25 return tokenCache.token;26 }2728 const clientId = process.env.EBAY_CLIENT_ID!;29 const clientSecret = process.env.EBAY_CLIENT_SECRET!;30 const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');3132 const response = await fetch('https://api.ebay.com/identity/v1/oauth2/token', {33 method: 'POST',34 headers: {35 'Authorization': `Basic ${credentials}`,36 'Content-Type': 'application/x-www-form-urlencoded',37 },38 body: 'grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope',39 });4041 if (!response.ok) {42 throw new Error(`eBay token request failed: ${response.status}`);43 }4445 const data = await response.json();46 tokenCache = {47 token: data.access_token,48 expiresAt: Date.now() + data.expires_in * 1000,49 };5051 return data.access_token;52}5354export async function GET(request: NextRequest) {55 try {56 const { searchParams } = new URL(request.url);57 const query = searchParams.get('q');5859 if (!query) {60 return NextResponse.json({ error: 'Query parameter q is required' }, { status: 400 });61 }6263 const token = await getEbayToken();64 const encodedQuery = encodeURIComponent(query);6566 const response = await fetch(67 `https://api.ebay.com/buy/browse/v1/item_summary/search?q=${encodedQuery}&limit=20&sort=price`,68 {69 headers: {70 'Authorization': `Bearer ${token}`,71 'X-EBAY-C-MARKETPLACE-ID': 'EBAY_US',72 'Content-Type': 'application/json',73 },74 }75 );7677 if (!response.ok) {78 throw new Error(`eBay Browse API error: ${response.status}`);79 }8081 const data = await response.json();82 const items: EbayItem[] = (data.itemSummaries || []).map((item: Record<string, unknown>) => ({83 title: item.title as string,84 price: (item.price as Record<string, string>)?.value || '0',85 currency: (item.price as Record<string, string>)?.currency || 'USD',86 imageUrl: (item.image as Record<string, string>)?.imageUrl || '',87 itemUrl: item.itemWebUrl as string,88 condition: item.condition as string || 'Unknown',89 sellerName: (item.seller as Record<string, string>)?.username || 'Unknown',90 feedbackScore: (item.seller as Record<string, number>)?.feedbackScore || 0,91 }));9293 return NextResponse.json({ items, total: data.total || 0 });94 } catch (error) {95 console.error('eBay API error:', error);96 return NextResponse.json({ error: 'Failed to fetch eBay listings' }, { status: 500 });97 }98}Pro tip: The X-EBAY-C-MARKETPLACE-ID header controls which eBay marketplace to search. Use EBAY_US for US listings, EBAY_GB for UK, EBAY_DE for Germany, and so on. You can make this dynamic based on the user's locale.
Expected result: The API route file exists. Visiting /api/ebay?q=vintage+camera in your browser (or via curl) returns a JSON object with an items array containing listing data from eBay.
Add Environment Variables in Vercel
Add Environment Variables in Vercel
Your API route reads EBAY_CLIENT_ID and EBAY_CLIENT_SECRET from environment variables. These must be configured in Vercel's environment settings so your serverless function can access them when it runs in production. The module-level token cache in the API route only works once the credentials are available at function startup. Go to your Vercel Dashboard and open your project. Click Settings at the top, then Environment Variables in the left sidebar. Add the following two variables: First, EBAY_CLIENT_ID with the value of your eBay App ID from the Developer Portal. The Production App ID looks like YourAppName-PRD-xxxxxxxxxxxxxxxx-xxxxxxxx. Do not add any prefix — this is a client ID, not a browser-exposed publishable key. It should remain server-side only. Second, EBAY_CLIENT_SECRET with your eBay Client Secret. This is sensitive and must never have the NEXT_PUBLIC_ prefix. It only needs to be accessible in your Next.js API route, which runs on Vercel's serverless infrastructure and never sends this value to the browser. For both variables, set the environment scope to Production, Preview, and Development so your app works in all Vercel deployment environments. After saving, you need to trigger a redeployment for the new variables to take effect — push a commit to your GitHub repository or click the Redeploy button in the Vercel Dashboard under Deployments. For local development, create a .env.local file in your project root and add both variables there. The .env.local file is read by Next.js in development mode and is excluded from version control by default in V0-generated projects.
1# .env.local (for local development only — never commit this file)2EBAY_CLIENT_ID=YourAppName-PRD-xxxxxxxxxxxxxxxx-xxxxxxxx3EBAY_CLIENT_SECRET=PRD-xxxxxxxxxxxxxxxxxxxxxxxxxPro tip: eBay's Sandbox environment uses different credentials (your Sandbox App ID and Secret) and a different API base URL (api.sandbox.ebay.com). If you want to test in Sandbox first, create a separate set of Vercel environment variables for Preview deployments using Sandbox credentials.
Expected result: Vercel Dashboard shows EBAY_CLIENT_ID and EBAY_CLIENT_SECRET in your environment variables list. After redeployment, the API route can authenticate with eBay without errors.
Deploy and Test the eBay Integration
Deploy and Test the eBay Integration
With your API route and environment variables in place, it is time to deploy and test the full integration. Push your code to GitHub — your V0 project's Git panel handles this — and Vercel will automatically deploy. The deployment typically takes 30 to 60 seconds. Once deployed, test the API route directly first by visiting your Vercel URL with a search query: https://your-project.vercel.app/api/ebay?q=laptop. You should see a JSON response with an items array. If you see an authentication error, double-check your environment variables in the Vercel Dashboard and ensure you redeployed after adding them. If you see an empty items array, try a broader search term. Next, test the full UI flow. Navigate to your search page and enter a product query. The V0-generated component should display cards with listing titles, prices, and images. Common things to check: images loading correctly (eBay image URLs are HTTPS and should load in Next.js with proper next/image domain configuration), prices displaying with currency symbols, and condition badges showing the right color based on value. For production use, consider adding a few enhancements. Pagination is important for useful search tools — the eBay Browse API supports limit and offset parameters. Category filtering helps users narrow results — eBay's category IDs can be passed as the category_ids parameter. For complex eBay integrations involving seller accounts, order management, or inventory synchronization, RapidDev's team can help you set up the more advanced Authorization Code OAuth flow that requires user authentication. Check your Vercel Function logs (Vercel Dashboard → your project → Functions tab) to see API route execution times and any errors. eBay API responses typically take 200 to 500 milliseconds, which is well within Vercel's 300-second timeout limit. If you are seeing slow responses, the token fetch adds an extra round-trip — verify the caching logic is working by watching for repeated token requests in your logs.
Add pagination to the eBay search results. Show a 'Load More' button below the results grid. When clicked, it should fetch the next page from /api/ebay/search?q={query}&offset={currentCount} and append the new items to the existing results. Show a 'No more results' message when all items have been loaded.
Paste this in V0 chat
Pro tip: eBay's Browse API returns a warnings array when your query matches restricted categories or returns unusual results. Log these in your API route for debugging: console.log('eBay warnings:', data.warnings).
Expected result: The deployed V0 app shows real eBay listings when you search. Images load, prices display correctly, and clicking 'View on eBay' opens the correct listing on ebay.com.
Common use cases
Product Price Comparison Tool
A founder builds a product research tool where users enter a keyword and see matching eBay listings with current prices, sold prices, and condition data. V0 generates the search form and results grid. The Next.js API route calls the eBay Browse API's search endpoint and returns structured listing data. Users can sort by price or condition to find the best deal.
Create a product search page with a search input at the top and a results grid below. Each result card shows a product image, title, current price, condition (New/Used), and a link that opens the eBay listing in a new tab. Include a loading skeleton while results load and an empty state when no results are found. The search should POST to /api/ebay/search with a query parameter.
Copy this prompt to try it in V0
Auction Deal Finder Dashboard
A reseller dashboard that surfaces eBay auction listings ending within 24 hours at a price below estimated market value. V0 generates the dashboard layout with filter controls. The API route queries the eBay Browse API with ending-soon filters and price thresholds, returning deals sorted by time remaining. The founder uses this to source inventory for their own store.
Build a reseller dashboard with a table of auction listings. Each row shows item title, current bid price, number of bids, time remaining (formatted as '2h 30m'), condition, and a clickable link to the listing. Add filter buttons at the top for condition (All, New, Used) and price range. Fetch data from /api/ebay/auctions on page load.
Copy this prompt to try it in V0
Embedded Marketplace Widget
An e-commerce site displays related eBay listings on product pages to help users see secondary market pricing and availability. V0 generates a compact listing widget with three to five relevant items. The API route searches eBay using the current page's product title as the query and returns matching listings. This adds marketplace context to a product page without building a full integration.
Create a compact 'Available on eBay' widget component showing 3 listing cards in a horizontal row. Each card has a small product image, truncated title (max 2 lines), price, and 'View on eBay' button. The component accepts a 'query' prop and fetches from /api/ebay/search?q={query} on mount. Show a loading state and hide the widget if no results come back.
Copy this prompt to try it in V0
Troubleshooting
API route returns 401 'IAF_0001: Invalid access token' from eBay
Cause: The OAuth token request is failing, likely because EBAY_CLIENT_ID or EBAY_CLIENT_SECRET is incorrect, or you are mixing Sandbox credentials with the Production API endpoint.
Solution: Verify your credentials in the Vercel Dashboard environment variables. Make sure you are using Production credentials (your App ID starting with YourName-PRD-) against the Production API endpoint (api.ebay.com). If you copied credentials from the Sandbox section of the Developer Portal, they will not work with the production URL.
1// Verify the token endpoint URL — Production vs Sandbox:2// Production: https://api.ebay.com/identity/v1/oauth2/token3// Sandbox: https://api.sandbox.ebay.com/identity/v1/oauth2/tokenSearch returns 200 but itemSummaries is undefined or empty array
Cause: The query returned no results, the category is restricted, or the marketplace ID does not match the listings you expect to find.
Solution: Try a very broad search term like 'laptop' or 'shoes' to confirm the API is returning data. Check that X-EBAY-C-MARKETPLACE-ID is set to the correct marketplace (EBAY_US for US listings). Some categories require category-specific API scopes — check the eBay API documentation for the Browse API scope requirements.
Next.js Image component throws 'hostname not configured' error for eBay images
Cause: Next.js blocks external image domains by default for security. eBay images are hosted on i.ebayimg.com which must be explicitly allowed in next.config.ts.
Solution: Add the eBay image hostname to your next.config.ts remotePatterns configuration. This tells Next.js it is safe to optimize images from that domain.
1// next.config.ts2const nextConfig = {3 images: {4 remotePatterns: [5 {6 protocol: 'https',7 hostname: 'i.ebayimg.com',8 },9 ],10 },11};12export default nextConfig;Token cache does not work and every request fetches a new eBay token
Cause: Vercel serverless functions are stateless — each cold start creates a fresh function instance, losing the module-level tokenCache variable. On high-traffic apps, multiple concurrent instances also do not share cache.
Solution: For production apps with significant traffic, replace the module-level cache with Upstash Redis using the @upstash/redis package. Store the token string and expiry time as a Redis key with a TTL of 7,200 seconds. For low-traffic apps, the module-level cache is acceptable since Vercel reuses warm instances for subsequent requests.
1// With Upstash Redis caching (more reliable for production)2import { Redis } from '@upstash/redis';3const redis = new Redis({4 url: process.env.UPSTASH_REDIS_REST_URL!,5 token: process.env.UPSTASH_REDIS_REST_TOKEN!,6});78async function getEbayToken(): Promise<string> {9 const cached = await redis.get<string>('ebay_token');10 if (cached) return cached;11 // ... fetch new token ...12 await redis.setex('ebay_token', 7100, data.access_token); // 7100s TTL13 return data.access_token;14}Best practices
- Always proxy eBay API calls through a Next.js API route — never call the eBay API directly from client-side React components, as CORS blocks it and would expose credentials.
- Cache OAuth tokens for up to two hours (7,200 seconds) to reduce latency and stay well within eBay's rate limits. Module-level caching works for low-traffic apps; use Upstash Redis for production.
- Transform the eBay response shape in your API route before returning it to the client, so your React components are not tightly coupled to eBay's API response structure.
- Store EBAY_CLIENT_SECRET without any NEXT_PUBLIC_ prefix — it must only ever be accessed in server-side code.
- Use the X-EBAY-C-MARKETPLACE-ID header to target the correct regional marketplace, and consider making it configurable based on the user's country.
- Handle the case where itemSummaries is undefined — the Browse API returns no itemSummaries key (not an empty array) when there are no results, which will cause runtime errors if not guarded.
- Test with eBay's Sandbox environment during initial development to avoid consuming Production API quota while iterating on your code.
- Respect eBay's 5,000 calls per day limit on the free tier by implementing server-side caching of search results for popular queries, storing them for 15 to 30 minutes before re-fetching.
Alternatives
Etsy is a better fit if your audience shops for handmade, vintage, or craft items rather than general merchandise and auction lots.
AliExpress is an alternative if you need wholesale pricing and dropshipping product sourcing from Asian manufacturers rather than auction-style marketplace listings.
Shift4Shop is worth considering if you want to build and sell through your own storefront rather than embedding a third-party marketplace's inventory.
Frequently asked questions
Can I use the eBay API for free?
Yes. eBay's developer program is free to join and the Browse API (for searching and viewing public listings) includes a generous free tier of 5,000 API calls per day in Production. More advanced APIs for sellers and order management may have additional requirements. Register at developer.ebay.com with your eBay account.
Why can't I call the eBay API directly from my V0 React components?
Two reasons. First, eBay's API servers block cross-origin browser requests (CORS), so a direct fetch from a React component will fail with a CORS error. Second, you would need to include your Client Secret in client-side code, which is visible to anyone who inspects your page source. Always route eBay API calls through a Next.js API route on Vercel.
Does V0 have a native eBay integration?
V0 does not have a built-in eBay connector in its Marketplace integrations (which are limited to Neon, Supabase, Upstash, and Stripe). You build the integration manually using V0 for the UI scaffolding and a Next.js API route for the server-side eBay communication. V0 can generate the API route code when you prompt it with the specific requirements.
What is the difference between the eBay Browse API and the Finding API?
The Browse API is the modern REST API (v2) for buying-side features: searching listings, viewing item details, fetching deals. The Finding API is older and being phased out but still works. For new integrations, always use the Browse API — it is better documented, returns richer data, and will receive future improvements.
How do I filter eBay search results by price range?
The Browse API's search endpoint accepts a price filter in the format filter=price:[minPrice..maxPrice],priceCurrency:USD. For example, to find items between $10 and $100, add &filter=price:[10..100],priceCurrency:USD to your search URL. You can expose this as query parameters in your Next.js API route and add price range inputs to your V0 UI.
Can I display sold (completed) eBay listings to show historical prices?
The Browse API only returns active listings. For sold listing data (to show what items actually sold for), you need eBay's Deal API or third-party price history services. Showing historical sale prices requires eBay's seller-focused APIs which need additional permissions and an approved developer account.
My V0 preview shows eBay cards with broken images. What is wrong?
V0's preview sandbox may block external image requests. The images will work correctly after deployment to Vercel once you add i.ebayimg.com to the remotePatterns in next.config.ts. Alternatively, use a standard img HTML tag instead of Next.js's Image component for eBay thumbnails if you do not need image optimization.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation