Create a Product Item

Install the package, then run this complete example:

from datetime import datetime, timezone

import pystac
from pystac.extensions.product import (
    AcquisitionType,
    ProductExtension,
    ProductStatus,
    QualityStatus,
)

item = pystac.Item(
    id="example-product",
    geometry=None,
    bbox=None,
    datetime=datetime(2026, 1, 1, tzinfo=timezone.utc),
    properties={},
)
product = ProductExtension.ext(item, add_if_missing=True)
product.apply(
    product_type="L1C",
    timeliness="PT3H",
    timeliness_category="NRT",
    acquisition_type=AcquisitionType.NOMINAL,
    status=ProductStatus.ACCEPTED,
    quality_status=QualityStatus.NOMINAL,
)

serialized = item.to_dict()
assert ProductExtension.get_schema_uri() in serialized["stac_extensions"]
assert serialized["properties"]["product:type"] == "L1C"
assert serialized["properties"]["product:timeliness"] == "PT3H"

restored_item = pystac.Item.from_dict(serialized)
restored = ProductExtension.ext(restored_item)
assert restored.product_type == "L1C"
assert restored.acquisition_type == AcquisitionType.NOMINAL
assert restored.timeliness_category == "NRT"
assert restored.status is ProductStatus.ACCEPTED
assert restored.quality_status is QualityStatus.NOMINAL

add_if_missing=True declares the extension on the Item. The wrapper writes directly to Item properties. to_dict() serializes without running JSON Schema validation.

A timeliness category needs a duration. apply(timeliness_category="NRT") raises ValueError unless a duration is supplied in the same call or already readable from the wrapper. See update semantics before using apply() to update existing metadata.