From 2dd8edacbb95b3918ce35dd6c27c40f4889a896e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 05:13:51 +0000 Subject: [PATCH 1/6] Add SWIFT pay-in API surface: holder name, readiness webhook, failure reason PaymentSwiftAccountInfo gains accountHolderName (required) and bankAddress, and reference becomes optional (SWIFT collections are attributed by the destination account, not a memo). New INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED webhook type announces funding-coordinate changes. IncomingTransactionFailureReason gains COLLECTION_FAILED. Hygiene: PaymentAccountType gains the SWIFT_ACCOUNT value its discriminator already maps; SwiftAccountInfoBase documents accountNumber/IBAN co-presence; incoming-payment webhook docs cover bank-rail pay-ins and their exemption from the approval gate. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DLYJSn6VRoZeLV15wcuZHy --- mintlify/openapi.yaml | 66 +++++++++++++++++-- openapi.yaml | 66 +++++++++++++++++-- .../schemas/common/PaymentAccountType.yaml | 1 + .../common/PaymentSwiftAccountInfo.yaml | 23 ++++++- .../schemas/common/SwiftAccountInfoBase.yaml | 5 ++ .../IncomingTransactionFailureReason.yaml | 6 +- .../InternalAccountStatusWebhook.yaml | 1 + .../schemas/webhooks/WebhookType.yaml | 1 + openapi/webhooks/incoming-payment.yaml | 11 +++- openapi/webhooks/internal-account-status.yaml | 45 +++++++++++++ 10 files changed, 211 insertions(+), 14 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 1bcf10b32..4e29c9fb8 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -10149,7 +10149,7 @@ webhooks: post: summary: Incoming payment webhook and approval mechanism description: | - Webhook that is called when an incoming payment is received by a customer's UMA address. + Webhook that is called when an incoming payment is received by a customer — over UMA to the customer's UMA address, or over a bank rail (e.g. a SWIFT wire to the customer's funding coordinates from `fundingPaymentInstructions`). This endpoint should be implemented by clients of the Grid API. ### Authentication @@ -10174,6 +10174,8 @@ webhooks: The Grid system will proceed or cancel the payment based on your response. For transactions with other statuses (COMPLETED, FAILED, REFUNDED), this webhook is purely informational. + + Bank-rail incoming payments (e.g. SWIFT) are informational at every status, including PENDING: the funds have already moved interbank, so the approval mechanism and the 5-second response window do not apply. operationId: incomingPaymentWebhook tags: - Webhooks @@ -10949,6 +10951,7 @@ webhooks: ### Event types - `INTERNAL_ACCOUNT.BALANCE_UPDATED` — Fired when the balance of an internal account changes. The `data` payload contains the full internal account object. - `INTERNAL_ACCOUNT.STATUS_UPDATED` — Fired when the status of an internal account changes (e.g., `OPEN` → `FROZEN`). The `data` payload contains the full internal account object. + - `INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED` — Fired when the account's `fundingPaymentInstructions` change: new funding coordinates became available (e.g., a SWIFT collection account finished provisioning) or previously served coordinates were withdrawn. The `data` payload contains the full internal account object, including the current `fundingPaymentInstructions`. operationId: internalAccountStatusWebhook tags: - Webhooks @@ -11017,6 +11020,44 @@ webhooks: fundingPaymentInstructions: [] createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' + fundingInstructionsUpdated: + summary: A SWIFT collection account finished provisioning and the account gained wire coordinates + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED + timestamp: '2025-08-15T14:32:00Z' + data: + id: InternalAccount:019542f5-b3e7-1d02-0000-000000000005 + customerId: Customer:019542f5-b3e7-1d02-0000-000000000001 + type: INTERNAL_FIAT + status: ACTIVE + balance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + totalBalance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + fundingPaymentInstructions: + - accountOrWalletInfo: + accountType: SWIFT_ACCOUNT + country: SG + swiftCode: DBSSSGSG + bankName: DBS Bank + accountNumber: '8850123456' + accountHolderName: Acme Exports Pte Ltd + paymentRails: + - SWIFT + instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + createdAt: '2025-08-01T10:00:00Z' + updatedAt: '2025-08-15T14:32:00Z' responses: '200': description: | @@ -14532,6 +14573,7 @@ components: - SGD_ACCOUNT - THB_ACCOUNT - VND_ACCOUNT + - SWIFT_ACCOUNT - SPARK_WALLET - LIGHTNING - SOLANA_WALLET @@ -16891,6 +16933,7 @@ components: example: '{"type":"ACTIVITY_TYPE_SIGN_TRANSACTION_V2","timestampMs":"1746736509954","organizationId":"org_abc123","parameters":{"signWith":"wallet_abc123def456","unsignedTransaction":"ea69b4bf05f775209f26ff0a34a05569180f7936579d5c4af9377ae550194f72","type":"TRANSACTION_TYPE_ETHEREUM"},"generateAppProofs":true}' SwiftAccountInfoBase: type: object + description: 'At least one of accountNumber or iban is always present: IBAN-only corridors (e.g. BR, GB) use iban, other corridors use accountNumber, and both appear when the bank exposes both identifiers for the same account.' required: - accountType - swiftCode @@ -16960,11 +17003,23 @@ components: - $ref: '#/components/schemas/SwiftAccountInfo' - type: object required: - - reference + - accountHolderName properties: + accountHolderName: + type: string + description: The name of the account holder as it must appear on the wire. Remitting banks match this against the beneficiary name field, so payers should copy it exactly. + example: Acme Exports Pte Ltd + minLength: 1 + maxLength: 255 + bankAddress: + type: string + description: The address of the bank holding the account, when known. + example: 12 Marina Boulevard, Singapore 018982 + minLength: 1 + maxLength: 1024 reference: type: string - description: Unique reference code that must be included with the payment to properly credit it + description: Reference code to include with the payment when present. SWIFT payments are attributed by the destination account number/IBAN, so this account type typically requires no reference. example: UMA-Q12345-REF CnyAccountInfoBase: type: object @@ -21499,7 +21554,8 @@ components: - MISSING_MANDATORY_PAYEE_DATA - QUOTE_EXPIRED - QUOTE_EXECUTION_FAILED - description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. + - COLLECTION_FAILED + description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection (e.g. a SWIFT wire) failed after arrival — typically a compliance-screening rejection or an unresolved request for information — and the funds were returned to the sender by the collection provider. IncomingTransaction: title: Incoming Transaction allOf: @@ -25240,6 +25296,7 @@ components: - EXTERNAL_ACCOUNT.STATUS_UPDATED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED - BULK_UPLOAD.FAILED @@ -25432,6 +25489,7 @@ components: enum: - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED ExternalAccountStatusWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' diff --git a/openapi.yaml b/openapi.yaml index 1bcf10b32..4e29c9fb8 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -10149,7 +10149,7 @@ webhooks: post: summary: Incoming payment webhook and approval mechanism description: | - Webhook that is called when an incoming payment is received by a customer's UMA address. + Webhook that is called when an incoming payment is received by a customer — over UMA to the customer's UMA address, or over a bank rail (e.g. a SWIFT wire to the customer's funding coordinates from `fundingPaymentInstructions`). This endpoint should be implemented by clients of the Grid API. ### Authentication @@ -10174,6 +10174,8 @@ webhooks: The Grid system will proceed or cancel the payment based on your response. For transactions with other statuses (COMPLETED, FAILED, REFUNDED), this webhook is purely informational. + + Bank-rail incoming payments (e.g. SWIFT) are informational at every status, including PENDING: the funds have already moved interbank, so the approval mechanism and the 5-second response window do not apply. operationId: incomingPaymentWebhook tags: - Webhooks @@ -10949,6 +10951,7 @@ webhooks: ### Event types - `INTERNAL_ACCOUNT.BALANCE_UPDATED` — Fired when the balance of an internal account changes. The `data` payload contains the full internal account object. - `INTERNAL_ACCOUNT.STATUS_UPDATED` — Fired when the status of an internal account changes (e.g., `OPEN` → `FROZEN`). The `data` payload contains the full internal account object. + - `INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED` — Fired when the account's `fundingPaymentInstructions` change: new funding coordinates became available (e.g., a SWIFT collection account finished provisioning) or previously served coordinates were withdrawn. The `data` payload contains the full internal account object, including the current `fundingPaymentInstructions`. operationId: internalAccountStatusWebhook tags: - Webhooks @@ -11017,6 +11020,44 @@ webhooks: fundingPaymentInstructions: [] createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' + fundingInstructionsUpdated: + summary: A SWIFT collection account finished provisioning and the account gained wire coordinates + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED + timestamp: '2025-08-15T14:32:00Z' + data: + id: InternalAccount:019542f5-b3e7-1d02-0000-000000000005 + customerId: Customer:019542f5-b3e7-1d02-0000-000000000001 + type: INTERNAL_FIAT + status: ACTIVE + balance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + totalBalance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + fundingPaymentInstructions: + - accountOrWalletInfo: + accountType: SWIFT_ACCOUNT + country: SG + swiftCode: DBSSSGSG + bankName: DBS Bank + accountNumber: '8850123456' + accountHolderName: Acme Exports Pte Ltd + paymentRails: + - SWIFT + instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + createdAt: '2025-08-01T10:00:00Z' + updatedAt: '2025-08-15T14:32:00Z' responses: '200': description: | @@ -14532,6 +14573,7 @@ components: - SGD_ACCOUNT - THB_ACCOUNT - VND_ACCOUNT + - SWIFT_ACCOUNT - SPARK_WALLET - LIGHTNING - SOLANA_WALLET @@ -16891,6 +16933,7 @@ components: example: '{"type":"ACTIVITY_TYPE_SIGN_TRANSACTION_V2","timestampMs":"1746736509954","organizationId":"org_abc123","parameters":{"signWith":"wallet_abc123def456","unsignedTransaction":"ea69b4bf05f775209f26ff0a34a05569180f7936579d5c4af9377ae550194f72","type":"TRANSACTION_TYPE_ETHEREUM"},"generateAppProofs":true}' SwiftAccountInfoBase: type: object + description: 'At least one of accountNumber or iban is always present: IBAN-only corridors (e.g. BR, GB) use iban, other corridors use accountNumber, and both appear when the bank exposes both identifiers for the same account.' required: - accountType - swiftCode @@ -16960,11 +17003,23 @@ components: - $ref: '#/components/schemas/SwiftAccountInfo' - type: object required: - - reference + - accountHolderName properties: + accountHolderName: + type: string + description: The name of the account holder as it must appear on the wire. Remitting banks match this against the beneficiary name field, so payers should copy it exactly. + example: Acme Exports Pte Ltd + minLength: 1 + maxLength: 255 + bankAddress: + type: string + description: The address of the bank holding the account, when known. + example: 12 Marina Boulevard, Singapore 018982 + minLength: 1 + maxLength: 1024 reference: type: string - description: Unique reference code that must be included with the payment to properly credit it + description: Reference code to include with the payment when present. SWIFT payments are attributed by the destination account number/IBAN, so this account type typically requires no reference. example: UMA-Q12345-REF CnyAccountInfoBase: type: object @@ -21499,7 +21554,8 @@ components: - MISSING_MANDATORY_PAYEE_DATA - QUOTE_EXPIRED - QUOTE_EXECUTION_FAILED - description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. + - COLLECTION_FAILED + description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection (e.g. a SWIFT wire) failed after arrival — typically a compliance-screening rejection or an unresolved request for information — and the funds were returned to the sender by the collection provider. IncomingTransaction: title: Incoming Transaction allOf: @@ -25240,6 +25296,7 @@ components: - EXTERNAL_ACCOUNT.STATUS_UPDATED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED - BULK_UPLOAD.FAILED @@ -25432,6 +25489,7 @@ components: enum: - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED ExternalAccountStatusWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' diff --git a/openapi/components/schemas/common/PaymentAccountType.yaml b/openapi/components/schemas/common/PaymentAccountType.yaml index 343aae353..d7ac415c1 100644 --- a/openapi/components/schemas/common/PaymentAccountType.yaml +++ b/openapi/components/schemas/common/PaymentAccountType.yaml @@ -18,6 +18,7 @@ enum: - SGD_ACCOUNT - THB_ACCOUNT - VND_ACCOUNT + - SWIFT_ACCOUNT - SPARK_WALLET - LIGHTNING - SOLANA_WALLET diff --git a/openapi/components/schemas/common/PaymentSwiftAccountInfo.yaml b/openapi/components/schemas/common/PaymentSwiftAccountInfo.yaml index c2c1dad8a..126a48be4 100644 --- a/openapi/components/schemas/common/PaymentSwiftAccountInfo.yaml +++ b/openapi/components/schemas/common/PaymentSwiftAccountInfo.yaml @@ -4,10 +4,27 @@ allOf: - $ref: ./SwiftAccountInfo.yaml - type: object required: - - reference + - accountHolderName properties: + accountHolderName: + type: string + description: >- + The name of the account holder as it must appear on the wire. + Remitting banks match this against the beneficiary name field, + so payers should copy it exactly. + example: Acme Exports Pte Ltd + minLength: 1 + maxLength: 255 + bankAddress: + type: string + description: The address of the bank holding the account, when known. + example: 12 Marina Boulevard, Singapore 018982 + minLength: 1 + maxLength: 1024 reference: type: string - description: Unique reference code that must be included with the payment to - properly credit it + description: >- + Reference code to include with the payment when present. SWIFT + payments are attributed by the destination account number/IBAN, + so this account type typically requires no reference. example: UMA-Q12345-REF diff --git a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml index d8550a5e5..925f43d0c 100644 --- a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml +++ b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml @@ -1,4 +1,9 @@ type: object +description: >- + At least one of accountNumber or iban is always present: IBAN-only + corridors (e.g. BR, GB) use iban, other corridors use accountNumber, + and both appear when the bank exposes both identifiers for the same + account. required: - accountType - swiftCode diff --git a/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml b/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml index d4fe63733..aa82d38a3 100644 --- a/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml +++ b/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml @@ -8,7 +8,11 @@ enum: - MISSING_MANDATORY_PAYEE_DATA - QUOTE_EXPIRED - QUOTE_EXECUTION_FAILED + - COLLECTION_FAILED description: >- Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed - state, this field is omitted. + state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail + collection (e.g. a SWIFT wire) failed after arrival — typically a + compliance-screening rejection or an unresolved request for information — + and the funds were returned to the sender by the collection provider. diff --git a/openapi/components/schemas/webhooks/InternalAccountStatusWebhook.yaml b/openapi/components/schemas/webhooks/InternalAccountStatusWebhook.yaml index a6fdfd125..eed810418 100644 --- a/openapi/components/schemas/webhooks/InternalAccountStatusWebhook.yaml +++ b/openapi/components/schemas/webhooks/InternalAccountStatusWebhook.yaml @@ -11,3 +11,4 @@ allOf: enum: - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED diff --git a/openapi/components/schemas/webhooks/WebhookType.yaml b/openapi/components/schemas/webhooks/WebhookType.yaml index d27f1b6e2..56c090250 100644 --- a/openapi/components/schemas/webhooks/WebhookType.yaml +++ b/openapi/components/schemas/webhooks/WebhookType.yaml @@ -29,6 +29,7 @@ enum: - EXTERNAL_ACCOUNT.STATUS_UPDATED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INTERNAL_ACCOUNT.STATUS_UPDATED + - INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED - BULK_UPLOAD.FAILED diff --git a/openapi/webhooks/incoming-payment.yaml b/openapi/webhooks/incoming-payment.yaml index 79f7f9c0e..19dc57614 100644 --- a/openapi/webhooks/incoming-payment.yaml +++ b/openapi/webhooks/incoming-payment.yaml @@ -1,8 +1,10 @@ post: summary: Incoming payment webhook and approval mechanism description: > - Webhook that is called when an incoming payment is received by a customer's UMA - address. + Webhook that is called when an incoming payment is received by a customer — + over UMA to the customer's UMA address, or over a bank rail (e.g. a SWIFT + wire to the customer's funding coordinates from + `fundingPaymentInstructions`). This endpoint should be implemented by clients of the Grid API. @@ -55,6 +57,11 @@ post: For transactions with other statuses (COMPLETED, FAILED, REFUNDED), this webhook is purely informational. + + + Bank-rail incoming payments (e.g. SWIFT) are informational at every + status, including PENDING: the funds have already moved interbank, so the + approval mechanism and the 5-second response window do not apply. operationId: incomingPaymentWebhook tags: - Webhooks diff --git a/openapi/webhooks/internal-account-status.yaml b/openapi/webhooks/internal-account-status.yaml index 6078386f0..5e969313d 100644 --- a/openapi/webhooks/internal-account-status.yaml +++ b/openapi/webhooks/internal-account-status.yaml @@ -38,6 +38,13 @@ post: account changes (e.g., `OPEN` → `FROZEN`). The `data` payload contains the full internal account object. + - `INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED` — Fired when the + account's `fundingPaymentInstructions` change: new funding coordinates + became available (e.g., a SWIFT collection account finished provisioning) + or previously served coordinates were withdrawn. The `data` payload + contains the full internal account object, including the current + `fundingPaymentInstructions`. + operationId: internalAccountStatusWebhook tags: @@ -107,6 +114,44 @@ post: fundingPaymentInstructions: [] createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' + fundingInstructionsUpdated: + summary: A SWIFT collection account finished provisioning and the account gained wire coordinates + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: INTERNAL_ACCOUNT.FUNDING_INSTRUCTIONS_UPDATED + timestamp: '2025-08-15T14:32:00Z' + data: + id: InternalAccount:019542f5-b3e7-1d02-0000-000000000005 + customerId: Customer:019542f5-b3e7-1d02-0000-000000000001 + type: INTERNAL_FIAT + status: ACTIVE + balance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + totalBalance: + amount: 10000 + currency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + fundingPaymentInstructions: + - accountOrWalletInfo: + accountType: SWIFT_ACCOUNT + country: SG + swiftCode: DBSSSGSG + bankName: DBS Bank + accountNumber: '8850123456' + accountHolderName: Acme Exports Pte Ltd + paymentRails: + - SWIFT + instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + createdAt: '2025-08-01T10:00:00Z' + updatedAt: '2025-08-15T14:32:00Z' responses: '200': description: > From 8d5aad70526c3a0b0d663b879304eb5d5e8411a3 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 05:37:11 +0000 Subject: [PATCH 2/6] Make COLLECTION_FAILED deposit-level and side-agnostic A collection deposit can fail on either the provider's leg or Grid's (compliance rejection on the incoming-balance leg, terminal flow failure), and the producer cannot always distinguish them. The reason describes the deposit outcome, not which side failed, and no longer claims the provider has already returned the funds. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DLYJSn6VRoZeLV15wcuZHy --- mintlify/openapi.yaml | 2 +- openapi.yaml | 2 +- .../transactions/IncomingTransactionFailureReason.yaml | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 4e29c9fb8..4a33e1df3 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -21555,7 +21555,7 @@ components: - QUOTE_EXPIRED - QUOTE_EXECUTION_FAILED - COLLECTION_FAILED - description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection (e.g. a SWIFT wire) failed after arrival — typically a compliance-screening rejection or an unresolved request for information — and the funds were returned to the sender by the collection provider. + description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection deposit (e.g. a SWIFT wire) failed after arrival and did not credit — most commonly a compliance-screening rejection or an unresolved request for information, on either the collection provider's side or Grid's. Failed collections are returned to the sender per the collection provider's process. IncomingTransaction: title: Incoming Transaction allOf: diff --git a/openapi.yaml b/openapi.yaml index 4e29c9fb8..4a33e1df3 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -21555,7 +21555,7 @@ components: - QUOTE_EXPIRED - QUOTE_EXECUTION_FAILED - COLLECTION_FAILED - description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection (e.g. a SWIFT wire) failed after arrival — typically a compliance-screening rejection or an unresolved request for information — and the funds were returned to the sender by the collection provider. + description: Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail collection deposit (e.g. a SWIFT wire) failed after arrival and did not credit — most commonly a compliance-screening rejection or an unresolved request for information, on either the collection provider's side or Grid's. Failed collections are returned to the sender per the collection provider's process. IncomingTransaction: title: Incoming Transaction allOf: diff --git a/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml b/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml index aa82d38a3..bd389a1bd 100644 --- a/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml +++ b/openapi/components/schemas/transactions/IncomingTransactionFailureReason.yaml @@ -13,6 +13,8 @@ description: >- Reason for failure of an incoming transaction. This is used to provide more context on why a transaction failed. If the transaction is not in a failed state, this field is omitted. COLLECTION_FAILED means an inbound bank-rail - collection (e.g. a SWIFT wire) failed after arrival — typically a - compliance-screening rejection or an unresolved request for information — - and the funds were returned to the sender by the collection provider. + collection deposit (e.g. a SWIFT wire) failed after arrival and did not + credit — most commonly a compliance-screening rejection or an unresolved + request for information, on either the collection provider's side or + Grid's. Failed collections are returned to the sender per the collection + provider's process. From e648518ee2f2d29da31cdeb8c930580fa7df0907 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 15:51:38 +0000 Subject: [PATCH 3/6] Match the webhook example's instructions note to the served text Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DLYJSn6VRoZeLV15wcuZHy --- mintlify/openapi.yaml | 2 +- openapi.yaml | 2 +- openapi/webhooks/internal-account-status.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 4a33e1df3..ed7b38770 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -11055,7 +11055,7 @@ webhooks: accountHolderName: Acme Exports Pte Ltd paymentRails: - SWIFT - instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + instructionsNotes: Payments are attributed automatically by the destination account; no reference code is required. createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' responses: diff --git a/openapi.yaml b/openapi.yaml index 4a33e1df3..ed7b38770 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -11055,7 +11055,7 @@ webhooks: accountHolderName: Acme Exports Pte Ltd paymentRails: - SWIFT - instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + instructionsNotes: Payments are attributed automatically by the destination account; no reference code is required. createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' responses: diff --git a/openapi/webhooks/internal-account-status.yaml b/openapi/webhooks/internal-account-status.yaml index 5e969313d..90a26ee23 100644 --- a/openapi/webhooks/internal-account-status.yaml +++ b/openapi/webhooks/internal-account-status.yaml @@ -149,7 +149,7 @@ post: accountHolderName: Acme Exports Pte Ltd paymentRails: - SWIFT - instructionsNotes: Payments are attributed automatically by the destination account number; no reference code is required. + instructionsNotes: Payments are attributed automatically by the destination account; no reference code is required. createdAt: '2025-08-01T10:00:00Z' updatedAt: '2025-08-15T14:32:00Z' responses: From f592920d4dea19da42000145dd509488bed63801 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 19:42:47 +0000 Subject: [PATCH 4/6] Qualify response descriptions for bank-rail incoming payments Greptile P2 on the ready round: the operation description said bank-rail PENDING events are informational, but the 200/202/403/422 response descriptions still read as unconditional approve/reject/RFI semantics. Each now carves out bank rails explicitly. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DLYJSn6VRoZeLV15wcuZHy --- mintlify/openapi.yaml | 11 ++++++++--- openapi.yaml | 11 ++++++++--- openapi/webhooks/incoming-payment.yaml | 17 +++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 370e3edaf..5698cbe67 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -10326,7 +10326,7 @@ webhooks: '200': description: | Webhook received successfully. - For PENDING transactions, this indicates approval to proceed with the payment. + For PENDING transactions on approval-mechanism rails, this indicates approval to proceed with the payment. For bank-rail incoming payments (e.g. SWIFT) a 200 only acknowledges receipt: there is nothing to approve. If `requestedReceiverCustomerInfoFields` were present in the webhook request, the corresponding fields for the recipient must be included in this response in the `receiverCustomerInfo` object. content: application/json: @@ -10337,6 +10337,7 @@ webhooks: Webhook received and will be processed asynchronously. The synchronous 200 response should be preferred where possible. This asycnhronous path should only be used in cases where the platform's architecture requires async (but still very quick) processing before approving or rejecting the payment. The platform must call the `/transactions/{transactionId}/approve` or `/transactions/{transactionId}/reject` endpoint to approve or reject the payment within 5 seconds or the payment will be automatically rejected. + Bank-rail incoming payments (e.g. SWIFT) need no approve/reject call: a 202 is treated the same as a 200 acknowledgment. '400': description: Bad request content: @@ -10352,7 +10353,9 @@ webhooks: '403': description: | Forbidden - Payment rejected by the client. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + a bank-rail incoming payment (e.g. SWIFT) cannot be rejected through + this response because the funds have already moved interbank. content: application/json: schema: @@ -10366,7 +10369,9 @@ webhooks: '422': description: | Unprocessable Entity - Additional counterparty information required. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + for bank-rail incoming payments (e.g. SWIFT) this response has no + effect on the already-received funds. content: application/json: schema: diff --git a/openapi.yaml b/openapi.yaml index 370e3edaf..5698cbe67 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -10326,7 +10326,7 @@ webhooks: '200': description: | Webhook received successfully. - For PENDING transactions, this indicates approval to proceed with the payment. + For PENDING transactions on approval-mechanism rails, this indicates approval to proceed with the payment. For bank-rail incoming payments (e.g. SWIFT) a 200 only acknowledges receipt: there is nothing to approve. If `requestedReceiverCustomerInfoFields` were present in the webhook request, the corresponding fields for the recipient must be included in this response in the `receiverCustomerInfo` object. content: application/json: @@ -10337,6 +10337,7 @@ webhooks: Webhook received and will be processed asynchronously. The synchronous 200 response should be preferred where possible. This asycnhronous path should only be used in cases where the platform's architecture requires async (but still very quick) processing before approving or rejecting the payment. The platform must call the `/transactions/{transactionId}/approve` or `/transactions/{transactionId}/reject` endpoint to approve or reject the payment within 5 seconds or the payment will be automatically rejected. + Bank-rail incoming payments (e.g. SWIFT) need no approve/reject call: a 202 is treated the same as a 200 acknowledgment. '400': description: Bad request content: @@ -10352,7 +10353,9 @@ webhooks: '403': description: | Forbidden - Payment rejected by the client. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + a bank-rail incoming payment (e.g. SWIFT) cannot be rejected through + this response because the funds have already moved interbank. content: application/json: schema: @@ -10366,7 +10369,9 @@ webhooks: '422': description: | Unprocessable Entity - Additional counterparty information required. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + for bank-rail incoming payments (e.g. SWIFT) this response has no + effect on the already-received funds. content: application/json: schema: diff --git a/openapi/webhooks/incoming-payment.yaml b/openapi/webhooks/incoming-payment.yaml index 19dc57614..bd7d19d6a 100644 --- a/openapi/webhooks/incoming-payment.yaml +++ b/openapi/webhooks/incoming-payment.yaml @@ -213,8 +213,10 @@ post: description: > Webhook received successfully. - For PENDING transactions, this indicates approval to proceed with the - payment. + For PENDING transactions on approval-mechanism rails, this indicates + approval to proceed with the payment. For bank-rail incoming payments + (e.g. SWIFT) a 200 only acknowledges receipt: there is nothing to + approve. If `requestedReceiverCustomerInfoFields` were present in the webhook request, the corresponding fields for the recipient must be included in @@ -236,6 +238,9 @@ post: The platform must call the `/transactions/{transactionId}/approve` or `/transactions/{transactionId}/reject` endpoint to approve or reject the payment within 5 seconds or the payment will be automatically rejected. + + Bank-rail incoming payments (e.g. SWIFT) need no approve/reject call: a + 202 is treated the same as a 200 acknowledgment. '400': description: Bad request content: @@ -251,7 +256,9 @@ post: '403': description: | Forbidden - Payment rejected by the client. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + a bank-rail incoming payment (e.g. SWIFT) cannot be rejected through + this response because the funds have already moved interbank. content: application/json: schema: @@ -265,7 +272,9 @@ post: '422': description: | Unprocessable Entity - Additional counterparty information required. - Only applicable for PENDING transactions. + Only applicable for PENDING transactions on approval-mechanism rails; + for bank-rail incoming payments (e.g. SWIFT) this response has no + effect on the already-received funds. content: application/json: schema: From aab23ffc25ed7d2aa564231928b088720076ea8d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 20:45:11 +0000 Subject: [PATCH 5/6] Enforce SwiftAccountInfoBase's at-least-one identifier invariant structurally The description already promised that accountNumber or iban is always present; encode it as anyOf so validators and codegen see the invariant instead of trusting prose. Both identifiers remain legal together. The redocly ignore entries follow the existing precedent for anyOf branches that reference parent-level properties. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01DLYJSn6VRoZeLV15wcuZHy --- .redocly.lint-ignore.yaml | 2 ++ mintlify/openapi.yaml | 5 +++++ openapi.yaml | 5 +++++ .../components/schemas/common/SwiftAccountInfoBase.yaml | 7 +++++++ 4 files changed, 19 insertions(+) diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml index c9009ae0e..d8e077511 100644 --- a/.redocly.lint-ignore.yaml +++ b/.redocly.lint-ignore.yaml @@ -14,6 +14,8 @@ openapi.yaml: - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/0/required/0' - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/1/required/0' - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/1/required/1' + - '#/components/schemas/SwiftAccountInfoBase/anyOf/0/required/0' + - '#/components/schemas/SwiftAccountInfoBase/anyOf/1/required/0' no-invalid-media-type-examples: - >- #/paths/~1customers~1external-accounts/post/requestBody/content/application~1json/schema diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 5698cbe67..bb05106f4 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -16944,6 +16944,11 @@ components: - swiftCode - bankName - country + anyOf: + - required: + - accountNumber + - required: + - iban properties: accountType: type: string diff --git a/openapi.yaml b/openapi.yaml index 5698cbe67..bb05106f4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -16944,6 +16944,11 @@ components: - swiftCode - bankName - country + anyOf: + - required: + - accountNumber + - required: + - iban properties: accountType: type: string diff --git a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml index 925f43d0c..2bf5a917e 100644 --- a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml +++ b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml @@ -9,6 +9,13 @@ required: - swiftCode - bankName - country +# Structural form of the description's invariant: at least one destination +# identifier, with both allowed when the bank exposes both. +anyOf: +- required: + - accountNumber +- required: + - iban properties: accountType: type: string From 082bf7f14bdf4e6ace4c51806de3339729883d34 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 20:49:26 +0000 Subject: [PATCH 6/6] Revert "Enforce SwiftAccountInfoBase's at-least-one identifier invariant structurally" This reverts commit aab23ffc25ed7d2aa564231928b088720076ea8d. --- .redocly.lint-ignore.yaml | 2 -- mintlify/openapi.yaml | 5 ----- openapi.yaml | 5 ----- .../components/schemas/common/SwiftAccountInfoBase.yaml | 7 ------- 4 files changed, 19 deletions(-) diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml index d8e077511..c9009ae0e 100644 --- a/.redocly.lint-ignore.yaml +++ b/.redocly.lint-ignore.yaml @@ -14,8 +14,6 @@ openapi.yaml: - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/0/required/0' - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/1/required/0' - '#/components/schemas/BeneficiaryTrustConfirmRequest/anyOf/1/required/1' - - '#/components/schemas/SwiftAccountInfoBase/anyOf/0/required/0' - - '#/components/schemas/SwiftAccountInfoBase/anyOf/1/required/0' no-invalid-media-type-examples: - >- #/paths/~1customers~1external-accounts/post/requestBody/content/application~1json/schema diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index bb05106f4..5698cbe67 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -16944,11 +16944,6 @@ components: - swiftCode - bankName - country - anyOf: - - required: - - accountNumber - - required: - - iban properties: accountType: type: string diff --git a/openapi.yaml b/openapi.yaml index bb05106f4..5698cbe67 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -16944,11 +16944,6 @@ components: - swiftCode - bankName - country - anyOf: - - required: - - accountNumber - - required: - - iban properties: accountType: type: string diff --git a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml index 2bf5a917e..925f43d0c 100644 --- a/openapi/components/schemas/common/SwiftAccountInfoBase.yaml +++ b/openapi/components/schemas/common/SwiftAccountInfoBase.yaml @@ -9,13 +9,6 @@ required: - swiftCode - bankName - country -# Structural form of the description's invariant: at least one destination -# identifier, with both allowed when the bank exposes both. -anyOf: -- required: - - accountNumber -- required: - - iban properties: accountType: type: string