feat(payouts): surface vop response - #2074
Open
heykulthe wants to merge 3 commits into
Open
Conversation
14 tasks
Auto-applied by CI: - cargo +nightly fmt --all - make -C sdk generate (if applicable) - make docs (if applicable) This commit was automatically generated by GitHub Actions.
deepanshu-iiitu
requested changes
Aug 7, 2026
Sakilmostak
reviewed
Aug 7, 2026
| // Only an eligible payee yields a payout id to act on; the VoP reference is | ||
| // reported separately so a refusal is still traceable, and so it survives the | ||
| // transfer overwriting `connector_payout_id`. | ||
| let connector_payout_id = is_eligible.then(|| vop_id.clone()); |
Contributor
There was a problem hiding this comment.
can you confirm, that this will be the payout reference id for the transaction?
Comment on lines
+420
to
+421
| pub error_code: Option<String>, | ||
| pub error_message: Option<String>, |
Contributor
There was a problem hiding this comment.
why are we putting error code and message here, shouldn't this be accompanied with error response?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Surfaces Deutsche Bank's Verification-of-Payee (VoP) outcome on the payout eligibility response, so the caller can tell why a payee was refused and can reconcile the check afterwards.
Motivation and Context
A VoP refusal was previously indistinguishable from any other ineligible payee, the caller got a status and nothing else, so a merchant could not be told whether the IBAN failed to match the payee name, or the payee simply could not be checked.
NMTCandNOAPnow carry the verdict and Deutsche Bank's own explanation.Additional Changes
How did you test it?
Payout Create Response:
Payouts that result in VOP MTCH/CMTC result in additional info being surfaced to merchant in
metadatawhilst if it's a NMTC/NOAP,error_codeanderror_messagefields are populated.Create Payout Response (CMTC case):
{ "payout_id": "payout_dcTH1SFAsaRkixQitBss", "merchant_id": "merchant_1786014217", "merchant_order_reference_id": null, "amount": 101, "currency": "EUR", "connector": "deutschebank", "payout_type": "bank", "payout_method_data": { "bank": { "iban": "DE945************80002", "bank_name": "Deutsche Bank", "bank_country_code": "DE", "bank_city": null, "bic": "DEU*****237", "account_holder_name": "John Doe" } }, "source_bank_data": { "iban": "DE991************89001", "bank_name": null, "bank_country_code": null, "bank_city": null, "bic": "DEU*****237", "account_holder_name": "ABC Inc." }, "billing": { "address": { "city": "Frankfurt", "country": "DE", "line1": "Taunusanlage 12", "line2": null, "line3": null, "zip": "60325", "state": "HE", "first_name": "John", "last_name": "Doe", "origin_zip": null }, "phone": null, "email": null }, "auto_fulfill": true, "customer_id": "payout_customer121", "customer": { "id": "payout_customer121", "name": "John Doe", "email": "payout_customer@example.com", "phone": "999999999", "phone_country_code": "+49", "customer_document_details": null }, "client_secret": "payout_payout_dcTH1SFAsaRkixQitBss_secret_hZxcgLlpCZkJ9h1T8oRd", "return_url": null, "business_country": null, "business_label": null, "description": "any-purpose", "billing_descriptor": null, "entity_type": "Individual", "recurring": false, "metadata": { "vop_status": "CMTC", "additional_info": "The IBAN almost matches the name of the payee. This is the name of the account holder that belongs to the IBAN: CRON HOLDING GMBH. If you authorize the order anyway, this may result in the money being transferred to a payment account whose owner is not the payee you specified.", "eligibility_reference_id": "65992296-71d9-58fa-bc79-3f159e4a33bf" }, "merchant_connector_id": "mca_l9oDd6NGEAsvyptN4H3C", "status": "pending", "error_message": null, "error_code": null, "profile_id": "pro_jaLf7s7GauSiowdxrCEY", "created": "2026-08-06T22:38:26.592Z", "connector_transaction_id": "4EA1FDCFE05957C8BBEBCFF7D98B1BD6", "priority": null, "payout_link": null, "email": "payout_customer@example.com", "name": "John Doe", "phone": "999999999", "phone_country_code": "+49", "unified_code": null, "unified_message": null, "payout_method_id": null }Get Payout Response (NMTC case)
{ "payout_id": "payout_7AKlp8jmxZtCHm6iGuQX", "merchant_id": "merchant_1786014217", "merchant_order_reference_id": null, "amount": 101, "currency": "EUR", "connector": "deutschebank", "payout_type": "bank", "payout_method_data": { "bank": { "iban": "DE945************80002", "bank_name": "Deutsche Bank", "bank_country_code": "DE", "bank_city": null, "bic": "DEU*****237", "account_holder_name": "John Doe" } }, "source_bank_data": { "iban": "DE712************40602", "bank_name": null, "bank_country_code": null, "bank_city": null, "bic": "DEU*****237", "account_holder_name": "ABC Inc." }, "billing": { "address": { "city": "Frankfurt", "country": "DE", "line1": "Taunusanlage 12", "line2": null, "line3": null, "zip": "60325", "state": "HE", "first_name": "John", "last_name": "Doe", "origin_zip": null }, "phone": null, "email": null }, "auto_fulfill": true, "customer_id": "payout_customer121", "customer": { "id": "payout_customer121", "name": "John Doe", "email": "payout_customer@example.com", "phone": "999999999", "phone_country_code": "+49", "customer_document_details": null }, "client_secret": "payout_payout_7AKlp8jmxZtCHm6iGuQX_secret_tFD6wiKLSsMdG8x2xnXR", "return_url": null, "business_country": null, "business_label": null, "description": "any-purpose", "billing_descriptor": null, "entity_type": "Individual", "recurring": false, "metadata": { "eligibility_reference_id": "29d8b78b-eb88-5f4b-b126-9bdf42b4b921" }, "merchant_connector_id": "mca_l9oDd6NGEAsvyptN4H3C", "status": "not_permitted", "error_message": "The IBAN does not match the name of the payee. If you authorize the order anyway, this may result in the money being transferred to a payment account whose owner is not the payee you specified.", "error_code": "NMTC", "profile_id": "pro_jaLf7s7GauSiowdxrCEY", "created": "2026-08-06T22:41:41.695Z", "connector_transaction_id": null, "priority": null, "payout_link": null, "email": "payout_customer@example.com", "name": "John Doe", "phone": "999999999", "phone_country_code": "+49", "unified_code": null, "unified_message": null, "payout_method_id": null }