BuyWhere API Developer FAQ & Troubleshooting Guide
By Draft · April 2026
Common questions and issues from developers integrating the BuyWhere API.
Authentication
Q: How do I authenticate requests?
A: Include your API key in the Authorization header:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.buywhere.ai/v1/search?q=laptop"
You can also use the X-API-Key header:
curl -H "X-API-Key: YOUR_API_KEY" \
"https://api.buywhere.ai/v1/search?q=laptop"
Q: How do I get an API key? A: Sign up at buywhere.ai/api-keys. Free tier requires no credit card.
Q: My API key isn't working — getting 401 errors A: Check these common causes:
- Key format: Ensure you're using the full key (e.g.,
bw_live_xxxorbw_free_xxx) - Key type: Live keys start with
bw_live_, free keys withbw_free_, partner keys withbw_partner_ - Key validity: Keys may have been revoked — check your dashboard
- Header format: Use
Bearer YOUR_KEY(with a space after Bearer), notBearerYOUR_KEY
Q: Can I rotate keys without downtime? A: Yes. New keys become active immediately. Old keys remain valid for a 24-hour grace period after rotation. To rotate:
curl -X POST "https://api.buywhere.ai/v1/keys/{key_id}/rotate" \
-H "Authorization: Bearer YOUR_API_KEY"
Rate Limits
Q: What are the rate limits? A:
| Tier | Requests/minute | Monthly Quota |
|---|---|---|
Free (bw_free_*) | 60 | 10,000 |
Live (bw_live_*) | 600 | Unlimited |
Partner (bw_partner_*) | Unlimited | Unlimited |
Q: How do I check my current usage? A: Every response includes rate limit headers:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 547
X-RateLimit-Reset: 1713246000
Q: What happens when I hit the rate limit?
A: The API returns 429 Too Many Requests with a retry_after value:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"details": { "retry_after": 32 }
}
}
Q: How should I handle rate limit errors? A: Implement exponential backoff with jitter:
import time
import random
import requests
def fetch_with_retry(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
jitter = random.uniform(0, 1)
wait = (2 ** attempt) * retry_after + jitter
print(f"Rate limited. Waiting {wait:.1f}s before retry...")
time.sleep(wait)
elif response.status_code >= 500:
time.sleep(2 ** attempt)
else:
return response
raise Exception("Max retries exceeded")
async function fetchWithRetry(url, options, maxRetries = 5) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
const backoff = Math.pow(2, i) * retryAfter + Math.random() * 1000;
console.log(`Rate limited. Waiting ${backoff.toFixed(0)}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, backoff));
continue;
}
if (response.status >= 500) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Search & Query Issues
Q: My search returns no results A: Check these possibilities:
- Query terms: Try fewer or different keywords. "iphone 15 pro" may return fewer results than "iphone"
- Category filter: If using
categoryfilter, ensure the category exists — check/v1/categoriesfor valid categories - Platform filter: If using
platformfilter, ensure the source is supported (e.g.,shopee_sg,lazada_sg) - Country filter: If filtering by country, ensure products exist for that country
- Price range: Your
min_price/max_pricefilters may be too restrictive
Q: Search results seem wrong or irrelevant A: Try these approaches:
- Remove filters to see if base results improve
- Use semantic search for natural language:
GET /v1/search/semantic?q=phone+for+gaming - Shorten query — fewer words often yield better results
- Check
confidence_scorein results — low scores indicate uncertain matches
Q: Query too long error (422) A: Search queries are limited to 500 characters. Shorten your query or split it into multiple requests.
Q: How does semantic search differ from regular search? A: Semantic search understands intent rather than exact keyword matching:
- Regular search: matches exact terms in product names/descriptions
- Semantic search: understands "phone for gaming" relates to gaming smartphones
Use semantic when users ask naturally (e.g., "best laptop for college students").
MCP (Model Context Protocol)
Q: What is the BuyWhere MCP server? A: The BuyWhere MCP server exposes product catalog data to AI agents via the Model Context Protocol. It lets AI agents search products, compare prices, and find deals through standardized JSON-RPC 2.0 tool calls.
Q: What tools does the MCP server expose? A: Seven tools:
| Tool | Description |
|---|---|
search_products | Full-text search across e-commerce platforms |
get_product | Retrieve a specific product by BuyWhere ID |
compare_prices | Search products sorted by price |
get_deals | Find products with 10%+ discounts |
find_deals | Find 20%+ off deals with expiration dates |
browse_categories | Browse the category taxonomy tree |
get_category_products | Get paginated products within a category |
Q: How do I connect to the BuyWhere MCP server? A: Add the BuyWhere MCP server to your AI agent client configuration:
{
"mcpServers": {
"buywhere": {
"command": "python",
"args": ["/path/to/buywhere-api/mcp_server.py"],
"env": {
"BUYWHERE_API_KEY": "your_api_key_here",
"BUYWHERE_API_URL": "https://api.buywhere.ai"
}
}
}
}
Configuration paths:
- Claude Desktop (macOS):
~/Library/Application Support/Claude/claude_desktop_config.json - Claude Desktop (Linux):
~/.config/Claude/claude_desktop_config.json - Cursor: Cursor Settings → MCP Servers → Add New Server
Q: What MCP transport options are available? A:
- STDIO (default): For desktop integrations like Claude Desktop and Cursor
- HTTP/SSE: For web integrations — run with
--transport http --port 8080 - Both: Run with
--transport both --port 8080
Q: MCP server not appearing in Claude Desktop A: Troubleshooting steps:
- Ensure the path to
mcp_server.pyis absolute, not relative - Restart Claude Desktop completely (quit and relaunch)
- Check Claude's developer console for MCP errors
- Verify your
claude_desktop_config.jsonis valid JSON (use a linter)
Q: "Connection refused" errors with MCP A: Check:
- Your API key is set:
echo $BUYWHERE_API_KEY - The API URL is correct (must include
https://api.buywhere.ai) - Try the health endpoint:
curl https://api.buywhere.ai/health
Q: "Permission denied" errors with MCP A:
- Verify your API key is valid and active
- Check if you've exceeded rate limits
- Ensure the key type supports MCP (all production keys do)
Q: Can I use MCP with LangChain or CrewAI agents? A: Yes. The BuyWhere SDK has built-in support:
# LangChain integration
pip install "buywhere-sdk[langchain]"
# CrewAI integration
pip install "buywhere-sdk[crewai]"
See the SDK README for complete examples of price comparison agents and shopping research crews.
Data Freshness & Accuracy
Q: How often is product data updated? A: Prices and availability refresh every 6–24 hours depending on the retailer. High-traffic retailers (Amazon, Shopee) update more frequently.
Q: Is this "live" data? A: Our catalog is refreshed periodically, not scraped in real-time. For transaction-critical live pricing, check the retailer's website directly.
Q: Why does price seem outdated?
A: Each product has a data_freshness field:
fresh: Updated within the last hourrecent: Updated within the last 6 hoursstale: Updated within the last 24 hoursvery_stale: Data older than 24 hours
Check this field to gauge data currency.
Q: Do you track price history?
A: Yes. The GET /v1/products/{id}/price-history endpoint provides historical price data.
Q: Product shows in stock but retailer is sold out A: Stock status is refreshed periodically. If critical, verify directly on the retailer's website. Report discrepancies via support.
Product Coverage
Q: How many products do you have? A: Over 1 million product listings across all markets. Coverage varies by retailer and category.
Q: What retailers are supported? A:
- Singapore: Shopee, Lazada, Amazon SG, Qoo10, Carousell, Zalora, Fairprice, Guardian
- Southeast Asia: Lazada PH/MY/ID/TH, Shopee PH/MY/ID/TH/VN, Tokopedia ID, Tiki VN
- US: Amazon US, Walmart, Target, Best Buy, Nike, Zappos, Chewy, Costco US
Q: What categories are covered? A: Electronics, Fashion, Home & Living, Health & Beauty, Sports & Outdoors, Grocery, Mobiles & Tablets, Shoes, Luggage, Kids & Baby, and more.
Q: A product I expected isn't found A: Products are added through:
- Direct retailer API integrations
- Approved data feeds
- Authorized web scraping
Not all products may be in our catalog. Use the POST /v1/products/bulk-lookup to check if specific SKUs or URLs are indexed.
Batch Operations
Q: Can I look up multiple products at once?
A: Yes, use the POST /v1/products/batch endpoint:
curl -X POST "https://api.buywhere.ai/v1/products/batch" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"product_ids": [12345, 67890, 11111]}'
Q: What's the maximum batch size? A: 100 product IDs per batch request.
Q: Are batch queries more efficient? A: Yes. Batch queries have lower per-product overhead than multiple individual calls. Use batch when comparing or retrieving multiple known products.
Q: Can I look up products by SKU or URL?
A: Yes, use POST /v1/products/bulk-lookup:
curl -X POST "https://api.buywhere.ai/v1/products/bulk-lookup" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"lookups": [
{"type": "sku", "value": "iphone-15-pro-max-256"},
{"type": "upc", "value": "194253397731"},
{"type": "url", "value": "https://shopee.sg/iphone-15-pro-max"}
]
}'
Error Handling
Q: What error codes does the API return? A: Standard HTTP status codes:
| Code | Meaning | Common Cause |
|---|---|---|
| 200 | Success | Request succeeded |
| 400 | Bad Request | Malformed request syntax |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Valid key but insufficient scope |
| 404 | Not Found | Resource does not exist |
| 422 | Unprocessable Entity | Validation error in parameters |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | BuyWhere server error |
| 503 | Service Unavailable | Temporary downtime |
Q: What does a 422 validation error mean? A: Your request parameters failed validation. The response includes details:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": {
"errors": [
{"field": "price_min", "message": "Value must be greater than or equal to 0"}
]
}
}
}
Q: I'm getting 500 Internal Server Errors A: These are server-side issues. Try:
- Retry after 30 seconds — transient errors often resolve
- Check status.buywhere.ai for ongoing incidents
- If persistent, contact support with your request ID (found in
X-Request-Idresponse header)
Q: How do I report an API bug? A: Email api@buywhere.ai with:
- Request ID from
X-Request-Idheader - Endpoint and parameters used
- Response received
- Timestamp of request
Troubleshooting Guide
Issue: Authentication Failures (401)
Symptoms: API returns {"error": {"code": "UNAUTHORIZED", ...}}
Diagnosis:
- Is the key being passed at all? Test with:
curl -H "Authorization: Bearer test" "https://api.buywhere.ai/v1/products/stats" - Is the key format correct? Should be
bw_live_xxx,bw_free_xxx, orbw_partner_xxx - Is the key still valid? Check your dashboard at buywhere.ai/api-keys
Common fixes:
- Remove quotes around the key in curl commands
- Ensure
Bearer+ space + key (notBearerKey) - Check for trailing spaces or newlines in config
Issue: Rate Limit Hit Immediately (429 on first requests)
Symptoms: Getting 429 errors even with low request volume
Diagnosis:
- Check
X-RateLimit-Limitheader — you may be on a lower tier than expected - Are other parts of your application using the same API key?
- Check if multiple servers/processes share the same key
Fixes:
- Use separate API keys per server/process
- Implement request queuing to stay within limits
- Upgrade to a higher tier for more headroom
Issue: Slow Response Times
Symptoms: API requests taking longer than expected
Diagnosis: Expected latencies by endpoint:
| Endpoint | Baseline p95 | Heavy Load p95 |
|---|---|---|
GET /v1/products/{id} | < 10ms | < 200ms |
GET /v1/products | < 100ms | < 1000ms |
GET /v1/search | < 150ms | < 1200ms |
Fixes:
- Use specific queries — broad searches are slower
- Cache responses (product data updates every 5-10 minutes)
- Use cursor pagination instead of offset pagination
- Enable only needed response fields
Issue: Pagination Problems
Symptoms: Can't get beyond page 1, missing results, duplicate results
If using offset pagination:
- Offset pagination is deprecated — switch to cursor pagination
- Deep offsets (> 100 pages) become slow
Fix: Use cursor-based pagination:
# Instead of this (slow at high offsets)
curl "https://api.buywhere.ai/v1/products?limit=20&offset=1000"
# Use this (constant time at any depth)
curl "https://api.buywhere.ai/v1/products?limit=20&after=12345"
The response includes next_cursor for the next page.
Issue: Missing or Empty Results
Symptoms: Search returns 0 results, batch lookup returns empty
Diagnosis:
- Empty search: Try
/v1/categoriesto verify the category exists - Empty batch: Verify product IDs are correct — try looking up one at a time
- Empty suggestions: Check if query terms are too specific
Fixes:
- Use
POST /v1/products/bulk-lookupwith SKU or URL if you know the product - Search without filters first to establish baseline results
- Use semantic search for natural language queries
Issue: Product Not Found (404)
Symptoms: GET /v1/products/{id} returns 404
Causes:
- Product ID may be wrong or from a different system
- Product may have been removed from catalog
- Using wrong ID type (BuyWhere ID vs retailer ID)
Fix:
- Search for the product first to get the BuyWhere ID:
curl "https://api.buywhere.ai/v1/search?q=PRODUCT+NAME" \ -H "Authorization: Bearer YOUR_KEY" - Or use bulk-lookup by SKU/UPC/url:
curl -X POST "https://api.buywhere.ai/v1/products/bulk-lookup" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{"lookups": [{"type": "sku", "value": "KNOWN-SKU"}]}'
Issue: Invalid Currency Error (422)
Symptoms: {"error": {"code": "...", "message": "Unsupported currency"}}
Cause: Using an unsupported currency code
Fix: Use one of: SGD, MYR, THB, PHP, VND, IDR, USD, EUR
Issue: Region/Country Filter Not Working
Symptoms: Country filter returns unexpected results or errors
Fix: Use ISO 2-letter country codes:
SG— SingaporeMY— MalaysiaTH— ThailandPH— PhilippinesVN— VietnamID— IndonesiaUS— United States
Example: ?country=SG,MY for Singapore and Malaysia
Issue: CORS Errors in Browser
Symptoms: Browser console shows CORS policy errors
Cause: Browser-based requests may trigger CORS checks
Fix:
- Make API calls from your server/backend, not directly from browser JavaScript
- BuyWhere's API is designed for server-to-server communication
- If testing, use curl or Postman instead of browser
Issue: Webhook Events Not Received
Symptoms: Webhooks not triggering or events not arriving
Diagnosis:
- Verify webhook URL is publicly accessible (not localhost)
- Check endpoint accepts POST requests with JSON body
- Verify your server returns 200 quickly (before 30 seconds)
Fix:
- Use a tool like ngrok for local testing
- Ensure your webhook handler is fast — respond immediately, process async
- Check webhook logs in your BuyWhere dashboard
Performance Tips
DO
- Use batch endpoints —
POST /v1/products/batchcounts as one request for up to 100 products - Cache responses — product data updates every 5-10 minutes
- Use cursor pagination — O(1) vs offset's O(n) degradation
- Filter narrowly — specific queries return faster than broad ones
- Monitor rate limit headers to stay within quotas
DON'T
- Deep offset pagination — use cursor-based navigation instead
- High-frequency polling — implement exponential backoff
- Large result sets without pagination — request 20-50 items per page
- Parallel request bursts — space out requests
Recommended Cache TTLs
| Data Type | TTL | Rationale |
|---|---|---|
| Product details | 5–10 min | Updates infrequently |
| Search results | 60 sec | More dynamic |
| Deals | 5 min | Prices change but not every second |
| Categories | 1 hour | Category structure rarely changes |
| Price history | 1 hour | Historical data doesn't change |
Getting Help
- Documentation: docs.buywhere.ai
- API Status: status.buywhere.ai
- Support Email: api@buywhere.ai
- Community: developer.buywhere.ai
When contacting support, include:
- Request ID (
X-Request-Idheader from response) - Endpoint and parameters used
- Full error response
- Timestamp of request
Schema.org FAQPage JSON-LD
For SEO, the FAQ content above can be marked up as:
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How do I authenticate requests?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Include your API key in the Authorization header as 'Bearer YOUR_API_KEY', or use the X-API-Key header."
}
},
{
"@type": "Question",
"name": "What are the rate limits?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Free tier: 60 req/min. Live tier: 600 req/min. Partner tier: unlimited."
}
},
{
"@type": "Question",
"name": "How often is product data updated?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Prices and availability refresh every 6-24 hours depending on the retailer. Check the data_freshness field to gauge currency."
}
},
{
"@type": "Question",
"name": "How should I handle rate limit errors?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Implement exponential backoff. When you receive a 429, wait retry_after seconds and retry with increasing delays."
}
},
{
"@type": "Question",
"name": "Can I look up multiple products at once?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes, use POST /v1/products/batch with up to 100 product IDs per request."
}
}
]
}
Last Updated: 2026-04-19