shipzil

Quickstart

Configure sources, request rates and buy a label.

uv add shipzil

Or with pip:

pip install shipzil

Configure sources

import shipzil as z

gateway = z.Gateway(
    shippo="shippo_test_...",
    shipstation_v2="...",
)

The keyword is both the adapter name and the default source name. ShipStation v1 needs a key and secret:

gateway = z.Gateway(shipstation_v1=("key", "secret"))

Use explicit adapters when you need custom source names, two accounts from one provider, a shorter timeout or a custom transport:

from shipzil.providers import ShippoAdapter

gateway = z.Gateway({
    "shippo-us": ShippoAdapter(us_token, timeout=30),
    "shippo-eu": ShippoAdapter(eu_token, timeout=30),
})

Describe the shipment

sender = z.Address(
    street1="215 Clayton St",
    city="San Francisco",
    state="CA",
    postal_code="94117",
)

recipient = z.Address(
    street1="1600 Pennsylvania Ave NW",
    city="Washington",
    state="DC",
    postal_code="20500",
)

parcel = z.Parcel(
    weight=z.Weight.of(16, "oz"),
    dimensions=z.Dimensions.of(10, 8, 4, "in"),
)

shipment = z.Shipment(sender, recipient, (parcel,))

Shipment.parcels is always a tuple, including single-parcel shipments.

Request rates

quote = gateway.get_rates(shipment, carriers={"usps"})

for rate in quote:
    print(rate.source, rate.service, rate.amount, rate.currency)

Eligible sources are called concurrently. Rates are grouped by configured source, then left in the order returned by that provider.

Inspect diagnostics even when rates were returned:

for error in quote.errors:
    log.warning("source failed: %s", error)

for exclusion in quote.excluded:
    log.info("rate excluded: %s", exclusion.message)

quote.excluded includes rates removed by shipzil's filters and exclusions reported by providers when available. It cannot describe a service that a provider silently omitted.

Select a rate

rate = quote.cheapest
if rate is None:
    raise NoShippingOption(quote.explain())

cheapest compares amounts only when every returned rate has the same known currency. It returns None for mixed currencies and for ShipStation v1 rates, whose API does not return a rate currency. In those cases, filter or select using your application's currency policy.

fastest considers only rates with a reported delivery_days value.

Buy

label = gateway.buy(shipment, rate)

print(label.tracking_number)
print(label.label_url)   # URL providers
print(label.label_data)  # base64 providers, currently ShipStation v1

The purchase goes to rate.source. It is not redirected to another provider.

Purchases are not retried. A provider or network failure after dispatch raises AmbiguousPurchaseError; reconcile with the provider before trying again. See Errors and exclusions.

Cancel or request a refund

accepted = gateway.void(label)

True means the provider accepted or confirmed the request. Some providers settle refunds asynchronously, so it does not always mean the money has already returned.

Next

On this page