feat(openapi): add rail + settlement-timing fields to OutgoingTransaction#633
Conversation
…tion Add four optional, nullable fields to the OutgoingTransaction schema so the rail and settlement-timing data that sparkcore already emits on outgoing_payment.* webhooks becomes first-class in the typed API model: - paymentRail: nullable PaymentRail enum, the rail used to settle the txn - railSelectionMode: nullable AUTO/MANUAL enum (new RailSelectionMode schema) - expectedSettlementAt: nullable date-time of expected settlement - settlementTimelineSeconds: nullable integer seconds to settlement All four are additive and backward-compatible: not in `required`, and nullable for instant rails, AUTO mode before a rail is resolved, and non-direct-destination transactions. Bump the spec version to 2026-06-29, rebundle openapi.yaml + mintlify/openapi.yaml, and surface the new fields in the ramps outgoing-payment webhook payload example. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FTtfvC6Qcsh3M62jVaCT1Y
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
✱ Stainless preview builds for gridThis PR will update the cli csharp go kotlin openapi php python ruby typescript ✅ grid-ruby studio · code
|
Greptile SummaryThis PR promotes four settlement-timing and rail-selection fields (
Confidence Score: 4/5Safe to merge — purely additive schema extension with no breaking changes to existing fields or required properties. The change is clean and backward-compatible. Two field descriptions in OutgoingTransaction.yaml use phrasing that could mislead consumers: openapi/components/schemas/transactions/OutgoingTransaction.yaml — the two description suggestions on paymentRail and expectedSettlementAt are worth a quick look before publishing the new API version.
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/transactions/OutgoingTransaction.yaml | Adds four optional nullable fields (paymentRail, railSelectionMode, expectedSettlementAt, settlementTimelineSeconds); structure and nullable idioms follow existing conventions, but two field descriptions have minor accuracy issues |
| openapi/components/schemas/common/RailSelectionMode.yaml | New two-value enum (AUTO/MANUAL) matching the structure of the adjacent PaymentRail.yaml; clean and consistent |
| openapi/openapi.yaml | Source root spec with version bump only (2026-06-25 → 2026-06-29); RailSelectionMode is auto-discovered by bundler via $ref chain |
| openapi.yaml | Generated bundle; diff matches source changes exactly — version bump plus RailSelectionMode schema and four new OutgoingTransaction fields |
| mintlify/openapi.yaml | Second generated bundle (Mintlify copy); identical changes to openapi.yaml, consistent |
| mintlify/ramps/platform-tools/webhooks.mdx | Adds the four new fields to the OUTGOING_PAYMENT webhook example; JSON syntax is valid and example values are plausible for an ACH transaction |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Platform
participant GridAPI
participant SparkCore
participant Beneficiary
Platform->>GridAPI: "POST /quotes/{id}/execute"
GridAPI->>SparkCore: Initiate OutgoingTransaction
SparkCore-->>GridAPI: "Transaction created (paymentRail=null, railSelectionMode=AUTO)"
GridAPI-->>Platform: OUTGOING_PAYMENT.PENDING webhook
SparkCore->>SparkCore: Resolve payment rail
SparkCore-->>GridAPI: "Rail resolved (paymentRail=ACH, expectedSettlementAt set)"
GridAPI-->>Platform: OUTGOING_PAYMENT.PROCESSING webhook (paymentRail, railSelectionMode, expectedSettlementAt, settlementTimelineSeconds)
SparkCore->>Beneficiary: Initiate ACH transfer
SparkCore-->>GridAPI: Transaction settled on Grid side
GridAPI-->>Platform: "OUTGOING_PAYMENT.COMPLETED webhook (settledAt=now, expectedSettlementAt=T+1d)"
Beneficiary-->>Beneficiary: ACH clears at T+1d (expectedSettlementAt)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Platform
participant GridAPI
participant SparkCore
participant Beneficiary
Platform->>GridAPI: "POST /quotes/{id}/execute"
GridAPI->>SparkCore: Initiate OutgoingTransaction
SparkCore-->>GridAPI: "Transaction created (paymentRail=null, railSelectionMode=AUTO)"
GridAPI-->>Platform: OUTGOING_PAYMENT.PENDING webhook
SparkCore->>SparkCore: Resolve payment rail
SparkCore-->>GridAPI: "Rail resolved (paymentRail=ACH, expectedSettlementAt set)"
GridAPI-->>Platform: OUTGOING_PAYMENT.PROCESSING webhook (paymentRail, railSelectionMode, expectedSettlementAt, settlementTimelineSeconds)
SparkCore->>Beneficiary: Initiate ACH transfer
SparkCore-->>GridAPI: Transaction settled on Grid side
GridAPI-->>Platform: "OUTGOING_PAYMENT.COMPLETED webhook (settledAt=now, expectedSettlementAt=T+1d)"
Beneficiary-->>Beneficiary: ACH clears at T+1d (expectedSettlementAt)
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
openapi/components/schemas/transactions/OutgoingTransaction.yaml:76-83
The `paymentRail` description says "Null until a rail is resolved," but the phrase "until" implies the field will eventually become non-null for every transaction. Per the PR description, it is *permanently* null for instant rails and non-direct-destination transactions. Consumers relying on polling for a non-null value would wait forever in those cases.
```suggestion
paymentRail:
anyOf:
- $ref: ../common/PaymentRail.yaml
- type: 'null'
description: >-
The payment rail used to settle this transaction (e.g. ACH, WIRE,
NEFT, FASTER_PAYMENTS). Uses the same values as the PaymentRail sent
on quote requests. Null when no external rail is used (e.g. instant
or intra-network transfers) or before a rail is resolved.
```
### Issue 2 of 2
openapi/components/schemas/transactions/OutgoingTransaction.yaml:92-99
The parenthetical "e.g. instant rails" is listed as an example of when settlement time is *not yet known*, but instant rails settle immediately — so the time is actually known (it's now). This makes the description self-contradictory. A developer reading it might conclude instant-rail transactions can eventually gain a non-null `expectedSettlementAt`, which is incorrect.
```suggestion
expectedSettlementAt:
type:
- string
- 'null'
format: date-time
description: >-
Expected settlement time at the beneficiary. Null for instant rails
(settlement is immediate) and before a rail with deferred settlement
is resolved.
```
Reviews (1): Last reviewed commit: "feat(openapi): add rail + settlement-tim..." | Re-trigger Greptile
| paymentRail: | ||
| anyOf: | ||
| - $ref: ../common/PaymentRail.yaml | ||
| - type: 'null' | ||
| description: >- | ||
| The payment rail used to settle this transaction (e.g. ACH, WIRE, | ||
| NEFT, FASTER_PAYMENTS). Uses the same values as the PaymentRail sent | ||
| on quote requests. Null until a rail is resolved. |
There was a problem hiding this comment.
The
paymentRail description says "Null until a rail is resolved," but the phrase "until" implies the field will eventually become non-null for every transaction. Per the PR description, it is permanently null for instant rails and non-direct-destination transactions. Consumers relying on polling for a non-null value would wait forever in those cases.
| paymentRail: | |
| anyOf: | |
| - $ref: ../common/PaymentRail.yaml | |
| - type: 'null' | |
| description: >- | |
| The payment rail used to settle this transaction (e.g. ACH, WIRE, | |
| NEFT, FASTER_PAYMENTS). Uses the same values as the PaymentRail sent | |
| on quote requests. Null until a rail is resolved. | |
| paymentRail: | |
| anyOf: | |
| - $ref: ../common/PaymentRail.yaml | |
| - type: 'null' | |
| description: >- | |
| The payment rail used to settle this transaction (e.g. ACH, WIRE, | |
| NEFT, FASTER_PAYMENTS). Uses the same values as the PaymentRail sent | |
| on quote requests. Null when no external rail is used (e.g. instant | |
| or intra-network transfers) or before a rail is resolved. |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/transactions/OutgoingTransaction.yaml
Line: 76-83
Comment:
The `paymentRail` description says "Null until a rail is resolved," but the phrase "until" implies the field will eventually become non-null for every transaction. Per the PR description, it is *permanently* null for instant rails and non-direct-destination transactions. Consumers relying on polling for a non-null value would wait forever in those cases.
```suggestion
paymentRail:
anyOf:
- $ref: ../common/PaymentRail.yaml
- type: 'null'
description: >-
The payment rail used to settle this transaction (e.g. ACH, WIRE,
NEFT, FASTER_PAYMENTS). Uses the same values as the PaymentRail sent
on quote requests. Null when no external rail is used (e.g. instant
or intra-network transfers) or before a rail is resolved.
```
How can I resolve this? If you propose a fix, please make it concise.| expectedSettlementAt: | ||
| type: | ||
| - string | ||
| - 'null' | ||
| format: date-time | ||
| description: >- | ||
| Expected settlement time at the beneficiary. Null when not yet known | ||
| (e.g. instant rails, or before a rail is resolved). |
There was a problem hiding this comment.
The parenthetical "e.g. instant rails" is listed as an example of when settlement time is not yet known, but instant rails settle immediately — so the time is actually known (it's now). This makes the description self-contradictory. A developer reading it might conclude instant-rail transactions can eventually gain a non-null
expectedSettlementAt, which is incorrect.
| expectedSettlementAt: | |
| type: | |
| - string | |
| - 'null' | |
| format: date-time | |
| description: >- | |
| Expected settlement time at the beneficiary. Null when not yet known | |
| (e.g. instant rails, or before a rail is resolved). | |
| expectedSettlementAt: | |
| type: | |
| - string | |
| - 'null' | |
| format: date-time | |
| description: >- | |
| Expected settlement time at the beneficiary. Null for instant rails | |
| (settlement is immediate) and before a rail with deferred settlement | |
| is resolved. |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/transactions/OutgoingTransaction.yaml
Line: 92-99
Comment:
The parenthetical "e.g. instant rails" is listed as an example of when settlement time is *not yet known*, but instant rails settle immediately — so the time is actually known (it's now). This makes the description self-contradictory. A developer reading it might conclude instant-rail transactions can eventually gain a non-null `expectedSettlementAt`, which is incorrect.
```suggestion
expectedSettlementAt:
type:
- string
- 'null'
format: date-time
description: >-
Expected settlement time at the beneficiary. Null for instant rails
(settlement is immediate) and before a rail with deferred settlement
is resolved.
```
How can I resolve this? If you propose a fix, please make it concise.Address review feedback on OutgoingTransaction field descriptions: - paymentRail: replace "Null until a rail is resolved" (which implied the field always eventually becomes non-null) with an accurate description of the permanent-null cases — instant/intra-network transfers and non-direct-destination transactions — as well as the pre-resolution case. - expectedSettlementAt: instant rails settle immediately (time is known, not "not yet known"); reword so it's null for instant rails and before a deferred-settlement rail is resolved. Wording only; no schema, type, or required-field changes. Rebundled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FTtfvC6Qcsh3M62jVaCT1Y
Summary
Adds four optional, nullable fields to the
OutgoingTransactionschema so the rail and settlement-timing data that sparkcore already emits onoutgoing_payment.*webhooks (today as a raw-JSON post-process, webdev #29090) becomes first-class in the typed API model. This makes the fields show up in generated clients/SDKs and the public webhook docs. The change is purely additive and backward-compatible.Fields added
paymentRailPaymentRailenum refanyOf: [$ref, {type: 'null'}]railSelectionModeRailSelectionModeenum (AUTO/MANUAL)anyOf: [$ref, {type: 'null'}]expectedSettlementAtformat: date-timetype: [string, 'null']settlementTimelineSecondstype: [integer, 'null']All four are not added to
requiredand are nullable — they are null for instant rails, AUTO mode before a rail is resolved, and non-direct-destination transactions.Changes
openapi/components/schemas/transactions/OutgoingTransaction.yaml— the four new properties.openapi/components/schemas/common/RailSelectionMode.yaml— new named enum schema (placed alongsidePaymentRail.yaml, matching the repo's one-enum-per-file convention).openapi/openapi.yaml— version bump2026-06-25→2026-06-29(date-based release convention).openapi.yaml+mintlify/openapi.yaml— regenerated bundles (npm run build:openapi).mintlify/ramps/platform-tools/webhooks.mdx— surfaced the new fields in theOUTGOING_PAYMENTwebhook payload example. Other webhook docs render the model via$refand pick up the fields automatically.Conventions followed
anyOf+type: 'null'for refs (as inCard.yaml), andtype: [..., 'null']lists for scalars (as inAgentSpendingLimits.yaml).paymentRailvalue is the grid-apiPaymentRailname (e.g.FASTER_PAYMENTS), matching the enum exactly — no internal aliases.Verification
redoclyvalidation: ✅ valid (warnings are all pre-existing and unrelated).spectral lint --fail-severity=error: ✅ exit 0, no errors.requiredis unchanged (still onlytype,sentAmount,source) and the regeneratedOutgoingTransactionmodel includes all four fields as optional/nullable. The only non-additive line across the bundles is the version bump.Follow-up
Downstream webdev change is tracked as AT-5666: once a new grid-api package version is published, bump the pinned version, regenerate the client, and move sparkcore's webhook enrichment out of the raw-dict post-process into the typed model.
🤖 Generated with Claude Code
Generated by Claude Code