shippo-tracking
Shippo shipping & tracking client with optional Firestore persistence.
Installation
Published on PyPI as altissimo-shippo-tracking; the import name is
altissimo.shippo_tracking.
# Basic (API client + models only)
pip install altissimo-shippo-tracking
# With Firestore persistence
pip install "altissimo-shippo-tracking[firestore]"
The firestore extra installs altissimo-firedantic,
Altissimo's maintained fork of firedantic. It is still imported as firedantic, so don't
install the upstream firedantic package alongside it.
Quick Start
from altissimo.shippo_tracking import ShippoClient
client = ShippoClient() # reads SHIPPO_API_KEY from env
status = client.get_tracking_status("usps", "9400111899223456789012")
print(status.tracking_status.status) # "TRANSIT", "DELIVERED", etc.
With Firestore Persistence
from altissimo.shippo_tracking import ShippoService
service = ShippoService()
# Fetch from API, save to Firestore, and register for webhooks if this
# tracking number hasn't been seen before
detail = service.save_tracking_detail("usps", "9400111899223456789012", register_if_new=True)
# List records, optionally filtered by status (case-insensitive)
in_flight = service.list_tracking_details(exclude_status="DELIVERED")
delivered = service.list_tracking_details(status="DELIVERED")
The Shippo GET tracking endpoint does not subscribe a shipment to
track_updated webhooks — only register_tracking() does. Pass
register_if_new=True so new tracking numbers are registered automatically;
without it, saving a new tracking number logs a warning.
Delivery Callback Hook
Inject your own logic for when a package is delivered:
from altissimo.shippo_tracking import ShippoService, ShippoTrackingDetail
def handle_delivery(detail: ShippoTrackingDetail):
print(f"Package {detail.tracking_number} delivered!")
# Send email, update order, notify team, etc.
service = ShippoService(on_delivery=handle_delivery)
Status Downgrade Protection
The service guards against status regression. Tracking statuses have a natural lifecycle ordering:
UNKNOWN → PRE_TRANSIT → TRANSIT → DELIVERED → RETURNED → FAILURE
If a persisted record already has a status further along in this progression (e.g.
DELIVERED), and the Shippo API or a webhook returns a lower status (e.g.
PRE_TRANSIT — common when USPS purges old tracking data), the update is
silently skipped and the existing record is preserved.
This applies to both save_tracking_detail() and incoming webhook events.
FastAPI Webhook Router
import os
from fastapi import FastAPI
from altissimo.shippo_tracking.router import create_shippo_router
app = FastAPI()
# Simple — no delivery callback
app.include_router(create_shippo_router())
# With delivery callback
app.include_router(create_shippo_router(on_delivery=handle_delivery))
# With a self-generated URL token (401 on missing/wrong ?token=)
app.include_router(create_shippo_router(webhook_token=os.environ["SHIPPO_WEBHOOK_TOKEN"]))
# With HMAC signature verification (401 on missing/invalid signature)
app.include_router(create_shippo_router(webhook_secret=os.environ["SHIPPO_WEBHOOK_SECRET"]))
Webhook authentication
Shippo offers three ways to secure webhooks; this router supports the two that are checked per request, and they can be combined.
- Self-generated token (
webhook_token): in the Shippo dashboard (Settings → API → Webhooks), append?token=<your token>to the webhook URL. Shippo echoes it back on every POST and the router compares it in constant time. - HMAC (
webhook_secret): requires Shippo's solutions team to provision a secret (up to ~10 business days). - IP allowlist: enforce at your load balancer/firewall; not handled here.
When webhook_secret is set, requests must carry a
Shippo-Auth-Signature: t=<timestamp>,v1=<hex HMAC-SHA256(secret, "<timestamp>.<raw body>")>
header. signature_tolerance_seconds optionally rejects stale timestamps.
To send signed test payloads, use
altissimo.shippo_tracking.webhook.compute_signature_header(secret, body).
Testing
poetry install --with dev
poetry run pytest -v
All unit tests use in-memory fakes — no Firestore or network access required.
Integration tests in tests/test_repo_integration.py exercise ShippoRepo
against the Firestore emulator and are skipped unless FIRESTORE_EMULATOR_HOST
is set. To run them (requires the Firebase CLI and Java):
poetry install --with dev --all-extras
firebase emulators:exec --only firestore --project demo-shippo-tracking "poetry run pytest -m integration -v"
Metadata
Release files for altissimo-shippo-tracking 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| altissimo_shippo_tracking-0.2.1.tar.gz | 17.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| altissimo_shippo_tracking-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.6 kB
Release files / altissimo_shippo_tracking-0.2.1.tar.gz
| Download URL | altissimo_shippo_tracking-0.2.1.tar.gz |
|---|---|
| Size | 17.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d0864ad771cb17fdba537e2c174ffd2bb416fda3ee882bc36c2348903873968
|
|
BLAKE2b-256 checksum How to use checksums |
36d6690f6df122b60a7bae2ae323730548239d8b5cd9bde1b17d2d8d1e4c1601
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / altissimo_shippo_tracking-0.2.1-py3-none-any.whl
| Download URL | altissimo_shippo_tracking-0.2.1-py3-none-any.whl |
|---|---|
| Size | 20.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
80db8101d5d3d90305629e15cb923290f4ea104ece7ad4bdb6df7ca1520f4043
|
|
BLAKE2b-256 checksum How to use checksums |
012855f383d290fa2367be3af24bcba301220bb9f24589f96fcd5d625dd0f163
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log