# Min transaction amount enforced with clear error

- **Pattern:** `ab-001446` (`finserv-form-validation.account-routing.min-amount-enforcement`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001446
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001446)

## Why it matters

Accepting zero-amount or sub-minimum transactions creates two concrete problems: payment processors (Stripe, Adyen) reject amounts below their floor and return errors that must be handled; and zero-amount transactions that do commit pollute the ledger with noise records that complicate reconciliation. OWASP A03 covers this as inadequate input validation. The error message matters too — WCAG 2.2 SC 3.3.1 and 3.3.3 require error messages to identify the constraint, not just report failure, so users know what to correct.

## Severity rationale

Medium because zero and sub-minimum amounts cause payment processor rejections that surface as user-visible errors and create invalid ledger records.

## Remediation

Enforce a minimum of 1 cent server-side and return a message that states the actual threshold, not a generic failure string.

```ts
// src/app/api/transfers/route.ts
const schema = z.object({
  amountCents: z.number().int().min(1, 'Minimum transaction amount is $0.01'),
});
const parsed = schema.safeParse(await req.json());
if (!parsed.success) {
  return Response.json(
    { error: parsed.error.issues[0]?.message },
    { status: 422 }
  );
}
```

Mirror the constraint in `src/components/TransferForm.tsx` with `min="0.01"` on the amount input and a visible hint below the field.

## Detection

- **ID:** `min-amount-enforcement`
- **Severity:** `medium`
- **What to look for:** Count all financial amount submission endpoints. For each, check whether a minimum amount (at least 1 cent / $0.01) is enforced server-side. Quote the minimum value and the error message text returned when the minimum is violated. Report: "X of Y amount endpoints enforce a server-side minimum with a descriptive error message."
- **Pass criteria:** At least 100% of amount endpoints enforce a minimum (at least 1 cent) server-side. The error message explicitly states the minimum value (e.g., "Minimum transaction is $0.01"), not a generic message like "Invalid amount". Report even on pass: "X endpoints enforce min of $Y with descriptive errors."
- **Fail criteria:** Any endpoint accepts zero or sub-minimum amounts, or the error message is generic (fewer than 5 words describing the requirement).
- **Must not pass when:** The minimum is enforced but the error message says only "Validation failed" or "Invalid input" — users need to know the actual threshold.
- **Skip (N/A) when:** The project has no minimum transaction amount concept (0 financial submission endpoints found).
- **Detail on fail:** Example: `"Server accepts zero and negative amounts. No minimum validation or error message."` or `"Minimum enforced but error message is 'Validation failed' instead of 'Minimum transaction is $0.01'"`
- **Cross-reference:** The max-amount-limits check in this category covers the upper bound; together they define the valid amount range.
- **Remediation:** Enforce minimums with clear messaging in `src/app/api/` route handlers:

  **In `src/app/api/transfers/route.ts`:**
  ```ts
  const MIN_TRANSACTION_AMOUNT = 1; // 1 cent, i.e., $0.01

  if (amountCents < MIN_TRANSACTION_AMOUNT) {
    throw new ValidationError('Minimum transaction amount is $0.01');
  }
  ```

## External references

- cwe CWE-20
- owasp A03
- wcag 3.3.1

Taxons: injection-and-input-trust, user-experience

HTML version: https://auditbuffet.com/patterns/ab-001446
