Skip to content

plan: ACH companyEntryDescription via quote destination railOptions - #1139

Closed
ls-bolt[bot] wants to merge 1 commit into
mainfrom
10-07-ach-statement-descriptor
Closed

ls-bolt[bot] wants to merge 1 commit into
mainfrom
10-07-ach-statement-descriptor

Conversation

@ls-bolt

@ls-bolt ls-bolt Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

This PR has been claimed. The active PR is now #1142.

Summary

  • Lets a platform set an ACH companyEntryDescription on a quote. This is the 10-character NACHA batch header field shown on the recipient's statement.
  • POST /quotes AccountDestination gains an optional railOptions. Like railDetails, it is a oneOf discriminated by paymentRail, and its discriminator is the rail selection. The AchRailOptions variant (ACH and ACH_SAME_DAY) carries companyEntryDescription. A BasicRailOptions variant lets the platform select any other rail with no extra fields.
  • AchRailDetails gains companyEntryDescription, so the value appears on transactions and webhooks.

Approach

The client picks the rail by choosing a railOptions variant, so ACH-only fields cannot be sent with another rail. There is no rule that two fields must match. The flat destination.paymentRail is marked deprecated and is still accepted. A destination carries one or the other, expressed in the schema as not: {required: [paymentRail, railOptions]}. Only the quote + execute surface changes. transfer-in and transfer-out are deprecated and stay as they are. Everything is additive.

Changes: about 9 files, plus the bundle

  • openapi/components/schemas/quotes/AchRailOptions.yaml, BasicRailOptions.yaml and RailOptionsOneOf.yaml (new)
  • quotes/AccountDestination.yaml: adds railOptions, deprecates paymentRail, and adds the one-or-the-other rule
  • transactions/AchRailDetails.yaml: adds companyEntryDescription
  • Quote request examples, the outgoing-payment webhook example, the send-payment docs, and the changelog
  • make build bundle

Full plan with code sketches, verification and risks: docs/plans/2026-10-07-ach-statement-descriptor.md in this PR's diff.

Reply with a comment (e.g. LGTM) to approve. Emoji reactions don't notify me here.

@ls-bolt ls-bolt Bot added the bolt label Oct 7, 2026
@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated
grid-cards-demo Ignored Ignored Preview Oct 7, 2026 9:10pm UTC
grid-flow-builder Ignored Ignored Preview Oct 7, 2026 9:10pm UTC
grid-wallet-demo Ignored Ignored Preview Oct 7, 2026 9:10pm UTC

Request Review

@ls-bolt

ls-bolt Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

@greptile review

Copy link
Copy Markdown

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Low risk] Documents a planned feature for ACH payment descriptors.

This planning-only PR appears safe to merge.

What we checked:

  • ACH mappings fit the existing pattern: The existing RailDetailsOneOf already maps ACH and ACH_SAME_DAY to the same schema. The plan follows that pattern.

Summary

This PR adds an implementation plan, not the ACH descriptor feature itself.

  • Proposes optional destination.railOptions for ACH and ACH_SAME_DAY.
  • Defines descriptor limits, matching-rail rules, response fields, examples, and verification steps.
  • ls-bolt[bot] explicitly defers backend support and sweep destinations. The author also identifies reserved descriptors as a possible later restriction; these are not reported as omissions.

Reviews (1) · Last reviewed commit: "plan: ACH statement descriptor via desti..." · Reviewed by Greptile

Add an optional **`railOptions`** object to the two request-side destinations that
already take a `paymentRail`. Like `railDetails`, it is a oneOf discriminated by
`paymentRail`, so rail-specific inputs live on a per-rail schema. Its only variant for
now is `AchRailOptions` (`paymentRail: ACH | ACH_SAME_DAY`, `statementDescriptor`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, we should call it something like companyEntryDescription since that's what it literally is for ACH

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, renamed it to companyEntryDescription on both AchRailOptions and AchRailDetails.


🤖 molten-geyser-yh(#1) | Feedback


## Changes

### 1. `openapi/components/schemas/transfers/AchRailOptions.yaml` (new)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how relevant this is, but we only really care about this on the quote+execute API surface. transfer-in/transfer-out are both deprecated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I narrowed the scope to the quote + execute surface (AccountDestination) and left the deprecated transfer-in/out alone.


🤖 molten-geyser-yh(#1) | Feedback

paymentRail:
type: string
enum: [ACH, ACH_SAME_DAY]
description: Must match `destination.paymentRail`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to make this more baked-in at a structural level instead of saying "it must match" and catching it in a validator?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. railOptions now selects the rail: its paymentRail discriminator is the rail choice (AchRailOptions for ACH/ACH_SAME_DAY plus a field-less BasicRailOptions for every other rail), so ACH fields can only appear with an ACH rail and nothing needs to match. The flat destination.paymentRail is deprecated, and a schema not: {required: [paymentRail, railOptions]} says you can't send both.


🤖 molten-geyser-yh(#1) | Feedback

@ls-bolt

ls-bolt Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

🦣 Congratulations @akanter - your substantive review earned a Giant beaver! (rare)

It reached roughly black-bear size but had ridged incisors unlike those of modern tree-felling beavers.

View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/akanter?section=ice-age

@ls-bolt
ls-bolt Bot force-pushed the 10-07-ach-statement-descriptor branch from 785e0ed to 6c6babd Compare October 7, 2026 19:43
@ls-bolt ls-bolt Bot changed the title plan: ACH statement descriptor via destination railOptions plan: ACH companyEntryDescription via quote destination railOptions Oct 7, 2026
@ls-bolt

ls-bolt Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

⚡ Review ledger

Round 1

  1. Name it companyEntryDescription → FIXED: renamed on AchRailOptions and AchRailDetails in the plan
  2. Only the quote+execute surface matters; transfer-in/out are deprecated → FIXED: scope narrowed to AccountDestination on POST /quotes
  3. Make the rail match structural instead of a validator → FIXED: railOptions discriminator is now the rail selection (AchRailOptions + BasicRailOptions); flat paymentRail deprecated with not: {required: [paymentRail, railOptions]}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants