# ๐๏ธ ShopSavvy Data API - Python SDK
[](https://badge.fury.io/py/shopsavvy-sdk)
[](https://pypi.org/project/shopsavvy-sdk/)
[](https://opensource.org/licenses/MIT)
[](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[](https://badge.fury.io/py/shopsavvy-sdk)\n[](https://pypi.org/project/shopsavvy-sdk/)\n[](https://opensource.org/licenses/MIT)\n[](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"
}