Uh oh!
There was an error while loading. Please reload this page.
Add SCA_NOT_COMPLETED outgoing transaction failure reason - #762
Conversation
akanter
commented
Jul 29, 2026
✱ Stainless preview builds for gridThis PR will update the cli go kotlin openapi php python ruby typescript ✅ grid-rubystudio · code
|
Greptile SummaryNO FUNDS MOVED — FORGE A NEW QUOTE AND AUTHORIZE AGAIN.
Confidence Score: 5/5The 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.
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yaml | Adds and documents the new outgoing transaction failure reason in the canonical modular schema. |
| openapi.yaml | Correctly reflects the enum and description changes in the generated root bundle. |
| mintlify/openapi.yaml | Remains 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
Uh oh!
There was an error while loading. Please reload this page.
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>
…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>
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.
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.

Summary
Adds
SCA_NOT_COMPLETEDtoOutgoingTransactionFailureReason.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
failureReasonat 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 breakingagainstmainreports 0 errors, 17 warnings — all the sameresponse-property-enum-value-addedinformational warning, one per operation that returns an outgoing transaction. The repo's breaking-changes gate runs with--fail-on ERR, so this passes, andinfo.versionis unchanged per the repo convention of bumping only for breaking changes.Test plan
make build— rebundledopenapi.yaml+mintlify/openapi.yaml; the diff is limited to this enum and its descriptionmake lint-openapi— "Woohoo! Your API description is valid. 🎉", 0 errors (remaining warnings are pre-existing repo-wideschema-properties-have-examplesnoise, untouched by this change)oasdiff breaking main HEAD --fail-on ERR— exit 0Requested by @jklein24
Original PR: #760