---
id: CAP-COM-FUL-013
title: Purchase and follow carrier labels safely
feature: FEAT-COM-FUL-03
product_area: commerce
module: fulfillment
revision: 1
status: draft
product_intent: proposed
implementation_evidence: partially-observed
supersedes:
  - CAP-COM-SHP-011
  - CAP-COM-SHP-012
  - CAP-COM-SHP-015
  - CAP-COM-SHP-023
  - CAP-COM-SHP-025
  - CAP-COM-SHP-029
  - CAP-COM-SHP-031
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-commerce:docs/migrations/shipping/README.md#D-P8S-15 (Andrew
    2026-10-18 21:10 UTC)
purpose: >-
  Staff obtain labels and track parcels while preserving uncertain carrier
  outcomes.
outcomes:
  - Carrier-purchase identity protects against duplicate label charges.
  - Requested tracking helps staff follow parcel progress.
concepts:
  - CON-COM-FUL-004
actors:
  - ACT-COM-010
surfaces:
  - api
  - console
preconditions: []
postconditions: []
permissions:
  - key: commerce.shipments.update
    where_checked: api
    scope: tenant
  - key: orders.shipments.printLabel
    where_checked: console
    scope: tenant
  - key: orders.shipments.voidLabel
    where_checked: console
    scope: tenant
rules:
  - id: BR-CAP-COM-FUL-013-01
    proved_by: [ATS-COM-FUL-012-10, ATS-COM-FUL-013-01, ATS-COM-FUL-013-10, ATS-COM-FUL-013-11, ATS-COM-FUL-014-07, ATS-COM-FUL-015-10, TST-COM-FUL-077, TST-COM-FUL-078]
    statement: >-
      Label purchase records its attempt before contacting the carrier and
      stores tracking, cost and label afterward, returning a purchased result on
      repetition.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#buys
      the first label through UPS under package:<id>:1 (the intent then the
      outcome), the tracking number and the cost on the label, the package
      labelled
    origin: none
  - id: BR-CAP-COM-FUL-013-02
    proved_by: [ATS-COM-FUL-013-02, TST-COM-FUL-075, TST-COM-FUL-078, TST-COM-FUL-084]
    statement: >-
      An uncertain purchase is recovered by querying its existing key and, if
      needed, resending that key; unresolved purchases remain in flight and
      never use a new purchase key.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#asks
      the carrier by the key before buying again, then the same purchase under
      the same key, and refuses label_purchase_in_flight while neither settles
      it, buying under no new key
    origin: >-
      D-P8S-08 (build decision, not a product ruling):
      services-commerce:docs/migrations/shipping/README.md#D-P8S-08
  - id: BR-CAP-COM-FUL-013-03
    proved_by: [ATS-COM-FUL-013-03]
    statement: >-
      Staff can resolve an in-flight label purchase using the result visible in
      the carrier's console.
    kind: lifecycle
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:resolveLabelPurchase
    origin: none
  - id: BR-CAP-COM-FUL-013-04
    proved_by: [ATS-COM-FUL-013-01, TST-COM-FUL-077, TST-COM-FUL-078]
    statement: >-
      An unavailable carrier reached before any operation executes produces a
      failed attempt, allowing the next purchase to use a new attempt.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#records
      the refused purchase failed (carrier_unavailable), not in flight, so the
      next purchase buys on attempt 2
    origin: none
  - id: BR-CAP-COM-FUL-013-05
    proved_by: [ATS-COM-FUL-013-04, TST-COM-FUL-084]
    statement: >-
      The manual carrier requires staff-supplied tracking and whole nonnegative
      cost, provides no quotes, accepts label voids and records delivery only
      from staff input.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#fails
      a purchase with no details, not retryable, and one with a cost that is not
      a whole non-negative number
    origin: none
  - id: BR-CAP-COM-FUL-013-06
    proved_by: [ATS-COM-FUL-010-07, ATS-COM-FUL-013-05, ATS-COM-FUL-013-09, TST-COM-FUL-084]
    statement: >-
      UPS calls use Commerce's Integration Platform connection and invocation
      grant; missing connection or grant yields carrier-unavailable without
      sending a request.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#refuses
      every call 503 carrier_unavailable in a function without the
      integrations_invoke grant, sending nothing
    origin: >-
      UPS through the Integration Platform, Andrew 2026-10-18 21:10 UTC ("move
      it now"): services-commerce:docs/migrations/shipping/README.md#D-P8S-15
  - id: BR-CAP-COM-FUL-013-07
    proved_by: [ATS-COM-FUL-013-05, TST-COM-FUL-084]
    statement: >-
      UPS timeouts and rate limits are retryable, invalid requests are permanent
      failures, unanswered purchases are uncertain and disconnected connections
      are unavailable.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/unit/carriers/carrier-adapters.spec.js#answers
      a timeout and a rate limit as failed and retryable
    origin: none
  - id: BR-CAP-COM-FUL-013-08
    proved_by: []
    statement: >-
      Label requests use the connection's default format unless a supported
      format is selected, including thermal output, and unsupported formats are
      rejected before contacting a carrier.
    kind: validation
    enforced_at:
      - api
    must_prove: false
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/e2e/shipping.e2e.spec.js#refuses
      a label format the contract does not take (gif) 400, asking no carrier
    origin: none
  - id: BR-CAP-COM-FUL-013-09
    proved_by: [ATS-COM-FUL-013-06, TST-COM-FUL-078, TST-COM-FUL-084]
    statement: >-
      Voiding records a distinct keyed attempt, returns the parcel to packing or
      pulls it, retains cost and a finding after refusal, and retries an unknown
      void outcome with the next void-attempt key.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#keeps
      a void the carrier refused (refused.void_window_closed): the label
      void_failed with its cost, the void_failed finding
    origin: none
  - id: BR-CAP-COM-FUL-013-10
    proved_by: [ATS-COM-FUL-013-07, TST-COM-FUL-078]
    statement: >-
      Requested tracking updates parcels from carrier history to in transit,
      delivered, exception or returned to sender, and marks the shipment
      delivered after all parcels are delivered.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#tracks
      the UPS package to delivery from the platform’s history, records the
      counter package delivered by hand, and the shipment is delivered once both
      are
    origin: none
  - id: BR-CAP-COM-FUL-013-11
    proved_by: [ATS-COM-FUL-013-08, TST-COM-FUL-075, TST-COM-FUL-078]
    statement: >-
      Pickup shipments reject label purchase, void, tracking, manifest and
      carrier handoff as unsupported operations.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#refuses
      the carrier’s label purchase, void, manifest and handoff
      operation_not_supported
    origin: >-
      Decision L, Andrew 2026-10-18 ("add it now"):
      services-commerce:docs/migrations/shipping/README.md#D-P8S-14
  - id: BR-CAP-COM-FUL-013-12
    proved_by: []
    statement: >-
      Tracking is requested explicitly without a scheduled sweep or carrier
      notification, and carrier charges are not posted to Accounting.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:trackPackage
    origin: none
scenarios:
  - id: SC-CAP-COM-FUL-013-01
    given: UPS accepted a label purchase whose answer was lost.
    when: Request the parcel's label again.
    then: Recovery stores the first-attempt label without making a second purchase.
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#settles
      the ups:03 label by asking the carrier, then the same purchase under the
      same key: the label sold recorded on attempt 1, a pdf data URI, never a
      second sale
edge_cases:
  - id: SC-CAP-COM-FUL-013-02
    given: The carrier's void window has ended.
    when: Request a label void.
    then: The refused void retains cost and creates a void-failure finding.
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#keeps
      a void the carrier refused (refused.void_window_closed): the label
      void_failed with its cost, the void_failed finding
constraints: []
depends_on:
  - CAP-COM-FUL-010
  - CAP-COM-FUL-012
related:
  - CAP-COM-FUL-014
  - CAP-COM-FUL-015
journeys:
  - JNY-COM-FUL-003
open_questions: []
evidence:
  - repository: services-commerce
    paths:
      - >-
        modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js
      - modules/shipping/services/fulfillment/labels.ts
      - modules/shipping/tests/unit/carriers/carrier-adapters.spec.js
      - modules/shipping/tests/e2e/shipping.e2e.spec.js
  - repository: react-console
    paths: []
controls: [TC-IAM-006, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-SEC-001, TC-SEC-002, TC-SEC-003, TC-SEC-004, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-LOG-004, TC-LOG-005, TC-AVL-004, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-VEN-001, TC-VEN-002, TC-VEN-003, TC-PRV-001, TC-PRV-002]
exercised_by: [FAS-COM-FUL-03-01, FAS-COM-FUL-03-03, FAS-COM-FUL-03-05]
suites: [TST-COM-FUL-075, TST-COM-FUL-077, TST-COM-FUL-078, TST-COM-FUL-084]
---

# Purchase and follow carrier labels safely

## Purpose

Staff obtain labels and track parcels while preserving uncertain carrier outcomes.

## How It Works

Label work begins with a packed parcel and a configured carrier. Commerce records the purchase attempt before asking the carrier to act. A missing answer requires recovery of that existing purchase rather than a fresh purchase. Staff can resolve uncertain work using the carrier's own result. Voids have their own attempt history, and tracking updates arrive only when requested. Manual carrier work depends on information entered by a clerk. The product should provide packing, manual-label details and uncertainty resolution together in the console.

## Relationships

- Configure shipping coverage and collection options supplies or consumes related delivery records.
- Prepare an order's goods for dispatch supplies or consumes related delivery records.
- Record goods leaving with a carrier or collector supplies or consumes related delivery records.
- Process returned goods through inspection and disposition supplies or consumes related delivery records.
