---
id: STATE-ACC-TRX-005
title: Payment intent lifecycle
object: DOM-ACC-TRX-003
product_area: accounting
module: transactions
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: not created
    meaning: No collection attempt has been committed.
  - name: processing
    meaning: The committed attempt is claimed for processor collection or recovery.
  - name: in review
    meaning: >-
      The processing record carries a human-review marker after scheduled key
      lookups are exhausted.
  - name: succeeded
    meaning: Capture is recorded with one corresponding receipt.
  - name: failed
    meaning: The attempt has a definite failure outcome and no recorded capture.
  - name: abandoned
    meaning: >-
      The sweeper closed a day-old unresolved processing attempt outside human
      review.
transitions:
  - from: not created
    to: processing
    trigger: start electronic collection
    guard: >-
      Merchant account, unit currency, batch, open period and allocation plan
      must be eligible, with required fees accepted.
    side_effects:
      - commit and claim the intent
      - create any required fee invoice
      - append attempt history
    who: Staff with payment-create permission or the Commerce tender function.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/tender.integration.spec.js#it
      resolves the intent succeeded, naming the payment, claimed and resolved,
      with the batch chosen at initiation
  - from: processing
    to: succeeded
    trigger: record confirmed capture
    guard: The attempt must still be processing.
    side_effects:
      - create the receipt with current-balance allocation caps
      - create the reconciliation movement where eligible
      - append financial facts and history
    who: 'The collection call, its replay or scheduled recovery.'
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/tender.integration.spec.js#it
      is capped at what the line owes then and the rest stays unapplied: the
      charged money is never refused
  - from: processing
    to: failed
    trigger: record definite collection failure
    guard: The attempt must still be processing.
    side_effects:
      - save the failure code
      - release request-key ownership
      - cancel the fee invoice
    who: The collection call or scheduled recovery.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/tender.integration.spec.js#it
      frees the key: the same key sent again is tendered again, as a new intent
      (declined again here)
  - from: processing
    to: processing
    trigger: retain an uncertain outcome
    guard: >-
      The response is uncertain or absent within its applicable lookup grace
      period.
    side_effects:
      - retain request-key ownership
      - update due-lookup progress
    who: 'The collection call, its replay or scheduled recovery.'
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/tender.integration.spec.js#it
      answers the payment to a replay of the same key, from what the processor
      holds, with no second charge
  - from: processing
    to: in review
    trigger: request human resolution
    guard: Scheduled key lookup recovery must have exhausted its steps.
    side_effects:
      - mark the processing attempt for review
      - publish the attention item
    who: Scheduled recovery.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/lost-answers.integration.spec.js#it
      hands the intent to a person at the last lookup: needs_review, the item
      published with its facts
  - from: in review
    to: succeeded
    trigger: confirm capture manually
    guard: >-
      The attempt must be in review and staff must supply the verified provider
      reference.
    side_effects:
      - record the receipt once
      - resolve the attention item
    who: Staff with payment-update permission.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/lost-answers.integration.spec.js#it
      refuses both decisions before the last lookup (lost_answer_not_in_review)
  - from: in review
    to: failed
    trigger: confirm failure manually
    guard: The attempt must be in review.
    side_effects:
      - record definitive failure
      - resolve the attention item
    who: Staff with payment-update permission.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts;
      services-accounting:modules/transactions/services/payments/lost-answer-commands.ts;
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts;
      services-accounting:modules/transactions/db/payment-intents.table.ts;
      services-accounting:modules/transactions/tests/integration/services/payments/lost-answers.integration.spec.js#it
      refuses both decisions before the last lookup (lost_answer_not_in_review)
  - from: processing
    to: abandoned
    trigger: close day-old unresolved collection
    guard: >-
      The attempt remains processing after lookup or error and is outside human
      review.
    side_effects:
      - record abandonment history
      - emit an error log
    who: Scheduled recovery.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/intent-sweeper.ts:sweepProcessingIntents
invalid:
  - from: failed
    to: processing
    why: >-
      Retry after a definite failure starts another intent instead of resuming
      this one.
  - from: succeeded
    to: processing
    why: >-
      Captured attempts stay successful; subsequent returns belong to payment
      records.
  - from: succeeded
    to: failed
    why: >-
      A captured attempt cannot be rewritten as failed; reversal or refund
      describes a later return.
concurrency: >-
  Resolution updates only a processing attempt, allowing a call, replay and
  sweeper to race without duplicate receipt creation. The gateway uses the
  intent identity as its collection key.
invariants:
  - INV-DOM-ACC-TRX-003-06
  - INV-DOM-ACC-TRX-003-07
evidence:
  - >-
    services-accounting at f47cb263: services/payments/payment-receive.ts,
    intent-sweeper.ts, lost-answer-rules.ts, lost-answer-commands.ts;
    attention/processor-answer-lost.attention.ts;
    docs/architecture/accounting-2.0/05-lifecycles.md §2.
---
# Payment intent lifecycle

## The Lifecycle

Human review is a marker on processing, not another stored status. Empty lookup by provider reference can establish failure after its grace period; lookup by request key follows scheduled escalation.

```mermaid
stateDiagram-v2
  direction LR
  state "not created" as s0
  state "processing" as s1
  state "in review" as s2
  state "succeeded" as s3
  state "failed" as s4
  state "abandoned" as s5
  s0 --> s1 : start electronic collection
  s1 --> s3 : record confirmed capture
  s1 --> s4 : record definite collection failure
  s1 --> s1 : retain an uncertain outcome
  s1 --> s2 : request human resolution
  s2 --> s3 : confirm capture manually
  s2 --> s4 : confirm failure manually
  s1 --> s5 : close day-old unresolved collection
```

## Transitions Explained

The transition rows identify the initiating action, eligibility checks, resulting records and responsible caller. They retain the pinned evidence for each path.

## What Cannot Happen

The invalid-transition rows describe final-state protection and unsupported paths; command eligibility remains distinct from the declared state vocabulary.

## Concurrency and Timing

Resolution updates only a processing attempt, allowing a call, replay and sweeper to race without duplicate receipt creation. The gateway uses the intent identity as its collection key. The minute sweeper also abandons unresolved day-old processing attempts outside human review. Refund and void recovery use different abandonment rules.
