---
id: CAP-COM-ORD-012
title: Sell through the application that owns the purchase
feature: FEAT-COM-ORD-04
product_area: commerce
module: orders
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - CAP-COM-CFG-007
  - CAP-COM-CFG-008
  - CAP-COM-CHK-013
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
intent_sources:
  - 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#D14'
  - 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#Words used in this plan.'
purpose: Owning applications contribute their product knowledge to a common sale process.
outcomes:
  - Applications can register products for the common Commerce sale process.
  - A plain Accounting product can be sold without external delivery work.
concepts:
  - CON-COM-ORD-003
actors:
  - ACT-COM-018
  - ACT-COM-015
surfaces:
  - api
  - job
preconditions: []
postconditions: []
permissions:
  - key: commerce.checkouts.read
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-COM-ORD-012-01
    proved_by: [ATS-COM-ORD-005-19, ATS-COM-ORD-012-01, ATS-COM-ORD-013-15, TST-COM-ORD-146]
    statement: >-
      Deployment registration validates an application manifest and reconciles its registry, advancing the
      version on a repeat and retiring or reactivating types as declarations change.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#registers
      the same manifest again as one reconcile: the version moves, nothing else does
    origin: none
  - id: BR-CAP-COM-ORD-012-02
    proved_by: [ATS-COM-ORD-012-02, TST-COM-ORD-146]
    statement: >-
      Registration rejects malformed manifests, unsupported contract versions and missing or non-executable
      claim functions with the detected problems.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
      manifest that does not parse, every problem named (400 manifest_invalid)
    origin: none
  - id: BR-CAP-COM-ORD-012-03
    proved_by: [ATS-COM-ORD-012-03, TST-COM-ORD-146]
    statement: A declared product type cannot belong to two active selling applications.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
      product type another active participant sells (the floor is the partial unique index)
    origin: none
  - id: BR-CAP-COM-ORD-012-04
    proved_by: [ATS-COM-ORD-012-09, TST-COM-ORD-146]
    statement: >-
      The application database role reads the participant registry, with writes admitted only through
      registration.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#the
      application role writing the registry itself: SELECT alone, the function the one way in
    origin: none
  - id: BR-CAP-COM-ORD-012-05
    proved_by: [ATS-COM-ORD-003-14, ATS-COM-ORD-012-04, ATS-COM-ORD-012-13, TST-COM-ORD-149]
    statement: >-
      Application calls include the acting subject and use operation timeouts of five seconds for advice, ten
      for preparation and sixty otherwise, distinguishing unavailable calls from invalid responses.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/unit/client/lambda-participant-client.spec.js#times out by
      the contract’s timeout for the operation, aborting the call: advise 5 s, prepare 10 s
    origin: none
  - id: BR-CAP-COM-ORD-012-06
    proved_by: [ATS-COM-ORD-012-05, TST-COM-ORD-002]
    statement: >-
      Contract schemas reject undeclared structural fields in requests and responses, with support for the
      current major version and its predecessor when a second major exists.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: 'macroservice-libraries:packages/commerce-contracts/src/envelope.spec.ts#refuses an extra key'
    origin: none
  - id: BR-CAP-COM-ORD-012-07
    proved_by: [ATS-COM-ORD-012-06, TST-COM-ORD-148]
    statement: >-
      Item details must use a declared schema version and satisfy a published parser, while a remote type
      without a published parser relies on its version declaration.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/registry/table-registry.integration.spec.js#parses
      a payload through the in-process participant’s schema, refusing an undeclared version and a payload
      outside it
    origin: none
  - id: BR-CAP-COM-ORD-012-08
    proved_by: [ATS-COM-ORD-008-13, ATS-COM-ORD-012-07, TST-COM-ORD-082, TST-COM-ORD-150]
    statement: >-
      Commerce’s built-in plain-product application accepts empty details for Accounting products, takes no
      claim, plans one delivery unit and completes that unit without external work.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/unit/plain/plain-product-participant.spec.js#claims nothing
      for an item: ok, no claim, an attested empty payload and one unit to deliver
    origin: 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#D14'
  - id: BR-CAP-COM-ORD-012-09
    proved_by: [ATS-COM-ORD-012-10, TST-COM-ORD-029]
    statement: >-
      Readers can discover product types owned by active selling applications and their supported schemas;
      unsellable and unowned types are excluded.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/checkout/tests/e2e/holds-and-claims.e2e.spec.js#lists the sellable product
      types with the participant that sells each, to a reader; not the unsellable one
    origin: none
  - id: BR-CAP-COM-ORD-012-10
    proved_by: [ATS-COM-ORD-012-11, TST-COM-ORD-152]
    statement: >-
      A product type’s declared order kind classifies its sale, with the application identity used when no
      kind is declared.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/unit/registration/manifest-contract-versions.spec.js#classifies
      a sale by the declared order_kind, else by the participant’s id
    origin: none
  - id: BR-CAP-COM-ORD-012-11
    proved_by: [ATS-COM-ORD-012-12, TST-COM-ORD-154]
    statement: >-
      A type can declare up to twenty provisional pricing audiences for purchases that qualify other items in
      the same order.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/unit/registry/manifest-pricing-policy.spec.js#answers what
      a line grants: the audiences once each when the switch is on, nothing when off, undeclared, on with no
      audience, or not a policy
    origin: 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#D7'
  - id: BR-CAP-COM-ORD-012-12
    proved_by: [ATS-COM-ORD-012-08, ATS-COM-ORD-012-14, TST-COM-ORD-001]
    statement: >-
      Claim calls use a consistent ordering of application, resource and line to reduce competing lock-order
      conflicts.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      macroservice-libraries:packages/commerce-contracts/src/claims.spec.ts#orders by participant, then
      resource key, then line
    origin: none
  - id: BR-CAP-COM-ORD-012-13
    proved_by: [ATS-COM-ORD-012-15]
    statement: >-
      Placed-line delivery belongs to the fulfilment register, which calls the selling application when the
      frozen delivery condition opens.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#A3'
    origin: 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#A3'
    note: Fulfilment owns the delivery work register referenced here.
scenarios:
  - id: SC-CAP-COM-ORD-012-01
    given: A certificate fee needs billing but no shipping or application record creation.
    when: Staff buy the plain product and meet the order’s payment requirement.
    then: The fee follows normal pricing and billing and its built-in delivery completes without external work.
    provenance: documented
    source: 'services-commerce:docs/milestones/plans/COMM-M2-plan.md#D14'
edge_cases:
  - id: SC-CAP-COM-ORD-012-02
    given: An application manifest declares a claim function unavailable to the claimer.
    when: Register the manifest at deployment.
    then: Registration identifies the unusable function and does not activate the declaration.
    provenance: test
    source: >-
      services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
      claim function that does not exist, and one the claimer role cannot execute, each named (400
      sql_function_not_executable)
constraints: []
depends_on: []
related:
  - CAP-COM-ORD-003
  - CAP-COM-ORD-005
  - CAP-COM-ORD-013
journeys: []
open_questions:
  - OQ-COM-ORD-003
evidence:
  - >-
    Examined reference: macroservice-libraries:packages/commerce-contracts/src/claims.spec.ts#orders by
    participant, then resource key, then line
  - >-
    Examined reference: macroservice-libraries:packages/commerce-contracts/src/envelope.spec.ts#refuses an
    extra key
  - 'Examined reference: services-commerce:docs/milestones/plans/COMM-M2-plan.md#A3'
  - 'Examined reference: services-commerce:docs/milestones/plans/COMM-M2-plan.md#D14'
  - 'Examined reference: services-commerce:docs/milestones/plans/COMM-M2-plan.md#D7'
  - 'Examined reference: services-commerce:docs/milestones/plans/COMM-M2-plan.md#Words used in this plan.'
  - >-
    Examined reference: services-commerce:modules/checkout/tests/e2e/holds-and-claims.e2e.spec.js#lists the
    sellable product types with the participant that sells each, to a reader; not the unsellable one
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
    claim function that does not exist, and one the claimer role cannot execute, each named (400
    sql_function_not_executable)
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
    manifest that does not parse, every problem named (400 manifest_invalid)
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#a
    product type another active participant sells (the floor is the partial unique index)
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#registers
    the same manifest again as one reconcile: the version moves, nothing else does
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/persistence/participants.integration.spec.js#the
    application role writing the registry itself: SELECT alone, the function the one way in
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/integration/services/registry/table-registry.integration.spec.js#parses
    a payload through the in-process participant’s schema, refusing an undeclared version and a payload
    outside it
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/unit/client/lambda-participant-client.spec.js#times out by
    the contract’s timeout for the operation, aborting the call: advise 5 s, prepare 10 s
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/unit/plain/plain-product-participant.spec.js#claims nothing
    for an item: ok, no claim, an attested empty payload and one unit to deliver
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/unit/registration/manifest-contract-versions.spec.js#classifies
    a sale by the declared order_kind, else by the participant’s id
  - >-
    Examined reference:
    services-commerce:modules/participants/tests/unit/registry/manifest-pricing-policy.spec.js#answers what a
    line grants: the audiences once each when the switch is on, nothing when off, undeclared, on with no
    audience, or not a policy
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-TEN-004, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-LOG-004, TC-LOG-005, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CHG-007, TC-AVL-004, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, 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-ORD-01-05, FAS-COM-ORD-04-01, FAS-COM-ORD-04-02, FAS-COM-ORD-04-03, FAS-COM-ORD-04-04, FAS-COM-ORD-04-05]
suites: [TST-COM-ORD-001, TST-COM-ORD-002, TST-COM-ORD-029, TST-COM-ORD-082, TST-COM-ORD-146, TST-COM-ORD-148, TST-COM-ORD-149, TST-COM-ORD-150, TST-COM-ORD-152, TST-COM-ORD-154]
---

# Sell through the application that owns the purchase

## Purpose

Owning applications contribute their product knowledge to a common sale process. Commerce can coordinate the sale without implementing every application’s domain work.

## How It Works

An owning application registers its product types and contract information during deployment. Commerce uses that declaration to locate the application for an item. During preview and placement, the application evaluates details and prepares what it can sell. Limited resources use the declared claim arrangement. Delivery later passes through the fulfilment register to the appropriate owning application. Registration or invocation problems are reported instead of allowing Commerce to guess the application’s answer.

## Relationships

Cart review asks for application advice, placement asks for preparation and claims, and the neighbouring fulfilment module requests delivery or reversal.
