diff --git a/src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs b/src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs index 32aab90e..6cf455c5 100644 --- a/src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs +++ b/src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs @@ -5,6 +5,7 @@ namespace TrueLayer.Payouts.Model { using BeneficiaryUnion = OneOf; + using SchemeSelectionUnion = OneOf; /// /// Represents a request for payout @@ -19,18 +20,21 @@ public record CreatePayoutRequest /// The three-letter ISO alpha currency code /// The payout beneficiary details /// Metadata + /// Metadata public CreatePayoutRequest( string merchantAccountId, long amountInMinor, string currency, BeneficiaryUnion beneficiary, - Dictionary? metadata = null) + Dictionary? metadata = null, + SchemeSelectionUnion? schemeSelection = null) { MerchantAccountId = merchantAccountId; AmountInMinor = amountInMinor.GreaterThan(0, nameof(amountInMinor)); Currency = currency.NotNullOrWhiteSpace(nameof(currency)); Beneficiary = beneficiary; Metadata = metadata; + SchemeSelection = schemeSelection; } /// @@ -54,6 +58,14 @@ public CreatePayoutRequest( /// public BeneficiaryUnion Beneficiary { get; } + /// + /// Gets the metadata + /// public Dictionary? Metadata { get; } + + /// + /// Gets the scheme selection + /// + public SchemeSelectionUnion? SchemeSelection { get; } } } diff --git a/src/TrueLayer/Payouts/Model/SchemeSelection.cs b/src/TrueLayer/Payouts/Model/SchemeSelection.cs new file mode 100644 index 00000000..2c4bc5fd --- /dev/null +++ b/src/TrueLayer/Payouts/Model/SchemeSelection.cs @@ -0,0 +1,55 @@ +using TrueLayer.Serialization; + +namespace TrueLayer.Payouts.Model; + +/// +/// Payout scheme selection types +/// +public static class SchemeSelection +{ + /// + /// Automatically select a payment scheme that supports instant payments based on currency and geography. + /// + [JsonDiscriminator("instant_only")] + public record InstantOnly : IDiscriminated + { + /// + /// Gets the scheme selection type + /// + public string Type => "instant_only"; + } + + /// + /// Automatically select a payment scheme that supports instant payments based on currency and geography, + /// with a fallback to a non-instant scheme if instant payment is unavailable. + /// The payout_executed webhook will specify the actual scheme used. + /// This is optimal when slow settlement is not a concern. This is used by default if no scheme_selection is provided. + /// + [JsonDiscriminator("instant_preferred")] + public record InstantPreferred : IDiscriminated + { + /// + /// Gets the scheme selection type + /// + public string Type => "instant_preferred"; + } + + + /// + /// Represents that the scheme for the payout is preselected. + /// + [JsonDiscriminator("preselected")] + public record Preselected : IDiscriminated + { + /// + /// Gets the scheme selection type + /// + public string Type => "preselected"; + + /// + /// Select a payment scheme compatible with the currency and geographic region to avoid payout failures after submission. + /// This helps with payouts by selecting the better-performing scheme between two similar options in a region, based on various criteria + /// + public string? SchemeId { get; init; } + } +} diff --git a/test/TrueLayer.AcceptanceTests/PayoutTests.cs b/test/TrueLayer.AcceptanceTests/PayoutTests.cs index 77c76f56..cd13727c 100644 --- a/test/TrueLayer.AcceptanceTests/PayoutTests.cs +++ b/test/TrueLayer.AcceptanceTests/PayoutTests.cs @@ -23,8 +23,7 @@ public async Task Can_create_payout() { CreatePayoutRequest payoutRequest = CreatePayoutRequest(); - var response = await _fixture.TlClients[0].Payouts.CreatePayout( - payoutRequest, idempotencyKey: Guid.NewGuid().ToString()); + var response = await _fixture.TlClients[0].Payouts.CreatePayout(payoutRequest); response.StatusCode.Should().Be(HttpStatusCode.Accepted); response.Data.Should().NotBeNull(); @@ -81,8 +80,8 @@ private CreatePayoutRequest CreatePayoutRequest() new AccountIdentifier.Iban("GB33BUKB20201555555555"), dateOfBirth: new DateTime(1970, 12, 31), address: new Address("London", "England", "EC1R 4RB", "GB", "1 Hardwick St")), - metadata: new() { { "a", "b" } } + metadata: new() { { "a", "b" } }, + schemeSelection: new SchemeSelection.InstantOnly() ); - } } diff --git a/test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs b/test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs index e5930895..b836e77c 100644 --- a/test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs +++ b/test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs @@ -107,7 +107,8 @@ private static CreatePayoutRequest CreatePayoutRequest(PayoutBeneficiary benefic 100, Currencies.GBP, beneficiary, - metadata: new() { { "a", "b" } }); + metadata: new() { { "a", "b" } }, + schemeSelection: new SchemeSelection.InstantPreferred()); public static IEnumerable TestData => new List