Skip to main content

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)

Source distribution for altissimo-shippo-tracking 0.2.1
File Size Uploaded
altissimo_shippo_tracking-0.2.1.tar.gz 17.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for altissimo-shippo-tracking 0.2.1
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page