Python library for Printify API
Project description
Printify Python Library
A Python library for interacting with the Printify REST API. This library provides an intuitive, easy-to-use interface for managing Printify shops, products, orders, and shipping calculations.
Features
- 🛍️ Shop Management: Initialize shops by ID or name
- 📦 Product Operations: Retrieve and filter products with structured data models
- 🚚 Shipping Calculations: Calculate accurate shipping costs for any destination
- 📋 Order Creation: Programmatically create orders with validation
- 🔄 Automatic Retries: Built-in retry logic with exponential backoff
- 💾 Optional Caching: Reduce API calls with configurable TTL caching
- 🔒 Type Safety: Full type hints for better IDE support
- ⚡ Concurrent Requests: Parallel API calls for improved performance
Installation
Install the library using pip:
pip install printify-client
For development:
pip install printify-client[dev]
Quick Start
Initialize a Shop
from printify_client import Shop
# Using shop ID
shop = Shop(shop_id="12345", api_key="your_api_key")
# Using shop name (library will lookup the ID)
shop = Shop(shop_name="My Shop", api_key="your_api_key")
# Using environment variable for API key
import os
os.environ['PRINTIFY_API_KEY'] = 'your_api_key'
shop = Shop(shop_id="12345")
Retrieve Products
# Get all products
products = shop.get_products()
for product in products:
print(f"{product.title}: ${product.price_range[0]:.2f} - ${product.price_range[1]:.2f}")
print(f" Variants: {len(product.enabled_variants)}")
print(f" Default image: {product.default_image.src if product.default_image else 'None'}")
# Get a single product
product = shop.get_product("product_123")
print(f"Product: {product.title}")
# Filter products
tshirts = shop.filter_products(blueprint_id=3)
Calculate Shipping Costs
from printify_client import LineItem, Address
# Create line items
items = [
LineItem(product_id="prod_123", variant_id=456, quantity=2),
LineItem(product_id="prod_789", variant_id=101, quantity=1)
]
# Create shipping address
address = Address(
first_name="John",
last_name="Doe",
email="john@example.com",
country="US",
region="CA",
city="San Francisco",
zip_code="94102",
address1="123 Main St"
)
# Calculate shipping
shipping = shop.calculate_shipping(items, address)
print(f"Shipping cost: {shipping}") # e.g., "5.99 USD"
# View breakdown
for item in shipping.breakdown:
print(f" Product {item.product_id}: ${item.cost:.2f}")
Create an Order
from printify_client import LineItem, Address
# Create order
order = shop.create_order(
line_items=items,
shipping_address=address,
external_id="order_12345", # Your order ID
label="John Doe",
send_notification=True
)
print(f"Order created: {order.id}")
print(f"Status: {order.status}")
print(f"Created at: {order.created_at}")
Error Handling
The library provides specific exception types for different error scenarios:
from printify_client import (
Shop,
AuthenticationError,
NotFoundError,
APIError,
ValidationError,
ShippingCalculationError,
PrintifyTimeoutError
)
# Handle authentication errors
try:
shop = Shop(shop_id="12345", api_key="invalid_key")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
# Check your API key and ensure it's valid
# Handle not found errors
try:
product = shop.get_product("nonexistent_id")
except NotFoundError as e:
print(f"Resource not found: {e}")
print(f"Resource type: {e.resource_type}")
print(f"Identifier: {e.identifier}")
# Handle shipping calculation errors
try:
shipping = shop.calculate_shipping(items, address)
except ShippingCalculationError as e:
print(f"Shipping calculation failed: {e}")
# Check that products support shipping to the destination
# Handle API errors
try:
order = shop.create_order(items, address)
except APIError as e:
print(f"API error occurred: {e}")
print(f"Status code: {e.status_code}")
print(f"Response: {e.response}")
# Handle timeout errors
try:
products = shop.get_products()
except PrintifyTimeoutError as e:
print(f"Request timed out: {e}")
# Consider increasing timeout or retrying
# Handle validation errors
try:
shop = Shop() # Missing required parameters
except ValidationError as e:
print(f"Validation error: {e}")
Advanced Examples
Working with Product Variants
# Get a product and work with its variants
product = shop.get_product("prod_123")
# Get all enabled variants
for variant in product.enabled_variants:
print(f"{variant.title}: ${variant.price:.2f}")
# Get price range
min_price, max_price = product.price_range
print(f"Price range: ${min_price:.2f} - ${max_price:.2f}")
# Get a specific variant
variant = product.get_variant(variant_id=456)
if variant:
print(f"Found variant: {variant.title}")
# Get default image
if product.default_image:
print(f"Default image URL: {product.default_image.src}")
Filtering Products
# Filter by blueprint ID (product type)
tshirts = shop.filter_products(blueprint_id=3)
hoodies = shop.filter_products(blueprint_id=6)
# Filter by print provider
products_by_provider = shop.filter_products(print_provider_id=5)
# Filter by title (partial match)
custom_products = shop.filter_products(title="Custom")
# Combine with Python filtering for complex queries
affordable_tshirts = [
p for p in shop.filter_products(blueprint_id=3)
if p.price_range[0] < 20
]
Batch Order Processing
from printify_client import Shop, LineItem, Address
shop = Shop(shop_id="12345", api_key="your_api_key")
# Process multiple orders
orders_to_create = [
{
"items": [LineItem(product_id="prod_123", variant_id=456, quantity=1)],
"address": Address(
first_name="John",
last_name="Doe",
email="john@example.com",
country="US",
region="CA",
city="San Francisco",
zip_code="94102",
address1="123 Main St"
),
"external_id": "order_001"
},
# ... more orders
]
created_orders = []
for order_data in orders_to_create:
try:
order = shop.create_order(
line_items=order_data["items"],
shipping_address=order_data["address"],
external_id=order_data["external_id"]
)
created_orders.append(order)
print(f"Created order {order.id} for {order_data['external_id']}")
except Exception as e:
print(f"Failed to create order {order_data['external_id']}: {e}")
Calculating Shipping for Multiple Destinations
# Calculate shipping to different countries
destinations = [
Address(first_name="John", last_name="Doe", email="john@example.com",
country="US", region="CA", city="Los Angeles",
zip_code="90001", address1="123 Main St"),
Address(first_name="Jane", last_name="Smith", email="jane@example.com",
country="GB", region="England", city="London",
zip_code="SW1A 1AA", address1="10 Downing St"),
Address(first_name="Bob", last_name="Johnson", email="bob@example.com",
country="CA", region="ON", city="Toronto",
zip_code="M5H 2N2", address1="100 Queen St"),
]
items = [LineItem(product_id="prod_123", variant_id=456, quantity=2)]
for address in destinations:
try:
shipping = shop.calculate_shipping(items, address)
print(f"Shipping to {address.country}: {shipping}")
# View per-item breakdown
for item in shipping.breakdown:
print(f" Item {item.product_id}: ${item.cost:.2f}")
except ShippingCalculationError as e:
print(f"Cannot ship to {address.country}: {e}")
Using Cache Effectively
# Initialize with custom cache settings
shop = Shop(
shop_id="12345",
api_key="your_api_key",
enable_cache=True,
cache_ttl=3600 # 1 hour
)
# First call - fetches from API
products = shop.get_products() # API call made
# Second call - returns cached data
products = shop.get_products() # No API call, returns cached data
# Clear cache when you need fresh data
shop.clear_cache()
products = shop.get_products() # API call made again
# Disable caching entirely
shop_no_cache = Shop(
shop_id="12345",
api_key="your_api_key",
enable_cache=False
)
Shop Information
# Get shop details
shop = Shop(shop_id="12345", api_key="your_api_key")
info = shop.get_info()
print(f"Shop ID: {info.id}")
print(f"Shop Name: {info.title}")
print(f"Sales Channel: {info.sales_channel}")
Configuration
Environment Variables
The library supports configuration through environment variables:
| Variable | Description | Default | Required |
|---|---|---|---|
PRINTIFY_API_KEY |
Your Printify API key | None | Yes (if not provided to constructor) |
Setting environment variables:
# Linux/macOS
export PRINTIFY_API_KEY="your_api_key_here"
# Windows (Command Prompt)
set PRINTIFY_API_KEY=your_api_key_here
# Windows (PowerShell)
$env:PRINTIFY_API_KEY="your_api_key_here"
# Python
import os
os.environ['PRINTIFY_API_KEY'] = 'your_api_key_here'
Getting your API key:
- Log in to your Printify account
- Go to Connections > API
- Generate a new API token
- Copy the token and use it as your
PRINTIFY_API_KEY
Programmatic Configuration
You can configure the library when creating a Shop instance:
shop = Shop(
shop_id="12345",
api_key="your_key", # Override environment variable
enable_cache=True, # Enable caching (default: True)
cache_ttl=3600 # Cache TTL in seconds (default: 7200)
)
# Clear cache manually when needed
shop.clear_cache()
Configuration options:
enable_cache(bool): Enable/disable response caching. Caching improves performance by reducing API calls.cache_ttl(int): Time-to-live for cached data in seconds. Default is 7200 (2 hours).
Troubleshooting
Common Issues
Authentication Errors
Problem: AuthenticationError: Invalid API key
Solutions:
- Verify your API key is correct
- Check that the API key hasn't expired
- Ensure the API key has the necessary permissions
- Make sure there are no extra spaces or characters in the key
# Test your API key
try:
shop = Shop(shop_id="12345", api_key="your_api_key")
info = shop.get_info()
print(f"Successfully connected to shop: {info.title}")
except AuthenticationError:
print("API key is invalid or expired")
Shop Not Found
Problem: NotFoundError: Shop not found
Solutions:
- Verify the shop ID is correct
- Check that the shop name matches exactly (case-insensitive)
- Ensure your API key has access to the shop
# List all accessible shops
from printify_client.client import APIClient
client = APIClient(api_key="your_api_key")
shops = client.get("/shops.json")
for shop in shops:
print(f"Shop ID: {shop['id']}, Name: {shop['title']}")
Shipping Calculation Errors
Problem: ShippingCalculationError: No shipping profile found
Solutions:
- Verify the product supports shipping to the destination country
- Check that the variant ID is correct and enabled
- Ensure the print provider ships to the destination
# Check if product ships to a country
product = shop.get_product("prod_123")
print(f"Product: {product.title}")
print(f"Blueprint ID: {product.blueprint_id}")
print(f"Print Provider: {product.print_provider_id}")
# Try calculating shipping with error handling
try:
shipping = shop.calculate_shipping(items, address)
print(f"Shipping: {shipping}")
except ShippingCalculationError as e:
print(f"Cannot calculate shipping: {e}")
print("This product may not ship to the specified destination")
Timeout Errors
Problem: PrintifyTimeoutError: Request timed out
Solutions:
- Check your internet connection
- The Printify API may be experiencing issues
- Try again after a short delay
import time
max_attempts = 3
for attempt in range(max_attempts):
try:
products = shop.get_products()
break
except PrintifyTimeoutError:
if attempt < max_attempts - 1:
print(f"Timeout, retrying in 5 seconds... (attempt {attempt + 1}/{max_attempts})")
time.sleep(5)
else:
print("Failed after multiple attempts")
raise
Rate Limiting
The library automatically handles rate limiting with exponential backoff. If you're still experiencing rate limit issues:
- Reduce the frequency of API calls
- Enable caching to minimize redundant requests
- Batch operations when possible
# Enable caching to reduce API calls
shop = Shop(
shop_id="12345",
api_key="your_api_key",
enable_cache=True,
cache_ttl=7200 # Cache for 2 hours
)
Debug Mode
To see detailed information about API requests and responses, you can enable logging:
import logging
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
# Now all API requests will be logged
shop = Shop(shop_id="12345", api_key="your_api_key")
products = shop.get_products()
API Reference
Shop Class
The main entry point for interacting with Printify. All operations start with creating a Shop instance.
Constructor
Shop(
shop_id: Optional[str] = None,
shop_name: Optional[str] = None,
api_key: Optional[str] = None,
enable_cache: bool = True,
cache_ttl: int = 7200
)
Parameters:
shop_id(str, optional): Printify shop IDshop_name(str, optional): Shop name to lookup ID (alternative to shop_id)api_key(str, optional): Printify API key (defaults toPRINTIFY_API_KEYenv var)enable_cache(bool): Enable response caching (default: True)cache_ttl(int): Cache time-to-live in seconds (default: 7200)
Raises:
ValidationError: If neither shop_id nor shop_name provided, or if API key is missingAuthenticationError: If API key is invalidNotFoundError: If shop is not found
Methods
get_info() -> ShopInfo
Retrieve shop information and metadata.
Returns: ShopInfo object with shop details
Raises: NotFoundError, AuthenticationError, APIError
get_products(include_disabled: bool = False) -> List[Product]
Retrieve all products from the shop.
Parameters:
include_disabled(bool): If True, include products without enabled variants
Returns: List of Product objects
get_product(product_id: str) -> Product
Retrieve a single product by ID.
Parameters:
product_id(str): The product ID to retrieve
Returns: Product object
Raises: NotFoundError if product doesn't exist
filter_products(**filters) -> List[Product]
Filter products by attributes.
Parameters:
**filters: Keyword arguments for filtering (e.g.,title="Shirt",blueprint_id=3)
Returns: List of Product objects matching the filters
calculate_shipping(line_items: List[LineItem], address: Address) -> ShippingCost
Calculate shipping cost for items and destination.
Parameters:
line_items(List[LineItem]): List of items to shipaddress(Address): Destination address
Returns: ShippingCost object with total cost and breakdown
Raises: ShippingCalculationError, ValidationError
create_order(line_items: List[LineItem], shipping_address: Address, external_id: Optional[str] = None, label: Optional[str] = None, send_notification: bool = True) -> Order
Create an order in Printify.
Parameters:
line_items(List[LineItem]): List of items to include in the ordershipping_address(Address): Destination address for shippingexternal_id(str, optional): External order referencelabel(str, optional): Customer label or notesend_notification(bool): Whether to send order notification (default: True)
Returns: Order object with created order details
Raises: ValidationError, APIError, AuthenticationError
clear_cache() -> None
Clear all cached data for this shop.
Data Models
Product
Represents a Printify product with all its variants and images.
Attributes:
id(str): Product IDtitle(str): Product titledescription(str): Product descriptionblueprint_id(int): Blueprint ID (product type)print_provider_id(int): Print provider IDvariants(List[Variant]): List of product variantsimages(List[Image]): List of product images
Properties:
enabled_variants(List[Variant]): Returns only enabled variantsdefault_image(Optional[Image]): Returns the default product imageprice_range(Tuple[Decimal, Decimal]): Returns (min_price, max_price) for enabled variants
Methods:
get_variant(variant_id: int) -> Optional[Variant]: Get variant by ID
Variant
Represents a product variant (size/color combination).
Attributes:
id(int): Variant IDtitle(str): Variant title (e.g., "Small / Black")is_enabled(bool): Whether variant is availableprice(Decimal): Variant price in decimal format
Image
Represents a product image.
Attributes:
src(str): Image URLvariant_ids(List[int]): List of variant IDs this image applies toposition(str): Image positionis_default(bool): Whether this is the default image
Order
Represents a Printify order.
Attributes:
id(str): Order IDexternal_id(Optional[str]): External order referencestatus(str): Order statuscreated_at(datetime): Order creation timestampline_items(List[LineItem]): List of order itemsshipping_address(Address): Shipping address
Properties:
is_pending(bool): Returns True if order status is 'pending'
LineItem
Represents an item in an order or cart.
Attributes:
product_id(str): Product IDvariant_id(int): Variant IDquantity(int): Quantity
Methods:
to_dict() -> Dict: Convert to API request format
Address
Represents a shipping address.
Attributes:
first_name(str): First namelast_name(str): Last nameemail(str): Email addresscountry(str): Country code (e.g., "US")region(str): State/regioncity(str): Cityzip_code(str): Postal/ZIP codeaddress1(str): Address line 1address2(Optional[str]): Address line 2phone(Optional[str]): Phone number
Methods:
to_dict() -> Dict: Convert to API request format
ShippingCost
Represents calculated shipping cost.
Attributes:
cost(Decimal): Total shipping costcurrency(str): Currency code (e.g., "USD")breakdown(List[ShippingBreakdown]): Per-item cost breakdown
ShippingBreakdown
Shipping cost breakdown for a single product.
Attributes:
product_id(str): Product IDvariant_id(int): Variant IDquantity(int): Quantitycost(Decimal): Shipping cost for this item
ShopInfo
Represents shop information.
Attributes:
id(str): Shop IDtitle(str): Shop namesales_channel(Optional[str]): Sales channel information
Exceptions
All exceptions inherit from PrintifyError base class.
PrintifyError
Base exception for all Printify library errors.
AuthenticationError
Raised when API key is invalid or missing.
NotFoundError
Raised when a resource is not found (404).
Attributes:
resource_type(str): Type of resource not foundidentifier(str): Identifier used in lookup
APIError
Raised when API returns an error response.
Attributes:
status_code(int): HTTP status codemessage(str): Error messageresponse(Optional[Dict]): Full API response
ValidationError
Raised when input validation fails.
ShippingCalculationError
Raised when shipping cost calculation fails.
PrintifyTimeoutError
Raised when API request times out.
Requirements
- Python 3.8 or higher
- requests >= 2.31.0
- urllib3 >= 2.0.0
- python-dateutil >= 2.8.0
Development
Setup Development Environment
# Clone the repository
git clone https://github.com/printify/printify-client.git
cd printify-client
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
Run Tests
pytest
Code Formatting
# Format code
black printify tests
# Lint code
ruff check printify tests
# Type checking
mypy printify
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues and questions, please use the GitHub issue tracker.
Documentation
- Quick Reference Guide - Quick reference for common operations
- Comprehensive Examples - Detailed usage examples and patterns
- API Integration Guide - Printify API integration details
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file printify_client-0.2.0.tar.gz.
File metadata
- Download URL: printify_client-0.2.0.tar.gz
- Upload date:
- Size: 39.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ab80172d5d297f98419bc28a5cb1b961d6a099267da05d1a73670fac19fdee3
|
|
| MD5 |
2ac6afe9c3f74985b4b862617a65386a
|
|
| BLAKE2b-256 |
2bd92856e6cb964e18e0cd708372462a5740518e7c6c92f083db073cd265e529
|
Provenance
The following attestation bundles were made for printify_client-0.2.0.tar.gz:
Publisher:
publish.yml on aahlijia/printify-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
printify_client-0.2.0.tar.gz -
Subject digest:
9ab80172d5d297f98419bc28a5cb1b961d6a099267da05d1a73670fac19fdee3 - Sigstore transparency entry: 1695255508
- Sigstore integration time:
-
Permalink:
aahlijia/printify-client@2128ef5ae19712ef06cb94bb9efb39bc3a54084a -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/aahlijia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2128ef5ae19712ef06cb94bb9efb39bc3a54084a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file printify_client-0.2.0-py3-none-any.whl.
File metadata
- Download URL: printify_client-0.2.0-py3-none-any.whl
- Upload date:
- Size: 31.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d616bd7171f9ba68e97959ceceb4d197aa09ef8d01a59b59162c287d4d836108
|
|
| MD5 |
aefe81cec43007d38ccc8a15b0cc7ca0
|
|
| BLAKE2b-256 |
2642cbda527a804d2c731ce0e6c11962acc9012f0966bb5f440734709412e25d
|
Provenance
The following attestation bundles were made for printify_client-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on aahlijia/printify-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
printify_client-0.2.0-py3-none-any.whl -
Subject digest:
d616bd7171f9ba68e97959ceceb4d197aa09ef8d01a59b59162c287d4d836108 - Sigstore transparency entry: 1695255700
- Sigstore integration time:
-
Permalink:
aahlijia/printify-client@2128ef5ae19712ef06cb94bb9efb39bc3a54084a -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/aahlijia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2128ef5ae19712ef06cb94bb9efb39bc3a54084a -
Trigger Event:
workflow_dispatch
-
Statement type: