Carrier Integration
Karrio is designed to be easily extensible with new carrier integrations. This guide will walk you through the process of creating a custom carrier integration using Karrioβs built-in CLI tools and following established patterns.
Overview
Integrating a new carrier into Karrio involves several key steps:
- Environment Setup: Activate the Karrio development environment
- Bootstrapping: Use the CLI to generate the extension structure
- Schema Preparation: Create API schema files from carrier documentation
- Schema Generation: Generate Python types from carrier API schemas
- Implementation: Implement the mapping and API communication logic
- Testing: Validate the integration works correctly
Prerequisites
Before you begin, ensure you have:
- A Karrio development environment set up
- Basic Python programming knowledge
- Access to the carrierβs API documentation
- Understanding of the carrierβs authentication and request/response format
Extension Structure
Karrio supports two integration patterns:
Direct Carrier Pattern (Standard)
Located in modules/connectors/[carrier_name]/
for carriers like UPS, FedEx, DHL with direct APIs.
Hub Carrier Pattern (Aggregators)
Located in community/plugins/[carrier_name]/
for multi-carrier services like Easyship, ShipEngine.
Standard Extension Structure:
1modules/connectors/[carrier_name]/ 2βββ pyproject.toml # Package configuration 3βββ setup.py # Legacy setup file 4βββ README.md # Documentation 5βββ generate # Schema generation script 6βββ schemas/ # Raw API schema files 7β βββ error_response.json 8β βββ rate_request.json 9β βββ rate_response.json 10β βββ ... 11βββ karrio/ 12β βββ mappers/ # Integration layer 13β β βββ [carrier_name]/ 14β β βββ __init__.py # Legacy metadata 15β β βββ mapper.py # Main integration class 16β β βββ proxy.py # API client 17β β βββ settings.py # Connection settings 18β βββ providers/ # Implementation logic 19β β βββ [carrier_name]/ 20β β βββ __init__.py 21β β βββ rate.py # Rating implementation 22β β βββ tracking.py # Tracking implementation 23β β βββ shipment.py # Shipping implementation 24β β βββ units.py # Enums and constants 25β β βββ utils.py # Utility functions 26β β βββ error.py # Error handling 27β βββ plugins/ # New plugin structure 28β β βββ [carrier_name]/ 29β β βββ __init__.py # Plugin metadata 30β βββ schemas/ # Generated Python types 31β βββ [carrier_name]/ 32β βββ __init__.py 33β βββ rate_request.py 34β βββ ... 35βββ tests/ # Test suite 36 βββ [carrier_name]/ 37 βββ __init__.py 38 βββ fixture.py 39 βββ test_rate.py 40 βββ ...
Step 1: Environment Setup
CRITICAL: Always start by activating the Karrio development environment:
From the project root directory1source ./bin/activate-env
This makes the Karrio CLI (kcli
) and development tools available.
Step 2: Bootstrap the Extension
Use the Karrio CLI to generate the complete extension structure:
Interactive mode - CLI will prompt for details1./bin/cli sdk add-extension 2 3# Or with parameters 4./bin/cli sdk add-extension \ 5 --path modules/connectors \ 6 --carrier-slug dhl_express \ 7 --display-name "DHL Express" \ 8 --features "rating,shipping,tracking" \ 9 --is-xml-api false \ 10 --confirm
Available Parameters:
--path
:modules/connectors
(direct carriers) orcommunity/plugins
(hub carriers)--carrier-slug
: Unique identifier (e.g.,dhl_express
,fedex
)--display-name
: Human-readable name (e.g., βDHL Expressβ)--features
: Comma-separated list:address
,document
,manifest
,pickup
,rating
,shipping
,tracking
--is-xml-api
:true
for XML/SOAP APIs,false
for JSON APIs
Step 3: Prepare Schema Files
Create JSON (or XML) schema files in the schemas/
directory based on the carrierβs API documentation:
Required Files:
error_response.json
(always required)rate_request.json
+rate_response.json
(if rating enabled)shipment_request.json
+shipment_response.json
(if shipping enabled)tracking_request.json
+tracking_response.json
(if tracking enabled)
Note: Use actual API request/response examples, not JSON Schema definitions.
Step 4: Generate Python Types
Generate strongly-typed Python classes from your schema files:
Generate schemas for a specific carrier1./bin/run-generate-on modules/connectors/[carrier_name] 2 3# For hub carriers 4./bin/run-generate-on community/plugins/[carrier_name]
This command:
- Finds and executes the
generate
script in your extension - Uses
kcli codegen generate
to convert JSON/XML to Python classes - Creates type-safe classes with
attrs
andjstruct
decorators
Step 5: Implementation
After generation, implement the integration logic in the created files:
- Settings (
karrio/mappers/[carrier_name]/settings.py
): Define connection credentials - Units (
karrio/providers/[carrier_name]/units.py
): Define services, options, packaging types - Proxy (
karrio/mappers/[carrier_name]/proxy.py
): Implement API communication - Provider Logic (
karrio/providers/[carrier_name]/*.py
): Implement request/response mapping
Step 6: Testing & Validation
CRITICAL: Karrio uses a standardized testing framework. Follow these patterns exactly:
Testing Framework Rules
- Use Pythonβs
unittest
(never pytest) - Follow exact naming patterns for test files and methods
- Include mandatory debug prints before all assertions
- Use
assertListEqual
with full dict data structures - Mock carrier API responses with actual formats
Test Structure (NEVER DEVIATE)
Every feature requires exactly 4 test methods:
1class Test[CarrierName][Feature](unittest.TestCase): 2 def test_create_[feature]_request(self): # Request transformation 3 def test_[action_verb](self): # HTTP endpoint (mocked) 4 def test_parse_[feature]_response(self): # Success parsing 5 def test_parse_error_response(self): # Error handling
Run Tests
Test specific carrier - MANDATORY BEFORE COMPLETION1python -m unittest discover -v -f modules/connectors/[carrier_name]/tests 2 3# All SDK tests must still pass - MANDATORY 4source ./bin/activate-env && ./bin/run-sdk-tests 5 6# Plugin registration check - MANDATORY 7./bin/cli plugins list | grep [carrier_name]
Test Data Pattern
Each test file must end with exactly these structures:
[Feature]Payload
- Karrio input format[Feature]Request
- Carrier request format[Feature]Response
- Mock carrier responseErrorResponse
- Mock error responseParsed[Feature]Response
- Expected Karrio output[data, []]
ParsedErrorResponse
- Expected error format[[], [errors]]
Validation Checklist
π¨ MANDATORY: All criteria must pass before integration is considered complete:
Phase 1: Setup & Generation
- Environment:
source ./bin/activate-env
executed successfully - CLI Scaffolding: Used
./bin/cli sdk add-extension
(never manual creation) - Schema Files: API samples created in
schemas/
directory - Schema Generation:
./bin/run-generate-on [path]
executed successfully - Generated Types: Python classes exist in
karrio/schemas/[carrier_name]/
- Import Test:
python -c "import karrio.schemas.[carrier_name]"
works
Phase 2: Implementation
- Settings: Connection credentials configured properly
- Units: Services, options, packaging types defined
- Proxy: HTTP communication implemented with proper authentication
- Provider Logic: All required features implemented using generated types
- Mapper Untouched:
mapper.py
left unchanged from CLI generation - Error Handling: Carrier errors parsed to Karrio
Message
objects
Phase 3: Testing & Registration
- Test Structure: All test files follow exact naming patterns
- Test Methods: Each feature has exactly 4 required test methods
- Carrier Tests:
python -m unittest discover -v -f [path]/tests
passes - SDK Tests:
./bin/run-sdk-tests
still passes (no regressions) - Plugin List:
./bin/cli plugins list | grep [carrier_name]
shows plugin - Plugin Details:
./bin/cli plugins show [carrier_name]
works - Installation:
pip install -e [path]
succeeds without errors
Phase 4: Final Validation
- Schema Regeneration:
./bin/run-generate-on [path]
still works - Fresh Install: Clean reinstall works after uninstall
- All Features: Every enabled feature (rating, shipping, etc.) tested
- Error Scenarios: Error responses properly handled and tested
Architecture Overview
Next Steps
Follow the detailed guides for specific implementation areas:
- Schema Generation: Generate Python types from API schemas
- Metadata: Configure connection settings and data units
- API Requests: Implement HTTP communication
- Data Mapping: Transform between formats
β οΈ Critical Rules & Common Pitfalls
ABSOLUTE RULES (Violation Will Cause Failure)
-
π¨ NEVER Manual File Creation:
- Always use
./bin/cli sdk add-extension
for scaffolding - If CLI fails, fix the tool - never create files manually
- Manually created integrations will not work correctly
- Always use
-
π¨ NEVER Edit Generated Files:
- Never modify files in
karrio/schemas/[carrier_name]/
- Never modify
mapper.py
(CLI generated, delegation only) - Only edit source schema files and regenerate
- Never modify files in
-
π¨ NEVER Skip Environment Activation:
- Must run
source ./bin/activate-env
before ANY command - This makes CLI tools available and ensures correct dependencies
- Must run
-
π¨ NEVER Deviate from Test Patterns:
- Test file names, class names, method names are FIXED
- Only adapt data content, never structure or naming
- Use
unittest
framework only (never pytest)
Common Mistakes
- Editing mapper.py: This file only contains delegation methods
- Wrong test assertions: Use
assertListEqual
with full dict structures - Missing debug prints: Always add print statements before assertions
- Inconsistent naming: Follow exact patterns from existing integrations
- Manual schema editing: Only modify source files in
schemas/
directory
Success Tips
- Study existing integrations like UPS, FedEx for direct carriers
- Study Easyship, ShipEngine for hub carrier patterns
- Always test both success and error scenarios
- Ensure all 6 success criteria pass before considering complete