Skip to main content

Python client library for Best Buy's Catalog and Commerce APIs

Project description

python-bestbuy

CI

A Python client library for Best Buy's APIs, providing synchronous and asynchronous HTTP clients for interacting with Best Buy's Catalog and Commerce services.

Features

  • Dual API Support: Full support for both the Catalog API (product information, categories, stores, recommendations) and Commerce API (orders, fulfillment, pricing)
  • Sync and Async Clients: Both synchronous and asynchronous clients for each API
  • Automatic Pagination: Built-in paginators for iterating over large result sets
  • Type Safety: Full Pydantic model validation for requests and responses
  • Session Management: Automatic session handling for Commerce API authentication
  • Payment Encryption: Built-in utilities for encrypting credit card data for guest orders
  • Sandbox Support: Easy switching between production and sandbox environments

Installation

pip install python-bestbuy

Or using uv:

uv add python-bestbuy

Requirements

  • Python 3.10+
  • httpx
  • pydantic-xml
  • cryptography

Usage

Catalog API

The Catalog API provides access to Best Buy's product catalog, categories, store locations, and product recommendations.

from bestbuy.clients.catalog import CatalogClient, AsyncCatalogClient

# Initialize the client
client = CatalogClient(api_key="your-api-key")

Products

# Get a single product by SKU
product = client.products.get(sku=6487435)
print(f"{product.name}: ${product.sale_price}")

# Get specific attributes only
product = client.products.get(sku=6487435, show=["name", "salePrice", "manufacturer"])

# Search for products
results = client.products.search(
    query="manufacturer=apple&salePrice<1000",
    show=["sku", "name", "salePrice"],
    sort="salePrice",
    sort_order="asc",
    page=1,
    page_size=10
)
for product in results.products:
    print(f"{product.sku}: {product.name}")

# List all products
results = client.products.list(page=1, page_size=10)

# Get warranties for a product
warranties = client.products.get_warranties(sku=6487435)

# Paginate through search results
for page in client.products.search_pages(query="onSale=true", page_size=100):
    for product in page.products:
        print(product.name)

# Iterate over individual products across all pages
for product in client.products.search_pages(query="onSale=true").items():
    print(product.name)

# Limit pagination to a maximum number of pages
for product in client.products.search_pages(query="onSale=true", max_pages=5).items():
    print(product.name)

Categories

# Get a single category
category = client.categories.get(category_id="abcat0100000")
print(f"{category.name}: {category.id}")

# Search for categories
results = client.categories.search(query="name=Laptops*")
for category in results.categories:
    print(category.name)

# List all categories
results = client.categories.list(page=1, page_size=10)

# Paginate through categories
for category in client.categories.search_pages().items():
    print(category.name)

Stores

# Get a single store by ID
store = client.stores.get(store_id=281)
print(f"{store.name}: {store.city}, {store.region}")

# Search for stores
results = client.stores.search(query="city=Minneapolis")
for store in results.stores:
    print(f"{store.store_id}: {store.name}")

# List all stores
results = client.stores.list(page=1, page_size=10)

# Find stores near a ZIP code
results = client.stores.search_by_area(postal_code="55401", distance=25)
for store in results.stores:
    print(f"{store.name} - {store.distance} miles")

# Find stores near coordinates
results = client.stores.search_by_area(lat=44.9778, lng=-93.2650, distance=10)

# Paginate through stores by area
for store in client.stores.search_by_area_pages(postal_code="55401").items():
    print(store.name)

Recommendations

# Get trending products
trending = client.recommendations.trending()
for product in trending.results:
    print(f"Trending: {product.name}")

# Get trending products in a specific category
trending = client.recommendations.trending(category_id="abcat0502000")

# Get most viewed products
most_viewed = client.recommendations.most_viewed()
for product in most_viewed.results:
    print(f"Most viewed: {product.name}")

# Get products also viewed with a specific product
also_viewed = client.recommendations.also_viewed(sku=6487435)
for product in also_viewed.results:
    print(f"Also viewed: {product.name}")

# Get products also bought with a specific product
also_bought = client.recommendations.also_bought(sku=6487435)

# Get products ultimately bought after viewing a product
ultimately_bought = client.recommendations.viewed_ultimately_bought(sku=6487435)

Async Catalog Client

import asyncio
from bestbuy.clients.catalog import AsyncCatalogClient

async def main():
    client = AsyncCatalogClient(api_key="your-api-key")

    # All operations are async
    product = await client.products.get(sku=6487435)
    print(product.name)

    # Async pagination
    async for product in client.products.search_pages(query="onSale=true").items():
        print(product.name)

asyncio.run(main())

Commerce API

The Commerce API provides access to Best Buy's order management, fulfillment options, pricing, and payment services.

from bestbuy.clients.commerce import CommerceClient, AsyncCommerceClient

# Initialize the client (sandbox mode by default)
client = CommerceClient(
    api_key="your-api-key",
    username="your-username",  # For registered orders
    password="your-password",
    sandbox=True  # Use sandbox environment
)

# Production mode
client = CommerceClient(
    api_key="your-api-key",
    sandbox=False
)

Authentication

Authentication is required for registered orders (orders charged to your company credit card).

# Using context manager (recommended)
with client.auth:
    # Session is automatically managed
    response = client.orders.submit_registered(order)
# Session is automatically logged out

# With explicit credentials
with client.auth(username="user", password="pass"):
    response = client.orders.submit_registered(order)

# Manual login/logout
client.auth.login()
try:
    response = client.orders.submit_registered(order)
finally:
    client.auth.logout()

Fulfillment Operations

# Check product availability
availability = client.fulfillment.check_availability(sku="5628900")
print(f"Shipping available: {availability.available_for_shipping}")
print(f"Pickup available: {availability.available_for_pickup}")
print(f"Delivery available: {availability.available_for_delivery}")
print(f"Max quantity: {availability.max_quantity}")

# Get shipping options
shipping = client.fulfillment.get_shipping_options(
    sku="5628900",
    address1="123 Main St",
    city="Minneapolis",
    state="MN",
    postalcode="55401"
)
for option in shipping.options:
    print(f"{option.name}: ${option.price} - Delivery by {option.expected_delivery_date}")

# Find stores with product availability
stores = client.fulfillment.find_stores(
    sku="5628900",
    zip_code="55401",
    store_count=5
)
for store in stores.stores:
    print(f"{store.name}: {store.availability_msg}")

# Get home delivery options (for large items)
delivery_options = client.fulfillment.get_delivery_options(
    sku="5628900",
    zip_code="55401"
)
for option in delivery_options.options:
    print(f"{option.delivery_date}: {option.start_time} - {option.end_time}")

# Get delivery services (installation, haul away, etc.)
services = client.fulfillment.get_delivery_services(
    sku="5628900",
    zip_code="55401"
)
for service in services.delivery_services:
    print(f"{service.service_display_name}: ${service.price}")

Pricing Operations

# Get unit price for a SKU
price = client.pricing.get_unit_price(sku="5628900")
print(f"Price: ${price.unit_price.value}")

# Get combined product service info (availability, price, shipping, stores)
product_info = client.pricing.get_product_service(
    sku="5628900",
    zip_code="55401"
)

Order Operations

from bestbuy.models.commerce import (
    OrderSubmitRegisteredRequest,
    OrderSubmitGuestRequest,
    OrderList,
    OrderItem,
    Fulfillment,
    AddressFulfillment,
    ShippingAddress,
    Tender,
)

# Create a registered order (requires authentication)
order = OrderSubmitRegisteredRequest(
    id="my-order-123",
    order_list=OrderList(
        id="list-1",
        items=[
            OrderItem(
                id="item-1",
                quantity=1,
                sku="5628900"
            )
        ]
    ),
    fulfillment=Fulfillment(
        address_fulfillment=AddressFulfillment(
            address=ShippingAddress(
                address1="123 Main St",
                city="Minneapolis",
                state="MN",
                postalcode="55401"
            ),
            shipping_option_key="1"  # From get_shipping_options
        )
    ),
    tender=Tender()
)

# Review order (get accurate tax calculation)
with client.auth:
    review_response = client.orders.review(order)
    print(f"Total: ${review_response.total}")

    # Submit the order
    submit_response = client.orders.submit_registered(order)
    print(f"Order ID: {submit_response.id_map}")

# Query an existing order (no auth required)
order_details = client.orders.query(
    order_id="BBY01-123456789",
    last_name="Smith",
    phone_number="6125551234"
)
print(f"Status: {order_details.status}")

# Lookup order by ID (requires auth)
with client.auth:
    order_details = client.orders.lookup(order_id="BBY01-123456789")

Guest Orders

Guest orders are charged to the customer's credit card and require payment encryption.

from bestbuy.utils.encryption import create_encrypted_payment_token

# Get encryption key
encryption_key = client.encryption.get_encryption_key()

# Create encrypted payment token
payment_token = create_encrypted_payment_token(
    card_number="5424180279791773",
    base64_encoded_public_key=encryption_key.base64_encoded_public_key_bytes,
    terminal_id=encryption_key.terminal_id,
    track_id=encryption_key.track_id,
    key_id=encryption_key.key_id
)

# Create guest order with encrypted payment
guest_order = OrderSubmitGuestRequest(
    id="guest-order-123",
    order_list=OrderList(
        id="list-1",
        items=[
            OrderItem(id="item-1", quantity=1, sku="5628900")
        ]
    ),
    fulfillment=Fulfillment(
        address_fulfillment=AddressFulfillment(
            address=ShippingAddress(
                address1="123 Main St",
                city="Minneapolis",
                state="MN",
                postalcode="55401"
            ),
            shipping_option_key="1"
        )
    ),
    tender=Tender(
        # Include encrypted payment token in tender
    )
)

# Submit guest order (no auth required)
response = client.orders.submit_guest(guest_order)

Encryption Operations

# Get the public encryption key for guest orders
key_response = client.encryption.get_encryption_key()
print(f"Terminal ID: {key_response.terminal_id}")
print(f"Track ID: {key_response.track_id}")
print(f"Key ID: {key_response.key_id}")

Async Commerce Client

import asyncio
from bestbuy.clients.commerce import AsyncCommerceClient

async def main():
    client = AsyncCommerceClient(
        api_key="your-api-key",
        username="your-username",
        password="your-password"
    )

    # Check availability
    availability = await client.fulfillment.check_availability(sku="5628900")
    print(availability.available_for_shipping)

    # Async authentication context
    async with client.auth:
        response = await client.orders.submit_registered(order)

asyncio.run(main())

Configuration Options

Catalog Client Options

Option Type Default Description
api_key str Required Best Buy API key
base_url str https://api.bestbuy.com API base URL
timeout_ms int 30000 Request timeout in milliseconds
log_level int logging.WARNING Logging level

Commerce Client Options

Option Type Default Description
api_key str Required Best Buy API key
username str None Billing account username
password str None Billing account password
partner_id str None Partner ID for orders
sandbox bool True Use sandbox environment
auto_logout bool True Auto-logout on session end
base_url str Auto API base URL (auto-set based on sandbox)
timeout_ms int 30000 Request timeout in milliseconds
log_level int logging.WARNING Logging level

Error Handling

from bestbuy.exceptions import APIError, ConfigError, SessionRequiredError

try:
    product = client.products.get(sku=999999999)
except APIError as e:
    print(f"API Error: {e.message}")
    print(f"Error Code: {e.code}")
    print(f"Response: {e.response_text}")
except ConfigError as e:
    print(f"Configuration Error: {e}")

# Commerce API specific
try:
    client.orders.submit_registered(order)  # Without authentication
except SessionRequiredError as e:
    print("Must be logged in to submit orders")

Sandbox Testing

For the Commerce API, use the sandbox environment for testing:

client = CommerceClient(
    api_key="your-sandbox-api-key",
    sandbox=True  # Default
)

# Test credit card for sandbox
# Card Number: 5424180279791773
# Expiration: 12/2025
# CVV: 999

Development

Running Tests

uv run pytest

Running Type Checks

uv run mypy

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_bestbuy-0.1.0.tar.gz (33.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_bestbuy-0.1.0-py3-none-any.whl (39.1 kB view details)

Uploaded Python 3

File details

Details for the file python_bestbuy-0.1.0.tar.gz.

File metadata

  • Download URL: python_bestbuy-0.1.0.tar.gz
  • Upload date:
  • Size: 33.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_bestbuy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9b9dedefc1bb4cc47be24116b4c39ec9edaced527c9f6b104c68a3b0b1c99a2f
MD5 949613aba14013c0c2508fd0b19046d4
BLAKE2b-256 3abfc06537459e19761b0ec6eec31a60e5ea04b6e50e1842dac4d765a1e8fb6e

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_bestbuy-0.1.0.tar.gz:

Publisher: ci.yml on bbify/python-bestbuy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_bestbuy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: python_bestbuy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_bestbuy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8313a7ed4ed11fc2c501f0f8a3e8cd67a310cd358d345c9d6b275e949b2749b
MD5 b9efa78b8fc1936f65aa0364ff63d833
BLAKE2b-256 c310ed6608010f6b5a9de134453d7f76c5eae18881960cd598403f6f84e2a2dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_bestbuy-0.1.0-py3-none-any.whl:

Publisher: ci.yml on bbify/python-bestbuy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page