Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/TrueLayer/Payouts/Model/CreatePayoutRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace TrueLayer.Payouts.Model
{
using BeneficiaryUnion = OneOf<PaymentSource, ExternalAccount, BusinessAccount>;
using SchemeSelectionUnion = OneOf<SchemeSelection.InstantPreferred, SchemeSelection.InstantOnly, SchemeSelection.Preselected>;

/// <summary>
/// Represents a request for payout
Expand All @@ -19,18 +20,21 @@ public record CreatePayoutRequest
/// <param name="currency">The three-letter ISO alpha currency code</param>
/// <param name="beneficiary">The payout beneficiary details</param>
/// <param name="metadata">Metadata</param>
/// <param name="schemeSelection">Metadata</param>
public CreatePayoutRequest(
string merchantAccountId,
long amountInMinor,
string currency,
BeneficiaryUnion beneficiary,
Dictionary<string, string>? metadata = null)
Dictionary<string, string>? metadata = null,
SchemeSelectionUnion? schemeSelection = null)
{
MerchantAccountId = merchantAccountId;
AmountInMinor = amountInMinor.GreaterThan(0, nameof(amountInMinor));
Currency = currency.NotNullOrWhiteSpace(nameof(currency));
Beneficiary = beneficiary;
Metadata = metadata;
SchemeSelection = schemeSelection;
}

/// <summary>
Expand All @@ -54,6 +58,14 @@ public CreatePayoutRequest(
/// </summary>
public BeneficiaryUnion Beneficiary { get; }

/// <summary>
/// Gets the metadata
/// </summary>
public Dictionary<string, string>? Metadata { get; }

/// <summary>
/// Gets the scheme selection
/// </summary>
public SchemeSelectionUnion? SchemeSelection { get; }
}
}
55 changes: 55 additions & 0 deletions src/TrueLayer/Payouts/Model/SchemeSelection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using TrueLayer.Serialization;

namespace TrueLayer.Payouts.Model;

/// <summary>
/// Payout scheme selection types
/// </summary>
public static class SchemeSelection
{
/// <summary>
/// Automatically select a payment scheme that supports instant payments based on currency and geography.
/// </summary>
[JsonDiscriminator("instant_only")]
public record InstantOnly : IDiscriminated
{
/// <summary>
/// Gets the scheme selection type
/// </summary>
public string Type => "instant_only";
}

/// <summary>
/// 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.
/// </summary>
[JsonDiscriminator("instant_preferred")]
public record InstantPreferred : IDiscriminated
{
/// <summary>
/// Gets the scheme selection type
/// </summary>
public string Type => "instant_preferred";
}


/// <summary>
/// Represents that the scheme for the payout is preselected.
/// </summary>
[JsonDiscriminator("preselected")]
public record Preselected : IDiscriminated
{
/// <summary>
/// Gets the scheme selection type
/// </summary>
public string Type => "preselected";

/// <summary>
/// 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
/// </summary>
public string? SchemeId { get; init; }
}
}
7 changes: 3 additions & 4 deletions test/TrueLayer.AcceptanceTests/PayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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()
);

}
}
3 changes: 2 additions & 1 deletion test/TrueLayer.Tests/Payouts/PayoutsApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<object[]> TestData =>
new List<object[]>
Expand Down
Loading