---
id: WF-ACC-TRX-006
title: Take a card or bank payment through the processor
trigger: Staff or Commerce request electronic collection through the payment gateway.
product_area: accounting
module: transactions
revision: 1
status: draft
design_intent: confirmed
origin: >-
  Andrew’s D-01 (payment intents) and the kept decisions on hosted fields and
  processor calls,
  services-accounting:docs/architecture/accounting-2.0/02-decisions.md#1. The
  assessment's decisions, D-01 to D-07 (Andrew, 2026-10-17)
implementation_evidence: observed
inference: []
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-ACC-TRX-007
  - CAP-ACC-TRX-008
  - CAP-ACC-TRX-020
moves:
  - STATE-ACC-TRX-005
  - STATE-ACC-TRX-006
crosses:
  - SVC-ACC-TRX-transactions
hops:
  - 'n': 1
    actor_or_service: Payment receive (transaction one)
    action: >-
      Validate merchant and accounting context and fee policy, then commit the
      claimed processing intent.
    anchor: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:receivePayment
    seam: sync
    on_failure: Reject preparation without making the external charge call.
    left_inconsistent: The complete transaction is undone.
    observer: The API response reports the outcome and applicable refusal code.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:receivePayment;
      services-accounting:modules/transactions/tests/integration/services/payments/tender.integration.spec.js#it
      refuses a planned allocation over the line’s balance (over_application),
      charging nothing
  - 'n': 2
    actor_or_service: Integration Platform gateway
    action: >-
      Call the provider outside a database transaction using the intent identity
      for deduplication and without persisting the instrument token.
    anchor: >-
      services-accounting:modules/transactions/services/payments/integrations-processor.ts:sendToGateway
    seam: sync
    on_failure: >-
      Definite refusal or gateway unavailability fails collection; an
      indeterminate response enters recovery.
    left_inconsistent: The attempt remains unresolved and the provider may have collected money.
    observer: >-
      The caller receives uncertainty and scheduled recovery monitors the
      attempt.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/integrations-processor.ts:sendToGateway;
      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
  - 'n': 3
    actor_or_service: Payment receive (transaction two)
    action: >-
      Record a still-processing outcome, creating the receipt, capped
      allocations, eligible reconciliation movement and history after capture.
    anchor: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:recordIntentOutcome
    seam: sync
    on_failure: Return the outcome stored by the resolver that won the race.
    left_inconsistent: The completed outcome leaves no partial financial transition.
    observer: The API response reports the outcome and applicable refusal code.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:recordIntentOutcome;
      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
  - 'n': 4
    actor_or_service: Payment receive (transaction two)
    action: >-
      Record definite failure, cancel the fee invoice and release the request
      key for another attempt.
    anchor: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:recordIntentOutcome
    seam: sync
    on_failure: Another request using the released key starts a separate attempt.
    left_inconsistent: The cancelled fee document remains retained.
    observer: The API response reports the outcome and applicable refusal code.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:recordIntentOutcome;
      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)
  - 'n': 5
    actor_or_service: Replay of the same key
    action: >-
      Resolve a matching retry from saved state or provider lookup without
      issuing a second charge.
    anchor: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:resolveIntentWithProcessor
    seam: sync
    on_failure: Return an uncertain outcome while recovery remains incomplete.
    left_inconsistent: Collection remains unresolved on the intent.
    observer: The client reads attempt progress by polling.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/payment-receive.ts:resolveIntentWithProcessor;
      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
idempotency: >-
  The request identifies the collection attempt; the intent identity keys the
  provider charge. A database constraint permits one receipt for each successful
  intent.
concurrency: >-
  Conditional outcome updates resolve the attempt once, with invoice locks used
  during planning and application.
branches:
  - Accepted bank debits await clearing before successful settlement.
  - >-
    Development can use the dummy processor while production selects the
    integration gateway.
waits:
  - >-
    Uncertain collection awaits retry lookup, scheduled recovery or staff
    resolution; payment events here handle subsequent bank clearing.
evidence:
  - >-
    services-accounting at f47cb263: services/payments/payment-receive.ts,
    integrations-processor.ts, dummy-processor.ts;
    services/settlements/card-fees.ts;
    docs/architecture/accounting-2.0/05-lifecycles.md §2, 06-integrity-model.md
    §7.
controls: [TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-AVL-001, 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]
---
# Take a card or bank payment through the processor

## What It Does

Collection deliberately separates committed preparation from external processing and outcome recording. Captured excess remains held for the customer rather than being rejected.

## The Flow

```mermaid
flowchart TD
  h0["Payment receive (transaction one)"]
  h1["Integration Platform gateway"]
  h0 --> h1
  h2["Payment receive (transaction two)"]
  h1 --> h2
  h3["Payment receive (transaction two)"]
  h2 --> h3
  h4["Replay of the same key"]
  h3 --> h4
```

The numbered hops identify the participating services, synchronization boundary and evidence. Branch conditions in the frontmatter explain where preparation, completion and recovery diverge.

## When Something Fails

Each hop records its rollback, retry or compensation boundary and the result visible to callers or operators. External outcomes can remain unresolved after local preparation commits; the listed recovery behavior defines what remains pending.

## Open Design Questions

The unresolved matters are recorded in the module findings; this workflow does not establish additional product approval.
