Back to Website
Show / Hide Table of Contents

Python API Client

  • Last updated on February 13, 2026
  • •
  • 7 minutes to read

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:
    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):

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:

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:

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.

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.

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.

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:

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.

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.

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.

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:

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.

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.

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.

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.
  • Learn about Authentication.
  • Try other API clients: .NET.

Need Help?

Submit a support ticket

Was this page helpful?
Thanks for your feedback!
Back to top Copyright © 2001–2025 Aurigma, Inc. All rights reserved.
Loading...
    Thank for your vote
    Your opinion is important to us. To provide details, send feedback.
    Send feedback