A modern, pythonic Python client for the Katana Manufacturing ERP API. Built from a comprehensive OpenAPI 3.1.0 specification with 100% endpoint coverage and automatic resilience.
- π― Production Ready: Automatic retries, rate limiting, and error handling
- π Zero Configuration: Works out of the box with environment variables
- π¦ Complete API Coverage: All 76+ Katana API endpoints with full type hints
- π Smart Pagination: Automatic pagination with built-in safety limits
- π‘οΈ Transport-Layer Resilience: httpx-native approach, no decorators needed
- β‘ Async/Sync Support: Use with asyncio or traditional synchronous code
- π Rich Observability: Built-in logging and metrics
- ποΈ Streamlined Architecture: Flattened imports, automated regeneration, zero patches
# Clone the repository
git clone https://github.com/dougborg/katana-openapi-client.git
cd katana-openapi-client
# Install with uv (recommended)
uv sync --all-extras
# Or with pip
pip install -e .The Katana client supports multiple authentication methods (in priority order):
- Direct parameter: Pass
api_keytoKatanaClient() - Environment variable: Set
KATANA_API_KEY .envfile: Create a.envfile with your credentials~/.netrcfile: Use standard Unix credential file
Create a .env file with your Katana API credentials:
KATANA_API_KEY=your-api-key-here
# Optional: defaults to https://api.katanamrp.com/v1
KATANA_BASE_URL=https://api.katanamrp.com/v1For centralized credential management, add to ~/.netrc:
machine api.katanamrp.com
password your-api-key-here
Note: Ensure your netrc file has restricted permissions (chmod 600 ~/.netrc)
export KATANA_API_KEY=your-api-key-hereasync with KatanaClient(api_key="your-api-key-here") as client:
# ...The modern, pythonic client with automatic resilience:
import asyncio
from katana_public_api_client import KatanaClient
from katana_public_api_client.api.product import get_all_products
from katana_public_api_client.api.sales_order import get_all_sales_orders
async def main():
# Automatic configuration from .env file
async with KatanaClient() as client:
response = await get_all_products.asyncio_detailed(
client=client,
limit=50
)
print(f"Status: {response.status_code}")
print(f"Products: {len(response.parsed.data)}")
# Automatic pagination happens transparently
all_products_response = await get_all_products.asyncio_detailed(
client=client,
is_sellable=True
)
print(f"Total sellable products: {len(all_products_response.parsed.data)}")
# Direct API usage with automatic resilience
orders_response = await get_all_sales_orders.asyncio_detailed(
client=client,
status="open"
)
orders = orders_response.parsed.data if orders_response.parsed else []
print(f"Open orders: {len(orders)}")
asyncio.run(main())See the Cookbook for more practical examples including inventory management, order processing, webhook handlers, and performance optimization.
The client provides access to all major Katana functionality:
| Category | Endpoints | Description |
|---|---|---|
| Products & Inventory | 25+ | Products, variants, materials, stock levels |
| Orders | 20+ | Sales orders, purchase orders, fulfillment |
| Manufacturing | 15+ | BOMs, manufacturing orders, operations |
| Business Relations | 10+ | Customers, suppliers, addresses |
| Configuration | 6+ | Locations, webhooks, custom fields |
Total: 76+ endpoints with 150+ fully-typed data models.
Every API call through KatanaClient automatically includes:
- Smart Retries: Exponential backoff (1s, 2s, 4s, 8s, 16s) for network errors and server errors
- Rate Limit Handling: All HTTP methods (including POST/PATCH) are automatically
retried on 429 errors with
Retry-Afterheader support - Idempotent Server Error Retry: Only safe methods (GET, PUT, DELETE) are retried on 502/503/504 errors
- Error Recovery: Intelligent retry logic that doesn't retry other 4xx client errors
- Observability: Rich logging for debugging and monitoring
# No decorators, no wrapper methods needed
async with KatanaClient() as client:
# Just use the generated API methods directly
response = await get_all_products.asyncio_detailed(
client=client,
limit=100
)
# Automatic retries, rate limiting, logging - all transparent!Uses httpx's native transport layer for resilience - the most pythonic approach:
- Zero Dependencies: Built on httpx's standard extension points
- Maximum Compatibility: Works with any httpx-based code
- Easy Testing: Simple to mock and test
- Performance: Minimal overhead compared to decorators
import logging
from katana_public_api_client import KatanaClient
# Custom configuration
async with KatanaClient(
api_key="custom-key",
base_url="https://custom.katana.com/v1",
timeout=60.0,
max_retries=3,
logger=logging.getLogger("katana")
) as client:
# Your API calls here
passfrom katana_public_api_client import KatanaClient
from katana_public_api_client.api.product import get_all_products
async with KatanaClient() as client:
# Get all products with automatic pagination
all_products_response = await get_all_products.asyncio_detailed(
client=client,
is_sellable=True
)
sellable_products = all_products_response.parsed.data
print(f"Found {len(sellable_products)} sellable products")Convenient helpers to unwrap responses and handle errors:
from katana_public_api_client import (
KatanaClient,
unwrap,
unwrap_data,
APIError,
AuthenticationError,
ValidationError,
)
from katana_public_api_client.api.product import get_all_products
async with KatanaClient() as client:
# unwrap() extracts parsed data and raises typed exceptions on errors
response = await get_all_products.asyncio_detailed(client=client)
product_list = unwrap(response) # Raises APIError on failure
# unwrap_data() directly extracts the .data field from list responses
products = unwrap_data(response) # Returns list of Product objects
for product in products:
print(f"Product: {product.name}")
# Handle errors with typed exceptions
try:
response = await get_all_products.asyncio_detailed(client=client)
products = unwrap(response)
except AuthenticationError as e:
print(f"Auth failed: {e}")
except ValidationError as e:
print(f"Validation error: {e.validation_errors}")
except APIError as e:
print(f"API error {e.status_code}: {e}")See examples/using_utils.py for more examples.
This is a monorepo managed with uv workspace, containing multiple packages:
katana-openapi-client/ # Repository root (workspace)
βββ pyproject.toml # Workspace configuration
βββ uv.lock # Unified lock file for all packages
βββ docs/katana-openapi.yaml # OpenAPI 3.1.0 specification
βββ katana_public_api_client/ # Main package - Generated Python client
β βββ katana_client.py # KatanaClient with transport-layer resilience
β βββ client.py # Base generated client classes
β βββ api/ # 76+ API endpoint modules
β βββ models/ # 150+ data models
β βββ types.py # Type definitions
βββ katana_mcp_server/ # MCP server package (coming soon)
β βββ pyproject.toml # Package-specific configuration
βββ docs/ # Documentation
βββ tests/ # Test suite
βββ scripts/ # Development utilities
The workspace configuration enables:
- Unified dependency management across packages
- Version compatibility guarantees
- Single lock file for reproducible builds
- Parallel development of client and server
See ADR-010 for architectural details.
# Run all tests
uv run poe test
# Run with coverage
uv run poe test-coverage
# Run specific test categories
uv run poe test-unit # Unit tests only
uv run poe test-integration # Integration tests only- Cookbook - Practical recipes for common integration scenarios
- KatanaClient Guide - Complete KatanaClient usage guide
- API Reference - Generated API documentation
- Migration Guide - Upgrading from previous versions
- Testing Guide - Testing patterns and examples
- Architecture Decision Records (ADRs) - Key architectural decisions
- Revised Assessment - Comprehensive review (Grade: A, 95/100)
- Coverage Analysis - Test coverage breakdown (74.8% core logic)
- Builder Pattern Analysis - Builder vs domain helpers
- Domain Helpers Design - Complete helper design
# Install dependencies
uv sync --all-extras
# Install pre-commit hooks (important!)
uv run poe pre-commit-install
# See all available tasks
uv run poe help
# Quick development check
uv run poe check
# Auto-fix common issues
uv run poe fix# Formatting
uv run poe format # Format all code and documentation
uv run poe format-check # Check formatting without changes
uv run poe format-python # Format Python code only
# Linting and Type Checking
uv run poe lint # Run all linters (ruff, ty, yaml)
uv run poe lint-ruff # Fast linting with ruff
uv run poe typecheck # Type checking with ty
# Testing
uv run poe test # Run all tests
uv run poe test-coverage # Run tests with coverage
uv run poe test-unit # Unit tests only
uv run poe test-integration # Integration tests only# Regenerate client from OpenAPI spec
uv run poe regenerate-client
# Validate OpenAPI specification
uv run poe validate-openapi
# Full preparation workflow
uv run poe prepare # Format + lint + test + validate# Install pre-commit hooks (run once after clone)
uv run poe pre-commit-install
# Run pre-commit on all files manually
uv run poe pre-commit-run
# Update pre-commit hook versions
uv run poe pre-commit-update# Full CI pipeline (what runs in GitHub Actions)
uv run poe ci
# Pre-commit preparation
uv run poe prepare
# Clean build artifacts
uv run poe cleanAll tool configurations are consolidated in pyproject.toml following modern Python
packaging standards:
- uv: Fast, modern package and dependency manager
- Hatchling: Build backend for package distribution
- Ruff: Code formatting and linting (replaces Black, isort, flake8)
- MyPy: Type checking configuration
- Pytest: Test discovery and execution settings
- Coverage: Code coverage reporting
- Poe: Task automation and scripts
- Semantic Release: Automated versioning and releases
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.