feat(ACL-306): Add support for Transaction Verified Payouts#254
feat(ACL-306): Add support for Transaction Verified Payouts#254tl-Roberto-Mancinelli merged 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for Verified Payouts to the TrueLayer .NET client library, enabling UK merchants to verify payout beneficiaries before funds are transferred. The feature allows verification of account holder names and optionally searching for specific transactions before executing payouts.
Key changes include:
- New verification models and beneficiary types for user-determined payouts
- Updated return types to handle both standard and verified payout responses
- HPP link builder helper for generating verification URLs
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/TrueLayer/Payouts/Model/Verification.cs | New verification models for name and transaction verification |
| src/TrueLayer/Payouts/Model/PayoutUser.cs | New user models for beneficiary details in verified payouts |
| src/TrueLayer/Payouts/Model/CreatePayoutBeneficiary.cs | Updated beneficiary types with UserDetermined support |
| src/TrueLayer/Payouts/Model/CreatePayoutResponse.cs | New response types for AuthorizationRequired and Created responses |
| src/TrueLayer/Payouts/Model/PayoutHppLinkBuilder.cs | Helper class for building verification HPP links |
| src/TrueLayer/Payouts/IPayoutsApi.cs | Updated CreatePayout return type to OneOf union |
| test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs | Comprehensive unit tests for verified payouts and HPP link generation |
| test/TrueLayer.AcceptanceTests/PayoutTests.cs | Acceptance tests for verified payout scenarios |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| { | ||
| const string Discriminator = "user_determined"; | ||
|
|
||
| public UserDetermined(string reference, string accountHolderName, AccountIdentifierUnion accountIdentifier) |
There was a problem hiding this comment.
yes it was already there
| { | ||
| const string Discriminator = "user_determined"; | ||
|
|
||
| public UserDetermined(string reference, string accountHolderName, AccountIdentifierUnion accountIdentifier) |
This comment was marked as duplicate.
This comment was marked as duplicate.
Sorry, something went wrong.
| /// <param name="address">The physical address of the end user</param> | ||
| public PayoutUserRequest( | ||
| string? id = null, | ||
| string? name = null, |
There was a problem hiding this comment.
Name must be provided for TVP, at least until we only support regulated clients.
With that said, LGTM - It makes sense to be flexible.
| /// <summary> | ||
| /// Helper class for building verification Hosted Payment Page (HPP) links for verified payouts | ||
| /// </summary> | ||
| public static class PayoutHppLinkBuilder |
There was a problem hiding this comment.
It's HP2, not HPP in theory... With that said I'm happy keeping a simple unified name, I would not bother about this detail here
add changelog fix typo add AuthorizationRequired in GetPayoutsResponse update changelog
30e7f6d to
4ae19d9
Compare
Summary
Adds support for Verified Payouts to the TrueLayer .NET client library, enabling verification of payout beneficiaries before funds are transferred. This is a UK-only feature that allows merchants to verify account holder names and optionally search for specific transactions before executing payouts.
Implements the API specification from: https://docs.truelayer.com/docs/make-a-verified-payout
Changes
New Models
Verification Models (
/src/TrueLayer/Payouts/Model/Verification.cs)Verification: Configuration for verified payoutsVerifyName: Boolean flag for name verificationTransactionSearchCriteria: Optional transaction search configurationTransactionSearchCriteria: Criteria for transaction detectionTokens: Search tokens to find in transaction descriptionsAmountInMinor: Expected transaction amountCurrency: Transaction currencyCreatedAt: Expected transaction date (serialized as YYYY-MM-DD)User Models (
/src/TrueLayer/Payouts/Model/PayoutUser.cs)PayoutUserRequest: User details for CREATE payout requestsId,Name,Email,Phone,DateOfBirth,Address(all optional)PayoutUserResponse: User details in API responsesId: User identifierBeneficiary Models
Updated
CreatePayoutBeneficiary.UserDetermined: Beneficiary type for verified payoutsReference: Payout reference for bank statementUser: PayoutUserRequest with beneficiary detailsVerification: Verification configurationProviderSelection: Provider selection (UserSelected or Preselected)Updated
CreatePayoutBeneficiary.BusinessAccount: Simplified to match API specAccountHolderNameandAccountIdentifierparametersReferenceNew
GetPayoutBeneficiarynamespace: Separate beneficiary types for GET responsesPaymentSource: AddedAccountHolderNameandAccountIdentifiersfieldsUserDetermined: Includes optionalAccountHolderName,AccountIdentifiers, andVerificationExternalAccount,BusinessAccount: Match GET response formatsResponse Models (
/src/TrueLayer/Payouts/Model/CreatePayoutResponse.cs)CreatePayoutResponse.AuthorizationRequired: Response for verified payouts requiring authorizationId: Payout identifierStatus: Always "authorization_required"ResourceToken: Token for HPP authenticationUser: User details with IDCreatePayoutResponse.Created: Response for standard non-verified payoutsId: Payout identifier[DefaultJsonDiscriminator]for fallback deserializationHPP Link Builder (
/src/TrueLayer/Payouts/Model/PayoutHppLinkBuilder.cs)Static helper class for building Hosted Payment Page verification links:
CreateVerificationLink(string payoutId, string resourceToken, string returnUri, bool useSandbox): Base methodCreateVerificationLink(AuthorizationRequired response, string returnUri, bool useSandbox): Convenience overloadReturns properly formatted HPP URLs:
https://app.truelayer-sandbox.com/payouts#payout_id={id}&resource_token={token}&return_uri={encoded_uri}https://app.truelayer.com/payouts#payout_id={id}&resource_token={token}&return_uri={encoded_uri}Enhanced JSON Serialization
Default Discriminator Support (
/src/TrueLayer/Serialization/DefaultJsonDiscriminatorAttribute.cs)[DefaultJsonDiscriminator]attribute for fallback type matchingOneOfJsonConverterto support default types when no discriminator field is present{"id": "..."}without astatusfieldAPI Updates
Updated Return Types
IPayoutsApi.CreatePayout: ReturnsOneOf<AuthorizationRequired, Created>IPayoutsApi.GetPayout: Updated to useGetPayoutBeneficiarytypesGetTransactions: Updated to useGetPayoutBeneficiarytypes for payout transactionsTests
Unit Tests (
/test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs)CreatePayout_With_Verified_Payout_Returns_AuthorizationRequired: Verifies verified payout creationCreateVerificationLink_Should_Build_Correct_Sandbox_Url: Tests sandbox HPP link generationCreateVerificationLink_Should_Build_Correct_Production_Url: Tests production HPP link generationCreateVerificationLink_From_Response_Should_Build_Correct_Url: Tests convenience overloadCreateVerificationLink_With_Empty_ResourceToken_Should_Throw: Tests validationCreateVerificationLink_With_Real_Production_Data_Should_Build_Valid_Link: Tests realistic production dataCreateVerificationLink_With_Real_Sandbox_Data_Should_Build_Valid_Link: Tests realistic sandbox dataCreateVerificationLink_With_Complex_Return_Uri_Should_Encode_Properly: Tests URL encodingAcceptance Tests (
/test/TrueLayer.AcceptanceTests/PayoutTests.cs)Can_create_verified_payout_with_name_verification: Tests name-only verificationCan_create_verified_payout_with_transaction_verification: Tests name + transaction verificationCan_create_verified_payout_with_preselected_provider: Tests with preselected providerBased on sandbox test requirements from: https://docs.truelayer.com/docs/make-a-verified-payout#test-verified-payouts-in-sandbox
Breaking Changes
CreatePayoutnow returnsOneOf<AuthorizationRequired, Created>instead ofCreatePayoutResponse.Match()to handle both response typesBeneficiaryrenamed toCreatePayoutBeneficiaryfor clarityGetPayoutBeneficiarytypes for GET responsesMigration Example:
Testing
All tests pass successfully:
Documentation
Added comprehensive XML documentation for all new types and methods, including:
Checklist