diff --git a/src/TrueLayer/Payments/IPaymentsApi.cs b/src/TrueLayer/Payments/IPaymentsApi.cs
index a8ff9a59..87ad26e1 100644
--- a/src/TrueLayer/Payments/IPaymentsApi.cs
+++ b/src/TrueLayer/Payments/IPaymentsApi.cs
@@ -42,11 +42,14 @@ public interface IPaymentsApi
///
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
+ /// If not provided a idempotency key is automatically generated.
///
/// The cancellation token to cancel the operation
/// An API response that includes details of the created payment if successful, otherwise problem details
Task> CreatePayment(
- CreatePaymentRequest paymentRequest, string idempotencyKey, CancellationToken cancellationToken = default);
+ CreatePaymentRequest paymentRequest,
+ string? idempotencyKey = null,
+ CancellationToken cancellationToken = default);
///
/// Gets the details of an existing payment
@@ -54,7 +57,9 @@ Task> CreatePayment(
/// The payment identifier
/// The cancellation token to cancel the operation
/// An API response that includes the payment details if successful, otherwise problem details
- Task> GetPayment(string id, CancellationToken cancellationToken = default);
+ Task> GetPayment(
+ string id,
+ CancellationToken cancellationToken = default);
///
/// Generates a link to the TrueLayer hosted payment page
@@ -66,7 +71,10 @@ Task> CreatePayment(
/// Note this should be configured in the TrueLayer console under your application settings.
///
/// The HPP link you can redirect the end user to
- string CreateHostedPaymentPageLink(string paymentId, string paymentToken, Uri returnUri);
+ string CreateHostedPaymentPageLink(
+ string paymentId,
+ string paymentToken,
+ Uri returnUri);
///
/// Start the authorization flow for a payment.
@@ -75,13 +83,14 @@ Task> CreatePayment(
///
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
+ /// If not provided a idempotency key is automatically generated.
///
/// The start authorization request details
/// The cancellation token to cancel the operation
///
Task> StartAuthorizationFlow(
string paymentId,
- string idempotencyKey,
+ string? idempotencyKey,
StartAuthorizationFlowRequest request,
CancellationToken cancellationToken = default);
@@ -92,12 +101,14 @@ Task> StartAuthorizationFlow(
///
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
+ /// If not provided a idempotency key is automatically generated.
///
/// The create payment refund request
/// The cancellation token to cancel the operation
/// The id of the created refund
- Task> CreatePaymentRefund(string paymentId,
- string idempotencyKey,
+ Task> CreatePaymentRefund(
+ string paymentId,
+ string? idempotencyKey,
CreatePaymentRefundRequest request,
CancellationToken cancellationToken = default);
@@ -107,7 +118,8 @@ Task> CreatePaymentRefund(string paymen
/// The payment identifier
/// The cancellation token to cancel the operation
/// The list of refunds for a payment.
- Task> ListPaymentRefunds(string paymentId,
+ Task> ListPaymentRefunds(
+ string paymentId,
CancellationToken cancellationToken = default);
///
@@ -117,7 +129,8 @@ Task> ListPaymentRefunds(string paymentI
/// The refund identifier
/// The cancellation token to cancel the operation
/// The details of the selected refund
- Task> GetPaymentRefund(string paymentId,
+ Task> GetPaymentRefund(
+ string paymentId,
string refundId,
CancellationToken cancellationToken = default);
@@ -128,9 +141,13 @@ Task> GetPaymentRefund(string paymentId,
///
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
+ /// If not provided a idempotency key is automatically generated.
///
/// The cancellation token to cancel the operation
/// HTTP 202 Accepted if successful, otherwise problem details.
- Task CancelPayment(string paymentId, string idempotencyKey, CancellationToken cancellationToken = default);
+ Task CancelPayment(
+ string paymentId,
+ string? idempotencyKey = null,
+ CancellationToken cancellationToken = default);
}
}
diff --git a/src/TrueLayer/Payments/Model/CreatePaymentRefundRequest.cs b/src/TrueLayer/Payments/Model/CreatePaymentRefundRequest.cs
index b6140063..d3a84cab 100644
--- a/src/TrueLayer/Payments/Model/CreatePaymentRefundRequest.cs
+++ b/src/TrueLayer/Payments/Model/CreatePaymentRefundRequest.cs
@@ -2,6 +2,7 @@
namespace TrueLayer.Payments.Model;
-public record CreatePaymentRefundRequest(string Reference,
+public record CreatePaymentRefundRequest(
+ string Reference,
uint? AmountInMinor = null,
Dictionary? Metadata = null);
diff --git a/src/TrueLayer/Payments/PaymentsApi.cs b/src/TrueLayer/Payments/PaymentsApi.cs
index 958a6ecd..d5e092b9 100644
--- a/src/TrueLayer/Payments/PaymentsApi.cs
+++ b/src/TrueLayer/Payments/PaymentsApi.cs
@@ -55,10 +55,9 @@ public PaymentsApi(IApiClient apiClient, IAuthApi auth, TrueLayerOptions options
}
///
- public async Task> CreatePayment(CreatePaymentRequest paymentRequest, string idempotencyKey, CancellationToken cancellationToken = default)
+ public async Task> CreatePayment(CreatePaymentRequest paymentRequest, string? idempotencyKey = null, CancellationToken cancellationToken = default)
{
paymentRequest.NotNull(nameof(paymentRequest));
- idempotencyKey.NotNullOrWhiteSpace(nameof(idempotencyKey));
var authResponse = await _auth.GetAuthToken(new GetAuthTokenRequest(AuthorizationScope.Payments), cancellationToken);
@@ -70,7 +69,7 @@ public async Task> CreatePayment(CreatePaymentRe
return await _apiClient.PostAsync(
_baseUri,
paymentRequest,
- idempotencyKey,
+ idempotencyKey ?? Guid.NewGuid().ToString(),
authResponse.Data!.AccessToken,
_options.Payments!.SigningKey,
cancellationToken
@@ -105,12 +104,11 @@ public string CreateHostedPaymentPageLink(string paymentId, string paymentToken,
///
public async Task> StartAuthorizationFlow(
string paymentId,
- string idempotencyKey,
+ string? idempotencyKey,
StartAuthorizationFlowRequest request,
CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
- idempotencyKey.NotNullOrWhiteSpace(nameof(idempotencyKey));
request.NotNull(nameof(request));
var authResponse = await _auth.GetAuthToken(
@@ -124,15 +122,18 @@ public async Task> StartAuthorizationFlo
return await _apiClient.PostAsync(
_baseUri.Append(paymentId).Append(PaymentsEndpoints.AuthorizationFlow),
request,
- idempotencyKey,
+ idempotencyKey ?? Guid.NewGuid().ToString(),
authResponse.Data!.AccessToken,
_options.Payments!.SigningKey,
cancellationToken
);
}
- public async Task> CreatePaymentRefund(string paymentId,
- string idempotencyKey, CreatePaymentRefundRequest request, CancellationToken cancellationToken = default)
+ public async Task> CreatePaymentRefund(
+ string paymentId,
+ string? idempotencyKey,
+ CreatePaymentRefundRequest request,
+ CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
request.NotNull(nameof(request));
@@ -148,14 +149,15 @@ public async Task> CreatePaymentRefund(
return await _apiClient.PostAsync(
_baseUri.Append(paymentId).Append(PaymentsEndpoints.Refunds),
request,
- idempotencyKey,
+ idempotencyKey ?? Guid.NewGuid().ToString(),
authResponse.Data!.AccessToken,
_options.Payments!.SigningKey,
cancellationToken
);
}
- public async Task> ListPaymentRefunds(string paymentId,
+ public async Task> ListPaymentRefunds(
+ string paymentId,
CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
@@ -175,8 +177,10 @@ public async Task> ListPaymentRefunds(st
);
}
- public async Task> GetPaymentRefund(string paymentId,
- string refundId, CancellationToken cancellationToken = default)
+ public async Task> GetPaymentRefund(
+ string paymentId,
+ string refundId,
+ CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
refundId.NotNullOrWhiteSpace(nameof(refundId));
@@ -196,10 +200,12 @@ public async Task> GetPaymentRefund(string paymentId,
);
}
- public async Task CancelPayment(string paymentId, string idempotencyKey, CancellationToken cancellationToken = default)
+ public async Task CancelPayment(
+ string paymentId,
+ string? idempotencyKey = null,
+ CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
- idempotencyKey.NotNullOrWhiteSpace(nameof(idempotencyKey));
var authResponse = await _auth.GetAuthToken(
new GetAuthTokenRequest(AuthorizationScope.Payments), cancellationToken);
@@ -211,7 +217,7 @@ public async Task CancelPayment(string paymentId, string idempotenc
return await _apiClient.PostAsync(
_baseUri.Append(paymentId).Append(PaymentsEndpoints.Cancel),
- idempotencyKey: idempotencyKey,
+ idempotencyKey: idempotencyKey ?? Guid.NewGuid().ToString(),
accessToken: authResponse.Data!.AccessToken,
signingKey: _options.Payments!.SigningKey,
cancellationToken: cancellationToken);
diff --git a/src/TrueLayer/Payouts/IPayoutsApi.cs b/src/TrueLayer/Payouts/IPayoutsApi.cs
index d1266268..ba85f718 100644
--- a/src/TrueLayer/Payouts/IPayoutsApi.cs
+++ b/src/TrueLayer/Payouts/IPayoutsApi.cs
@@ -25,11 +25,14 @@ public interface IPayoutsApi
///
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
+ /// If not provided a idempotency key is automatically generated.
///
/// The cancellation token to cancel the operation
/// An API response that includes details of the created payout if successful, otherwise problem details
Task> CreatePayout(
- CreatePayoutRequest payoutRequest, string idempotencyKey, CancellationToken cancellationToken = default);
+ CreatePayoutRequest payoutRequest,
+ string? idempotencyKey = null,
+ CancellationToken cancellationToken = default);
///
/// Gets the details of an existing payment
@@ -37,6 +40,8 @@ Task> CreatePayout(
/// The payout identifier
/// The cancellation token to cancel the operation
/// An API response that includes the payout details if successful, otherwise problem details
- Task> GetPayout(string id, CancellationToken cancellationToken = default);
+ Task> GetPayout(
+ string id,
+ CancellationToken cancellationToken = default);
}
}
diff --git a/src/TrueLayer/Payouts/PayoutsApi.cs b/src/TrueLayer/Payouts/PayoutsApi.cs
index 937a7041..a39232a4 100644
--- a/src/TrueLayer/Payouts/PayoutsApi.cs
+++ b/src/TrueLayer/Payouts/PayoutsApi.cs
@@ -37,10 +37,12 @@ public PayoutsApi(IApiClient apiClient, IAuthApi auth, TrueLayerOptions options)
}
///
- public async Task> CreatePayout(CreatePayoutRequest payoutRequest, string idempotencyKey, CancellationToken cancellationToken = default)
+ public async Task> CreatePayout(
+ CreatePayoutRequest payoutRequest,
+ string? idempotencyKey = null,
+ CancellationToken cancellationToken = default)
{
payoutRequest.NotNull(nameof(payoutRequest));
- idempotencyKey.NotNullOrWhiteSpace(nameof(idempotencyKey));
var authResponse = await _auth.GetAuthToken(new GetAuthTokenRequest(AuthorizationScope.Payments), cancellationToken);
@@ -52,14 +54,16 @@ public async Task> CreatePayout(CreatePayoutRe
return await _apiClient.PostAsync(
_baseUri,
payoutRequest,
- idempotencyKey,
+ idempotencyKey ?? Guid.NewGuid().ToString(),
authResponse.Data!.AccessToken,
_options.Payments!.SigningKey,
cancellationToken
);
}
- public async Task> GetPayout(string id, CancellationToken cancellationToken = default)
+ public async Task> GetPayout(
+ string id,
+ CancellationToken cancellationToken = default)
{
id.NotNullOrWhiteSpace(nameof(id));
id.NotAUrl(nameof(id));
diff --git a/test/TrueLayer.AcceptanceTests/PaymentTests.cs b/test/TrueLayer.AcceptanceTests/PaymentTests.cs
index 9e91b408..61930996 100644
--- a/test/TrueLayer.AcceptanceTests/PaymentTests.cs
+++ b/test/TrueLayer.AcceptanceTests/PaymentTests.cs
@@ -60,8 +60,7 @@ public PaymentTests(ApiTestFixture fixture)
[MemberData(nameof(ExternalAccountPaymentRequests))]
public async Task can_create_external_account_payment(CreatePaymentRequest paymentRequest)
{
- var response = await _fixture.Client.Payments.CreatePayment(
- paymentRequest, idempotencyKey: Guid.NewGuid().ToString());
+ var response = await _fixture.Client.Payments.CreatePayment(paymentRequest);
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.Data.IsT0.Should().BeTrue();
@@ -122,8 +121,7 @@ public async Task can_create_merchant_account_gbp_verification_Payment()
Verification = new Verification.Automated { RemitterName = true }
});
- var response = await _fixture.Client.Payments.CreatePayment(
- paymentRequest, idempotencyKey: Guid.NewGuid().ToString());
+ var response = await _fixture.Client.Payments.CreatePayment(paymentRequest);
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.Data.IsT0.Should().BeTrue();
@@ -206,8 +204,7 @@ public async Task Can_create_payment_with_auth_flow()
[MemberData(nameof(ExternalAccountPaymentRequests))]
public async Task Can_get_authorization_required_payment(CreatePaymentRequest paymentRequest)
{
- var response = await _fixture.Client.Payments.CreatePayment(
- paymentRequest, idempotencyKey: Guid.NewGuid().ToString());
+ var response = await _fixture.Client.Payments.CreatePayment(paymentRequest);
response.IsSuccessful.Should().BeTrue();
response.Data.IsT0.Should().BeTrue();
@@ -280,7 +277,7 @@ public async Task Can_create_and_get_payment_refund()
// Act && assert
var createRefundResponse = await _fixture.Client.Payments.CreatePaymentRefund(
paymentId: payment.Id,
- idempotencyKey: Guid.NewGuid().ToString(),
+ null,
new CreatePaymentRefundRequest(Reference: "a-reference"));
createRefundResponse.IsSuccessful.Should().BeTrue();
createRefundResponse.Data!.Id.Should().NotBeNullOrWhiteSpace();
@@ -334,9 +331,7 @@ public async Task Can_cancel_a_payment()
var paymentId = payment.Data.AsT0.Id;
// act
- var cancelPaymentResponse = await _fixture.Client.Payments.CancelPayment(
- paymentId,
- idempotencyKey: Guid.NewGuid().ToString());
+ var cancelPaymentResponse = await _fixture.Client.Payments.CancelPayment(paymentId);
var getPaymentResponse = await _fixture.Client.Payments.GetPayment(paymentId);
diff --git a/test/TrueLayer.AcceptanceTests/PayoutTests.cs b/test/TrueLayer.AcceptanceTests/PayoutTests.cs
index a902530b..47f87861 100644
--- a/test/TrueLayer.AcceptanceTests/PayoutTests.cs
+++ b/test/TrueLayer.AcceptanceTests/PayoutTests.cs
@@ -26,8 +26,7 @@ public async Task Can_create_payout()
{
CreatePayoutRequest payoutRequest = CreatePayoutRequest();
- var response = await _fixture.Client.Payouts.CreatePayout(
- payoutRequest, idempotencyKey: Guid.NewGuid().ToString());
+ var response = await _fixture.Client.Payouts.CreatePayout(payoutRequest);
response.StatusCode.Should().Be(HttpStatusCode.Accepted);
response.Data.Should().NotBeNull();
@@ -73,11 +72,11 @@ public async Task InitializeAsync()
throw new InvalidOperationException("You must have a merchant account in order to perform a payout");
}
- _merchantAccount = accounts.Data.Items.Single(x => x.Currency == "GBP");
+ _merchantAccount = accounts.Data.Items.Single(x => x.Currency == Currencies.GBP);
}
private CreatePayoutRequest CreatePayoutRequest()
- => new CreatePayoutRequest(
+ => new(
_merchantAccount!.Id,
100,
Currencies.GBP,