🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

ach-conform

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ach-conform

Static check for the Stripe ACH "succeeded isn't final" trap: webhook handlers that treat payment_intent.succeeded as terminal for us_bank_account charges without also handling the later payment_intent.payment_failed / charge.failed flip.

latest
Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
13
-43.48%
Maintainers
1
Weekly downloads
 
Created
Source

ach-conform

A static check for one specific Stripe footgun: webhook handlers that treat payment_intent.succeeded as final for an ACH (us_bank_account) charge.

Card payments settle in seconds and succeeded really is the end of the story. ACH debits don't — Stripe can flip a succeeded PaymentIntent to failed up to several business days later when the bank returns it (R01 insufficient funds, R02/R03 account closed or unauthorized). If your webhook handler fulfils the order or marks the invoice paid on succeeded and never listens for the later payment_intent.payment_failed / charge.failed, you ship a silent false-success bug: paid-looking orders that were never actually paid.

ach-conform scans your webhook handler source for that pattern (and for a second one: ACH intents that never account for requires_action, the micro-deposit verification state card payments never hit) and fails your CI when it finds them.

Install

npm install --save-dev ach-conform

Or run it without installing:

npx ach-conform src/webhooks/

Usage

npx ach-conform [path...]

Defaults to scanning the current directory. Exits 1 if it finds a succeeded-without-failed handler, 0 otherwise (the requires_action check is a warning and doesn't fail the build on its own).

$ npx ach-conform src/
[error] src/webhooks/stripe.js:14 (ach-succeeded-not-final)
  Handles payment_intent.succeeded for an ACH (us_bank_account) charge but never handles
  payment_intent.payment_failed or charge.failed. ACH debits can flip from succeeded to failed
  days later (R01 insufficient funds, R02/R03 closed or unauthorized). Treating succeeded as
  terminal ships a silent false-success bug -- fulfil/mark-paid logic needs a corresponding
  failure-path reversal.

ach-conform: 1 finding(s) in src/.

CI

# .github/workflows/ach-conform.yml
name: ach-conform
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npx ach-conform src/

What it checks

  • ach-succeeded-not-final (error) — a file references us_bank_account and handles payment_intent.succeeded, but never references payment_intent.payment_failed or charge.failed.
  • ach-missing-requires-action (warn) — a file handles ACH succeeded/processing states but never references requires_action or micro-deposits, so verification-pending customers may have no path forward.

This is deliberately a narrow, textual check — a couple of regexes over your source, not a full AST analysis of control flow. It will miss handlers split across multiple files or built with heavy indirection, and it can false-flag a file that handles the failure case somewhere it doesn't expect to look. Treat a clean run as "no smoking gun found," not a correctness proof.

Testing the real thing

A static check only catches the anti-pattern in your code, not whether your Stripe integration actually behaves as expected end to end. examples/test-clock-replay.js uses Stripe Test Clocks to advance a test-mode ACH PaymentIntent through the multi-day settlement window and confirm your webhook handler receives both events and reverses fulfilment correctly:

STRIPE_SECRET_KEY=sk_test_... node examples/test-clock-replay.js

examples/bad-handler.js and examples/good-handler.js are minimal handlers ach-conform flags and clears, respectively — useful as a reference for what the fix looks like.

Provenance

Built autonomously by an AI agent (fernforge).

License

MIT

Keywords

stripe

FAQs

Package last updated on 24 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts