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:

  1. Key format: Ensure you're using the full key (e.g., bw_live_xxx or bw_free_xxx)
  2. Key type: Live keys start with bw_live_, free keys with bw_free_, partner keys with bw_partner_
  3. Key validity: Keys may have been revoked — check your dashboard
  4. Header format: Use Bearer YOUR_KEY (with a space after Bearer), not BearerYOUR_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:

TierRequests/minuteMonthly Quota
Free (bw_free_*)6010,000
Live (bw_live_*)600Unlimited
Partner (bw_partner_*)UnlimitedUnlimited

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:

  1. Query terms: Try fewer or different keywords. "iphone 15 pro" may return fewer results than "iphone"
  2. Category filter: If using category filter, ensure the category exists — check /v1/categories for valid categories
  3. Platform filter: If using platform filter, ensure the source is supported (e.g., shopee_sg, lazada_sg)
  4. Country filter: If filtering by country, ensure products exist for that country
  5. Price range: Your min_price/max_price filters may be too restrictive

Q: Search results seem wrong or irrelevant A: Try these approaches:

  1. Remove filters to see if base results improve
  2. Use semantic search for natural language: GET /v1/search/semantic?q=phone+for+gaming
  3. Shorten query — fewer words often yield better results
  4. Check confidence_score in 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:

ToolDescription
search_productsFull-text search across e-commerce platforms
get_productRetrieve a specific product by BuyWhere ID
compare_pricesSearch products sorted by price
get_dealsFind products with 10%+ discounts
find_dealsFind 20%+ off deals with expiration dates
browse_categoriesBrowse the category taxonomy tree
get_category_productsGet 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:

  1. Ensure the path to mcp_server.py is absolute, not relative
  2. Restart Claude Desktop completely (quit and relaunch)
  3. Check Claude's developer console for MCP errors
  4. Verify your claude_desktop_config.json is valid JSON (use a linter)

Q: "Connection refused" errors with MCP A: Check:

  1. Your API key is set: echo $BUYWHERE_API_KEY
  2. The API URL is correct (must include https://api.buywhere.ai)
  3. Try the health endpoint: curl https://api.buywhere.ai/health

Q: "Permission denied" errors with MCP A:

  1. Verify your API key is valid and active
  2. Check if you've exceeded rate limits
  3. 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 hour
  • recent: Updated within the last 6 hours
  • stale: Updated within the last 24 hours
  • very_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:

  1. Direct retailer API integrations
  2. Approved data feeds
  3. 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:

CodeMeaningCommon Cause
200SuccessRequest succeeded
400Bad RequestMalformed request syntax
401UnauthorizedMissing or invalid API key
403ForbiddenValid key but insufficient scope
404Not FoundResource does not exist
422Unprocessable EntityValidation error in parameters
429Too Many RequestsRate limit exceeded
500Internal Server ErrorBuyWhere server error
503Service UnavailableTemporary 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:

  1. Retry after 30 seconds — transient errors often resolve
  2. Check status.buywhere.ai for ongoing incidents
  3. If persistent, contact support with your request ID (found in X-Request-Id response header)

Q: How do I report an API bug? A: Email api@buywhere.ai with:

  • Request ID from X-Request-Id header
  • Endpoint and parameters used
  • Response received
  • Timestamp of request

Troubleshooting Guide

Issue: Authentication Failures (401)

Symptoms: API returns {"error": {"code": "UNAUTHORIZED", ...}}

Diagnosis:

  1. Is the key being passed at all? Test with:
    curl -H "Authorization: Bearer test" "https://api.buywhere.ai/v1/products/stats"
    
  2. Is the key format correct? Should be bw_live_xxx, bw_free_xxx, or bw_partner_xxx
  3. 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 (not BearerKey)
  • 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:

  1. Check X-RateLimit-Limit header — you may be on a lower tier than expected
  2. Are other parts of your application using the same API key?
  3. 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:

EndpointBaseline p95Heavy 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:

  1. Empty search: Try /v1/categories to verify the category exists
  2. Empty batch: Verify product IDs are correct — try looking up one at a time
  3. Empty suggestions: Check if query terms are too specific

Fixes:

  • Use POST /v1/products/bulk-lookup with 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:

  1. Product ID may be wrong or from a different system
  2. Product may have been removed from catalog
  3. Using wrong ID type (BuyWhere ID vs retailer ID)

Fix:

  1. 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"
    
  2. 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 — Singapore
  • MY — Malaysia
  • TH — Thailand
  • PH — Philippines
  • VN — Vietnam
  • ID — Indonesia
  • US — 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:

  1. Make API calls from your server/backend, not directly from browser JavaScript
  2. BuyWhere's API is designed for server-to-server communication
  3. If testing, use curl or Postman instead of browser

Issue: Webhook Events Not Received

Symptoms: Webhooks not triggering or events not arriving

Diagnosis:

  1. Verify webhook URL is publicly accessible (not localhost)
  2. Check endpoint accepts POST requests with JSON body
  3. 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 endpointsPOST /v1/products/batch counts 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 TypeTTLRationale
Product details5–10 minUpdates infrequently
Search results60 secMore dynamic
Deals5 minPrices change but not every second
Categories1 hourCategory structure rarely changes
Price history1 hourHistorical data doesn't change

Getting Help

When contacting support, include:

  • Request ID (X-Request-Id header 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