Official Python SDK for the Zid e-commerce platform API
Project description
Zid Python SDK
A Python client for the Zid e-commerce platform API.
Installation
pip install zid-client
Requires Python 3.10+.
Quick Start
from zid import ZidClient
# Initialize the client with your OAuth tokens
client = ZidClient(
authorization="your-partner-token",
store_token="store-access-token",
)
# List orders
for order in client.orders.list():
print(order.id, order.order_status.code)
# Get a specific customer
customer = client.customers.get(12345)
print(customer.name, customer.email)
Authentication
The SDK uses OAuth 2.0 tokens obtained through Zid's OAuth flow:
authorization: Your partner/app token (theAuthorizationvalue from OAuth callback)store_token: Store-level access token (theaccess_tokenfrom OAuth callback)
Basic Setup
client = ZidClient(
authorization="abc123...",
store_token="xyz789...",
)
With Automatic Token Refresh
Configure the client to automatically refresh expired tokens:
def save_tokens(auth):
"""Persist new tokens to your database."""
db.update_tokens(
store_token=auth.store_token,
refresh_token=auth.refresh_token,
authorization=auth.authorization,
)
client = ZidClient(
authorization="abc123...",
store_token="xyz789...",
refresh_token="refresh-token",
client_id="48",
client_secret="your-secret",
redirect_uri="https://yourapp.com/callback",
on_tokens_refreshed=save_tokens,
)
When a request fails with 401, the SDK will automatically refresh tokens and retry.
Features
- 13 resources, 50+ typed Pydantic models with full IDE autocomplete
- Composable sub-resources (e.g.
client.products.images,client.products.variants) - Automatic pagination across cursor-based and offset/limit APIs
- Auto token refresh with a callback to persist new credentials
- Retry with exponential backoff, jitter, and rate limit handling
- Dict-style access on models (
order["id"]works alongsideorder.id) .rawproperty on every model to access undocumented API fields- Automatic camelCase ↔ snake_case field mapping
- Lazy resource initialization — resources are created on first access
Resources
Products
# List products
for product in client.products.list():
print(product.id, product.name)
# CRUD
product = client.products.get("product-uuid")
product = client.products.create(name="Wireless Headphones", price=257, sku="WH-1000XM5")
product = client.products.update("product-uuid", price=79.99)
client.products.delete("product-uuid")
# Sub-resources
images = client.products.images.list("product-uuid")
client.products.images.upload("product-uuid", image=("photo.jpg", b"...", "image/jpeg"), alt_text="Front view")
client.products.variants.create("product-uuid", variants=[{"sku": "WH-BLK", "price": 257, "attributes": [...]}])
stocks = client.products.stocks.list("product-uuid")
categories = client.products.categories.list()
notifications = client.products.notifications.list(product_id="product-uuid")
Orders
# List orders (paginated, filterable)
for order in client.orders.list():
print(order.id, order.order_status.code)
for order in client.orders.list(order_status="new", payload_type="default"):
print(order.id, order.products)
# Get, update status, credit notes
order = client.orders.get(12345)
client.orders.update_status(12345, order_status="preparing")
credit_notes = client.orders.list_credit_notes(12345)
# Create a draft order (requires customer, consignee, products, shipping, payment)
order = client.orders.create(
currency_code="SAR",
customer={"full_name": "John Doe", "mobile_country_code": "966", "mobile_number": "500000000"},
consignee={
"contact": {"full_name": "John Doe", "mobile_country_code": "966", "mobile_number": "500000000"},
"address": {"line_1": "King Fahd Road", "city_name": "Riyadh", "country_code": "SA"},
},
products=[{"sku": "PROD-SKU-123", "quantity": 1}],
shipping_method={"type": "delivery", "id": 432480},
payment_method={"id": 555224},
)
Customers
# List customers
for customer in client.customers.list():
print(customer.name, customer.email)
# Get a specific customer
customer = client.customers.get(12345)
Other Resources
| Resource | Accessor | Key Methods |
|---|---|---|
| Coupons | client.coupons |
list(), get(id), create(...), delete(id) |
| Locations | client.locations |
list(), get(id), create(...), update(...), update_stock(id, items) |
| Abandoned Carts | client.abandoned_carts |
list(), get(cart_uuid) |
| Reverse Orders | client.reverse_orders |
create(...), list_reasons(), refund(...), create_waybill(...) |
| Delivery Options | client.delivery_options |
list() |
| Payment Methods | client.payment_methods |
list() |
| Store Profile | client.stores |
get_profile(), get_vat_settings() |
| Geography | client.geography |
list_operating_countries(), list_all_countries(), list_cities(country_id) |
| Webhooks | client.webhooks |
list(), create(event, target_url, original_id), delete(original_id) |
| Bundle Offers | client.bundle_offers |
list() |
| Loyalty | client.loyalty |
get_status(), get_program(), get_customer_summary(customer_id), adjust_customer_points(...) |
All list methods return a PaginatedIterator. All resources have full docstrings — use your IDE's autocomplete or help() for parameter details.
Pagination
List methods return a PaginatedIterator that handles pagination automatically:
# Iterate through all pages transparently
for order in client.orders.list():
print(order.id)
# Get total count without iterating
orders = client.orders.list()
print(f"Total orders: {len(orders)}")
# Control page size
for order in client.orders.list(per_page=100):
print(order.id)
# Convenience methods
latest = client.orders.list(order_status="new").first()
top_5 = client.products.list().take(5)
all_customers = client.customers.list().to_list()
Error Handling
The SDK raises specific exceptions for different error types:
from zid import (
ZidError,
ZidAPIError,
ZidAuthenticationError,
ZidAuthorizationError,
ZidNotFoundError,
ZidValidationError,
ZidRateLimitError,
ZidServerError,
ZidConnectionError,
)
try:
customer = client.customers.get(99999)
except ZidNotFoundError:
print("Customer not found")
except ZidAuthenticationError as e:
print(f"Auth failed: {e.error_code}")
except ZidRateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except ZidValidationError as e:
print(f"Validation errors: {e.errors}")
except ZidAPIError as e:
print(f"API error {e.status_code}: {e.message}")
except ZidConnectionError:
print("Network error")
Exception Hierarchy
ZidError— Base exceptionZidAPIError— API returned an error responseZidAuthenticationError— 401 UnauthorizedZidAuthorizationError— 403 ForbiddenZidNotFoundError— 404 Not FoundZidValidationError— 400/422 Validation errorsZidRateLimitError— 429 Too Many RequestsZidServerError— 5xx Server errors
ZidConnectionError— Network failuresAuthError— Invalid auth configurationTokenRefreshError— Token refresh failed
Context Manager
Use the client as a context manager to ensure proper cleanup:
with ZidClient(authorization="...", store_token="...") as client:
orders = list(client.orders.list())
# Connection is automatically closed
Configuration
client = ZidClient(
authorization="...",
store_token="...",
base_url="https://api.zid.sa", # Default
timeout=30.0, # Request timeout in seconds
language="en", # Accept-Language header (en/ar)
auto_refresh=True, # Auto-refresh tokens on 401
)
Retry & Rate Limit Handling
The SDK automatically retries failed requests with exponential backoff:
from zid import ZidClient, RetryConfig
# Default behavior: 3 retries with exponential backoff
client = ZidClient(authorization="...", store_token="...")
# Custom retry configuration
client = ZidClient(
authorization="...",
store_token="...",
retry=RetryConfig(
max_retries=5, # Number of retry attempts
base_delay=0.5, # Initial delay (seconds)
max_delay=30.0, # Maximum delay between retries
retry_on_rate_limit=True, # Auto-wait on 429 responses
max_rate_limit_wait=120.0, # Max seconds to wait for rate limit
),
)
# Disable retries entirely
client = ZidClient(
authorization="...",
store_token="...",
retry=RetryConfig(max_retries=0),
)
The retry logic handles:
- Server errors (500, 502, 503, 504) with exponential backoff + jitter
- Rate limits (429) by waiting for the
Retry-Afterduration - Connection errors and timeouts
License
MIT
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 zid_client-0.1.2.tar.gz.
File metadata
- Download URL: zid_client-0.1.2.tar.gz
- Upload date:
- Size: 154.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26d1606e00bfe98adf2dd0e99eda04081548a9a4cce13a30044cc5f4964f4f54
|
|
| MD5 |
37f41333012de4d22476a470a60d9021
|
|
| BLAKE2b-256 |
41d469aa8642d105991cccd3031201a75cc5c68a993a7d599ee8a943017b5096
|
File details
Details for the file zid_client-0.1.2-py3-none-any.whl.
File metadata
- Download URL: zid_client-0.1.2-py3-none-any.whl
- Upload date:
- Size: 108.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5064794f3af5f4299025a5c52c540842b57c63feba2838fa0aeaf02c0456de5
|
|
| MD5 |
ea43279dd86269afc90804dafbcf79e7
|
|
| BLAKE2b-256 |
022739011e2e993f5ff252292ac3908b1a4042c1ce761c6d0ec23a3adabb98dc
|