shopsavvy-sdk


Nameshopsavvy-sdk JSON
Version 1.0.2 PyPI version JSON
download
home_pageNone
SummaryOfficial Python SDK for ShopSavvy Data API - Access product data, pricing, and price history
upload_time2025-07-30 07:49:26
maintainerShopSavvy by Monolith Technologies, Inc.
docs_urlNone
authorShopSavvy by Monolith Technologies, Inc.
requires_python>=3.8
licenseNone
keywords shopsavvy product-data pricing e-commerce shopping price-comparison retail api-client python
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # ๐Ÿ›๏ธ ShopSavvy Data API - Python SDK

[![PyPI version](https://badge.fury.io/py/shopsavvy-sdk.svg)](https://badge.fury.io/py/shopsavvy-sdk)
[![Python Support](https://img.shields.io/pypi/pyversions/shopsavvy-sdk.svg)](https://pypi.org/project/shopsavvy-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Downloads](https://pepy.tech/badge/shopsavvy-sdk)](https://pepy.tech/project/shopsavvy-sdk)

**The most comprehensive Python SDK for e-commerce product data and pricing intelligence.** 

Access real-time product information, pricing data, and historical trends across **thousands of retailers** and **millions of products** with the official [ShopSavvy Data API](https://shopsavvy.com/data).

---

## ๐Ÿš€ Quick Start

### Installation

```bash
pip install shopsavvy-sdk
```

### Get Your API Key

1. ๐ŸŒŸ Visit [shopsavvy.com/data](https://shopsavvy.com/data)
2. ๐Ÿ“ Sign up for a free account
3. ๐Ÿ’ณ Choose a subscription plan
4. ๐Ÿ”‘ Get your API key from the dashboard

### 30-Second Example

```python
from shopsavvy import create_client

# Initialize the client
api = create_client("ss_live_your_api_key_here")

# Look up any product by barcode, ASIN, or URL
product = api.get_product_details("012345678901")
print(f"๐Ÿ“ฆ {product.data.name} by {product.data.brand}")

# Get current prices from all retailers
offers = api.get_current_offers("012345678901")
cheapest = min(offers.data, key=lambda x: x.price)
print(f"๐Ÿ’ฐ Best price: ${cheapest.price} at {cheapest.retailer}")

# Set up price monitoring
api.schedule_product_monitoring("012345678901", "daily")
print("๐Ÿ”” Price alerts activated!")
```

---

## ๐ŸŽฏ Key Features

| Feature | Description | Use Cases |
|---------|-------------|-----------|
| ๐Ÿ” **Universal Product Lookup** | Search by barcode, ASIN, URL, model number | Product catalogs, inventory management |
| ๐Ÿ’ฒ **Real-Time Pricing** | Current prices across major retailers | Price comparison, competitive analysis |
| ๐Ÿ“ˆ **Historical Data** | Price trends and availability over time | Market research, pricing strategy |
| ๐Ÿ”” **Smart Monitoring** | Automated price tracking and alerts | Price drops, stock notifications |
| ๐Ÿช **Multi-Retailer Support** | Amazon, Walmart, Target, Best Buy + more | Comprehensive market coverage |
| โšก **Batch Operations** | Process multiple products efficiently | Bulk analysis, data processing |
| ๐Ÿ›ก๏ธ **Type Safety** | Full Pydantic models with validation | Reliable data structures |
| ๐Ÿ“Š **Multiple Formats** | JSON and CSV response options | Easy data integration |

---

## ๐Ÿ—๏ธ Installation & Setup

### Basic Installation
```bash
pip install shopsavvy-sdk
```

### Development Installation
```bash
git clone https://github.com/shopsavvy/sdk-python
cd sdk-python
pip install -e ".[dev]"
```

### Environment Setup
```bash
# Optional: Store your API key securely
export SHOPSAVVY_API_KEY="ss_live_your_api_key_here"
```

---

## ๐Ÿ“– Complete API Reference

### ๐Ÿ”ง Client Configuration

#### Method 1: Simple Client Creation (Recommended)
```python
from shopsavvy import create_client

# Basic setup
api = create_client("ss_live_your_api_key_here")

# With custom timeout and base URL
api = create_client(
    api_key="ss_live_your_api_key_here",
    timeout=60.0,
    base_url="https://api.shopsavvy.com/v1"
)
```

#### Method 2: Configuration Object
```python
from shopsavvy import ShopSavvyDataAPI, ShopSavvyConfig

config = ShopSavvyConfig(
    api_key="ss_live_your_api_key_here",
    timeout=45.0
)
api = ShopSavvyDataAPI(config)
```

#### Method 3: Context Manager (Auto-cleanup)
```python
# Automatically closes connections when done
with create_client("ss_live_your_api_key_here") as api:
    product = api.get_product_details("012345678901")
    print(product.data.name)
# Connection automatically closed here
```

### ๐Ÿ” Product Lookup

#### Single Product Lookup
```python
# Search by barcode (UPC/EAN)
product = api.get_product_details("012345678901")

# Search by Amazon ASIN
amazon_product = api.get_product_details("B08N5WRWNW")

# Search by product URL
url_product = api.get_product_details("https://www.amazon.com/dp/B08N5WRWNW")

# Search by model number
model_product = api.get_product_details("iPhone-14-Pro")

# Access product information
print(f"๐Ÿ“ฆ Product: {product.data.name}")
print(f"๐Ÿท๏ธ Brand: {product.data.brand}")
print(f"๐Ÿ“‚ Category: {product.data.category}")
print(f"๐Ÿ”ข Product ID: {product.data.product_id}")
print(f"๐Ÿ“ท Image: {product.data.image_url}")
```

#### Batch Product Lookup
```python
# Look up multiple products at once
identifiers = [
    "012345678901",           # Barcode
    "B08N5WRWNW",            # Amazon ASIN
    "https://www.target.com/p/example",  # URL
    "MODEL-ABC123"            # Model number
]

products = api.get_product_details_batch(identifiers)

for product in products.data:
    print(f"โœ… Found: {product.name} by {product.brand}")
    print(f"   ID: {product.product_id}")
    print(f"   Category: {product.category}")
    print("---")
```

#### CSV Format Support
```python
# Get product data in CSV format for easy processing
product_csv = api.get_product_details("012345678901", format="csv")

# Process with pandas
import pandas as pd
import io

df = pd.read_csv(io.StringIO(product_csv.data))
print(df.head())
```

### ๐Ÿ’ฐ Current Pricing

#### Get All Current Offers
```python
# Get prices from all retailers
offers = api.get_current_offers("012345678901")

print(f"Found {len(offers.data)} offers:")
for offer in offers.data:
    print(f"๐Ÿช {offer.retailer}: ${offer.price}")
    print(f"   ๐Ÿ“ฆ Condition: {offer.condition}")
    print(f"   โœ… Available: {offer.availability}")
    print(f"   ๐Ÿ”— Buy: {offer.url}")
    if offer.shipping:
        print(f"   ๐Ÿšš Shipping: ${offer.shipping}")
    print("---")
```

#### Retailer-Specific Pricing
```python
# Get offers from specific retailers
amazon_offers = api.get_current_offers("012345678901", retailer="amazon")
walmart_offers = api.get_current_offers("012345678901", retailer="walmart")
target_offers = api.get_current_offers("012345678901", retailer="target")

print("Amazon prices:")
for offer in amazon_offers.data:
    print(f"  ${offer.price} - {offer.condition}")
```

#### Batch Pricing
```python
# Get current offers for multiple products
products = ["012345678901", "B08N5WRWNW", "045496596439"]
batch_offers = api.get_current_offers_batch(products)

for identifier, offers in batch_offers.data.items():
    best_price = min(offers, key=lambda x: x.price) if offers else None
    if best_price:
        print(f"{identifier}: Best price ${best_price.price} at {best_price.retailer}")
    else:
        print(f"{identifier}: No offers found")
```

### ๐Ÿ“ˆ Price History & Trends

#### Basic Price History
```python
from datetime import datetime, timedelta

# Get 30 days of price history
end_date = datetime.now().strftime("%Y-%m-%d")
start_date = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")

history = api.get_price_history("012345678901", start_date, end_date)

for offer in history.data:
    print(f"๐Ÿช {offer.retailer}:")
    print(f"   ๐Ÿ’ฐ Current price: ${offer.price}")
    print(f"   ๐Ÿ“Š Historical points: {len(offer.price_history)}")
    
    if offer.price_history:
        prices = [point.price for point in offer.price_history]
        print(f"   ๐Ÿ“‰ Lowest: ${min(prices)}")
        print(f"   ๐Ÿ“ˆ Highest: ${max(prices)}")
        print(f"   ๐Ÿ“Š Average: ${sum(prices) / len(prices):.2f}")
    print("---")
```

#### Retailer-Specific History
```python
# Get price history from Amazon only
amazon_history = api.get_price_history(
    "012345678901", 
    "2024-01-01", 
    "2024-01-31",
    retailer="amazon"
)

for offer in amazon_history.data:
    print(f"Amazon price trends for {offer.retailer}:")
    for point in offer.price_history[-10:]:  # Last 10 data points
        print(f"  {point.date}: ${point.price} ({point.availability})")
```

### ๐Ÿ”” Product Monitoring & Alerts

#### Schedule Single Product Monitoring
```python
# Monitor daily across all retailers
result = api.schedule_product_monitoring("012345678901", "daily")
if result.data.get("scheduled"):
    print("โœ… Daily monitoring activated!")

# Monitor hourly at specific retailer
result = api.schedule_product_monitoring(
    "012345678901", 
    "hourly", 
    retailer="amazon"
)
print(f"Amazon monitoring: {result.data}")
```

#### Batch Monitoring Setup
```python
# Schedule multiple products for monitoring
products_to_monitor = [
    "012345678901",
    "B08N5WRWNW", 
    "045496596439"
]

batch_result = api.schedule_product_monitoring_batch(products_to_monitor, "daily")

for item in batch_result.data:
    if item.get('scheduled'):
        print(f"โœ… Monitoring activated for {item['identifier']}")
    else:
        print(f"โŒ Failed to monitor {item['identifier']}")
```

#### Manage Scheduled Products
```python
# View all monitored products
scheduled = api.get_scheduled_products()
print(f"๐Ÿ“Š Currently monitoring {len(scheduled.data)} products:")

for product in scheduled.data:
    print(f"๐Ÿ”” {product.identifier}")
    print(f"   ๐Ÿ“… Frequency: {product.frequency}")
    print(f"   ๐Ÿช Retailer: {product.retailer or 'All retailers'}")
    print(f"   ๐Ÿ“… Created: {product.created_at}")
    if product.last_refreshed:
        print(f"   ๐Ÿ”„ Last refresh: {product.last_refreshed}")
    print("---")

# Remove products from monitoring
api.remove_product_from_schedule("012345678901")
print("๐Ÿ—‘๏ธ  Removed from monitoring")

# Remove multiple products
api.remove_products_from_schedule(["012345678901", "B08N5WRWNW"])
print("๐Ÿ—‘๏ธ  Batch removal complete")
```

### ๐Ÿ“Š Usage & Analytics

```python
# Check your API usage
usage = api.get_usage()

print("๐Ÿ“Š API Usage Summary:")
print(f"๐Ÿ’ณ Plan: {usage.data.plan_name}")
print(f"โœ… Credits used: {usage.data.credits_used:,}")
print(f"๐Ÿ”‹ Credits remaining: {usage.data.credits_remaining:,}")
print(f"๐Ÿ“Š Total credits: {usage.data.credits_total:,}")
print(f"๐Ÿ“… Billing period: {usage.data.billing_period_start} to {usage.data.billing_period_end}")

# Calculate usage percentage
usage_percent = (usage.data.credits_used / usage.data.credits_total) * 100
print(f"๐Ÿ“ˆ Usage: {usage_percent:.1f}%")
```

---

## ๐Ÿ› ๏ธ Advanced Usage & Examples

### ๐Ÿ† Price Comparison Tool

```python
def find_best_deals(identifier: str, max_results: int = 5):
    """Find the best deals for a product across all retailers"""
    try:
        # Get product info
        product = api.get_product_details(identifier)
        print(f"๐Ÿ” Searching deals for: {product.data.name}")
        print(f"๐Ÿ“ฆ Brand: {product.data.brand}")
        print("=" * 50)
        
        # Get all current offers
        offers = api.get_current_offers(identifier)
        
        if not offers.data:
            print("โŒ No offers found")
            return
        
        # Filter and sort offers
        available_offers = [
            offer for offer in offers.data 
            if offer.availability == "in_stock"
        ]
        
        if not available_offers:
            print("โŒ No in-stock offers found")
            return
            
        # Sort by total cost (price + shipping)
        def total_cost(offer):
            return offer.price + (offer.shipping or 0)
        
        sorted_offers = sorted(available_offers, key=total_cost)[:max_results]
        
        print(f"๐Ÿ† Top {len(sorted_offers)} Deals:")
        for i, offer in enumerate(sorted_offers, 1):
            total = total_cost(offer)
            print(f"{i}. ๐Ÿช {offer.retailer}")
            print(f"   ๐Ÿ’ฐ Price: ${offer.price}")
            if offer.shipping:
                print(f"   ๐Ÿšš Shipping: ${offer.shipping}")
            print(f"   ๐Ÿ’ณ Total: ${total}")
            print(f"   ๐Ÿ“ฆ Condition: {offer.condition}")
            print(f"   ๐Ÿ”— Buy now: {offer.url}")
            print("---")
            
        # Calculate savings
        if len(sorted_offers) > 1:
            cheapest = total_cost(sorted_offers[0])
            most_expensive = total_cost(sorted_offers[-1])
            savings = most_expensive - cheapest
            print(f"๐Ÿ’ฐ Potential savings: ${savings:.2f}")
            
    except Exception as e:
        print(f"โŒ Error: {e}")

# Usage
find_best_deals("012345678901")
```

### ๐Ÿšจ Smart Price Alert System

```python
import time
from datetime import datetime

class PriceAlertBot:
    def __init__(self, api_client):
        self.api = api_client
        self.alerts = {}  # identifier -> target_price
    
    def add_alert(self, identifier: str, target_price: float):
        """Add a price alert for a product"""
        self.alerts[identifier] = target_price
        
        # Schedule monitoring
        self.api.schedule_product_monitoring(identifier, "daily")
        print(f"๐Ÿ”” Alert set: {identifier} @ ${target_price}")
    
    def check_alerts(self):
        """Check all price alerts"""
        print(f"๐Ÿ” Checking {len(self.alerts)} price alerts...")
        
        for identifier, target_price in self.alerts.items():
            try:
                offers = self.api.get_current_offers(identifier)
                if not offers.data:
                    continue
                
                # Find best available offer
                best_offer = min(
                    [o for o in offers.data if o.availability == "in_stock"],
                    key=lambda x: x.price,
                    default=None
                )
                
                if best_offer and best_offer.price <= target_price:
                    self.trigger_alert(identifier, best_offer, target_price)
                    
            except Exception as e:
                print(f"โŒ Error checking {identifier}: {e}")
    
    def trigger_alert(self, identifier: str, offer, target_price: float):
        """Trigger price alert notification"""
        product = self.api.get_product_details(identifier)
        
        print("๐Ÿšจ" * 10)
        print("๐Ÿ’ฐ PRICE ALERT TRIGGERED!")
        print(f"๐Ÿ“ฆ Product: {product.data.name}")
        print(f"๐ŸŽฏ Target: ${target_price}")
        print(f"๐Ÿ’ธ Current: ${offer.price} at {offer.retailer}")
        print(f"โœ… Savings: ${target_price - offer.price:.2f}")
        print(f"๐Ÿ”— Buy now: {offer.url}")
        print("๐Ÿšจ" * 10)
        
        # Remove alert after triggering
        del self.alerts[identifier]

# Usage
alert_bot = PriceAlertBot(api)
alert_bot.add_alert("012345678901", 199.99)
alert_bot.add_alert("B08N5WRWNW", 299.99)

# Run periodic checks
alert_bot.check_alerts()
```

### ๐Ÿ“Š Market Analysis Dashboard

```python
import statistics
from collections import defaultdict

def analyze_market_trends(identifiers: list, days: int = 30):
    """Comprehensive market analysis for multiple products"""
    from datetime import datetime, timedelta
    
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
    
    print(f"๐Ÿ“Š Market Analysis Report ({days} days)")
    print("=" * 50)
    
    for identifier in identifiers:
        try:
            # Get product info
            product = api.get_product_details(identifier)
            print(f"\\n๐Ÿ“ฆ {product.data.name}")
            print(f"๐Ÿท๏ธ  {product.data.brand} | {product.data.category}")
            print("-" * 40)
            
            # Get price history
            history = api.get_price_history(identifier, start_date, end_date)
            
            retailer_stats = {}
            
            for offer in history.data:
                if not offer.price_history:
                    continue
                    
                prices = [point.price for point in offer.price_history]
                
                retailer_stats[offer.retailer] = {
                    'current_price': offer.price,
                    'avg_price': statistics.mean(prices),
                    'min_price': min(prices),
                    'max_price': max(prices),
                    'volatility': statistics.stdev(prices) if len(prices) > 1 else 0,
                    'data_points': len(prices),
                    'trend': calculate_trend(prices)
                }
            
            # Display results
            if retailer_stats:
                print("๐Ÿช Retailer Analysis:")
                for retailer, stats in sorted(retailer_stats.items()):
                    print(f"  {retailer}:")
                    print(f"    ๐Ÿ’ฐ Current: ${stats['current_price']}")
                    print(f"    ๐Ÿ“Š Average: ${stats['avg_price']:.2f}")
                    print(f"    ๐Ÿ“‰ Min: ${stats['min_price']} | ๐Ÿ“ˆ Max: ${stats['max_price']}")
                    print(f"    ๐Ÿ“ˆ Trend: {stats['trend']}")
                    print(f"    ๐Ÿ“Š Data points: {stats['data_points']}")
                
                # Find best value
                best_retailer = min(retailer_stats.items(), key=lambda x: x[1]['current_price'])
                print(f"\\n๐Ÿ† Best Price: {best_retailer[0]} @ ${best_retailer[1]['current_price']}")
            else:
                print("โŒ No price history available")
                
        except Exception as e:
            print(f"โŒ Error analyzing {identifier}: {e}")

def calculate_trend(prices: list) -> str:
    """Calculate price trend direction"""
    if len(prices) < 2:
        return "Unknown"
    
    recent = prices[-7:]  # Last week
    older = prices[:-7]   # Everything else
    
    if not older:
        return "New"
    
    recent_avg = statistics.mean(recent)
    older_avg = statistics.mean(older)
    
    if recent_avg > older_avg * 1.05:  # 5% threshold
        return "๐Ÿ“ˆ Rising"
    elif recent_avg < older_avg * 0.95:
        return "๐Ÿ“‰ Falling"
    else:
        return "โžก๏ธ  Stable"

# Usage
products_to_analyze = [
    "012345678901",
    "B08N5WRWNW",
    "045496596439"
]

analyze_market_trends(products_to_analyze, days=60)
```

### ๐Ÿ”„ Bulk Product Management

```python
def bulk_product_manager(csv_file_path: str):
    """Manage products from CSV file"""
    import csv
    
    print("๐Ÿ“‚ Loading products from CSV...")
    
    products = []
    with open(csv_file_path, 'r') as file:
        reader = csv.DictReader(file)
        for row in reader:
            products.append({
                'identifier': row['identifier'],
                'target_price': float(row.get('target_price', 0)),
                'monitor': row.get('monitor', 'true').lower() == 'true'
            })
    
    print(f"๐Ÿ“Š Processing {len(products)} products...")
    
    # Batch lookup
    identifiers = [p['identifier'] for p in products]
    try:
        product_details = api.get_product_details_batch(identifiers)
        current_offers = api.get_current_offers_batch(identifiers)
        
        results = []
        
        for product, details in zip(products, product_details.data):
            offers = current_offers.data.get(product['identifier'], [])
            best_price = min([o.price for o in offers if o.availability == "in_stock"], default=None)
            
            result = {
                'identifier': product['identifier'],
                'name': details.name,
                'brand': details.brand,
                'target_price': product['target_price'],
                'current_best_price': best_price,
                'price_alert': best_price <= product['target_price'] if best_price else False,
                'offers_count': len(offers)
            }
            results.append(result)
            
            # Setup monitoring if requested
            if product['monitor']:
                api.schedule_product_monitoring(product['identifier'], "daily")
        
        # Generate report
        print("\\n๐Ÿ“Š Bulk Analysis Report:")
        print("=" * 80)
        for result in results:
            status = "๐Ÿšจ ALERT" if result['price_alert'] else "๐Ÿ“Š TRACKING"
            print(f"{status} | {result['name']} by {result['brand']}")
            print(f"    ๐ŸŽฏ Target: ${result['target_price']} | ๐Ÿ’ฐ Current: ${result['current_best_price'] or 'N/A'}")
            print(f"    ๐Ÿช Offers: {result['offers_count']}")
            print()
            
    except Exception as e:
        print(f"โŒ Error processing bulk products: {e}")

# Usage
# bulk_product_manager("my_products.csv")
```

### ๐ŸŒ Multi-Format Data Export

```python
def export_product_data(identifiers: list, format: str = "json"):
    """Export product data in various formats"""
    import json
    import csv
    from datetime import datetime
    
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    
    if format.lower() == "json":
        # Export as JSON
        products = api.get_product_details_batch(identifiers)
        offers = api.get_current_offers_batch(identifiers)
        
        export_data = {
            "exported_at": datetime.now().isoformat(),
            "products": []
        }
        
        for product in products.data:
            product_offers = offers.data.get(product.product_id, [])
            export_data["products"].append({
                "product": product.dict(),
                "offers": [offer.dict() for offer in product_offers]
            })
        
        filename = f"shopsavvy_export_{timestamp}.json"
        with open(filename, 'w') as f:
            json.dump(export_data, f, indent=2)
            
        print(f"โœ… Exported {len(products.data)} products to {filename}")
        
    elif format.lower() == "csv":
        # Export as CSV
        filename = f"shopsavvy_export_{timestamp}.csv"
        
        with open(filename, 'w', newline='') as csvfile:
            fieldnames = ['product_id', 'name', 'brand', 'category', 'barcode', 
                         'retailer', 'price', 'availability', 'condition', 'url']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            
            for identifier in identifiers:
                try:
                    product = api.get_product_details(identifier)
                    offers = api.get_current_offers(identifier)
                    
                    for offer in offers.data:
                        writer.writerow({
                            'product_id': product.data.product_id,
                            'name': product.data.name,
                            'brand': product.data.brand,
                            'category': product.data.category,
                            'barcode': product.data.barcode,
                            'retailer': offer.retailer,
                            'price': offer.price,
                            'availability': offer.availability,
                            'condition': offer.condition,
                            'url': offer.url
                        })
                except Exception as e:
                    print(f"โŒ Error exporting {identifier}: {e}")
        
        print(f"โœ… Exported data to {filename}")

# Usage
export_product_data(["012345678901", "B08N5WRWNW"], format="json")
export_product_data(["012345678901", "B08N5WRWNW"], format="csv")
```

---

## ๐Ÿ”ง Error Handling & Best Practices

### Comprehensive Error Handling

```python
from shopsavvy import (
    APIError, 
    AuthenticationError, 
    RateLimitError, 
    NotFoundError,
    ValidationError,
    TimeoutError,
    NetworkError
)

def robust_product_lookup(identifier: str):
    """Example of robust error handling"""
    try:
        product = api.get_product_details(identifier)
        offers = api.get_current_offers(identifier)
        
        print(f"โœ… Success: {product.data.name}")
        print(f"๐Ÿ’ฐ Found {len(offers.data)} offers")
        
        return product, offers
        
    except AuthenticationError:
        print("โŒ Authentication failed - check your API key")
        print("๐Ÿ”‘ Get your key at: https://shopsavvy.com/data/dashboard")
        
    except NotFoundError:
        print(f"โŒ Product not found: {identifier}")
        print("๐Ÿ’ก Try a different identifier (barcode, ASIN, URL)")
        
    except RateLimitError:
        print("โณ Rate limit exceeded - please slow down")
        print("๐Ÿ’ก Consider upgrading your plan for higher limits")
        time.sleep(60)  # Wait before retrying
        
    except ValidationError as e:
        print(f"โŒ Invalid request: {e}")
        print("๐Ÿ’ก Check your parameters and try again")
        
    except TimeoutError:
        print("โฑ๏ธ  Request timeout - API might be slow")
        print("๐Ÿ’ก Try increasing timeout or retry later")
        
    except NetworkError as e:
        print(f"๐ŸŒ Network error: {e}")
        print("๐Ÿ’ก Check your internet connection")
        
    except APIError as e:
        print(f"๐Ÿšจ API Error: {e}")
        print("๐Ÿ’ก This might be a temporary issue")
        
    return None, None

# Usage with retry logic
def lookup_with_retry(identifier: str, max_retries: int = 3):
    """Lookup with automatic retry on failures"""
    for attempt in range(max_retries):
        try:
            return api.get_product_details(identifier)
        except (TimeoutError, NetworkError) as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f"โณ Retry {attempt + 1}/{max_retries} in {wait_time}s...")
                time.sleep(wait_time)
            else:
                raise e
```

### Rate Limiting Best Practices

```python
import time
from functools import wraps

def rate_limit(calls_per_second: float = 10):
    """Decorator to rate limit function calls"""
    min_interval = 1.0 / calls_per_second
    last_called = [0.0]
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            elapsed = time.time() - last_called[0]
            left_to_wait = min_interval - elapsed
            if left_to_wait > 0:
                time.sleep(left_to_wait)
            ret = func(*args, **kwargs)
            last_called[0] = time.time()
            return ret
        return wrapper
    return decorator

# Rate-limited API calls
@rate_limit(calls_per_second=5)  # Max 5 calls per second
def safe_get_offers(identifier: str):
    return api.get_current_offers(identifier)

# Batch processing with rate limiting
def process_products_safely(identifiers: list):
    """Process products with automatic rate limiting"""
    results = []
    total = len(identifiers)
    
    for i, identifier in enumerate(identifiers, 1):
        print(f"๐Ÿ”„ Processing {i}/{total}: {identifier}")
        try:
            offers = safe_get_offers(identifier)
            results.append((identifier, offers))
            print(f"   โœ… Found {len(offers.data)} offers")
        except Exception as e:
            print(f"   โŒ Error: {e}")
            results.append((identifier, None))
    
    return results
```

### Configuration Management

```python
import os
from dataclasses import dataclass

@dataclass
class ShopSavvySettings:
    """Application settings"""
    api_key: str
    timeout: float = 30.0
    max_retries: int = 3
    rate_limit: float = 10.0  # calls per second
    
    @classmethod
    def from_env(cls):
        """Load settings from environment variables"""
        api_key = os.getenv("SHOPSAVVY_API_KEY")
        if not api_key:
            raise ValueError("SHOPSAVVY_API_KEY environment variable required")
        
        return cls(
            api_key=api_key,
            timeout=float(os.getenv("SHOPSAVVY_TIMEOUT", "30.0")),
            max_retries=int(os.getenv("SHOPSAVVY_MAX_RETRIES", "3")),
            rate_limit=float(os.getenv("SHOPSAVVY_RATE_LIMIT", "10.0"))
        )

# Usage
settings = ShopSavvySettings.from_env()
api = create_client(settings.api_key, timeout=settings.timeout)
```

---

## ๐Ÿงช Testing & Development

### Running Tests

```bash
# Install development dependencies
pip install -e ".[dev]"

# Run all tests
pytest

# Run with coverage
pytest --cov=shopsavvy

# Run specific test file
pytest tests/test_client.py

# Run with verbose output
pytest -v
```

### Code Quality

```bash
# Format code
black src tests

# Sort imports
isort src tests

# Type checking
mypy src

# Linting
flake8 src tests
```

### Example Test

```python
import pytest
from unittest.mock import Mock, patch
from shopsavvy import create_client, AuthenticationError

def test_client_creation():
    """Test client creation with valid API key"""
    api = create_client("ss_test_valid_key")
    assert api is not None

def test_invalid_api_key():
    """Test invalid API key handling"""
    with pytest.raises(ValueError):
        create_client("invalid_key_format")

@patch('shopsavvy.client.httpx.Client.request')
def test_product_lookup(mock_request):
    """Test product lookup with mocked response"""
    # Mock successful response
    mock_response = Mock()
    mock_response.status_code = 200
    mock_response.is_success = True
    mock_response.json.return_value = {
        "success": True,
        "data": {
            "product_id": "12345",
            "name": "Test Product",
            "brand": "Test Brand"
        }
    }
    mock_request.return_value = mock_response
    
    # Test the client
    api = create_client("ss_test_valid_key")
    product = api.get_product_details("012345678901")
    
    assert product.success is True
    assert product.data.name == "Test Product"
```

---

## ๐Ÿš€ Production Deployment

### Docker Setup

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt

# Copy application
COPY . .

# Set environment variables
ENV SHOPSAVVY_API_KEY="your_api_key_here"
ENV SHOPSAVVY_TIMEOUT="30.0"

# Run application
CMD ["python", "app.py"]
```

### AWS Lambda Example

```python
import json
import os
from shopsavvy import create_client

# Initialize client outside handler for connection reuse
api = create_client(os.environ['SHOPSAVVY_API_KEY'])

def lambda_handler(event, context):
    """AWS Lambda handler for product lookup"""
    try:
        identifier = event.get('identifier')
        if not identifier:
            return {
                'statusCode': 400,
                'body': json.dumps({'error': 'identifier required'})
            }
        
        # Get product data
        product = api.get_product_details(identifier)
        offers = api.get_current_offers(identifier)
        
        # Find best price
        best_offer = min(offers.data, key=lambda x: x.price) if offers.data else None
        
        response = {
            'product': {
                'name': product.data.name,
                'brand': product.data.brand,
                'category': product.data.category
            },
            'best_price': {
                'price': best_offer.price,
                'retailer': best_offer.retailer,
                'url': best_offer.url
            } if best_offer else None,
            'total_offers': len(offers.data)
        }
        
        return {
            'statusCode': 200,
            'body': json.dumps(response)
        }
        
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({'error': str(e)})
        }
```

### Environment Variables

```bash
# Required
export SHOPSAVVY_API_KEY="ss_live_your_api_key_here"

# Optional
export SHOPSAVVY_TIMEOUT="30.0"
export SHOPSAVVY_BASE_URL="https://api.shopsavvy.com/v1"
export SHOPSAVVY_MAX_RETRIES="3"
```

---

## ๐ŸŒŸ Real-World Use Cases

### ๐Ÿ›’ E-commerce Platform Integration

```python
class EcommerceIntegration:
    """Integration with e-commerce platforms"""
    
    def __init__(self, api_key: str):
        self.api = create_client(api_key)
    
    def enrich_product_catalog(self, product_skus: list):
        """Enrich existing product catalog with market data"""
        enriched_products = []
        
        for sku in product_skus:
            try:
                # Get competitive pricing
                offers = self.api.get_current_offers(sku)
                competitor_prices = [
                    offer.price for offer in offers.data 
                    if offer.retailer != "your-store"
                ]
                
                enrichment = {
                    'sku': sku,
                    'competitor_count': len(competitor_prices),
                    'min_competitor_price': min(competitor_prices) if competitor_prices else None,
                    'avg_competitor_price': sum(competitor_prices) / len(competitor_prices) if competitor_prices else None,
                    'price_position': self.calculate_price_position(sku, competitor_prices)
                }
                
                enriched_products.append(enrichment)
                
            except Exception as e:
                print(f"โŒ Error enriching {sku}: {e}")
        
        return enriched_products
    
    def calculate_price_position(self, sku: str, competitor_prices: list) -> str:
        """Calculate where your price stands vs competitors"""
        if not competitor_prices:
            return "no_competition"
        
        your_price = self.get_your_price(sku)  # Your implementation
        if not your_price:
            return "unknown"
        
        cheaper_count = sum(1 for price in competitor_prices if price < your_price)
        total_competitors = len(competitor_prices)
        
        if cheaper_count == 0:
            return "most_expensive"
        elif cheaper_count == total_competitors:
            return "cheapest"
        elif cheaper_count < total_competitors / 3:
            return "premium"
        elif cheaper_count > total_competitors * 2/3:
            return "budget"
        else:
            return "competitive"
```

### ๐Ÿข Business Intelligence Dashboard

```python
class BusinessIntelligenceDashboard:
    """BI dashboard for retail insights"""
    
    def __init__(self, api_key: str):
        self.api = create_client(api_key)
    
    def generate_market_report(self, category: str, time_period: int = 30):
        """Generate comprehensive market report"""
        from datetime import datetime, timedelta
        
        # Get category products (you'd have your own product database)
        category_products = self.get_category_products(category)
        
        report = {
            'category': category,
            'analysis_date': datetime.now().isoformat(),
            'time_period_days': time_period,
            'products_analyzed': len(category_products),
            'insights': {}
        }
        
        # Analyze each product
        price_trends = []
        retailer_coverage = defaultdict(int)
        availability_stats = defaultdict(int)
        
        for product_id in category_products:
            try:
                # Get current market state
                offers = self.api.get_current_offers(product_id)
                
                for offer in offers.data:
                    retailer_coverage[offer.retailer] += 1
                    availability_stats[offer.availability] += 1
                
                # Get price trends
                start_date = (datetime.now() - timedelta(days=time_period)).strftime("%Y-%m-%d")
                end_date = datetime.now().strftime("%Y-%m-%d")
                
                history = self.api.get_price_history(product_id, start_date, end_date)
                
                for offer_history in history.data:
                    if offer_history.price_history:
                        prices = [p.price for p in offer_history.price_history]
                        trend = self.calculate_trend_percentage(prices)
                        price_trends.append(trend)
                        
            except Exception as e:
                print(f"โŒ Error analyzing {product_id}: {e}")
        
        # Compile insights
        report['insights'] = {
            'avg_price_trend': sum(price_trends) / len(price_trends) if price_trends else 0,
            'top_retailers': dict(sorted(retailer_coverage.items(), key=lambda x: x[1], reverse=True)[:10]),
            'availability_breakdown': dict(availability_stats),
            'market_volatility': statistics.stdev(price_trends) if len(price_trends) > 1 else 0
        }
        
        return report
```

### ๐Ÿ“ฑ Mobile App Backend

```python
from flask import Flask, jsonify, request
from shopsavvy import create_client

app = Flask(__name__)
api = create_client(os.environ['SHOPSAVVY_API_KEY'])

@app.route('/api/product/scan', methods=['POST'])
def scan_product():
    """Handle barcode scans from mobile app"""
    data = request.get_json()
    barcode = data.get('barcode')
    
    if not barcode:
        return jsonify({'error': 'Barcode required'}), 400
    
    try:
        # Get product details
        product = api.get_product_details(barcode)
        
        # Get current offers
        offers = api.get_current_offers(barcode)
        
        # Find best deals
        available_offers = [o for o in offers.data if o.availability == "in_stock"]
        best_offer = min(available_offers, key=lambda x: x.price) if available_offers else None
        
        response = {
            'product': {
                'name': product.data.name,
                'brand': product.data.brand,
                'image_url': product.data.image_url,
                'category': product.data.category
            },
            'pricing': {
                'best_price': best_offer.price if best_offer else None,
                'best_retailer': best_offer.retailer if best_offer else None,
                'buy_url': best_offer.url if best_offer else None,
                'total_offers': len(available_offers),
                'all_offers': [
                    {
                        'retailer': offer.retailer,
                        'price': offer.price,
                        'availability': offer.availability,
                        'condition': offer.condition,
                        'url': offer.url
                    }
                    for offer in available_offers[:5]  # Top 5 offers
                ]
            }
        }
        
        return jsonify(response)
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/product/alerts', methods=['POST'])
def create_price_alert():
    """Create price alert for mobile users"""
    data = request.get_json()
    product_id = data.get('product_id')
    target_price = data.get('target_price')
    user_id = data.get('user_id')  # Your user system
    
    try:
        # Schedule monitoring
        result = api.schedule_product_monitoring(product_id, "daily")
        
        # Store alert in your database
        # store_price_alert(user_id, product_id, target_price)
        
        return jsonify({
            'success': True,
            'message': 'Price alert created successfully',
            'monitoring_active': result.data.get('scheduled', False)
        })
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)
```

---

## ๐Ÿค Contributing

We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

### Quick Contribution Guide

1. **Fork the repository**
2. **Create a feature branch**: `git checkout -b feature/amazing-feature`
3. **Make your changes** with tests
4. **Run the test suite**: `pytest`
5. **Submit a pull request**

---

## ๐Ÿ“š Additional Resources

| Resource | Link | Description |
|----------|------|-------------|
| ๐ŸŒ **API Documentation** | [shopsavvy.com/data/documentation](https://shopsavvy.com/data/documentation) | Complete API reference |
| ๐Ÿ“Š **Dashboard** | [shopsavvy.com/data/dashboard](https://shopsavvy.com/data/dashboard) | Manage your API keys and usage |
| ๐Ÿ’ฌ **Support** | [business@shopsavvy.com](mailto:business@shopsavvy.com) | Get help from our team |
| ๐Ÿ› **Issues** | [GitHub Issues](https://github.com/shopsavvy/sdk-python/issues) | Report bugs and request features |
| ๐Ÿ“ฆ **PyPI** | [pypi.org/project/shopsavvy-sdk](https://pypi.org/project/shopsavvy-sdk/) | Python package repository |
| ๐Ÿ“– **Changelog** | [GitHub Releases](https://github.com/shopsavvy/sdk-python/releases) | Version history and updates |

---

## ๐Ÿ“„ License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

## ๐Ÿข About ShopSavvy

**ShopSavvy** has been helping shoppers save money since 2008. With over **40 million downloads** and **millions of active users**, we're the most trusted name in price comparison and shopping intelligence.

Our **Data API** provides the same powerful product data and pricing intelligence that powers our consumer app, now available to developers and businesses worldwide.

### Why Choose ShopSavvy?

- โœ… **13+ Years** of e-commerce data expertise
- โœ… **Millions of Products** across thousands of retailers
- โœ… **Real-Time Data** updated continuously
- โœ… **Enterprise Scale** trusted by major brands
- โœ… **Developer Friendly** with comprehensive tools and support

---

**๐Ÿš€ Ready to get started?** [Get your API key](https://shopsavvy.com/data) and start building amazing e-commerce applications today!

**๐Ÿ’ฌ Need help?** Contact us at [business@shopsavvy.com](mailto:business@shopsavvy.com) or visit [shopsavvy.com/data](https://shopsavvy.com/data) for more information.

---

<div align="center">

**Made with โค๏ธ by the ShopSavvy Team**

[Website](https://shopsavvy.com) โ€ข [API Docs](https://shopsavvy.com/data/documentation) โ€ข [Dashboard](https://shopsavvy.com/data/dashboard) โ€ข [Support](mailto:business@shopsavvy.com)

</div>

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "shopsavvy-sdk",
    "maintainer": "ShopSavvy by Monolith Technologies, Inc.",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "shopsavvy, product-data, pricing, e-commerce, shopping, price-comparison, retail, api-client, python",
    "author": "ShopSavvy by Monolith Technologies, Inc.",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/31/1e/59717cc7a453f6b26353ad85ac935da1e8302baba9ee5dd4650fa962684a/shopsavvy_sdk-1.0.2.tar.gz",
    "platform": null,
    "description": "# \ud83d\udecd\ufe0f ShopSavvy Data API - Python SDK\n\n[![PyPI version](https://badge.fury.io/py/shopsavvy-sdk.svg)](https://badge.fury.io/py/shopsavvy-sdk)\n[![Python Support](https://img.shields.io/pypi/pyversions/shopsavvy-sdk.svg)](https://pypi.org/project/shopsavvy-sdk/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Downloads](https://pepy.tech/badge/shopsavvy-sdk)](https://pepy.tech/project/shopsavvy-sdk)\n\n**The most comprehensive Python SDK for e-commerce product data and pricing intelligence.** \n\nAccess real-time product information, pricing data, and historical trends across **thousands of retailers** and **millions of products** with the official [ShopSavvy Data API](https://shopsavvy.com/data).\n\n---\n\n## \ud83d\ude80 Quick Start\n\n### Installation\n\n```bash\npip install shopsavvy-sdk\n```\n\n### Get Your API Key\n\n1. \ud83c\udf1f Visit [shopsavvy.com/data](https://shopsavvy.com/data)\n2. \ud83d\udcdd Sign up for a free account\n3. \ud83d\udcb3 Choose a subscription plan\n4. \ud83d\udd11 Get your API key from the dashboard\n\n### 30-Second Example\n\n```python\nfrom shopsavvy import create_client\n\n# Initialize the client\napi = create_client(\"ss_live_your_api_key_here\")\n\n# Look up any product by barcode, ASIN, or URL\nproduct = api.get_product_details(\"012345678901\")\nprint(f\"\ud83d\udce6 {product.data.name} by {product.data.brand}\")\n\n# Get current prices from all retailers\noffers = api.get_current_offers(\"012345678901\")\ncheapest = min(offers.data, key=lambda x: x.price)\nprint(f\"\ud83d\udcb0 Best price: ${cheapest.price} at {cheapest.retailer}\")\n\n# Set up price monitoring\napi.schedule_product_monitoring(\"012345678901\", \"daily\")\nprint(\"\ud83d\udd14 Price alerts activated!\")\n```\n\n---\n\n## \ud83c\udfaf Key Features\n\n| Feature | Description | Use Cases |\n|---------|-------------|-----------|\n| \ud83d\udd0d **Universal Product Lookup** | Search by barcode, ASIN, URL, model number | Product catalogs, inventory management |\n| \ud83d\udcb2 **Real-Time Pricing** | Current prices across major retailers | Price comparison, competitive analysis |\n| \ud83d\udcc8 **Historical Data** | Price trends and availability over time | Market research, pricing strategy |\n| \ud83d\udd14 **Smart Monitoring** | Automated price tracking and alerts | Price drops, stock notifications |\n| \ud83c\udfea **Multi-Retailer Support** | Amazon, Walmart, Target, Best Buy + more | Comprehensive market coverage |\n| \u26a1 **Batch Operations** | Process multiple products efficiently | Bulk analysis, data processing |\n| \ud83d\udee1\ufe0f **Type Safety** | Full Pydantic models with validation | Reliable data structures |\n| \ud83d\udcca **Multiple Formats** | JSON and CSV response options | Easy data integration |\n\n---\n\n## \ud83c\udfd7\ufe0f Installation & Setup\n\n### Basic Installation\n```bash\npip install shopsavvy-sdk\n```\n\n### Development Installation\n```bash\ngit clone https://github.com/shopsavvy/sdk-python\ncd sdk-python\npip install -e \".[dev]\"\n```\n\n### Environment Setup\n```bash\n# Optional: Store your API key securely\nexport SHOPSAVVY_API_KEY=\"ss_live_your_api_key_here\"\n```\n\n---\n\n## \ud83d\udcd6 Complete API Reference\n\n### \ud83d\udd27 Client Configuration\n\n#### Method 1: Simple Client Creation (Recommended)\n```python\nfrom shopsavvy import create_client\n\n# Basic setup\napi = create_client(\"ss_live_your_api_key_here\")\n\n# With custom timeout and base URL\napi = create_client(\n    api_key=\"ss_live_your_api_key_here\",\n    timeout=60.0,\n    base_url=\"https://api.shopsavvy.com/v1\"\n)\n```\n\n#### Method 2: Configuration Object\n```python\nfrom shopsavvy import ShopSavvyDataAPI, ShopSavvyConfig\n\nconfig = ShopSavvyConfig(\n    api_key=\"ss_live_your_api_key_here\",\n    timeout=45.0\n)\napi = ShopSavvyDataAPI(config)\n```\n\n#### Method 3: Context Manager (Auto-cleanup)\n```python\n# Automatically closes connections when done\nwith create_client(\"ss_live_your_api_key_here\") as api:\n    product = api.get_product_details(\"012345678901\")\n    print(product.data.name)\n# Connection automatically closed here\n```\n\n### \ud83d\udd0d Product Lookup\n\n#### Single Product Lookup\n```python\n# Search by barcode (UPC/EAN)\nproduct = api.get_product_details(\"012345678901\")\n\n# Search by Amazon ASIN\namazon_product = api.get_product_details(\"B08N5WRWNW\")\n\n# Search by product URL\nurl_product = api.get_product_details(\"https://www.amazon.com/dp/B08N5WRWNW\")\n\n# Search by model number\nmodel_product = api.get_product_details(\"iPhone-14-Pro\")\n\n# Access product information\nprint(f\"\ud83d\udce6 Product: {product.data.name}\")\nprint(f\"\ud83c\udff7\ufe0f Brand: {product.data.brand}\")\nprint(f\"\ud83d\udcc2 Category: {product.data.category}\")\nprint(f\"\ud83d\udd22 Product ID: {product.data.product_id}\")\nprint(f\"\ud83d\udcf7 Image: {product.data.image_url}\")\n```\n\n#### Batch Product Lookup\n```python\n# Look up multiple products at once\nidentifiers = [\n    \"012345678901\",           # Barcode\n    \"B08N5WRWNW\",            # Amazon ASIN\n    \"https://www.target.com/p/example\",  # URL\n    \"MODEL-ABC123\"            # Model number\n]\n\nproducts = api.get_product_details_batch(identifiers)\n\nfor product in products.data:\n    print(f\"\u2705 Found: {product.name} by {product.brand}\")\n    print(f\"   ID: {product.product_id}\")\n    print(f\"   Category: {product.category}\")\n    print(\"---\")\n```\n\n#### CSV Format Support\n```python\n# Get product data in CSV format for easy processing\nproduct_csv = api.get_product_details(\"012345678901\", format=\"csv\")\n\n# Process with pandas\nimport pandas as pd\nimport io\n\ndf = pd.read_csv(io.StringIO(product_csv.data))\nprint(df.head())\n```\n\n### \ud83d\udcb0 Current Pricing\n\n#### Get All Current Offers\n```python\n# Get prices from all retailers\noffers = api.get_current_offers(\"012345678901\")\n\nprint(f\"Found {len(offers.data)} offers:\")\nfor offer in offers.data:\n    print(f\"\ud83c\udfea {offer.retailer}: ${offer.price}\")\n    print(f\"   \ud83d\udce6 Condition: {offer.condition}\")\n    print(f\"   \u2705 Available: {offer.availability}\")\n    print(f\"   \ud83d\udd17 Buy: {offer.url}\")\n    if offer.shipping:\n        print(f\"   \ud83d\ude9a Shipping: ${offer.shipping}\")\n    print(\"---\")\n```\n\n#### Retailer-Specific Pricing\n```python\n# Get offers from specific retailers\namazon_offers = api.get_current_offers(\"012345678901\", retailer=\"amazon\")\nwalmart_offers = api.get_current_offers(\"012345678901\", retailer=\"walmart\")\ntarget_offers = api.get_current_offers(\"012345678901\", retailer=\"target\")\n\nprint(\"Amazon prices:\")\nfor offer in amazon_offers.data:\n    print(f\"  ${offer.price} - {offer.condition}\")\n```\n\n#### Batch Pricing\n```python\n# Get current offers for multiple products\nproducts = [\"012345678901\", \"B08N5WRWNW\", \"045496596439\"]\nbatch_offers = api.get_current_offers_batch(products)\n\nfor identifier, offers in batch_offers.data.items():\n    best_price = min(offers, key=lambda x: x.price) if offers else None\n    if best_price:\n        print(f\"{identifier}: Best price ${best_price.price} at {best_price.retailer}\")\n    else:\n        print(f\"{identifier}: No offers found\")\n```\n\n### \ud83d\udcc8 Price History & Trends\n\n#### Basic Price History\n```python\nfrom datetime import datetime, timedelta\n\n# Get 30 days of price history\nend_date = datetime.now().strftime(\"%Y-%m-%d\")\nstart_date = (datetime.now() - timedelta(days=30)).strftime(\"%Y-%m-%d\")\n\nhistory = api.get_price_history(\"012345678901\", start_date, end_date)\n\nfor offer in history.data:\n    print(f\"\ud83c\udfea {offer.retailer}:\")\n    print(f\"   \ud83d\udcb0 Current price: ${offer.price}\")\n    print(f\"   \ud83d\udcca Historical points: {len(offer.price_history)}\")\n    \n    if offer.price_history:\n        prices = [point.price for point in offer.price_history]\n        print(f\"   \ud83d\udcc9 Lowest: ${min(prices)}\")\n        print(f\"   \ud83d\udcc8 Highest: ${max(prices)}\")\n        print(f\"   \ud83d\udcca Average: ${sum(prices) / len(prices):.2f}\")\n    print(\"---\")\n```\n\n#### Retailer-Specific History\n```python\n# Get price history from Amazon only\namazon_history = api.get_price_history(\n    \"012345678901\", \n    \"2024-01-01\", \n    \"2024-01-31\",\n    retailer=\"amazon\"\n)\n\nfor offer in amazon_history.data:\n    print(f\"Amazon price trends for {offer.retailer}:\")\n    for point in offer.price_history[-10:]:  # Last 10 data points\n        print(f\"  {point.date}: ${point.price} ({point.availability})\")\n```\n\n### \ud83d\udd14 Product Monitoring & Alerts\n\n#### Schedule Single Product Monitoring\n```python\n# Monitor daily across all retailers\nresult = api.schedule_product_monitoring(\"012345678901\", \"daily\")\nif result.data.get(\"scheduled\"):\n    print(\"\u2705 Daily monitoring activated!\")\n\n# Monitor hourly at specific retailer\nresult = api.schedule_product_monitoring(\n    \"012345678901\", \n    \"hourly\", \n    retailer=\"amazon\"\n)\nprint(f\"Amazon monitoring: {result.data}\")\n```\n\n#### Batch Monitoring Setup\n```python\n# Schedule multiple products for monitoring\nproducts_to_monitor = [\n    \"012345678901\",\n    \"B08N5WRWNW\", \n    \"045496596439\"\n]\n\nbatch_result = api.schedule_product_monitoring_batch(products_to_monitor, \"daily\")\n\nfor item in batch_result.data:\n    if item.get('scheduled'):\n        print(f\"\u2705 Monitoring activated for {item['identifier']}\")\n    else:\n        print(f\"\u274c Failed to monitor {item['identifier']}\")\n```\n\n#### Manage Scheduled Products\n```python\n# View all monitored products\nscheduled = api.get_scheduled_products()\nprint(f\"\ud83d\udcca Currently monitoring {len(scheduled.data)} products:\")\n\nfor product in scheduled.data:\n    print(f\"\ud83d\udd14 {product.identifier}\")\n    print(f\"   \ud83d\udcc5 Frequency: {product.frequency}\")\n    print(f\"   \ud83c\udfea Retailer: {product.retailer or 'All retailers'}\")\n    print(f\"   \ud83d\udcc5 Created: {product.created_at}\")\n    if product.last_refreshed:\n        print(f\"   \ud83d\udd04 Last refresh: {product.last_refreshed}\")\n    print(\"---\")\n\n# Remove products from monitoring\napi.remove_product_from_schedule(\"012345678901\")\nprint(\"\ud83d\uddd1\ufe0f  Removed from monitoring\")\n\n# Remove multiple products\napi.remove_products_from_schedule([\"012345678901\", \"B08N5WRWNW\"])\nprint(\"\ud83d\uddd1\ufe0f  Batch removal complete\")\n```\n\n### \ud83d\udcca Usage & Analytics\n\n```python\n# Check your API usage\nusage = api.get_usage()\n\nprint(\"\ud83d\udcca API Usage Summary:\")\nprint(f\"\ud83d\udcb3 Plan: {usage.data.plan_name}\")\nprint(f\"\u2705 Credits used: {usage.data.credits_used:,}\")\nprint(f\"\ud83d\udd0b Credits remaining: {usage.data.credits_remaining:,}\")\nprint(f\"\ud83d\udcca Total credits: {usage.data.credits_total:,}\")\nprint(f\"\ud83d\udcc5 Billing period: {usage.data.billing_period_start} to {usage.data.billing_period_end}\")\n\n# Calculate usage percentage\nusage_percent = (usage.data.credits_used / usage.data.credits_total) * 100\nprint(f\"\ud83d\udcc8 Usage: {usage_percent:.1f}%\")\n```\n\n---\n\n## \ud83d\udee0\ufe0f Advanced Usage & Examples\n\n### \ud83c\udfc6 Price Comparison Tool\n\n```python\ndef find_best_deals(identifier: str, max_results: int = 5):\n    \"\"\"Find the best deals for a product across all retailers\"\"\"\n    try:\n        # Get product info\n        product = api.get_product_details(identifier)\n        print(f\"\ud83d\udd0d Searching deals for: {product.data.name}\")\n        print(f\"\ud83d\udce6 Brand: {product.data.brand}\")\n        print(\"=\" * 50)\n        \n        # Get all current offers\n        offers = api.get_current_offers(identifier)\n        \n        if not offers.data:\n            print(\"\u274c No offers found\")\n            return\n        \n        # Filter and sort offers\n        available_offers = [\n            offer for offer in offers.data \n            if offer.availability == \"in_stock\"\n        ]\n        \n        if not available_offers:\n            print(\"\u274c No in-stock offers found\")\n            return\n            \n        # Sort by total cost (price + shipping)\n        def total_cost(offer):\n            return offer.price + (offer.shipping or 0)\n        \n        sorted_offers = sorted(available_offers, key=total_cost)[:max_results]\n        \n        print(f\"\ud83c\udfc6 Top {len(sorted_offers)} Deals:\")\n        for i, offer in enumerate(sorted_offers, 1):\n            total = total_cost(offer)\n            print(f\"{i}. \ud83c\udfea {offer.retailer}\")\n            print(f\"   \ud83d\udcb0 Price: ${offer.price}\")\n            if offer.shipping:\n                print(f\"   \ud83d\ude9a Shipping: ${offer.shipping}\")\n            print(f\"   \ud83d\udcb3 Total: ${total}\")\n            print(f\"   \ud83d\udce6 Condition: {offer.condition}\")\n            print(f\"   \ud83d\udd17 Buy now: {offer.url}\")\n            print(\"---\")\n            \n        # Calculate savings\n        if len(sorted_offers) > 1:\n            cheapest = total_cost(sorted_offers[0])\n            most_expensive = total_cost(sorted_offers[-1])\n            savings = most_expensive - cheapest\n            print(f\"\ud83d\udcb0 Potential savings: ${savings:.2f}\")\n            \n    except Exception as e:\n        print(f\"\u274c Error: {e}\")\n\n# Usage\nfind_best_deals(\"012345678901\")\n```\n\n### \ud83d\udea8 Smart Price Alert System\n\n```python\nimport time\nfrom datetime import datetime\n\nclass PriceAlertBot:\n    def __init__(self, api_client):\n        self.api = api_client\n        self.alerts = {}  # identifier -> target_price\n    \n    def add_alert(self, identifier: str, target_price: float):\n        \"\"\"Add a price alert for a product\"\"\"\n        self.alerts[identifier] = target_price\n        \n        # Schedule monitoring\n        self.api.schedule_product_monitoring(identifier, \"daily\")\n        print(f\"\ud83d\udd14 Alert set: {identifier} @ ${target_price}\")\n    \n    def check_alerts(self):\n        \"\"\"Check all price alerts\"\"\"\n        print(f\"\ud83d\udd0d Checking {len(self.alerts)} price alerts...\")\n        \n        for identifier, target_price in self.alerts.items():\n            try:\n                offers = self.api.get_current_offers(identifier)\n                if not offers.data:\n                    continue\n                \n                # Find best available offer\n                best_offer = min(\n                    [o for o in offers.data if o.availability == \"in_stock\"],\n                    key=lambda x: x.price,\n                    default=None\n                )\n                \n                if best_offer and best_offer.price <= target_price:\n                    self.trigger_alert(identifier, best_offer, target_price)\n                    \n            except Exception as e:\n                print(f\"\u274c Error checking {identifier}: {e}\")\n    \n    def trigger_alert(self, identifier: str, offer, target_price: float):\n        \"\"\"Trigger price alert notification\"\"\"\n        product = self.api.get_product_details(identifier)\n        \n        print(\"\ud83d\udea8\" * 10)\n        print(\"\ud83d\udcb0 PRICE ALERT TRIGGERED!\")\n        print(f\"\ud83d\udce6 Product: {product.data.name}\")\n        print(f\"\ud83c\udfaf Target: ${target_price}\")\n        print(f\"\ud83d\udcb8 Current: ${offer.price} at {offer.retailer}\")\n        print(f\"\u2705 Savings: ${target_price - offer.price:.2f}\")\n        print(f\"\ud83d\udd17 Buy now: {offer.url}\")\n        print(\"\ud83d\udea8\" * 10)\n        \n        # Remove alert after triggering\n        del self.alerts[identifier]\n\n# Usage\nalert_bot = PriceAlertBot(api)\nalert_bot.add_alert(\"012345678901\", 199.99)\nalert_bot.add_alert(\"B08N5WRWNW\", 299.99)\n\n# Run periodic checks\nalert_bot.check_alerts()\n```\n\n### \ud83d\udcca Market Analysis Dashboard\n\n```python\nimport statistics\nfrom collections import defaultdict\n\ndef analyze_market_trends(identifiers: list, days: int = 30):\n    \"\"\"Comprehensive market analysis for multiple products\"\"\"\n    from datetime import datetime, timedelta\n    \n    end_date = datetime.now().strftime(\"%Y-%m-%d\")\n    start_date = (datetime.now() - timedelta(days=days)).strftime(\"%Y-%m-%d\")\n    \n    print(f\"\ud83d\udcca Market Analysis Report ({days} days)\")\n    print(\"=\" * 50)\n    \n    for identifier in identifiers:\n        try:\n            # Get product info\n            product = api.get_product_details(identifier)\n            print(f\"\\\\n\ud83d\udce6 {product.data.name}\")\n            print(f\"\ud83c\udff7\ufe0f  {product.data.brand} | {product.data.category}\")\n            print(\"-\" * 40)\n            \n            # Get price history\n            history = api.get_price_history(identifier, start_date, end_date)\n            \n            retailer_stats = {}\n            \n            for offer in history.data:\n                if not offer.price_history:\n                    continue\n                    \n                prices = [point.price for point in offer.price_history]\n                \n                retailer_stats[offer.retailer] = {\n                    'current_price': offer.price,\n                    'avg_price': statistics.mean(prices),\n                    'min_price': min(prices),\n                    'max_price': max(prices),\n                    'volatility': statistics.stdev(prices) if len(prices) > 1 else 0,\n                    'data_points': len(prices),\n                    'trend': calculate_trend(prices)\n                }\n            \n            # Display results\n            if retailer_stats:\n                print(\"\ud83c\udfea Retailer Analysis:\")\n                for retailer, stats in sorted(retailer_stats.items()):\n                    print(f\"  {retailer}:\")\n                    print(f\"    \ud83d\udcb0 Current: ${stats['current_price']}\")\n                    print(f\"    \ud83d\udcca Average: ${stats['avg_price']:.2f}\")\n                    print(f\"    \ud83d\udcc9 Min: ${stats['min_price']} | \ud83d\udcc8 Max: ${stats['max_price']}\")\n                    print(f\"    \ud83d\udcc8 Trend: {stats['trend']}\")\n                    print(f\"    \ud83d\udcca Data points: {stats['data_points']}\")\n                \n                # Find best value\n                best_retailer = min(retailer_stats.items(), key=lambda x: x[1]['current_price'])\n                print(f\"\\\\n\ud83c\udfc6 Best Price: {best_retailer[0]} @ ${best_retailer[1]['current_price']}\")\n            else:\n                print(\"\u274c No price history available\")\n                \n        except Exception as e:\n            print(f\"\u274c Error analyzing {identifier}: {e}\")\n\ndef calculate_trend(prices: list) -> str:\n    \"\"\"Calculate price trend direction\"\"\"\n    if len(prices) < 2:\n        return \"Unknown\"\n    \n    recent = prices[-7:]  # Last week\n    older = prices[:-7]   # Everything else\n    \n    if not older:\n        return \"New\"\n    \n    recent_avg = statistics.mean(recent)\n    older_avg = statistics.mean(older)\n    \n    if recent_avg > older_avg * 1.05:  # 5% threshold\n        return \"\ud83d\udcc8 Rising\"\n    elif recent_avg < older_avg * 0.95:\n        return \"\ud83d\udcc9 Falling\"\n    else:\n        return \"\u27a1\ufe0f  Stable\"\n\n# Usage\nproducts_to_analyze = [\n    \"012345678901\",\n    \"B08N5WRWNW\",\n    \"045496596439\"\n]\n\nanalyze_market_trends(products_to_analyze, days=60)\n```\n\n### \ud83d\udd04 Bulk Product Management\n\n```python\ndef bulk_product_manager(csv_file_path: str):\n    \"\"\"Manage products from CSV file\"\"\"\n    import csv\n    \n    print(\"\ud83d\udcc2 Loading products from CSV...\")\n    \n    products = []\n    with open(csv_file_path, 'r') as file:\n        reader = csv.DictReader(file)\n        for row in reader:\n            products.append({\n                'identifier': row['identifier'],\n                'target_price': float(row.get('target_price', 0)),\n                'monitor': row.get('monitor', 'true').lower() == 'true'\n            })\n    \n    print(f\"\ud83d\udcca Processing {len(products)} products...\")\n    \n    # Batch lookup\n    identifiers = [p['identifier'] for p in products]\n    try:\n        product_details = api.get_product_details_batch(identifiers)\n        current_offers = api.get_current_offers_batch(identifiers)\n        \n        results = []\n        \n        for product, details in zip(products, product_details.data):\n            offers = current_offers.data.get(product['identifier'], [])\n            best_price = min([o.price for o in offers if o.availability == \"in_stock\"], default=None)\n            \n            result = {\n                'identifier': product['identifier'],\n                'name': details.name,\n                'brand': details.brand,\n                'target_price': product['target_price'],\n                'current_best_price': best_price,\n                'price_alert': best_price <= product['target_price'] if best_price else False,\n                'offers_count': len(offers)\n            }\n            results.append(result)\n            \n            # Setup monitoring if requested\n            if product['monitor']:\n                api.schedule_product_monitoring(product['identifier'], \"daily\")\n        \n        # Generate report\n        print(\"\\\\n\ud83d\udcca Bulk Analysis Report:\")\n        print(\"=\" * 80)\n        for result in results:\n            status = \"\ud83d\udea8 ALERT\" if result['price_alert'] else \"\ud83d\udcca TRACKING\"\n            print(f\"{status} | {result['name']} by {result['brand']}\")\n            print(f\"    \ud83c\udfaf Target: ${result['target_price']} | \ud83d\udcb0 Current: ${result['current_best_price'] or 'N/A'}\")\n            print(f\"    \ud83c\udfea Offers: {result['offers_count']}\")\n            print()\n            \n    except Exception as e:\n        print(f\"\u274c Error processing bulk products: {e}\")\n\n# Usage\n# bulk_product_manager(\"my_products.csv\")\n```\n\n### \ud83c\udf10 Multi-Format Data Export\n\n```python\ndef export_product_data(identifiers: list, format: str = \"json\"):\n    \"\"\"Export product data in various formats\"\"\"\n    import json\n    import csv\n    from datetime import datetime\n    \n    timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n    \n    if format.lower() == \"json\":\n        # Export as JSON\n        products = api.get_product_details_batch(identifiers)\n        offers = api.get_current_offers_batch(identifiers)\n        \n        export_data = {\n            \"exported_at\": datetime.now().isoformat(),\n            \"products\": []\n        }\n        \n        for product in products.data:\n            product_offers = offers.data.get(product.product_id, [])\n            export_data[\"products\"].append({\n                \"product\": product.dict(),\n                \"offers\": [offer.dict() for offer in product_offers]\n            })\n        \n        filename = f\"shopsavvy_export_{timestamp}.json\"\n        with open(filename, 'w') as f:\n            json.dump(export_data, f, indent=2)\n            \n        print(f\"\u2705 Exported {len(products.data)} products to {filename}\")\n        \n    elif format.lower() == \"csv\":\n        # Export as CSV\n        filename = f\"shopsavvy_export_{timestamp}.csv\"\n        \n        with open(filename, 'w', newline='') as csvfile:\n            fieldnames = ['product_id', 'name', 'brand', 'category', 'barcode', \n                         'retailer', 'price', 'availability', 'condition', 'url']\n            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)\n            writer.writeheader()\n            \n            for identifier in identifiers:\n                try:\n                    product = api.get_product_details(identifier)\n                    offers = api.get_current_offers(identifier)\n                    \n                    for offer in offers.data:\n                        writer.writerow({\n                            'product_id': product.data.product_id,\n                            'name': product.data.name,\n                            'brand': product.data.brand,\n                            'category': product.data.category,\n                            'barcode': product.data.barcode,\n                            'retailer': offer.retailer,\n                            'price': offer.price,\n                            'availability': offer.availability,\n                            'condition': offer.condition,\n                            'url': offer.url\n                        })\n                except Exception as e:\n                    print(f\"\u274c Error exporting {identifier}: {e}\")\n        \n        print(f\"\u2705 Exported data to {filename}\")\n\n# Usage\nexport_product_data([\"012345678901\", \"B08N5WRWNW\"], format=\"json\")\nexport_product_data([\"012345678901\", \"B08N5WRWNW\"], format=\"csv\")\n```\n\n---\n\n## \ud83d\udd27 Error Handling & Best Practices\n\n### Comprehensive Error Handling\n\n```python\nfrom shopsavvy import (\n    APIError, \n    AuthenticationError, \n    RateLimitError, \n    NotFoundError,\n    ValidationError,\n    TimeoutError,\n    NetworkError\n)\n\ndef robust_product_lookup(identifier: str):\n    \"\"\"Example of robust error handling\"\"\"\n    try:\n        product = api.get_product_details(identifier)\n        offers = api.get_current_offers(identifier)\n        \n        print(f\"\u2705 Success: {product.data.name}\")\n        print(f\"\ud83d\udcb0 Found {len(offers.data)} offers\")\n        \n        return product, offers\n        \n    except AuthenticationError:\n        print(\"\u274c Authentication failed - check your API key\")\n        print(\"\ud83d\udd11 Get your key at: https://shopsavvy.com/data/dashboard\")\n        \n    except NotFoundError:\n        print(f\"\u274c Product not found: {identifier}\")\n        print(\"\ud83d\udca1 Try a different identifier (barcode, ASIN, URL)\")\n        \n    except RateLimitError:\n        print(\"\u23f3 Rate limit exceeded - please slow down\")\n        print(\"\ud83d\udca1 Consider upgrading your plan for higher limits\")\n        time.sleep(60)  # Wait before retrying\n        \n    except ValidationError as e:\n        print(f\"\u274c Invalid request: {e}\")\n        print(\"\ud83d\udca1 Check your parameters and try again\")\n        \n    except TimeoutError:\n        print(\"\u23f1\ufe0f  Request timeout - API might be slow\")\n        print(\"\ud83d\udca1 Try increasing timeout or retry later\")\n        \n    except NetworkError as e:\n        print(f\"\ud83c\udf10 Network error: {e}\")\n        print(\"\ud83d\udca1 Check your internet connection\")\n        \n    except APIError as e:\n        print(f\"\ud83d\udea8 API Error: {e}\")\n        print(\"\ud83d\udca1 This might be a temporary issue\")\n        \n    return None, None\n\n# Usage with retry logic\ndef lookup_with_retry(identifier: str, max_retries: int = 3):\n    \"\"\"Lookup with automatic retry on failures\"\"\"\n    for attempt in range(max_retries):\n        try:\n            return api.get_product_details(identifier)\n        except (TimeoutError, NetworkError) as e:\n            if attempt < max_retries - 1:\n                wait_time = 2 ** attempt  # Exponential backoff\n                print(f\"\u23f3 Retry {attempt + 1}/{max_retries} in {wait_time}s...\")\n                time.sleep(wait_time)\n            else:\n                raise e\n```\n\n### Rate Limiting Best Practices\n\n```python\nimport time\nfrom functools import wraps\n\ndef rate_limit(calls_per_second: float = 10):\n    \"\"\"Decorator to rate limit function calls\"\"\"\n    min_interval = 1.0 / calls_per_second\n    last_called = [0.0]\n    \n    def decorator(func):\n        @wraps(func)\n        def wrapper(*args, **kwargs):\n            elapsed = time.time() - last_called[0]\n            left_to_wait = min_interval - elapsed\n            if left_to_wait > 0:\n                time.sleep(left_to_wait)\n            ret = func(*args, **kwargs)\n            last_called[0] = time.time()\n            return ret\n        return wrapper\n    return decorator\n\n# Rate-limited API calls\n@rate_limit(calls_per_second=5)  # Max 5 calls per second\ndef safe_get_offers(identifier: str):\n    return api.get_current_offers(identifier)\n\n# Batch processing with rate limiting\ndef process_products_safely(identifiers: list):\n    \"\"\"Process products with automatic rate limiting\"\"\"\n    results = []\n    total = len(identifiers)\n    \n    for i, identifier in enumerate(identifiers, 1):\n        print(f\"\ud83d\udd04 Processing {i}/{total}: {identifier}\")\n        try:\n            offers = safe_get_offers(identifier)\n            results.append((identifier, offers))\n            print(f\"   \u2705 Found {len(offers.data)} offers\")\n        except Exception as e:\n            print(f\"   \u274c Error: {e}\")\n            results.append((identifier, None))\n    \n    return results\n```\n\n### Configuration Management\n\n```python\nimport os\nfrom dataclasses import dataclass\n\n@dataclass\nclass ShopSavvySettings:\n    \"\"\"Application settings\"\"\"\n    api_key: str\n    timeout: float = 30.0\n    max_retries: int = 3\n    rate_limit: float = 10.0  # calls per second\n    \n    @classmethod\n    def from_env(cls):\n        \"\"\"Load settings from environment variables\"\"\"\n        api_key = os.getenv(\"SHOPSAVVY_API_KEY\")\n        if not api_key:\n            raise ValueError(\"SHOPSAVVY_API_KEY environment variable required\")\n        \n        return cls(\n            api_key=api_key,\n            timeout=float(os.getenv(\"SHOPSAVVY_TIMEOUT\", \"30.0\")),\n            max_retries=int(os.getenv(\"SHOPSAVVY_MAX_RETRIES\", \"3\")),\n            rate_limit=float(os.getenv(\"SHOPSAVVY_RATE_LIMIT\", \"10.0\"))\n        )\n\n# Usage\nsettings = ShopSavvySettings.from_env()\napi = create_client(settings.api_key, timeout=settings.timeout)\n```\n\n---\n\n## \ud83e\uddea Testing & Development\n\n### Running Tests\n\n```bash\n# Install development dependencies\npip install -e \".[dev]\"\n\n# Run all tests\npytest\n\n# Run with coverage\npytest --cov=shopsavvy\n\n# Run specific test file\npytest tests/test_client.py\n\n# Run with verbose output\npytest -v\n```\n\n### Code Quality\n\n```bash\n# Format code\nblack src tests\n\n# Sort imports\nisort src tests\n\n# Type checking\nmypy src\n\n# Linting\nflake8 src tests\n```\n\n### Example Test\n\n```python\nimport pytest\nfrom unittest.mock import Mock, patch\nfrom shopsavvy import create_client, AuthenticationError\n\ndef test_client_creation():\n    \"\"\"Test client creation with valid API key\"\"\"\n    api = create_client(\"ss_test_valid_key\")\n    assert api is not None\n\ndef test_invalid_api_key():\n    \"\"\"Test invalid API key handling\"\"\"\n    with pytest.raises(ValueError):\n        create_client(\"invalid_key_format\")\n\n@patch('shopsavvy.client.httpx.Client.request')\ndef test_product_lookup(mock_request):\n    \"\"\"Test product lookup with mocked response\"\"\"\n    # Mock successful response\n    mock_response = Mock()\n    mock_response.status_code = 200\n    mock_response.is_success = True\n    mock_response.json.return_value = {\n        \"success\": True,\n        \"data\": {\n            \"product_id\": \"12345\",\n            \"name\": \"Test Product\",\n            \"brand\": \"Test Brand\"\n        }\n    }\n    mock_request.return_value = mock_response\n    \n    # Test the client\n    api = create_client(\"ss_test_valid_key\")\n    product = api.get_product_details(\"012345678901\")\n    \n    assert product.success is True\n    assert product.data.name == \"Test Product\"\n```\n\n---\n\n## \ud83d\ude80 Production Deployment\n\n### Docker Setup\n\n```dockerfile\nFROM python:3.11-slim\n\nWORKDIR /app\n\n# Install dependencies\nCOPY requirements.txt .\nRUN pip install -r requirements.txt\n\n# Copy application\nCOPY . .\n\n# Set environment variables\nENV SHOPSAVVY_API_KEY=\"your_api_key_here\"\nENV SHOPSAVVY_TIMEOUT=\"30.0\"\n\n# Run application\nCMD [\"python\", \"app.py\"]\n```\n\n### AWS Lambda Example\n\n```python\nimport json\nimport os\nfrom shopsavvy import create_client\n\n# Initialize client outside handler for connection reuse\napi = create_client(os.environ['SHOPSAVVY_API_KEY'])\n\ndef lambda_handler(event, context):\n    \"\"\"AWS Lambda handler for product lookup\"\"\"\n    try:\n        identifier = event.get('identifier')\n        if not identifier:\n            return {\n                'statusCode': 400,\n                'body': json.dumps({'error': 'identifier required'})\n            }\n        \n        # Get product data\n        product = api.get_product_details(identifier)\n        offers = api.get_current_offers(identifier)\n        \n        # Find best price\n        best_offer = min(offers.data, key=lambda x: x.price) if offers.data else None\n        \n        response = {\n            'product': {\n                'name': product.data.name,\n                'brand': product.data.brand,\n                'category': product.data.category\n            },\n            'best_price': {\n                'price': best_offer.price,\n                'retailer': best_offer.retailer,\n                'url': best_offer.url\n            } if best_offer else None,\n            'total_offers': len(offers.data)\n        }\n        \n        return {\n            'statusCode': 200,\n            'body': json.dumps(response)\n        }\n        \n    except Exception as e:\n        return {\n            'statusCode': 500,\n            'body': json.dumps({'error': str(e)})\n        }\n```\n\n### Environment Variables\n\n```bash\n# Required\nexport SHOPSAVVY_API_KEY=\"ss_live_your_api_key_here\"\n\n# Optional\nexport SHOPSAVVY_TIMEOUT=\"30.0\"\nexport SHOPSAVVY_BASE_URL=\"https://api.shopsavvy.com/v1\"\nexport SHOPSAVVY_MAX_RETRIES=\"3\"\n```\n\n---\n\n## \ud83c\udf1f Real-World Use Cases\n\n### \ud83d\uded2 E-commerce Platform Integration\n\n```python\nclass EcommerceIntegration:\n    \"\"\"Integration with e-commerce platforms\"\"\"\n    \n    def __init__(self, api_key: str):\n        self.api = create_client(api_key)\n    \n    def enrich_product_catalog(self, product_skus: list):\n        \"\"\"Enrich existing product catalog with market data\"\"\"\n        enriched_products = []\n        \n        for sku in product_skus:\n            try:\n                # Get competitive pricing\n                offers = self.api.get_current_offers(sku)\n                competitor_prices = [\n                    offer.price for offer in offers.data \n                    if offer.retailer != \"your-store\"\n                ]\n                \n                enrichment = {\n                    'sku': sku,\n                    'competitor_count': len(competitor_prices),\n                    'min_competitor_price': min(competitor_prices) if competitor_prices else None,\n                    'avg_competitor_price': sum(competitor_prices) / len(competitor_prices) if competitor_prices else None,\n                    'price_position': self.calculate_price_position(sku, competitor_prices)\n                }\n                \n                enriched_products.append(enrichment)\n                \n            except Exception as e:\n                print(f\"\u274c Error enriching {sku}: {e}\")\n        \n        return enriched_products\n    \n    def calculate_price_position(self, sku: str, competitor_prices: list) -> str:\n        \"\"\"Calculate where your price stands vs competitors\"\"\"\n        if not competitor_prices:\n            return \"no_competition\"\n        \n        your_price = self.get_your_price(sku)  # Your implementation\n        if not your_price:\n            return \"unknown\"\n        \n        cheaper_count = sum(1 for price in competitor_prices if price < your_price)\n        total_competitors = len(competitor_prices)\n        \n        if cheaper_count == 0:\n            return \"most_expensive\"\n        elif cheaper_count == total_competitors:\n            return \"cheapest\"\n        elif cheaper_count < total_competitors / 3:\n            return \"premium\"\n        elif cheaper_count > total_competitors * 2/3:\n            return \"budget\"\n        else:\n            return \"competitive\"\n```\n\n### \ud83c\udfe2 Business Intelligence Dashboard\n\n```python\nclass BusinessIntelligenceDashboard:\n    \"\"\"BI dashboard for retail insights\"\"\"\n    \n    def __init__(self, api_key: str):\n        self.api = create_client(api_key)\n    \n    def generate_market_report(self, category: str, time_period: int = 30):\n        \"\"\"Generate comprehensive market report\"\"\"\n        from datetime import datetime, timedelta\n        \n        # Get category products (you'd have your own product database)\n        category_products = self.get_category_products(category)\n        \n        report = {\n            'category': category,\n            'analysis_date': datetime.now().isoformat(),\n            'time_period_days': time_period,\n            'products_analyzed': len(category_products),\n            'insights': {}\n        }\n        \n        # Analyze each product\n        price_trends = []\n        retailer_coverage = defaultdict(int)\n        availability_stats = defaultdict(int)\n        \n        for product_id in category_products:\n            try:\n                # Get current market state\n                offers = self.api.get_current_offers(product_id)\n                \n                for offer in offers.data:\n                    retailer_coverage[offer.retailer] += 1\n                    availability_stats[offer.availability] += 1\n                \n                # Get price trends\n                start_date = (datetime.now() - timedelta(days=time_period)).strftime(\"%Y-%m-%d\")\n                end_date = datetime.now().strftime(\"%Y-%m-%d\")\n                \n                history = self.api.get_price_history(product_id, start_date, end_date)\n                \n                for offer_history in history.data:\n                    if offer_history.price_history:\n                        prices = [p.price for p in offer_history.price_history]\n                        trend = self.calculate_trend_percentage(prices)\n                        price_trends.append(trend)\n                        \n            except Exception as e:\n                print(f\"\u274c Error analyzing {product_id}: {e}\")\n        \n        # Compile insights\n        report['insights'] = {\n            'avg_price_trend': sum(price_trends) / len(price_trends) if price_trends else 0,\n            'top_retailers': dict(sorted(retailer_coverage.items(), key=lambda x: x[1], reverse=True)[:10]),\n            'availability_breakdown': dict(availability_stats),\n            'market_volatility': statistics.stdev(price_trends) if len(price_trends) > 1 else 0\n        }\n        \n        return report\n```\n\n### \ud83d\udcf1 Mobile App Backend\n\n```python\nfrom flask import Flask, jsonify, request\nfrom shopsavvy import create_client\n\napp = Flask(__name__)\napi = create_client(os.environ['SHOPSAVVY_API_KEY'])\n\n@app.route('/api/product/scan', methods=['POST'])\ndef scan_product():\n    \"\"\"Handle barcode scans from mobile app\"\"\"\n    data = request.get_json()\n    barcode = data.get('barcode')\n    \n    if not barcode:\n        return jsonify({'error': 'Barcode required'}), 400\n    \n    try:\n        # Get product details\n        product = api.get_product_details(barcode)\n        \n        # Get current offers\n        offers = api.get_current_offers(barcode)\n        \n        # Find best deals\n        available_offers = [o for o in offers.data if o.availability == \"in_stock\"]\n        best_offer = min(available_offers, key=lambda x: x.price) if available_offers else None\n        \n        response = {\n            'product': {\n                'name': product.data.name,\n                'brand': product.data.brand,\n                'image_url': product.data.image_url,\n                'category': product.data.category\n            },\n            'pricing': {\n                'best_price': best_offer.price if best_offer else None,\n                'best_retailer': best_offer.retailer if best_offer else None,\n                'buy_url': best_offer.url if best_offer else None,\n                'total_offers': len(available_offers),\n                'all_offers': [\n                    {\n                        'retailer': offer.retailer,\n                        'price': offer.price,\n                        'availability': offer.availability,\n                        'condition': offer.condition,\n                        'url': offer.url\n                    }\n                    for offer in available_offers[:5]  # Top 5 offers\n                ]\n            }\n        }\n        \n        return jsonify(response)\n        \n    except Exception as e:\n        return jsonify({'error': str(e)}), 500\n\n@app.route('/api/product/alerts', methods=['POST'])\ndef create_price_alert():\n    \"\"\"Create price alert for mobile users\"\"\"\n    data = request.get_json()\n    product_id = data.get('product_id')\n    target_price = data.get('target_price')\n    user_id = data.get('user_id')  # Your user system\n    \n    try:\n        # Schedule monitoring\n        result = api.schedule_product_monitoring(product_id, \"daily\")\n        \n        # Store alert in your database\n        # store_price_alert(user_id, product_id, target_price)\n        \n        return jsonify({\n            'success': True,\n            'message': 'Price alert created successfully',\n            'monitoring_active': result.data.get('scheduled', False)\n        })\n        \n    except Exception as e:\n        return jsonify({'error': str(e)}), 500\n\nif __name__ == '__main__':\n    app.run(debug=True)\n```\n\n---\n\n## \ud83e\udd1d Contributing\n\nWe welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n### Quick Contribution Guide\n\n1. **Fork the repository**\n2. **Create a feature branch**: `git checkout -b feature/amazing-feature`\n3. **Make your changes** with tests\n4. **Run the test suite**: `pytest`\n5. **Submit a pull request**\n\n---\n\n## \ud83d\udcda Additional Resources\n\n| Resource | Link | Description |\n|----------|------|-------------|\n| \ud83c\udf10 **API Documentation** | [shopsavvy.com/data/documentation](https://shopsavvy.com/data/documentation) | Complete API reference |\n| \ud83d\udcca **Dashboard** | [shopsavvy.com/data/dashboard](https://shopsavvy.com/data/dashboard) | Manage your API keys and usage |\n| \ud83d\udcac **Support** | [business@shopsavvy.com](mailto:business@shopsavvy.com) | Get help from our team |\n| \ud83d\udc1b **Issues** | [GitHub Issues](https://github.com/shopsavvy/sdk-python/issues) | Report bugs and request features |\n| \ud83d\udce6 **PyPI** | [pypi.org/project/shopsavvy-sdk](https://pypi.org/project/shopsavvy-sdk/) | Python package repository |\n| \ud83d\udcd6 **Changelog** | [GitHub Releases](https://github.com/shopsavvy/sdk-python/releases) | Version history and updates |\n\n---\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## \ud83c\udfe2 About ShopSavvy\n\n**ShopSavvy** has been helping shoppers save money since 2008. With over **40 million downloads** and **millions of active users**, we're the most trusted name in price comparison and shopping intelligence.\n\nOur **Data API** provides the same powerful product data and pricing intelligence that powers our consumer app, now available to developers and businesses worldwide.\n\n### Why Choose ShopSavvy?\n\n- \u2705 **13+ Years** of e-commerce data expertise\n- \u2705 **Millions of Products** across thousands of retailers\n- \u2705 **Real-Time Data** updated continuously\n- \u2705 **Enterprise Scale** trusted by major brands\n- \u2705 **Developer Friendly** with comprehensive tools and support\n\n---\n\n**\ud83d\ude80 Ready to get started?** [Get your API key](https://shopsavvy.com/data) and start building amazing e-commerce applications today!\n\n**\ud83d\udcac Need help?** Contact us at [business@shopsavvy.com](mailto:business@shopsavvy.com) or visit [shopsavvy.com/data](https://shopsavvy.com/data) for more information.\n\n---\n\n<div align=\"center\">\n\n**Made with \u2764\ufe0f by the ShopSavvy Team**\n\n[Website](https://shopsavvy.com) \u2022 [API Docs](https://shopsavvy.com/data/documentation) \u2022 [Dashboard](https://shopsavvy.com/data/dashboard) \u2022 [Support](mailto:business@shopsavvy.com)\n\n</div>\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Official Python SDK for ShopSavvy Data API - Access product data, pricing, and price history",
    "version": "1.0.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/shopsavvy/sdk-python/issues",
        "Documentation": "https://shopsavvy.com/data/documentation",
        "Homepage": "https://shopsavvy.com/data",
        "Repository": "https://github.com/shopsavvy/sdk-python"
    },
    "split_keywords": [
        "shopsavvy",
        " product-data",
        " pricing",
        " e-commerce",
        " shopping",
        " price-comparison",
        " retail",
        " api-client",
        " python"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4d093f5969da7e5e32a5961097c38fc9e1203a8825560e0fd61c6b7f0b4c2f25",
                "md5": "c1123181fe1e71040d9c87630a445746",
                "sha256": "877eac7eea0be1a35d783b51ae58511526bd9e23578d9441dfbbd12b3ac1de6d"
            },
            "downloads": -1,
            "filename": "shopsavvy_sdk-1.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c1123181fe1e71040d9c87630a445746",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 18778,
            "upload_time": "2025-07-30T07:49:24",
            "upload_time_iso_8601": "2025-07-30T07:49:24.849314Z",
            "url": "https://files.pythonhosted.org/packages/4d/09/3f5969da7e5e32a5961097c38fc9e1203a8825560e0fd61c6b7f0b4c2f25/shopsavvy_sdk-1.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "311e59717cc7a453f6b26353ad85ac935da1e8302baba9ee5dd4650fa962684a",
                "md5": "0a26b108db2e13cd3787c5e5c651c148",
                "sha256": "d2221d51e1c1d7c6e09caad529536f9905971eaba58c88d534359bc15323f6f8"
            },
            "downloads": -1,
            "filename": "shopsavvy_sdk-1.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "0a26b108db2e13cd3787c5e5c651c148",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 40293,
            "upload_time": "2025-07-30T07:49:26",
            "upload_time_iso_8601": "2025-07-30T07:49:26.301168Z",
            "url": "https://files.pythonhosted.org/packages/31/1e/59717cc7a453f6b26353ad85ac935da1e8302baba9ee5dd4650fa962684a/shopsavvy_sdk-1.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-30 07:49:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "shopsavvy",
    "github_project": "sdk-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "shopsavvy-sdk"
}
        
Elapsed time: 0.73565s