Skip to content

feat: add granular counterparty payout failure reasons#689

Open
JasonCWang wants to merge 4 commits into
mainfrom
feat/outgoing-counterparty-failure-reasons
Open

feat: add granular counterparty payout failure reasons#689
JasonCWang wants to merge 4 commits into
mainfrom
feat/outgoing-counterparty-failure-reasons

Conversation

@JasonCWang

Copy link
Copy Markdown
Contributor

Summary

Adds granular counterparty payout failure reasons to OutgoingTransactionFailureReason and syncs all documentation to match.

New enum values, set at the 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)

Also adds EXECUTION_FAILED_POST_DEBIT and LSP_OPERATIONAL_FAILURE, and marks LIGHTNING_PAYMENT_FAILED and COUNTERPARTY_POST_TX_FAILED as deprecated (coarse fallback, retained for historical rows).

Changes

  • OpenAPI (OutgoingTransactionFailureReason.yaml + bundle): full enum 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 — removed the non-existent INSUFFICIENT_BALANCE, added TIMEOUT/MANUAL_REFUND/SETTLEMENT_FAILED, reordered to enum order, and fixed a FAILED webhook example to use ACCOUNT_INVALID.

Test plan

  • make build — bundles cleanly, no spec diff beyond the enum work
  • make lint-openapi — OpenAPI validates ✅

🤖 Generated with Claude Code

JasonCWang and others added 3 commits July 7, 2026 12:45
Add 7 counterparty (payout-side) reasons to
OutgoingTransactionFailureReason so integrators can act on why a
payout partner rejected or failed a transaction, rather than
collapsing everything into the generic COUNTERPARTY_POST_TX_FAILED:

- COUNTERPARTY_COMPLIANCE_REJECTED
- COUNTERPARTY_ACCOUNT_INVALID
- COUNTERPARTY_ACCOUNT_CANNOT_RECEIVE
- COUNTERPARTY_LIMIT_EXCEEDED
- COUNTERPARTY_PAYOUT_RETURNED
- COUNTERPARTY_CURRENCY_EXCHANGE_FAILED
- COUNTERPARTY_PAYOUT_EXPIRED

Also document each value's customer-facing meaning in a markdown
table, matching the OutgoingTransactionStatus convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename granular counterparty payout reasons (drop COUNTERPARTY_ prefix),
remove COUNTERPARTY_CURRENCY_EXCHANGE_FAILED and COUNTERPARTY_PAYOUT_EXPIRED,
and add EXECUTION_FAILED_POST_DEBIT, SETTLEMENT_FAILED, TIMEOUT, MANUAL_REFUND,
and LSP_OPERATIONAL_FAILURE. Mark LIGHTNING_PAYMENT_FAILED and
COUNTERPARTY_POST_TX_FAILED as deprecated/legacy. Update transaction lifecycle
and error handling docs accordingly.

Co-authored-by: Cursor <cursoragent@cursor.com>
Align the MDX failure-reason references with OutgoingTransactionFailureReason:
drop the non-existent INSUFFICIENT_BALANCE, add TIMEOUT and MANUAL_REFUND
(plus SETTLEMENT_FAILED in the error-handling snippet), reorder to enum
order, and fix the FAILED webhook example to use ACCOUNT_INVALID.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Jul 14, 2026 10:47pm
grid-wallet-demo Ignored Ignored Preview Jul 14, 2026 10:47pm

Request Review

@mintlify

mintlify Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

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

Project Status Preview Updated (UTC)
Grid 🟢 Ready View Preview Jul 14, 2026, 9:55 PM

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds granular counterparty payout failure reasons to the OutgoingTransactionFailureReason enum and synchronizes all documentation surfaces (OpenAPI source, bundled specs, and Mintlify docs) to match.

  • OpenAPI schema (OutgoingTransactionFailureReason.yaml + both bundles): adds 8 new enum values (EXECUTION_FAILED_POST_DEBIT, SETTLEMENT_FAILED, TIMEOUT, MANUAL_REFUND, LSP_OPERATIONAL_FAILURE, PAYOUT_RETURNED, LIMIT_EXCEEDED, ACCOUNT_CANNOT_RECEIVE, ACCOUNT_INVALID, COMPLIANCE_REJECTED), moves LIGHTNING_PAYMENT_FAILED and COUNTERPARTY_POST_TX_FAILED to deprecated status with description-level notes.
  • transaction-lifecycle.mdx: failure reasons table rebuilt to match the full enum, INSUFFICIENT_BALANCE removed, and the FAILED webhook example corrected from INVALID_BANK_ACCOUNT to ACCOUNT_INVALID.
  • error-handling.mdx snippet: new failure reasons added to the bullet list, though INVALID_BANK_ACCOUNT remains in the getUserFriendlyMessage code example and no note is added about deprecated values that may still arrive for historical transactions.

Confidence Score: 4/5

Safe to merge; changes are additive enum expansions with consistent spec and doc updates, and no logic or runtime code is modified.

All three documentation surfaces are updated consistently and the enum values are well-described. The only gaps are in the error-handling snippet: the getUserFriendlyMessage code example still maps the old INVALID_BANK_ACCOUNT key without adding ACCOUNT_INVALID, and there is no note warning developers about deprecated values they may still receive for historical transactions.

mintlify/snippets/error-handling.mdx — the getUserFriendlyMessage example and the missing deprecated-values note

Important Files Changed

Filename Overview
openapi/components/schemas/transactions/OutgoingTransactionFailureReason.yaml Adds 8 new enum values and deprecates LIGHTNING_PAYMENT_FAILED and COUNTERPARTY_POST_TX_FAILED via description text. Descriptions are clear and accurate.
openapi.yaml Bundle file updated in sync with OutgoingTransactionFailureReason.yaml; changes are identical. No issues found.
mintlify/openapi.yaml Mintlify-specific bundle updated identically to openapi.yaml; properly kept in sync.
mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx Failure reasons table updated to match the full enum, INSUFFICIENT_BALANCE removed, deprecated values relegated to a prose note, and the FAILED webhook example corrected from INVALID_BANK_ACCOUNT to ACCOUNT_INVALID.
mintlify/snippets/error-handling.mdx New failure reasons added to the bullet list; however, the getUserFriendlyMessage code example still maps INVALID_BANK_ACCOUNT without ACCOUNT_INVALID, and there is no callout about deprecated values that may still arrive for historical transactions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Outgoing Transaction] --> B{Status}
    B -->|COMPLETED| C[Done]
    B -->|FAILED| D{failureReason}
    D --> E[Quote / Execution]
    D --> F[Settlement]
    D --> G[Funding]
    D --> H[Operational]
    D --> I[Payout Partner]
    E --> E1[QUOTE_EXPIRED]
    E --> E2[QUOTE_EXECUTION_FAILED]
    E --> E3[EXECUTION_FAILED_POST_DEBIT]
    F --> F1[SETTLEMENT_FAILED]
    F --> F2[TIMEOUT]
    G --> G1[FUNDING_AMOUNT_MISMATCH]
    G --> G2[MANUAL_REFUND]
    H --> H1[LSP_OPERATIONAL_FAILURE]
    I --> I1[PAYOUT_RETURNED]
    I --> I2[LIMIT_EXCEEDED]
    I --> I3[ACCOUNT_CANNOT_RECEIVE]
    I --> I4[ACCOUNT_INVALID]
    I --> I5[COMPLIANCE_REJECTED]
    I --> I6[COUNTERPARTY_POST_TX_FAILED deprecated]
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[Outgoing Transaction] --> B{Status}
    B -->|COMPLETED| C[Done]
    B -->|FAILED| D{failureReason}
    D --> E[Quote / Execution]
    D --> F[Settlement]
    D --> G[Funding]
    D --> H[Operational]
    D --> I[Payout Partner]
    E --> E1[QUOTE_EXPIRED]
    E --> E2[QUOTE_EXECUTION_FAILED]
    E --> E3[EXECUTION_FAILED_POST_DEBIT]
    F --> F1[SETTLEMENT_FAILED]
    F --> F2[TIMEOUT]
    G --> G1[FUNDING_AMOUNT_MISMATCH]
    G --> G2[MANUAL_REFUND]
    H --> H1[LSP_OPERATIONAL_FAILURE]
    I --> I1[PAYOUT_RETURNED]
    I --> I2[LIMIT_EXCEEDED]
    I --> I3[ACCOUNT_CANNOT_RECEIVE]
    I --> I4[ACCOUNT_INVALID]
    I --> I5[COMPLIANCE_REJECTED]
    I --> I6[COUNTERPARTY_POST_TX_FAILED deprecated]
Loading

Comments Outside Diff (1)

  1. mintlify/snippets/error-handling.mdx, line 373-390 (link)

    P2 INVALID_BANK_ACCOUNT not updated in getUserFriendlyMessage example

    The PR replaces INVALID_BANK_ACCOUNT with ACCOUNT_INVALID in the webhook FAILED example in transaction-lifecycle.mdx, but the getUserFriendlyMessage code sample still maps INVALID_BANK_ACCOUNT and doesn't include ACCOUNT_INVALID (or the other new failure reasons like COMPLIANCE_REJECTED, ACCOUNT_CANNOT_RECEIVE, etc.). A developer copying this pattern to handle transaction failureReason values won't have a mapping for the newly documented reasons.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: mintlify/snippets/error-handling.mdx
    Line: 373-390
    
    Comment:
    **`INVALID_BANK_ACCOUNT` not updated in `getUserFriendlyMessage` example**
    
    The PR replaces `INVALID_BANK_ACCOUNT` with `ACCOUNT_INVALID` in the webhook FAILED example in `transaction-lifecycle.mdx`, but the `getUserFriendlyMessage` code sample still maps `INVALID_BANK_ACCOUNT` and doesn't include `ACCOUNT_INVALID` (or the other new failure reasons like `COMPLIANCE_REJECTED`, `ACCOUNT_CANNOT_RECEIVE`, etc.). A developer copying this pattern to handle transaction `failureReason` values won't have a mapping for the newly documented reasons.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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
mintlify/snippets/error-handling.mdx:373-390
**`INVALID_BANK_ACCOUNT` not updated in `getUserFriendlyMessage` example**

The PR replaces `INVALID_BANK_ACCOUNT` with `ACCOUNT_INVALID` in the webhook FAILED example in `transaction-lifecycle.mdx`, but the `getUserFriendlyMessage` code sample still maps `INVALID_BANK_ACCOUNT` and doesn't include `ACCOUNT_INVALID` (or the other new failure reasons like `COMPLIANCE_REJECTED`, `ACCOUNT_CANNOT_RECEIVE`, etc.). A developer copying this pattern to handle transaction `failureReason` values won't have a mapping for the newly documented reasons.

### Issue 2 of 2
mintlify/snippets/error-handling.mdx:143-158
**Deprecated values not mentioned in snippet**

`transaction-lifecycle.mdx` adds a note that `LIGHTNING_PAYMENT_FAILED` and `COUNTERPARTY_POST_TX_FAILED` may still be returned for historical transactions, but this snippet (which is the first error-handling reference many developers will read) has no equivalent callout. A developer whose integration receives a deprecated value for an older transaction will not find it in this list and may treat it as an unexpected/undocumented response.

Reviews (1): Last reviewed commit: "docs: sync outgoing payment failure reas..." | Re-trigger Greptile

Comment on lines 143 to 158
**Common outgoing failure reasons:**

- `QUOTE_EXPIRED` - Quote expired before execution
- `QUOTE_EXECUTION_FAILED` - Error executing the quote
- `QUOTE_EXECUTION_FAILED` - Error executing the quote; no funds were debited
- `EXECUTION_FAILED_POST_DEBIT` - Execution failed after debit; funds are refunded automatically
- `SETTLEMENT_FAILED` - The settlement leg failed
- `FUNDING_AMOUNT_MISMATCH` - Funding amount doesn't match expected amount
- `TIMEOUT` - Transaction didn't complete within its processing window
- `MANUAL_REFUND` - Transaction was refunded manually
- `LSP_OPERATIONAL_FAILURE` - Lightspark-internal operational issue; contact Lightspark
- `PAYOUT_RETURNED` - Receiving bank returned or reversed the payout
- `LIMIT_EXCEEDED` - Payout exceeds a partner limit
- `ACCOUNT_CANNOT_RECEIVE` - Recipient account can't accept the payment
- `ACCOUNT_INVALID` - Recipient account details are wrong or not found
- `COMPLIANCE_REJECTED` - Payout partner rejected on compliance grounds

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.

P2 Deprecated values not mentioned in snippet

transaction-lifecycle.mdx adds a note that LIGHTNING_PAYMENT_FAILED and COUNTERPARTY_POST_TX_FAILED may still be returned for historical transactions, but this snippet (which is the first error-handling reference many developers will read) has no equivalent callout. A developer whose integration receives a deprecated value for an older transaction will not find it in this list and may treat it as an unexpected/undocumented response.

Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/snippets/error-handling.mdx
Line: 143-158

Comment:
**Deprecated values not mentioned in snippet**

`transaction-lifecycle.mdx` adds a note that `LIGHTNING_PAYMENT_FAILED` and `COUNTERPARTY_POST_TX_FAILED` may still be returned for historical transactions, but this snippet (which is the first error-handling reference many developers will read) has no equivalent callout. A developer whose integration receives a deprecated value for an older transaction will not find it in this list and may treat it as an unexpected/undocumented response.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Remove the negative guarantee from QUOTE_EXECUTION_FAILED across the enum
description and docs. EXECUTION_FAILED_POST_DEBIT still carries the
affirmative "debited then refunded automatically" wording.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant