Skip to content

Add SCA_NOT_COMPLETED outgoing transaction failure reason - #762

Merged
jklein24 merged 1 commit into
mainfrom
07-29-add-sca-not-completed-failure-reason
Jul 30, 2026
Merged

Add SCA_NOT_COMPLETED outgoing transaction failure reason#762
jklein24 merged 1 commit into
mainfrom
07-29-add-sca-not-completed-failure-reason

Conversation

@jklein24

Copy link
Copy Markdown
Contributor

Summary

Adds SCA_NOT_COMPLETED to OutgoingTransactionFailureReason.

When a customer in an SCA-regulated region (e.g. the EU) is issued a Strong Customer Authentication challenge for a money movement and never satisfies it, the challenge expires and the transaction fails. Today that surfaces with no failureReason at all, so integrators can't tell an abandoned authorization apart from a genuine payment failure — the two need completely different follow-up.

The new value is scoped narrowly to the case where nothing moved, so the guidance in the description ("no funds were moved; create a new quote and have the customer authorize it while the challenge is live") is always true when a client sees it. Failures where an intermediate leg already executed and needs operator reconciliation continue to surface as QUOTE_EXECUTION_FAILED, matching how other operational failures are reported.

Compatibility

Non-breaking. oasdiff breaking against main reports 0 errors, 17 warnings — all the same response-property-enum-value-added informational warning, one per operation that returns an outgoing transaction. The repo's breaking-changes gate runs with --fail-on ERR, so this passes, and info.version is unchanged per the repo convention of bumping only for breaking changes.

Test plan

  • make build — rebundled openapi.yaml + mintlify/openapi.yaml; the diff is limited to this enum and its description
  • make lint-openapi — "Woohoo! Your API description is valid. 🎉", 0 errors (remaining warnings are pre-existing repo-wide schema-properties-have-examples noise, untouched by this change)
  • oasdiff breaking main HEAD --fail-on ERR — exit 0

Requested by @jklein24

Original PR: #760

@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 Jul 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 SCA_NOT_COMPLETED to OutgoingTransactionFailureReason enum

kotlin

feat(api): add SCA_NOT_COMPLETED failure reason to OutgoingTransaction

openapi

feat(api): add SCA_NOT_COMPLETED to transaction failure reason enum

php

feat(api): add SCA_NOT_COMPLETED to OutgoingTransaction FailureReason enum

python

feat(api): add SCA_NOT_COMPLETED to OutgoingTransaction failure_reason enum

ruby

feat(api): add SCA_NOT_COMPLETED failure reason to OutgoingTransaction

typescript

feat(api): add SCA_NOT_COMPLETED failure reason 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@3e59b984666648a88616990d2ab965d3dd7757b4
⚠️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/8a535cc5d82e4c63e83355e8f8bbb18023b6c7d4/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 01:25:00 UTC

@jklein24
jklein24 marked this pull request as ready for review July 29, 2026 06:31
@jklein24
jklein24 enabled auto-merge (squash) July 29, 2026 06:31
@jklein24
jklein24 requested a review from shreyavJuly 29, 2026 06:32
@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Summary

 ⚡☠️ S C A D O O M ☠️⚡
/| _.-' METAL AUTHORIZATION '-._ |\
/_|_/_______________________________\|_\
\m/ LET THE EXPIRED CHALLENGE FALL \m/

NO FUNDS MOVED — FORGE A NEW QUOTE AND AUTHORIZE AGAIN.

  • Adds SCA_NOT_COMPLETED to the outgoing transaction failure-reason enum.
  • Documents that this reason represents an expired, unsatisfied SCA challenge where no funds moved.
  • Regenerates the root and Mintlify OpenAPI bundles with the updated contract.

Confidence Score: 5/5

The PR appears safe to merge, with the source schema and both generated OpenAPI bundles updated consistently.

The additive enum value is narrowly documented, requires no breaking-version bump under repository conventions, and introduces no concrete in-repository contract, build, or synchronization failure.

Important Files Changed

FilenameOverview
openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yamlAdds and documents the new outgoing transaction failure reason in the canonical modular schema.
openapi.yamlCorrectly reflects the enum and description changes in the generated root bundle.
mintlify/openapi.yamlRemains synchronized with the root generated bundle for local Mintlify API-reference rendering.

Reviews (1): Last reviewed commit: "Add SCA_NOT_COMPLETED outgoing transacti..." | Re-trigger Greptile

@jklein24
jklein24 merged commit 4b3fffe into mainJul 30, 2026
18 checks passed
@jklein24
jklein24 deleted the 07-29-add-sca-not-completed-failure-reason branch July 30, 2026 01:19
ls-boltBot pushed a commit that referenced this pull request Jul 30, 2026
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>
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>
ls-boltBot pushed a commit that referenced this pull request Aug 28, 2026
The SCA surface moved after this guide was written; bring it current:
- SCA login complete now requires `endUserIpAddress` and returns
`sessionExpiresAt` (#780); the session-scope guidance now tells
integrators to prompt re-login ahead of it.
- Quote authorize documents `409 SCA_SESSION_REQUIRED` and
`423 ACCOUNT_LOCKED` (#761); both join the error tables, and the
snippet notes authorizing requires an active login session.
- A challenge left to expire unsatisfied now fails the transaction with
`failureReason: SCA_NOT_COMPLETED` and no funds moved (#762).
- Trusted external accounts refuse `DELETE` with
`409 BENEFICIARY_TRUSTED`; untrust first (#770).
- The challenge lives on the quote, not the transaction — webhook
consumers route via the transaction's `quoteId` (#701).
- `POST /transfer-out` is deprecated in favor of `POST /quotes` with
`immediatelyExecute: true` (#856); the transfer-out tab now says so.
ls-boltBot pushed a commit that referenced this pull request Aug 29, 2026
The SCA surface moved after this guide was written; bring it current:
- SCA login complete now requires `endUserIpAddress` and returns
`sessionExpiresAt` (#780); the session-scope guidance now tells
integrators to prompt re-login ahead of it.
- Quote authorize documents `409 SCA_SESSION_REQUIRED` and
`423 ACCOUNT_LOCKED` (#761); both join the error tables, and the
snippet notes authorizing requires an active login session.
- A challenge left to expire unsatisfied now fails the transaction with
`failureReason: SCA_NOT_COMPLETED` and no funds moved (#762).
- Trusted external accounts refuse `DELETE` with
`409 BENEFICIARY_TRUSTED`; untrust first (#770).
- The challenge lives on the quote, not the transaction — webhook
consumers route via the transaction's `quoteId` (#701).
- `POST /transfer-out` is deprecated in favor of `POST /quotes` with
`immediatelyExecute: true` (#856); the transfer-out tab now says so.
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

@jklein24@akanter@shreyav