---
id: WF-ACC-TRX-009
title: 'Request, approve and pay a refund'
trigger: >-
  Staff or Commerce request a return from receipt or credit value, directly or
  during billing cancellation.
product_area: accounting
module: transactions
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-ACC-TRX-012
moves:
  - STATE-ACC-TRX-010
  - STATE-ACC-TRX-006
  - STATE-ACC-TRX-001
crosses:
  - SVC-ACC-TRX-transactions
hops:
  - 'n': 1
    actor_or_service: Refund request
    action: >-
      Lock the return source, validate refundable money and destination, choose
      batching and reserve money pending any required approval.
    anchor: >-
      services-accounting:modules/transactions/services/refunds/refund-commands.ts:requestRefund
    seam: sync
    on_failure: Reject a return beyond refundable money without effects.
    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/refunds/refund-commands.ts:requestRefund;
      services-accounting:modules/transactions/tests/integration/services/refunds/refunds.integration.spec.js#it
      refuses more than an allocation holds (over_refund) and more than the
      unapplied money (over_refund)
  - 'n': 2
    actor_or_service: Refund approval
    action: Obtain approval from someone other than the requester.
    anchor: >-
      services-accounting:modules/transactions/services/refunds/refund-commands.ts:approveRefund
    seam: sync
    on_failure: Reject approval by the requester.
    left_inconsistent: The requested refund remains awaiting approval.
    observer: The return record exposes its pending approval.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/refunds/refund-commands.ts:approveRefund;
      services-accounting:modules/transactions/tests/integration/services/refunds/refunds.integration.spec.js#it
      requests it pending_approval, refusing to execute it
      (refund_not_requested) or to let the requester approve it (self_approval)
  - 'n': 3
    actor_or_service: Refund execution (transaction one)
    action: >-
      Release returned allocations and create the required billing and fee
      reductions; finish manual returns in this command.
    anchor: >-
      services-accounting:modules/transactions/services/refunds/refund-commands.ts:executeRefund
    seam: sync
    on_failure: Undo all work in the transaction.
    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/refunds/refund-commands.ts:executeRefund;
      services-accounting:modules/transactions/tests/integration/services/refunds/refunds.integration.spec.js#it
      keeps the invoice settled for the credited 2000 (a credit memo line) and
      reopens the 1000: the line owes 1000
  - 'n': 4
    actor_or_service: Integration Platform gateway
    action: >-
      Commit electronic processing and return money through the original
      merchant account using the refund identity and configured reason metadata.
    anchor: >-
      services-accounting:modules/transactions/services/payments/integrations-processor.ts:refundReasonMetadataOf
    seam: sync
    on_failure: >-
      A definite provider refusal fails the return; uncertainty retains
      processing.
    left_inconsistent: The return remains unresolved with money held and allocations released.
    observer: Scheduled recovery and attention expose the unresolved return.
    provenance: observed
    source: >-
      services-accounting:modules/transactions/services/payments/integrations-processor.ts:refundReasonMetadataOf;
      services-accounting:modules/transactions/tests/integration/services/refunds/refund-card-original-method.integration.spec.js#it
      refuses a check refund of the card’s unapplied money, saying the money
      goes back to the card
  - 'n': 5
    actor_or_service: Refund outcome (transaction two)
    action: >-
      Record provider completion or restore released lines and cancel associated
      reductions on failure.
    anchor: >-
      services-accounting:modules/transactions/services/refunds/refund-commands.ts:recordRefundOutcome
    seam: sync
    on_failure: Use the already recorded outcome after another resolver wins.
    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/refunds/refund-commands.ts:recordRefundOutcome;
      services-accounting:modules/transactions/tests/integration/services/refunds/refunds.integration.spec.js#it
      leaves the payment as it was: nothing unapplied, refunded or pending, its
      facts unchanged
idempotency: >-
  Command retry keys protect request and execution, and the refund identity
  deduplicates provider return calls.
concurrency: >-
  Reserved amounts exclude competing allocation, grant and refund uses;
  processing-state updates resolve the outcome once.
branches:
  - Combined request and execution requires both permissions.
  - >-
    Refund approval defaults off at workspace scope and has no staff
    configuration control.
waits:
  - >-
    Approval waits for another person; processing waits for provider recovery or
    human resolution without abandonment.
evidence:
  - >-
    services-accounting at f47cb263: services/refunds/refund-commands.ts;
    services/payments/integrations-processor.ts;
    db/migrations/20261017192623_payments_operations.sql
    (refunds_require_approval default false);
    docs/debt/refund-reason-metadata-may-carry-personal-data.md.
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-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-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-AI-005, TC-VEN-001, TC-VEN-002, TC-VEN-003, TC-PRV-001, TC-PRV-002]
---
# Request, approve and pay a refund

## What It Does

Refund coordinates source reservation, optional approval and money return. Electronic uncertainty retains the financial reservation until an outcome is established.

## The Flow

```mermaid
flowchart TD
  h0["Refund request"]
  h1["Refund approval"]
  h0 --> h1
  h2["Refund execution (transaction one)"]
  h1 --> h2
  h3["Integration Platform gateway"]
  h2 --> h3
  h4["Refund outcome (transaction two)"]
  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

Decide the allowed externally transmitted reason representation and record approval scope for the implemented policy.
