Skip to main content

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 (the Authorization value from OAuth callback)
  • store_token: Store-level access token (the access_token from 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 alongside order.id)
  • .raw property 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 exception
    • ZidAPIError — API returned an error response
      • ZidAuthenticationError — 401 Unauthorized
      • ZidAuthorizationError — 403 Forbidden
      • ZidNotFoundError — 404 Not Found
      • ZidValidationError — 400/422 Validation errors
      • ZidRateLimitError — 429 Too Many Requests
      • ZidServerError — 5xx Server errors
    • ZidConnectionError — Network failures
    • AuthError — Invalid auth configuration
    • TokenRefreshError — 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-After duration
  • Connection errors and timeouts

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

zid_client-0.1.0.tar.gz (121.8 kB view details)

Uploaded Source

Built Distribution

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

zid_client-0.1.0-py3-none-any.whl (108.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: zid_client-0.1.0.tar.gz
  • Upload date:
  • Size: 121.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for zid_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 30ba8247c0561c98920889d2023fdedc89f2ae70ce8ed86b88fefbbadec6175f
MD5 e229e71b1c12d66df1e93a0c3d737bcf
BLAKE2b-256 09d72ff8bfcd0eaaf6c807d27fc3d389ab08d21fb6b42ed97c48efe67b1f78b1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: zid_client-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 108.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for zid_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 85dfa714044b972d1c99affc2ff6ba43691132068d392b1192c063669097c3df
MD5 de207d21e23b76ec5b5256ee3596558d
BLAKE2b-256 1c682602741fba5850147bccf599823fcee5eaad8cb4b842784328431f2afe34

See more details on using hashes here.

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