---
id: WF-COM-CAT-018
title: Accept or dismiss an offer
trigger: >-
  A response performs a supported checkout, code or page action and records the result. Completed repeats
  reuse history, while concurrent first actions remain a proof gap.
product_area: commerce
module: catalog
revision: 1
status: draft
design_intent: open
implementation_evidence: observed
inference: []
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
implements:
  - CAP-COM-CAT-020
moves:
  - STATE-COM-CAT-012
crosses:
  - SVC-COM-CAT-recommendations
  - SVC-COM-CAT-promotions
idempotency: >-
  The HTTP acceptance route requires a request key. Completed acceptance repeats return earlier history, whose
  index is unique; different concurrent keys have no proved once-only checkout-action guarantee.
concurrency: >-
  The acceptance-history index prevents duplicate history entries. Since action processing precedes that
  insert, competing first requests may repeat checkout effects and require stronger proof or serialization.
hops:
  - 'n': 1
    actor_or_service: Recommendations service
    action: >-
      Validate shown status, non-session subject and caller access; return completed acceptance before
      checking first-request expiry.
    anchor: 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
    seam: sync
    on_failure: 'Reject missing, inaccessible, anonymous-estimate or expired offers.'
    left_inconsistent: No action has run.
    observer: The requesting person or service receives the result and any returned refusal.
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#cannot have the estimate
      accepted, even by a signed-in member: 409 sign_in_required
  - 'n': 2
    actor_or_service: Recommendations service through checkout workflows
    action: >-
      For item actions, call checkout add or replacement with the offer reference and write acceptance history
      in that transaction.
    anchor: 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
    seam: sync
    on_failure: Record eligible checkout or participant refusal details and return the refusal.
    left_inconsistent: Failed item processing rolls back the attempted checkout change.
    observer: The requesting person or service receives the result and any returned refusal.
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first acceptance to a
      second, repeated, adding nothing
  - 'n': 3
    actor_or_service: Recommendations service through the promotions seam
    action: >-
      For promotion actions, commit code application and its preview before separately writing acceptance
      history.
    anchor: 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
    seam: sync
    on_failure: Return recording failure while retaining the previously applied code.
    left_inconsistent: Checkout can retain a code without accepted-offer history; a retry can repeat application.
    observer: Request feedback and service logs expose failures where the caller returns them.
    provenance: observed
    source: 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
  - 'n': 4
    actor_or_service: Recommendations service
    action: >-
      For page actions, record and return the target; reject application-flow actions; record dismissal once
      when requested.
    anchor: 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:dismissOffer'
    seam: sync
    on_failure: Return unsupported-action or access refusals.
    left_inconsistent: A refused unsupported action retains no checkout change.
    observer: The requesting person or service receives the result and any returned refusal.
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses a rule
      whose action is start_journey, 409 action_unavailable: the journeys are R3’s
branches:
  - Placement copies the accepted item’s offer reference to the order line for conversion reporting.
waits: []
evidence:
  - >-
    services-commerce at c8b66a98: modules/recommendations/services/acceptance/accept-offer.ts (acceptOffer,
    dismissOffer, ownedOffer); services/persistence/offer-interactions.ts; aws/api/offers.routes.ts
    (idempotency required on acceptance).
controls: [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-LOG-004, TC-LOG-005, TC-AVL-004, TC-AVL-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002]
---

# Accept or dismiss an offer

## What It Does

A response performs a supported checkout, code or page action and records the result. Completed repeats reuse history, while concurrent first actions remain a proof gap.

## The Flow

```mermaid
sequenceDiagram
  participant B as Buyer
  participant R as Recommendations service
  participant K as Checkout workflows
  participant P as Promotions seam
  B->>R: accept (idempotency key)
  R->>R: exists, shown, owner, not expired
  alt add or replace
    R->>K: add item with offer identity
    R->>R: record accepted (same transaction)
  else apply promotion
    R->>P: enter code on checkout
    R->>R: record accepted (separate)
  end
  R-->>B: outcome (or repeated)
```

## When Something Fails

Reject missing, inaccessible, anonymous-estimate or expired offers. No action has run. Record eligible checkout or participant refusal details and return the refusal. Failed item processing rolls back the attempted checkout change. Return recording failure while retaining the previously applied code. Checkout can retain a code without accepted-offer history; a retry can repeat application. Return unsupported-action or access refusals. A refused unsupported action retains no checkout change.

## Open Design Questions

The implemented recovery and concurrency behaviour above defines the current boundary. Any change to transaction scope or product authority requires a recorded decision.
