Skip to content

Add missing OutgoingTransactionFailureReason enum values - #629

Merged
peterrojs merged 3 commits into
mainfrom
06-29-grid-api-add-outgoing-failure-reasons
Jul 30, 2026
Merged

Add missing OutgoingTransactionFailureReason enum values#629
peterrojs merged 3 commits into
mainfrom
06-29-grid-api-add-outgoing-failure-reasons

Conversation

@peterrojs

Copy link
Copy Markdown
Contributor

Summary

Adds four missing values to the public OutgoingTransactionFailureReason enum so the Grid API can represent the full set of failure reasons the backend actually emits:

  • EXECUTION_FAILED_POST_DEBIT
  • SETTLEMENT_FAILED
  • TIMEOUT
  • MANUAL_REFUND

Why

sparkcore maps its internal UmaaasSendOperationFailureReason onto this public enum by name (sparkcore/grid/objects/transaction.py::_get_outgoing_transaction_failure_reason). The internal enum has these four members but the public enum didn't, so the mapping threw a (caught) KeyError, logged "Key does not exist in GridOutgoingTransactionFailureReason", and returned None — meaning the API reported an empty failure reason for settlement / timeout / manual-refund / post-debit failures, plus noisy ERROR logs on every render of such a transaction.

Surfaced while debugging the embedded-USDB onramp failures (those failed send-operations carry SETTLEMENT_FAILED).

What changed

  • openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yaml — source enum (the only hand edit)
  • openapi.yaml + mintlify/openapi.yaml — regenerated via make build (redocly bundle)

Notes / decisions

  • LSP_OPERATIONAL_FAILURE intentionally NOT added — sparkcore deliberately maps it to QUOTE_EXECUTION_FAILED (internal-only distinction for LSP-liquidity alerting), so it should never reach the public enum.
  • Alternative considered for EXECUTION_FAILED_POST_DEBIT: it's documented internally as an internal-only distinction (lets the compensation scanner safely credit). I chose to expose it for completeness so the mapping needs no special-case, but it could instead be mapped to QUOTE_EXECUTION_FAILED in sparkcore like LSP_OPERATIONAL_FAILURE. Easy to flip — happy to if you'd prefer to keep it internal.

Follow-up (separate PR, needed for the runtime fix)

This is the canonical spec change. webdev's vendored generated grid-api python package (webdev/grid-api, consumed by sparkcore as a path dep) must be regenerated from this spec via grid-api/update_schema.sh + a packageVersion bump + sparkcore/uv.lock update for sparkcore to actually pick up the new members. That regen needs the Java/Maven/openapi-generator toolchain and is a separate webdev PR — until it lands, sparkcore still KeyErrors.

Test plan

  • make lint-openapi (redocly + spectral, --fail-severity=error) passes — no new findings
  • Bundle is deterministic (clean rebuild produces no diff); change is exactly +4 enum lines across the source component and both bundled outputs

🤖 cryptic-tempest(#1) | Feedback

Original PR: #628

Add EXECUTION_FAILED_POST_DEBIT, SETTLEMENT_FAILED, TIMEOUT, and MANUAL_REFUND
to the OutgoingTransactionFailureReason enum so the public Grid API can
represent the full set of failure reasons the backend emits. Without them,
sparkcore's mapping from the internal UmaaasSendOperationFailureReason to this
public enum (by name) throws a KeyError and reports an empty failure reason for
settlement/timeout/manual-refund/post-debit failures.
@akanterGraphite App

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actionsBot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

cli

chore(internal): regenerate SDK with no functional changes

go

feat(api): add failure reasons to OutgoingTransaction

kotlin

feat(api): add failure reason values to OutgoingTransaction

openapi

feat(api): add enum values to OutgoingTransactionFailureReason

php

feat(api): add failure reason enum values to OutgoingTransaction

python

feat(api): add failure reason values to outgoing_transaction

ruby

feat(api): add failure reason enum values to outgoing transaction

typescript

feat(api): add failure reason values to OutgoingTransaction
⚠️grid-openapistudio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️

grid-rubystudio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ✅lint ✅test ✅

⚠️grid-gostudio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@6d9aee8b9efd37dee46397a15a62ec92565244bb
⚠️grid-kotlinstudio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
generate ⚠️build ✅lint ✅test ❗

⚠️grid-pythonstudio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/709761d4bd6fdd0ed29a7e68c9920bd722333711/grid-0.0.1-py3-none-any.whl
grid-typescriptstudio · conflict

Your SDK build had at least one note diagnostic.

grid-phpstudio · code

Your SDK build had at least one "note" diagnostic.
generate ✅lint ✅test ✅

⚠️grid-clistudio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
generate ⚠️build ⏭️lint ⏭️test ❗


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-07-30 18:40:56 UTC

@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds four missing OutgoingTransactionFailureReason enum values (EXECUTION_FAILED_POST_DEBIT, SETTLEMENT_FAILED, TIMEOUT, MANUAL_REFUND) to the public OpenAPI spec so it covers the full set of failure codes the backend can emit, eliminating the KeyError-and-None fallback in sparkcore's name-based mapping. The source YAML in openapi/ was edited directly and both bundled outputs were regenerated via make build, exactly following the repo's conventions.

  • openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yaml — the only hand-edited file; four enum values appended
  • openapi.yaml + mintlify/openapi.yaml — deterministic regenerations via make build; diffs are identical and match the source edit exactly

Confidence Score: 5/5

Safe to merge — a minimal, additive enum extension with no breaking changes and both bundled outputs correctly regenerated.

The change is purely additive (new enum values only), the source file is the only hand-edited file, both bundles were regenerated via make build and produce identical diffs, make lint-openapi is confirmed passing, and LSP_OPERATIONAL_FAILURE is intentionally kept out with clear justification. No existing consumers break since the values were previously missing rather than having different names.

No files require special attention.

Important Files Changed

FilenameOverview
openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yamlSource enum extended with four new values; this is the only hand-edited file in the PR and the change is correct
openapi.yamlRegenerated bundle (via make build); diff is exactly the four added enum lines, consistent with the source change
mintlify/openapi.yamlSecond regenerated bundle for Mintlify docs; identical diff to openapi.yaml, as expected

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[sparkcore internal\nUmaaasSendOperationFailureReason] -->|name-based mapping| B{Key in public\nGridOutgoingTransactionFailureReason?}
B -->|Before this PR\nEXECUTION_FAILED_POST_DEBIT\nSETTLEMENT_FAILED\nTIMEOUT\nMANUAL_REFUND| C[KeyError → None\nblank failure reason]
B -->|After this PR\nall four values added| D[Correct enum value\nreturned to API consumer]
B -->|LSP_OPERATIONAL_FAILURE\nintentionally omitted| E[Maps to\nQUOTE_EXECUTION_FAILED]
Loading
%%{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"}}}%%
flowchart TD
A[sparkcore internal\nUmaaasSendOperationFailureReason] -->|name-based mapping| B{Key in public\nGridOutgoingTransactionFailureReason?}
B -->|Before this PR\nEXECUTION_FAILED_POST_DEBIT\nSETTLEMENT_FAILED\nTIMEOUT\nMANUAL_REFUND| C[KeyError → None\nblank failure reason]
B -->|After this PR\nall four values added| D[Correct enum value\nreturned to API consumer]
B -->|LSP_OPERATIONAL_FAILURE\nintentionally omitted| E[Maps to\nQUOTE_EXECUTION_FAILED]
Loading

Reviews (1): Last reviewed commit: "Add missing OutgoingTransactionFailureRe..." | Re-trigger Greptile

@jklein24
jklein24 requested a review from shreyavJuly 13, 2026 21:20
@vercel

vercelBot commented Jul 17, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
grid-flow-builderReadyReadyPreviewJul 30, 2026 6:14pm
grid-wallet-demoReadyReadyPreviewJul 30, 2026 6:14pm

Request Review

@ls-bolt

ls-boltBot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

📌 Bolt Status

2026-07-17 17:05:45 UTC — ⚡ Agent cryptic-tempest-3(#3) started
2026-07-17 17:05:49 UTC — ⚡ Agent thundering-titanium(#1) started
2026-07-17 17:08:26 UTC — ⚡ Agent steady-hashrate(#1) started
2026-07-30 18:34:56 UTC — ⚡ Agent cryptic-tempest-4(#4) started


Feedback

@mintlify

mintlifyBot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

ProjectStatusPreviewUpdated (UTC)
Grid🟢 ReadyView PreviewJul 17, 2026, 5:08 PM

Both sides extended OutgoingTransactionFailureReason additively: main added
SCA_NOT_COMPLETED (#762), this branch adds EXECUTION_FAILED_POST_DEBIT,
SETTLEMENT_FAILED, TIMEOUT and MANUAL_REFUND. Resolved as the union and
regenerated both bundles with `make build`.
Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
@ls-bolt

ls-boltBot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Merged main in and resolved the conflict — the PR is MERGEABLE again.

What conflicted: both sides extended OutgoingTransactionFailureReason additively. main picked up SCA_NOT_COMPLETED (#762) after this branch was cut, so all three files collided.

How it was resolved: unioned the enum (SCA_NOT_COMPLETED first, then this branch's four values) and re-ran make build rather than hand-merging the bundled outputs. main's SCA_NOT_COMPLETED description paragraph merged cleanly and is preserved verbatim.

Verified:

  • Net diff vs main is exactly +12 lines (the 4 enum values × source + both bundles) and nothing else — no bundle churn from the rebuild.
  • openapi.yaml and mintlify/openapi.yaml are byte-identical to each other.
  • make lint-openapi exits 0 (0 errors; the 137 warnings / 495 infos are all pre-existing).
  • Required checks Lint Code & Documentation and Build OpenAPI Documentation both green, as is Detect breaking changes.

One thing I can't clear myself: this repo's ruleset has require_last_push_approval enabled, so my merge commit invalidated the earlier approval and the PR now reads REVIEW_REQUIRED. It needs a re-approve before it can merge — nothing is wrong with the diff, it's just the last-push policy.

One judgement call worth flagging: I deliberately kept the diff to exactly what was already approved. I did not add per-value description prose for the four new values, even though main's newer SCA_NOT_COMPLETED now sets that precedent — that would be unreviewed content on an approved PR. Happy to add it in a follow-up (or here, if you'd rather it ship together).


🤖 resonant-compass(#1) | Feedback

@peterrojsGraphite App

peterrojs commented Jul 30, 2026

Copy link
Copy Markdown
ContributorAuthor

Merge activity

  • Jul 30, 6:34 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 30, 6:35 PM UTC: @peterrojs merged this pull request with Graphite.

@peterrojs
peterrojs merged commit e994507 into mainJul 30, 2026
9 checks passed
@peterrojs
peterrojs deleted the 06-29-grid-api-add-outgoing-failure-reasons branch July 30, 2026 18:35
JasonCWang added a commit that referenced this pull request Aug 13, 2026
sparkcore maps LSP_OPERATIONAL_FAILURE onto QUOTE_EXECUTION_FAILED — the
distinction exists only for internal LSP-liquidity alerting, so the value
never reaches an integrator. #629 made this call when it added the other
missing enum members; this branch reintroduced it by mistake.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
Removes EXECUTION_FAILED_POST_DEBIT, SETTLEMENT_FAILED, TIMEOUT and
MANUAL_REFUND, added by #629 to mirror sparkcore's internal
UmaaasSendOperationFailureReason. They are internal distinctions, not
outcomes an integrator acts on differently:
- EXECUTION_FAILED_POST_DEBIT exists so the compensation scanner knows a
debit happened, and SETTLEMENT_FAILED is an internal leg failure. Both
collapse into QUOTE_EXECUTION_FAILED, whose description now covers any
internal failure on the way to settlement.
- TIMEOUT and MANUAL_REFUND are SoFi-specific ops-initiated refunds. The
outcome already surfaces on the refund object, whose reason enum carries
TIMEOUT and USER_CANCELLATION.
LIGHTNING_PAYMENT_FAILED's deprecation note now points at
QUOTE_EXECUTION_FAILED rather than the removed SETTLEMENT_FAILED.
BREAKING CHANGE: four values are removed from OutgoingTransactionFailureReason.
sparkcore maps its internal enum onto this one by name, so it needs explicit
mapping for these four before the vendored client is regenerated — otherwise
the mapping KeyErrors and failureReason renders empty (the bug #629 fixed).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
Removes three of the four values #629 added to mirror sparkcore's internal
UmaaasSendOperationFailureReason. They are internal distinctions, not
outcomes an integrator acts on differently:
- SETTLEMENT_FAILED is an internal leg failure with no distinct integrator
action, so it collapses into QUOTE_EXECUTION_FAILED.
- TIMEOUT and MANUAL_REFUND are SoFi-specific ops-initiated refunds. The
outcome already surfaces on the refund object, whose reason enum carries
TIMEOUT and USER_CANCELLATION.
EXECUTION_FAILED_POST_DEBIT is kept: pre-debit versus post-debit is exactly
what tells an integrator whether to expect a refund.
LIGHTNING_PAYMENT_FAILED's deprecation note now points at
QUOTE_EXECUTION_FAILED rather than the removed SETTLEMENT_FAILED.
BREAKING CHANGE: three values are removed from OutgoingTransactionFailureReason.
sparkcore maps its internal enum onto this one by name, so it needs explicit
mapping for these three before the vendored client is regenerated — otherwise
the mapping KeyErrors and failureReason renders empty (the bug #629 fixed).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
Removes the four values #629 added to mirror sparkcore's internal
UmaaasSendOperationFailureReason. They are internal distinctions, not
outcomes an integrator acts on differently:
- EXECUTION_FAILED_POST_DEBIT exists so the compensation scanner knows a
debit happened, and SETTLEMENT_FAILED is an internal leg failure. Both
collapse into QUOTE_EXECUTION_FAILED, whose description now covers any
internal failure on the way to settlement and states that a debited
amount is refunded automatically.
- TIMEOUT and MANUAL_REFUND are SoFi-specific ops-initiated refunds. The
outcome already surfaces on the refund object, whose reason enum carries
TIMEOUT and USER_CANCELLATION.
LIGHTNING_PAYMENT_FAILED's deprecation note now points at
QUOTE_EXECUTION_FAILED rather than the removed SETTLEMENT_FAILED.
BREAKING CHANGE: four values are removed from OutgoingTransactionFailureReason.
sparkcore maps its internal enum onto this one by name, so it needs explicit
mapping for these four before the vendored client is regenerated — otherwise
the mapping KeyErrors and failureReason renders empty (the bug #629 fixed).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
The value is never returned. An operational failure on the provider side
reaches integrators as QUOTE_EXECUTION_FAILED, which is the same outcome to
act on, so the finer distinction has no public meaning. #629 made this call
when it added the other missing enum members; this branch reintroduced it by
mistake.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
Removes the four values #629 added. Each describes an internal step of how a
payment is processed rather than an outcome an integrator acts on differently:
- EXECUTION_FAILED_POST_DEBIT and SETTLEMENT_FAILED say where on the way to
settlement the failure happened. Both collapse into QUOTE_EXECUTION_FAILED,
whose description now covers that whole path and states that a debited
amount is refunded automatically.
- TIMEOUT and MANUAL_REFUND describe operator-initiated refunds. That outcome
already surfaces on the refund object, whose reason enum carries TIMEOUT and
USER_CANCELLATION.
LIGHTNING_PAYMENT_FAILED's deprecation note now points at
QUOTE_EXECUTION_FAILED rather than the removed SETTLEMENT_FAILED.
BREAKING CHANGE: four values are removed from OutgoingTransactionFailureReason.
The server-side mapping for them has to be updated before clients are
regenerated, or failureReason renders empty — see #629.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JasonCWang added a commit that referenced this pull request Aug 13, 2026
…ly ones (#689)
## Summary
Reworks `OutgoingTransactionFailureReason` so every value is an outcome
an integrator acts on, and syncs the docs to match.
**Added** — granular payout failures, set at the payout-partner
boundary:
- `PAYOUT_RETURNED` — receiving bank accepted then returned/reversed the
payout
- `LIMIT_EXCEEDED` — payout exceeds a recipient-, account-, or
corridor-level limit
- `ACCOUNT_CANNOT_RECEIVE` — account exists but can't accept the payment
(dormant/frozen/restricted/unsupported currency)
- `ACCOUNT_INVALID` — recipient account not found or details wrong
- `COMPLIANCE_REJECTED` — rejected on compliance grounds
(sanctions/watchlist/KYC-AML)
**Removed** — the four values #629 added. Each names an internal step of
how a payment is processed rather than something an integrator handles
differently:
- `EXECUTION_FAILED_POST_DEBIT` and `SETTLEMENT_FAILED` say where on the
way to settlement the failure happened. Both collapse into
`QUOTE_EXECUTION_FAILED`, whose description now covers that whole path
and states that a debited amount is refunded automatically.
- `TIMEOUT` and `MANUAL_REFUND` describe operator-initiated refunds.
That outcome already surfaces on the refund object, whose `reason` enum
carries `TIMEOUT` and `USER_CANCELLATION`.
`LSP_OPERATIONAL_FAILURE` was on this branch earlier and is removed for
the same reason: an operational failure on the provider side reaches
integrators as `QUOTE_EXECUTION_FAILED`, the same outcome to act on.
**Deprecated** in the description, still returned:
`LIGHTNING_PAYMENT_FAILED` (superseded by `QUOTE_EXECUTION_FAILED`) and
`COUNTERPARTY_POST_TX_FAILED` (coarse fallback for historical rows).
`SCA_NOT_COMPLETED` (#762) is untouched — a customer letting an SCA
challenge expire is a distinct, actionable outcome.
Final enum: `QUOTE_EXPIRED`, `QUOTE_EXECUTION_FAILED`,
`FUNDING_AMOUNT_MISMATCH`, `SCA_NOT_COMPLETED`, `PAYOUT_RETURNED`,
`LIMIT_EXCEEDED`, `ACCOUNT_CANNOT_RECEIVE`, `ACCOUNT_INVALID`,
`COMPLIANCE_REJECTED`, `LIGHTNING_PAYMENT_FAILED`,
`COUNTERPARTY_POST_TX_FAILED`.
## Breaking change
Removing four values is flagged by oasdiff as
`request-property-enum-value-removed` (ERR), because `failureReason`
also appears in the `webhook:outgoing-payment` and
`webhook:agent-action` bodies. The PR carries the `breaking-change`
label and needs API-reviewer approval.
The server-side mapping for the removed values has to be updated before
clients are regenerated, or `failureReason` renders empty — the
regression #629 was fixing.
## Changes
- **OpenAPI** (`OutgoingTransactionFailureReason.yaml` + bundle): the
enum above, with per-value descriptions and deprecation notes.
- **Docs**: synced the failure-reasons table in
`transaction-lifecycle.mdx` and the list in the `error-handling.mdx`
snippet to the enum — dropped the non-existent `INSUFFICIENT_BALANCE`,
reordered to enum order, and fixed a `FAILED` webhook example to use
`ACCOUNT_INVALID`.
Rebased onto main, which added #629's values and #762's
`SCA_NOT_COMPLETED`.
## Test plan
- `make build` — bundles cleanly; clean rebuild produces no diff
- `make lint-openapi` — 0 errors (redocly + spectral)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for freeto 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.

3 participants

@peterrojs@akanter@jklein24