katana_public_api_client¶
katana_public_api_client
¶
Katana Public API Client - Python client for Katana Manufacturing ERP.
Classes¶
APIError(message, status_code, error_response=None)
¶
Bases: Exception
Base exception for API errors.
Parameters:
-
message(str) –Human-readable error message
-
status_code(int) –HTTP status code
-
error_response(ErrorResponse | DetailedErrorResponse | None, default:None) –The error response object from the API
Source code in katana_public_api_client/utils.py
Functions¶
AuthenticatedClient
¶
A Client which has been authenticated for use on secured endpoints
The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
``base_url``: The base URL for the API, all requests are made to a relative path to this URL
``cookies``: A dictionary of cookies to be sent with every request
``headers``: A dictionary of headers to be sent with every request
``timeout``: The maximum amount of a time a request can take. API functions will raise
httpx.TimeoutException if this is exceeded.
``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
but can be set to False for testing purposes.
``follow_redirects``: Whether or not to follow redirects. Default value is False.
``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.
Functions¶
__aenter__()
async
¶
Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)
__aexit__(*args, **kwargs)
async
¶
Exit a context manager for underlying httpx.AsyncClient (see httpx docs)
__enter__()
¶
Enter a context manager for self.client—you cannot enter twice (see httpx docs)
__exit__(*args, **kwargs)
¶
Exit a context manager for internal httpx.Client (see httpx docs)
get_async_httpx_client()
¶
Get the underlying httpx.AsyncClient, constructing a new one if not previously set
Source code in katana_public_api_client/client.py
get_httpx_client()
¶
Get the underlying httpx.Client, constructing a new one if not previously set
Source code in katana_public_api_client/client.py
set_async_httpx_client(async_client)
¶
Manually set the underlying httpx.AsyncClient
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
Source code in katana_public_api_client/client.py
set_httpx_client(client)
¶
Manually set the underlying httpx.Client
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
Source code in katana_public_api_client/client.py
with_cookies(cookies)
¶
Get a new client matching this one with additional cookies
Source code in katana_public_api_client/client.py
with_headers(headers)
¶
Get a new client matching this one with additional headers
Source code in katana_public_api_client/client.py
with_timeout(timeout)
¶
Get a new client matching this one with a new timeout configuration
Source code in katana_public_api_client/client.py
AuthenticationError(message, status_code, error_response=None)
¶
Bases: APIError
Raised when authentication fails (401).
Source code in katana_public_api_client/utils.py
Client
¶
A class for keeping track of data related to the API
The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
``base_url``: The base URL for the API, all requests are made to a relative path to this URL
``cookies``: A dictionary of cookies to be sent with every request
``headers``: A dictionary of headers to be sent with every request
``timeout``: The maximum amount of a time a request can take. API functions will raise
httpx.TimeoutException if this is exceeded.
``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
but can be set to False for testing purposes.
``follow_redirects``: Whether or not to follow redirects. Default value is False.
``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.
Functions¶
__aenter__()
async
¶
Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)
__aexit__(*args, **kwargs)
async
¶
Exit a context manager for underlying httpx.AsyncClient (see httpx docs)
__enter__()
¶
Enter a context manager for self.client—you cannot enter twice (see httpx docs)
__exit__(*args, **kwargs)
¶
Exit a context manager for internal httpx.Client (see httpx docs)
get_async_httpx_client()
¶
Get the underlying httpx.AsyncClient, constructing a new one if not previously set
Source code in katana_public_api_client/client.py
get_httpx_client()
¶
Get the underlying httpx.Client, constructing a new one if not previously set
Source code in katana_public_api_client/client.py
set_async_httpx_client(async_client)
¶
Manually set the underlying httpx.AsyncClient
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
Source code in katana_public_api_client/client.py
set_httpx_client(client)
¶
Manually set the underlying httpx.Client
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
Source code in katana_public_api_client/client.py
with_cookies(cookies)
¶
Get a new client matching this one with additional cookies
Source code in katana_public_api_client/client.py
with_headers(headers)
¶
Get a new client matching this one with additional headers
Source code in katana_public_api_client/client.py
with_timeout(timeout)
¶
Get a new client matching this one with a new timeout configuration
Source code in katana_public_api_client/client.py
KatanaClient(api_key=None, base_url=None, timeout=30.0, max_retries=5, max_pages=100, logger=None, *, requests_per_minute=60, **httpx_kwargs)
¶
Bases: AuthenticatedClient
The pythonic Katana API client with automatic resilience and pagination.
This client inherits from AuthenticatedClient and can be passed directly to generated API methods without needing the .client property.
Features: - Automatic retries on network errors and server errors (5xx) - Automatic rate limit handling with Retry-After header support - Auto-pagination ON by default for GET requests (collects all pages automatically) - Uses 250 items per page (Katana's max) for efficient pagination - Rich logging and observability - Minimal configuration - just works out of the box
Auto-pagination behavior:
- ON by default for GET requests with NO page parameter
- Uses 250 items per page when no limit specified by caller
- If caller specifies a limit, that limit is used per page
- ANY explicit page parameter disables auto-pagination (e.g., page=1)
- Disabled per-request via extensions: extensions={"auto_pagination": False}
- Control max pages via max_pages constructor parameter
- Limit total items via extensions: extensions={"max_items": 200}
Usage
async with KatanaClient() as client: from katana_public_api_client.api.product import get_all_products
# Auto-pagination is ON - all pages collected automatically
# Uses 250 items per page for efficiency
response = await get_all_products.asyncio_detailed(
client=client, # Pass client directly - no .client needed!
)
# Use a custom limit per page (100 instead of 250)
response = await get_all_products.asyncio_detailed(
client=client,
limit=100, # Use 100 per page
)
# Get a specific page only (ANY page param disables auto-pagination)
response = await get_all_products.asyncio_detailed(
client=client,
page=2, # Get page 2 only
limit=50
)
# Limit total items collected (via httpx client)
httpx_client = client.get_async_httpx_client()
response = await httpx_client.get(
"/products",
extensions={"max_items": 200} # Stop after 200 items
)
# Control max pages globally
client_limited = KatanaClient(max_pages=5) # Limit to 5 pages max
Parameters:
-
api_key(str | None, default:None) –Katana API key. If None, will try to load from KATANA_API_KEY env var, .env file, or ~/.netrc file (in that order).
-
base_url(str | None, default:None) –Base URL for the Katana API. Defaults to https://api.katanamrp.com/v1
-
timeout(float, default:30.0) –Request timeout in seconds. Defaults to 30.0.
-
max_retries(int, default:5) –Maximum number of retry attempts for failed requests. Defaults to 5.
-
max_pages(int, default:100) –Maximum number of pages to collect during auto-pagination. Defaults to 100.
-
requests_per_minute(int | None, default:60) –Steady-state request budget for the proactive rate limiter. Defaults to 60 (Katana's documented limit). Set to
Noneto disable the rate limiter entirely (e.g. when callers want to manage throttling themselves, or for tests that need raw throughput). When the limiter is active, every actual HTTP request — including retries and per-page paginated fetches — consumes one token, and the transport adapts to the server'sX-Ratelimit-Remaining/X-Ratelimit-Resetheaders. -
logger(Logger | None, default:None) –Any object whose debug/info/warning/error methods accept (msg, *args, **kwargs) — the standard logging.Logger call convention (e.g. logging.Logger, structlog.BoundLogger). If None, creates a default stdlib logger.
-
**httpx_kwargs(Any, default:{}) –Additional arguments passed to the base AsyncHTTPTransport. Common parameters include: - http2 (bool): Enable HTTP/2 support - limits (httpx.Limits): Connection pool limits - verify (bool | str | ssl.SSLContext): SSL certificate verification - cert (str | tuple): Client-side certificates - trust_env (bool): Trust environment variables for proxy configuration - event_hooks (dict): Custom event hooks (will be merged with built-in hooks)
Raises:
-
ValueError–If no API key is provided via api_key param, KATANA_API_KEY env var, .env file, or ~/.netrc file.
Note
Transport-related parameters (http2, limits, verify, etc.) are correctly passed to the innermost AsyncHTTPTransport layer, ensuring they take effect even with the layered transport architecture.
Example
async with KatanaClient() as client: ... # All API calls through client get automatic resilience ... response = await some_api_method.asyncio_detailed(client=client)
Source code in katana_public_api_client/katana_client.py
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 | |
Attributes¶
api
property
¶
Thin CRUD wrappers for all API resources. Returns raw attrs models.
Example
async with KatanaClient() as client: ... products = await client.api.products.list(is_sellable=True) ... product = await client.api.products.get(123) ... await client.api.products.delete(123)
materials
property
¶
Access material catalog operations.
Returns:
-
Materials–Materials instance for material CRUD operations.
Example
async with KatanaClient() as client: ... materials = await client.materials.list() ... material = await client.materials.get(123)
products
property
¶
Access product catalog operations.
Returns:
-
Products–Products instance for product CRUD and search operations.
Example
async with KatanaClient() as client: ... # Product CRUD ... products = await client.products.list(is_sellable=True) ... product = await client.products.get(123) ... results = await client.products.search("widget")
services
property
¶
Access service catalog operations.
Returns:
-
Services–Services instance for service CRUD operations.
Example
async with KatanaClient() as client: ... services = await client.services.list() ... service = await client.services.get(123)
variants
property
¶
Access variant catalog operations.
Returns:
-
Variants–Variants instance for variant CRUD operations.
Example
async with KatanaClient() as client: ... variants = await client.variants.list() ... variant = await client.variants.get(123)
Functions¶
RateLimitError(message, status_code, error_response=None)
¶
Bases: APIError
Raised when rate limit is exceeded (429).
Source code in katana_public_api_client/utils.py
ServerError(message, status_code, error_response=None)
¶
Bases: APIError
Raised when server error occurs (5xx).
Source code in katana_public_api_client/utils.py
ValidationError(message, status_code, error_response=None)
¶
Bases: APIError
Raised when request validation fails (422).
Parameters:
-
message(str) –Human-readable error message
-
status_code(int) –HTTP status code (should be 422)
-
error_response(DetailedErrorResponse | None, default:None) –The detailed error response with validation details
Source code in katana_public_api_client/utils.py
Functions¶
__str__()
¶
Format validation error with Ajv-keyword-specific details.
Each detail's typed subtype is dispatched into a keyword-specific
renderer that consults info.* for keyword metadata (limit,
pattern, allowed values, etc.). Unknown keywords route to
GenericValidationError and render through a fallback that
surfaces path/code/message plus any info captured
in additional_properties.
Source code in katana_public_api_client/utils.py
Functions¶
get_error_message(response)
¶
Extract error message from an error response.
Parameters:
-
response(Response[T]) –The Response object (typically an error response)
Returns:
-
str | None–Error message string, or None if no error message found
Example
Source code in katana_public_api_client/utils.py
get_variant_display_name(variant)
¶
Build the full variant display name matching Katana UI format.
Format: "{Product/Material Name} / {Config Value 1} / {Config Value 2} / ..."
Example: "Premium 140 / Glossy Black / Large / Type A"
Takes a VariantResponse (the discriminated-union variant schema with
typed product_or_material: Material | Product | Unset). Variants returned
without ?extend=product_or_material have product_or_material UNSET, in
which case the display name falls back to empty string.
Parameters:
-
variant(VariantResponse) –VariantResponse fetched with
?extend=product_or_material.
Returns:
-
str–Formatted variant name with config values, or empty string if no name available.
Example
from katana_public_api_client import KatanaClient
from katana_public_api_client.api.variant import get_all_variants
from katana_public_api_client.models.get_all_variants_extend_item import (
GetAllVariantsExtendItem,
)
from katana_public_api_client.utils import (
get_variant_display_name,
unwrap_data,
)
async with KatanaClient() as client:
response = await get_all_variants.asyncio_detailed(
client=client,
extend=[GetAllVariantsExtendItem.PRODUCT_OR_MATERIAL],
)
for variant in unwrap_data(response):
print(get_variant_display_name(variant))
# e.g. "Premium 140 / Glossy Black / Large / Type A"
Source code in katana_public_api_client/utils.py
handle_response(response, *, on_success=None, on_error=None, raise_on_error=False)
¶
Handle a response with custom success and error handlers.
This function provides a convenient way to handle both success and error cases with custom callbacks.
Parameters:
-
response(Response[T]) –The Response object from an API call
-
on_success(Callable[[T], Any] | None, default:None) –Callback function to call with parsed data on success
-
on_error(Callable[[APIError], Any] | None, default:None) –Callback function to call with APIError on error
-
raise_on_error(bool, default:False) –If True, raise the error even if on_error is provided
Returns:
-
Any–Result of on_success callback, result of on_error callback, or None
Example
def handle_products(product_list):
print(f"Got {len(product_list.data)} products")
return product_list.data
def handle_error(error):
print(f"Error: {error}")
return []
response = await get_all_products.asyncio_detailed(client=client)
products = handle_response(
response, on_success=handle_products, on_error=handle_error
)
Source code in katana_public_api_client/utils.py
is_error(response)
¶
Check if a response was an error (4xx or 5xx status code).
Parameters:
Returns:
-
bool–True if status code is 4xx or 5xx, False otherwise
Source code in katana_public_api_client/utils.py
is_success(response)
¶
Check if a response was successful (2xx status code).
Parameters:
Returns:
-
bool–True if status code is 2xx, False otherwise
Example
Source code in katana_public_api_client/utils.py
unwrap(response, *, raise_on_error=True)
¶
Unwrap a Response object and return the parsed data or raise an error.
This is the main utility function for handling API responses. It automatically raises appropriate exceptions for error responses and returns the parsed data for successful responses.
Parameters:
-
response(Response[T]) –The Response object from an API call
-
raise_on_error(bool, default:True) –If True, raise exceptions on error status codes. If False, return None on errors.
Returns:
-
T | None–The parsed response data
Raises:
-
AuthenticationError–When status is 401
-
ValidationError–When status is 422
-
RateLimitError–When status is 429
-
ServerError–When status is 5xx
-
APIError–For other error status codes
Example
from katana_public_api_client import KatanaClient
from katana_public_api_client.api.product import get_all_products
from katana_public_api_client.utils import unwrap
async with KatanaClient() as client:
response = await get_all_products.asyncio_detailed(client=client)
product_list = unwrap(
response
) # Raises on error, returns parsed data
products = product_list.data # List of Product objects
Source code in katana_public_api_client/utils.py
unwrap_data(response, *, raise_on_error=True, default=None)
¶
unwrap_data(
response: Response[T],
*,
raise_on_error: Literal[True] = True,
default: None = None
) -> Any
Unwrap a Response and extract the data list from list responses.
This is a convenience function that unwraps the response and extracts
the .data field from list response objects (like ProductListResponse,
WebhookListResponse, etc.).
Parameters:
-
response(Response[T]) –The Response object from an API call
-
raise_on_error(bool, default:True) –If True, raise exceptions on error status codes. If False, return default on errors.
-
default(list[DataT] | None, default:None) –Default value to return if data is not available
Returns:
-
Any | None–List of data objects, or default if not available
Example
from katana_public_api_client import KatanaClient
from katana_public_api_client.api.product import get_all_products
from katana_public_api_client.utils import unwrap_data
async with KatanaClient() as client:
response = await get_all_products.asyncio_detailed(client=client)
products = unwrap_data(response) # Directly get list of Products
for product in products:
print(product.name)