Skip to main content

Installation

pip install crossborderly
Requires Python 3.8+

Quick Start

from crossborderly import CrossBorderly

client = CrossBorderly(
    api_key="pk_your_api_key",
    environment="production"  # or "sandbox"
)

# Create an order
order = client.orders.create(
    idempotency_key="my-order-123",
    sender={...},
    receiver={...},
    parcel_details={...}
)

print(f"Tracking: {order.parcel.tracking_number}")

Configuration

from crossborderly import CrossBorderly

client = CrossBorderly(
    api_key="pk_your_api_key",
    environment="production",
    timeout=30,  # seconds
    max_retries=3,
    debug=False
)

Orders

Create Order

order = client.orders.create(
    idempotency_key=f"order-{int(time.time())}",
    sender={
        "full_name": "John Smith",
        "phone": "+1 305-555-0123",
        "address": {
            "line1": "1234 Main St",
            "city": "Miami",
            "state": "FL",
            "zip_code": "33101",
            "country": "US"
        }
    },
    receiver={
        "full_name": "María García",
        "phone": "+593 99 123 4567",
        "national_id": "1234567890",
        "address": {
            "line1": "Av. 9 de Octubre 123",
            "city": "Guayaquil",
            "province": "Guayas",
            "zip_code": "090101",
            "country": "EC"
        }
    },
    parcel_details={
        "weight_lbs": 2.5,
        "declared_value": 99.99
    }
)

print(order.parcel.tracking_number)
print(order.parcel.label_url)

Void Order

result = client.orders.void(
    idempotency_key="void-123",
    tracking_numbers=["CBECUSD123456789"],
    reason="Customer cancelled"
)

print(f"Voided: {result.voided}")

Manifests

Submit Manifest

manifest = client.manifests.submit(
    idempotency_key="manifest-123",
    awb_number="180-12345678",
    flight_number="LA2480",
    flight_date="2024-12-25",
    origin_airport="MIA",
    destination_airport="UIO",
    carrier="LATAM Airlines",
    country="EC",
    parcels=[
        {"tracking_number": "CBECUSD123456789"},
        {"tracking_number": "CBECUSD123456790"}
    ]
)

print(f"Linked: {manifest.linked}")

Tracking

Single Parcel

tracking = client.tracking.get(
    "CBECUSD123456789",
    include_history=True
)

print(f"Status: {tracking.status}")
for event in tracking.history:
    print(f"{event.timestamp}: {event.status_name}")

Batch Tracking

results = client.tracking.batch(
    tracking_numbers=["CBECUSD123456789", "CBECUSD123456790"],
    include_history=False
)

for parcel in results.results:
    print(f"{parcel.tracking_number}: {parcel.status}")

Labels

Download Label

# Get label info
label = client.labels.get("CBECUSD123456789")
print(f"Download: {label.label_url}")

# Download as bytes
pdf_bytes = client.labels.download("CBECUSD123456789", format="PDF")
with open("label.pdf", "wb") as f:
    f.write(pdf_bytes)

Reprint Label

reprint = client.labels.reprint(
    "CBECUSD123456789",
    idempotency_key="reprint-123",
    label_format="PDF"
)

print(f"New URL: {reprint.label_url}")

Webhooks

Verify Webhook Signature

from crossborderly import verify_webhook_signature
from flask import Flask, request

app = Flask(__name__)

@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-CrossBorderly-Signature')
    
    if not verify_webhook_signature(
        request.data,
        signature,
        webhook_secret
    ):
        return 'Invalid signature', 401
    
    event = request.json
    # Process webhook...
    return 'OK', 200

Error Handling

from crossborderly.exceptions import (
    CrossBorderlyError,
    ValidationError,
    RateLimitError,
    NotFoundError
)

try:
    order = client.orders.create(...)
except ValidationError as e:
    print(f"Validation failed: {e.errors}")
except RateLimitError as e:
    print(f"Rate limited, retry after: {e.retry_after}")
except NotFoundError as e:
    print(f"Resource not found: {e.message}")
except CrossBorderlyError as e:
    print(f"API error: {e.code} - {e.message}")

Async Support

import asyncio
from crossborderly import AsyncCrossBorderly

async def main():
    client = AsyncCrossBorderly(api_key="pk_your_api_key")
    
    order = await client.orders.create(...)
    print(order.parcel.tracking_number)
    
    await client.close()

asyncio.run(main())

Context Manager

with CrossBorderly(api_key="pk_your_api_key") as client:
    order = client.orders.create(...)
    print(order.parcel.tracking_number)
# Connection automatically closed

Type Hints

The SDK includes full type hints for IDE support:
from crossborderly.types import (
    CreateOrderRequest,
    CreateOrderResponse,
    ParcelStatus
)

request: CreateOrderRequest = {
    "idempotency_key": "order-123",
    "sender": {...},
    "receiver": {...},
    "parcel_details": {...}
}

response: CreateOrderResponse = client.orders.create(**request)