---
title: "Python API client | Customer&#x27;s Canvas Hub"
canonical: "https://customerscanvas.com/docs/hub/dev-center/api/clients/python-api-client/"
---

# Python API client

> Customer's Canvas provides separate Python API clients for each of its services. Each client is designed to interact with a specific API, ensuring modularity, ease of updates, and optimized dependencies.

## Available API Clients

| **API**             | **Description**           | **Installation Command**  |
|---------------------|---------------------------|---------------------------|
| **Asset Generator** | For generating assets (images, designs).  | `pip install aurigma-asset-generator-api-client` |
| **Asset Storage**   | For managing asset storage (upload, download, metadata). | `pip install aurigma-asset-storage-api-client` |
| **Asset Processor** | For processing assets (rendering, format conversion). | `pip install aurigma-asset-processor-api-client` |
| **BackOffice**      | For back-office operations (administration, settings, users). | `pip install aurigma-backoffice-api-client` |
| **Design Atoms**    | For working with Design Atoms (viewer, rendering). | `pip install aurigma-design-atoms-api-client` |
| **Storefront**      | For frontend integration (products, projects, storefront users). | `pip install aurigma-storefront-api-client` |

This tutorial demonstrates how to use the official Python client to interact with the API, covering essential operations like fetching build info, working with products, projects, and users.

## 1. Prerequisites

- **Python 3.9+**
- Required dependencies:
  ```bash
  pip install python-dateutil httpx pydantic typing-extensions requests
  ```
- Access to a cloud Customer's Canvas instance.

## 2. Installation and Setup

Install the client (e.g., supporting [Storefront API](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md)):

```bash
pip install aurigma-storefront-api-client
```

To maintain a clean structure, use the following imports to access the necessary API clients, models (DTOs), and exception handling:

```python
from typing import List, Optional, Dict, Any

# Core client components
from aurigma.storefront import ApiClient, Configuration, ApiException

# API Clients
from aurigma.storefront.api.build_info_api import BuildInfoApi
from aurigma.storefront.api.product_references_api import ProductReferencesApi
from aurigma.storefront.api.projects_api import ProjectsApi
from aurigma.storefront.api.storefront_users_api import StorefrontUsersApi

# Data Transfer Objects (DTOs)
from aurigma.storefront.models import (
    CreateSingleItemProjectDto,
    ProjectItemParametersDto,
    CreateStorefrontUserDto,
    ProductSummaryDto
)
```

Configure the client with your base URL:

```python
import aurigma.storefront
from aurigma.storefront.rest import ApiException

configuration = aurigma.storefront.Configuration(
    host="https://api.customerscanvashub.com"  # or https://api.eu.customerscanvashub.com
)
```

If your project requires more than one API, install their packages and configure each client separately in your project. Ensure that the package versions are compatible.

## 3. Authentication (OAuth 2.0 Client Credentials)

To interact with the Customer's Canvas Hub API, you need to obtain an access token using the `client_credentials` grant type.

```python
import requests

def get_access_token(base_url, client_id, client_secret):
    """Fetch a new access token from the OAuth server"""
    token_url = f"{base_url}/connect/token"
    payload = {
        "client_id": client_id,
        "client_secret": client_secret,
        "grant_type": "client_credentials",
    }
    
    response = requests.post(token_url, data=payload, timeout=30)
    
    if response.status_code == 200:
        return response.json().get("access_token")
    else:
        raise Exception(f"Failed to obtain token: {response.status_code} - {response.text}")

# Usage
# token = get_access_token("https://<your-hub-url>", "your_id", "your_secret")
```

## 4. API Usage Examples

### 4.1. Fetch Build Info

Fetching build info is useful for verifying API availability and version. You can first make this request to ensure everything is set up correctly.

```python
async def get_build_info():
    async with aurigma.storefront.ApiClient(configuration) as api_client:
        api = aurigma.storefront.BuildInfoApi(api_client)
        try:
            build_info = await api.build_info_get_info()
            print(f"Build Info: {build_info}")
        except ApiException as e:
            print(f"Exception: {e}")
```

### 4.2. Work with Product References

A product reference allows you to map your local database products (using a SKU or unique ID) to the Customer's Canvas PIM products.

#### Fetch Product Summary

The `ProductSummaryDto` contains essential details for the editor, such as the default design ID, available surfaces, and localized names. This is the starting point for launching a personalized editing session.

```python
async def get_product_summary(self, reference: str, sku: str) -> Optional[ProductSummaryDto]:
    """
    Retrieves the product metadata required for the editor.
    :param reference: Your internal product identifier.
    :param sku: The specific stock keeping unit.
    """
    async with ApiClient(self.configuration) as api_client:
        api = ProductReferencesApi(api_client)
        try:
            # We use storefront_id to contextually load the correct theme and pricing
            summary = await api.product_references_get_product_summary(
                reference=reference,
                sku=sku,
                storefront_id=self.storefront_id
            )
            return summary
        except ApiException as e:
            logger.error(f"Failed to fetch product summary for {sku}: {e}")
            return None
```

Once you have the `ProductSummaryDto`, you can access properties like the default design to initialize your editor:

```python
summary = await product_service.get_product_summary("t-shirt-ref", "TSHIRT-BLUE-L")
if summary:
    # Use the default design ID to create a new project later
    print(f"Product: {summary.name}")
    print(f"Default Design ID: {summary.default_design_id}")
```

### 4.3. Work with Projects

Create a project and retrieve the high-resolution rendering results (artifacts).

#### Create a Single-Item Project

When a user orders a personalized product, you can create a new project based on this product and start rendering the personalized design for a specific user (`owner_id`). We use `ProjectItemParametersDto` to define the item and `CreateSingleItemProjectDto` to wrap it with order details.

```python
async def create_single_item_project(
        self,
        order_id: str,
        product_ref: str,
        sku: str,
        design_ids: List[str],
        owner_id: Optional[str] = None
    ) -> Optional[ProjectDto]:
    # Define product item parameters
    item = ProjectItemParametersDto(
        name=sku, 
        product_reference=product_ref,
        sku=sku,
        design_ids=design_ids
    )

    # owner_id is required to assign the project to a specific user
    project = CreateSingleItemProjectDto(
        order_id=order_id,
        item=item,
        owner_id=owner_id
    )

    async with ApiClient(self.configuration) as api_client:
        api = ProjectsApi(api_client)
        try:
            response = await api.projects_create_with_single_item(
                storefront_id=self.storefront_id,
                create_single_item_project_dto=project
            )
            print(f"Project created: {response.id}")
            return response # Returns ProjectDto
        except ApiException as e:
            print(f"Project creation failed: {e}")
            return None
```

#### Fetch User Project History

To display a user's order history or manage projects, use the `projects_get_all` method. You can filter results by `owner_id`, `status`, or `order_id`, and use `skip`/`take` for pagination.

```python
async def get_user_projects(self, owner_id: str, limit: int = 10, offset: int = 0):
    """
    Retrieves a paginated list of projects for a specific user, 
    sorted by the most recently modified.
    """
    async with ApiClient(self.configuration) as api_client:
        api = ProjectsApi(api_client)
        try:
            # We use owner_id to filter projects for a specific user.
            # sorting="LastModified DESC" ensures new projects are at the top.
            response = await api.projects_get_all(
                owner_id=owner_id,
                storefront_id=self.storefront_id,
                take=limit,
                skip=offset,
                sorting="LastModified DESC"
            )
            
            # The response is a PagedOfProjectDto containing a list of items
            for project in response.items:
                print(f"Project: {project.id} | Status: {project.status} | Created: {project.created_at}")
            
            return response.items
            
        except ApiException as e:
            print(f"Failed to fetch projects for user {owner_id}: {e}")
            return []
```

Useful Filter Combinations:

- **Search by Order**: Use `order_id="12345"` to find all design projects associated with a specific checkout.
- **Substring search**: Use the `search="Business Card"` parameter to perform a partial match on the project name or SKU.

#### Get Rendering Results (Artifacts)

Once a project is processed (rendered), it generates output files (PDF, PNG, etc.). This helper method formats the raw API response into a clean dictionary for your application.

```python
def _format_artifact(self, file_detail) -> Optional[Dict]:
    if not file_detail.url:
        return None
    
    # Ensure proper file naming and format extraction
    fmt = (file_detail.format or 'pdf').lower()
    name = file_detail.name or 'result'
    if not name.lower().endswith(f'.{fmt}'):
        name = f'{name}.{fmt}'
    
    return {
        'file_name': name,
        'file_url': file_detail.url,
        'file_size': file_detail.size,
        'format': fmt
    }
```

After the project moves to the **"Completed"** state, you can retrieve the download links for the high-resolution output files as follows:

```python
async def get_project_results(self, project_id: str):
    async with ApiClient(self.configuration) as api_client:
        api = ProjectsApi(api_client)
        try:
            # Fetch processing results from the API
            results = await api.projects_get_project_processing_results(id=int(project_id))
            
            artifacts = []
            if results.output_file_details:
                # Map raw file details to our clean artifacts list
                artifacts = [self._format_artifact(f) for f in results.output_file_details]
                artifacts = [a for a in artifacts if a is not None]
            
            return {
                'status': results.status.value if results.status else None,
                'status_description': results.status_description,
                'artifacts': artifacts
            }
        except ApiException as e:
            print(f"Failed to fetch results for project {project_id}: {e}")
            return None
```

### 4.4. Work with Users

In many integration scenarios, you need to ensure a user exists in Customer's Canvas before they can start editing a design. A common pattern is to use a **Session ID** as a temporary **User ID**.

#### Check for an Existing User Token

First, try to retrieve an access token. If the user does not exist, the API will return a `404 Not Found` error.

```python
from aurigma.storefront import (
    ApiClient, StorefrontUsersApi, CreateStorefrontUserDto, ApiException
)

async def _get_user_token(self, api: StorefrontUsersApi, user_id: str) -> Optional[str]:
    try:
        response = await api.storefront_users_get_token(
            storefront_user_id=user_id,
            storefront_id=self.storefront_id
        )
        return response.access_token
    except ApiException as e:
        if e.status != 404:
            print(f"Unexpected error getting token: {e}")
        return None
```

#### Register a New User

If the token is missing, create a new anonymous user. We handle `409 Conflict` to avoid errors if the user was created by a simultaneous request.

```python
async def _create_user(self, api: StorefrontUsersApi, user_id: str):
    dto = CreateStorefrontUserDto(
        storefront_user_id=user_id,
        is_anonymous=True
    )
    try:
        await api.storefront_users_create(
            storefront_id=self.storefront_id,
            create_storefront_user_dto=dto
        )
    except ApiException as e:
        if e.status != 409:
            raise e
```

#### Arrange the Workflow

Combine the steps into a single public method that manages the `ApiClient` lifecycle.

```python
async def get_or_create_anonymous_user(self, session_id: str) -> Optional[Dict[str, Any]]:
    if not session_id:
        return None

    user_id = f"anon_{session_id}"

    async with ApiClient(self.configuration) as api_client:
        api = StorefrontUsersApi(api_client)
        try:
            # First try to get a token.
            token = await self._get_user_token(api, user_id)
            if not token:
                # Create the user if missing.
                await self._create_user(api, user_id)
                # Get token again.
                token = await self._get_user_token(api, user_id)

            if token:
                return {
                    'user_id': user_id, 
                    'token': token, 
                    'is_anonymous': True
                }
        except ApiException as e:
            print(f"Exception: {e}")
    return None
```

## 5. Web Framework Integration (Best Practices)

When integrating the client into **Django** or **FastAPI**, follow these patterns:

- Singleton Auth: Initialize `CCAuthService` once in a **services.py** or **dependencies.py** file to reuse cached tokens across requests.
- Environment Variables: Store `CLIENT_SECRET` in a **.env** file; never hardcode it.

## Next Steps

- Explore the [Full API Reference](https://customerscanvas.com/docs/hub/dev-center/api.md).
- Learn about [Authentication](https://customerscanvas.com/docs/hub/dev-center/api/auth.md).
- Try other API clients: [.NET](https://customerscanvas.com/docs/hub/dev-center/api/clients/cs-api-client.md).

### Need Help?

[Submit a support ticket](https://customerscanvas.com/account/cases)
