From 1d8c953b9617c32198387ed5dfef76bf7426f79b Mon Sep 17 00:00:00 2001 From: david ruiz Date: Mon, 1 Jun 2026 16:51:56 +0200 Subject: [PATCH 1/4] Issuing createCard and createControl with idempotencykey --- .../com/checkout/issuing/IssuingClient.java | 8 +- .../checkout/issuing/IssuingClientImpl.java | 18 +++-- .../create/VelocityCardControlResponse.java | 1 - .../checkout/issuing/BaseIssuingTestIT.java | 2 +- .../issuing/IssuingClientImplTest.java | 80 ++++++++++++++++++- .../issuing/IssuingControlsTestIT.java | 2 +- .../newfields/IssuingCardNewFieldsIT.java | 10 +-- 7 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/checkout/issuing/IssuingClient.java b/src/main/java/com/checkout/issuing/IssuingClient.java index 37a8b0b5..3e46a3a6 100644 --- a/src/main/java/com/checkout/issuing/IssuingClient.java +++ b/src/main/java/com/checkout/issuing/IssuingClient.java @@ -74,7 +74,7 @@ public interface IssuingClient { CompletableFuture getCardholderCards(String cardholderId); - CompletableFuture createCard(CardRequest cardRequest); + CompletableFuture createCard(CardRequest cardRequest, String idempotencyKey); CompletableFuture getCardDetails(String cardId); @@ -92,7 +92,7 @@ public interface IssuingClient { CompletableFuture suspendCard(final String cardId, final SuspendCardRequest suspendCardRequest); - CompletableFuture createControl(final CardControlRequest cardControlRequest); + CompletableFuture createControl(final CardControlRequest cardControlRequest, final String idempotencyKey); CompletableFuture getCardControls(final CardControlsQuery queryFilter); @@ -200,7 +200,7 @@ CompletableFuture simulateReversal( CardholderCardsResponse getCardholderCardsSync(String cardholderId); - CardResponse createCardSync(CardRequest cardRequest); + CardResponse createCardSync(CardRequest cardRequest, String idempotencyKey); CardDetailsResponse getCardDetailsSync(String cardId); @@ -218,7 +218,7 @@ CompletableFuture simulateReversal( VoidResponse suspendCardSync(String cardId, SuspendCardRequest suspendCardRequest); - CardControlResponse createControlSync(CardControlRequest cardControlRequest); + CardControlResponse createControlSync(CardControlRequest cardControlRequest, String idempotencyKey); CardControlsQueryResponse getCardControlsSync(CardControlsQuery queryFilter); diff --git a/src/main/java/com/checkout/issuing/IssuingClientImpl.java b/src/main/java/com/checkout/issuing/IssuingClientImpl.java index 9ecf3534..70a76c39 100644 --- a/src/main/java/com/checkout/issuing/IssuingClientImpl.java +++ b/src/main/java/com/checkout/issuing/IssuingClientImpl.java @@ -186,14 +186,14 @@ public CompletableFuture getCardholderCards(final Strin } @Override - public CompletableFuture createCard(final CardRequest cardRequest) { + public CompletableFuture createCard(final CardRequest cardRequest, final String idempotencyKey) { validateParams("cardRequest", cardRequest); return apiClient.postAsync( buildPath(ISSUING_PATH, CARDS_PATH), sdkAuthorization(), CardResponse.class, cardRequest, - null + idempotencyKey ); } @@ -301,7 +301,8 @@ public CompletableFuture suspendCard( @Override public CompletableFuture createControl( - final CardControlRequest cardControlRequest + final CardControlRequest cardControlRequest, + final String idempotencyKey ) { validateParams("cardControlRequest", cardControlRequest); return apiClient.postAsync( @@ -309,7 +310,7 @@ public CompletableFuture createControl( sdkAuthorization(), CardControlResponse.class, cardControlRequest, - null + idempotencyKey ); } @@ -739,14 +740,14 @@ public CardholderCardsResponse getCardholderCardsSync(final String cardholderId) } @Override - public CardResponse createCardSync(final CardRequest cardRequest) { + public CardResponse createCardSync(final CardRequest cardRequest, final String idempotencyKey) { validateCardRequest(cardRequest); return apiClient.post( buildPath(ISSUING_PATH, CARDS_PATH), sdkAuthorization(), CardResponse.class, cardRequest, - null + idempotencyKey ); } @@ -854,7 +855,8 @@ public VoidResponse suspendCardSync( @Override public CardControlResponse createControlSync( - final CardControlRequest cardControlRequest + final CardControlRequest cardControlRequest, + final String idempotencyKey ) { validateCardControlRequest(cardControlRequest); return apiClient.post( @@ -862,7 +864,7 @@ public CardControlResponse createControlSync( sdkAuthorization(), CardControlResponse.class, cardControlRequest, - null + idempotencyKey ); } diff --git a/src/main/java/com/checkout/issuing/controls/responses/create/VelocityCardControlResponse.java b/src/main/java/com/checkout/issuing/controls/responses/create/VelocityCardControlResponse.java index d434233a..9760e6bd 100644 --- a/src/main/java/com/checkout/issuing/controls/responses/create/VelocityCardControlResponse.java +++ b/src/main/java/com/checkout/issuing/controls/responses/create/VelocityCardControlResponse.java @@ -3,7 +3,6 @@ import com.checkout.issuing.controls.requests.ControlType; import com.checkout.issuing.controls.requests.VelocityLimit; import com.google.gson.annotations.SerializedName; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/src/test/java/com/checkout/issuing/BaseIssuingTestIT.java b/src/test/java/com/checkout/issuing/BaseIssuingTestIT.java index 81e064c3..7be3763c 100644 --- a/src/test/java/com/checkout/issuing/BaseIssuingTestIT.java +++ b/src/test/java/com/checkout/issuing/BaseIssuingTestIT.java @@ -92,7 +92,7 @@ protected CardResponse createCard(final String cardholderId, final Boolean activ final CardResponse cardResponse = blocking(() -> getIssuingCheckoutApi() .issuingClient() - .createCard(request)); + .createCard(request, null)); assertNotNull(cardResponse); diff --git a/src/test/java/com/checkout/issuing/IssuingClientImplTest.java b/src/test/java/com/checkout/issuing/IssuingClientImplTest.java index 09ea0e2a..09312685 100644 --- a/src/test/java/com/checkout/issuing/IssuingClientImplTest.java +++ b/src/test/java/com/checkout/issuing/IssuingClientImplTest.java @@ -215,7 +215,25 @@ void shouldCreateCard() throws ExecutionException, InterruptedException { null )).thenReturn(CompletableFuture.completedFuture(response)); - final CompletableFuture future = client.createCard(request); + final CompletableFuture future = client.createCard(request, null); + + validateCardResponse(response, future.get()); + } + + @Test + void shouldCreateCardWithIdempotencyKey() throws ExecutionException, InterruptedException { + final VirtualCardRequest request = createVirtualCardRequest(); + final CardResponse response = createCardResponse(); + + when(apiClient.postAsync( + "issuing/cards", + authorization, + CardResponse.class, + request, + "idempotencyKey" + )).thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture future = client.createCard(request, "idempotencyKey"); validateCardResponse(response, future.get()); } @@ -442,7 +460,25 @@ void shouldCreateControl() throws ExecutionException, InterruptedException { null )).thenReturn(CompletableFuture.completedFuture(response)); - final CompletableFuture future = client.createControl(request); + final CompletableFuture future = client.createControl(request, null); + + validateCardControlResponse(response, future.get()); + } + + @Test + void shouldCreateControlWithIdempotencyKey() throws ExecutionException, InterruptedException { + final CardControlRequest request = createCardControlRequest(); + final CardControlResponse response = createCardControlResponse(); + + when(apiClient.postAsync( + "issuing/controls", + authorization, + CardControlResponse.class, + request, + "idempotencyKey" + )).thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture future = client.createControl(request, "idempotencyKey"); validateCardControlResponse(response, future.get()); } @@ -1021,7 +1057,25 @@ void shouldCreateCardSync() { null )).thenReturn(expectedResponse); - final CardResponse actualResponse = client.createCardSync(request); + final CardResponse actualResponse = client.createCardSync(request, null); + + validateCardResponse(expectedResponse, actualResponse); + } + + @Test + void shouldCreateCardSyncWithIdempotencyKey() { + final VirtualCardRequest request = createVirtualCardRequest(); + final CardResponse expectedResponse = createCardResponse(); + + when(apiClient.post( + "issuing/cards", + authorization, + CardResponse.class, + request, + "idempotencyKey" + )).thenReturn(expectedResponse); + + final CardResponse actualResponse = client.createCardSync(request, "idempotencyKey"); validateCardResponse(expectedResponse, actualResponse); } @@ -1248,7 +1302,25 @@ void shouldCreateControlSync() { null )).thenReturn(expectedResponse); - final CardControlResponse actualResponse = client.createControlSync(request); + final CardControlResponse actualResponse = client.createControlSync(request, null); + + validateCardControlResponse(expectedResponse, actualResponse); + } + + @Test + void shouldCreateControlSyncWithIdempotencyKey() { + final CardControlRequest request = createCardControlRequest(); + final CardControlResponse expectedResponse = createCardControlResponse(); + + when(apiClient.post( + "issuing/controls", + authorization, + CardControlResponse.class, + request, + "idempotencyKey" + )).thenReturn(expectedResponse); + + final CardControlResponse actualResponse = client.createControlSync(request, "idempotencyKey"); validateCardControlResponse(expectedResponse, actualResponse); } diff --git a/src/test/java/com/checkout/issuing/IssuingControlsTestIT.java b/src/test/java/com/checkout/issuing/IssuingControlsTestIT.java index 726e1303..a3245a60 100644 --- a/src/test/java/com/checkout/issuing/IssuingControlsTestIT.java +++ b/src/test/java/com/checkout/issuing/IssuingControlsTestIT.java @@ -172,7 +172,7 @@ private CardControlResponse createCardControl(final String cardId) { .build(); final CardControlResponse cardControlResponse = blocking(() -> - issuingApi.issuingClient().createControl(request)); + issuingApi.issuingClient().createControl(request, null)); assertNotNull(cardControlResponse); return cardControlResponse; diff --git a/src/test/java/com/checkout/issuing/newfields/IssuingCardNewFieldsIT.java b/src/test/java/com/checkout/issuing/newfields/IssuingCardNewFieldsIT.java index cf9e7853..d224681d 100644 --- a/src/test/java/com/checkout/issuing/newfields/IssuingCardNewFieldsIT.java +++ b/src/test/java/com/checkout/issuing/newfields/IssuingCardNewFieldsIT.java @@ -49,7 +49,7 @@ void shouldCreateVirtualCardWithMetadata() { .build(); final CardResponse response = blocking(() -> - issuingApi.issuingClient().createCard(request)); + issuingApi.issuingClient().createCard(request, null)); assertNotNull(response); assertNotNull(response.getId()); @@ -65,7 +65,7 @@ void shouldCreateVirtualCardWithRevocationDate() { .build(); final CardResponse response = blocking(() -> - issuingApi.issuingClient().createCard(request)); + issuingApi.issuingClient().createCard(request, null)); assertNotNull(response); assertNotNull(response.getId()); @@ -86,7 +86,7 @@ void shouldCreateVirtualCardWithBothNewFields() { .build(); final CardResponse response = blocking(() -> - issuingApi.issuingClient().createCard(request)); + issuingApi.issuingClient().createCard(request, null)); assertNotNull(response); assertNotNull(response.getId()); @@ -104,7 +104,7 @@ void shouldCreatePhysicalCardWithMetadata() { .build(); final CardResponse response = blocking(() -> - issuingApi.issuingClient().createCard(request)); + issuingApi.issuingClient().createCard(request, null)); assertNotNull(response); assertNotNull(response.getId()); @@ -120,7 +120,7 @@ void shouldCreatePhysicalCardWithRevocationDate() { .build(); final CardResponse response = blocking(() -> - issuingApi.issuingClient().createCard(request)); + issuingApi.issuingClient().createCard(request, null)); assertNotNull(response); assertNotNull(response.getId()); From a67aab2ba7f8be8a9658387b60bd4b820c06e5a4 Mon Sep 17 00:00:00 2001 From: david ruiz Date: Mon, 1 Jun 2026 17:39:34 +0200 Subject: [PATCH 2/4] Idempotency key update --- .../AgenticCommerceClient.java | 4 +- .../AgenticCommerceClientImpl.java | 8 ++-- .../checkout/issuing/IssuingClientImpl.java | 8 ++++ .../contexts/PaymentContextsClient.java | 4 +- .../contexts/PaymentContextsClientImpl.java | 8 ++-- .../AgenticCommerceClientImplTest.java | 48 +++++++++++++++++-- .../AgenticCommerceTestIT.java | 6 +-- .../issuing/IssuingClientImplTest.java | 4 ++ .../PaymentContextsClientImplTest.java | 33 ++++++++++++- .../contexts/PaymentContextsTestIT.java | 20 ++++---- 10 files changed, 113 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java index fcbafc4e..c7a88f13 100644 --- a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java +++ b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java @@ -8,7 +8,7 @@ public interface AgenticCommerceClient { - CompletableFuture delegatePayment(DelegatePaymentRequest request, DelegatePaymentHeaders headers); + CompletableFuture delegatePayment(DelegatePaymentRequest request, String idempotencyKey, DelegatePaymentHeaders headers); - DelegatePaymentResponse delegatePaymentSync(DelegatePaymentRequest request, DelegatePaymentHeaders headers); + DelegatePaymentResponse delegatePaymentSync(DelegatePaymentRequest request, String idempotencyKey, DelegatePaymentHeaders headers); } diff --git a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java index 08a4b302..b0151716 100644 --- a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java +++ b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java @@ -21,26 +21,26 @@ public AgenticCommerceClientImpl(final ApiClient apiClient, final CheckoutConfig } @Override - public CompletableFuture delegatePayment(final DelegatePaymentRequest request, final DelegatePaymentHeaders headers) { + public CompletableFuture delegatePayment(final DelegatePaymentRequest request, final String idempotencyKey, final DelegatePaymentHeaders headers) { CheckoutUtils.validateParams("request", request, "headers", headers); return apiClient.postAsync( buildPath(AGENTIC_COMMERCE_PATH, DELEGATE_PAYMENT_PATH), sdkAuthorization(), DelegatePaymentResponse.class, request, - null, + idempotencyKey, headers); } @Override - public DelegatePaymentResponse delegatePaymentSync(final DelegatePaymentRequest request, final DelegatePaymentHeaders headers) { + public DelegatePaymentResponse delegatePaymentSync(final DelegatePaymentRequest request, final String idempotencyKey, final DelegatePaymentHeaders headers) { CheckoutUtils.validateParams("request", request, "headers", headers); return apiClient.post( buildPath(AGENTIC_COMMERCE_PATH, DELEGATE_PAYMENT_PATH), sdkAuthorization(), DelegatePaymentResponse.class, request, - null, + idempotencyKey, headers); } } diff --git a/src/main/java/com/checkout/issuing/IssuingClientImpl.java b/src/main/java/com/checkout/issuing/IssuingClientImpl.java index 70a76c39..5767bd2a 100644 --- a/src/main/java/com/checkout/issuing/IssuingClientImpl.java +++ b/src/main/java/com/checkout/issuing/IssuingClientImpl.java @@ -601,6 +601,7 @@ public CompletableFuture deleteScheduledRevocation(final String ca ); } + @Override public CompletableFuture createDispute(final CreateDisputeRequest createDisputeRequest, String idempotencyKey) { validateCreateDisputeRequest(createDisputeRequest); return apiClient.postAsync( @@ -612,6 +613,7 @@ public CompletableFuture createDispute(final CreateDisputeReque ); } + @Override public CompletableFuture getDispute(final String disputeId) { validateDisputeId(disputeId); return apiClient.getAsync( @@ -621,6 +623,7 @@ public CompletableFuture getDispute(final String disputeId) { ); } + @Override public CompletableFuture cancelDispute(final String disputeId, String idempotencyKey) { validateDisputeId(disputeId); return apiClient.postAsync( @@ -632,6 +635,7 @@ public CompletableFuture cancelDispute(final String disputeId, Str ); } + @Override public CompletableFuture escalateDispute(final String disputeId, String idempotencyKey, final EscalateDisputeRequest escalateDisputeRequest) { validateDisputeIdAndEscalateRequest(disputeId, escalateDisputeRequest); @@ -1154,6 +1158,7 @@ public VoidResponse deleteScheduledRevocationSync(final String cardId) { ); } + @Override public DisputeResponse createDisputeSync(final CreateDisputeRequest createDisputeRequest, String idempotencyKey) { validateCreateDisputeRequest(createDisputeRequest); return apiClient.post( @@ -1165,6 +1170,7 @@ public DisputeResponse createDisputeSync(final CreateDisputeRequest createDisput ); } + @Override public DisputeResponse getDisputeSync(final String disputeId) { validateDisputeId(disputeId); return apiClient.get( @@ -1174,6 +1180,7 @@ public DisputeResponse getDisputeSync(final String disputeId) { ); } + @Override public VoidResponse cancelDisputeSync(final String disputeId, String idempotencyKey) { validateDisputeId(disputeId); return apiClient.post( @@ -1185,6 +1192,7 @@ public VoidResponse cancelDisputeSync(final String disputeId, String idempotency ); } + @Override public VoidResponse escalateDisputeSync(final String disputeId, String idempotencyKey, final EscalateDisputeRequest escalateDisputeRequest) { validateDisputeIdAndEscalateRequest(disputeId, escalateDisputeRequest); diff --git a/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java b/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java index cc25744b..29e6392b 100644 --- a/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java +++ b/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java @@ -4,12 +4,12 @@ public interface PaymentContextsClient { - CompletableFuture requestPaymentContexts(PaymentContextsRequest paymentContextsRequest); + CompletableFuture requestPaymentContexts(PaymentContextsRequest paymentContextsRequest, String idempotencyKey); CompletableFuture getPaymentContextDetails(String paymentContextId); // Synchronous methods - PaymentContextsRequestResponse requestPaymentContextsSync(PaymentContextsRequest paymentContextsRequest); + PaymentContextsRequestResponse requestPaymentContextsSync(PaymentContextsRequest paymentContextsRequest, String idempotencyKey); PaymentContextDetailsResponse getPaymentContextDetailsSync(String paymentContextId); diff --git a/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java b/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java index 5f0a9fa1..1e2fa979 100644 --- a/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java +++ b/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java @@ -18,9 +18,9 @@ public PaymentContextsClientImpl(final ApiClient apiClient, final CheckoutConfig } @Override - public CompletableFuture requestPaymentContexts(final PaymentContextsRequest paymentContextsRequest) { + public CompletableFuture requestPaymentContexts(final PaymentContextsRequest paymentContextsRequest, final String idempotencyKey) { validatePaymentContextsRequest(paymentContextsRequest); - return apiClient.postAsync(PAYMENT_CONTEXTS_PATH, sdkAuthorization(), PaymentContextsRequestResponse.class, paymentContextsRequest, null); + return apiClient.postAsync(PAYMENT_CONTEXTS_PATH, sdkAuthorization(), PaymentContextsRequestResponse.class, paymentContextsRequest, idempotencyKey); } @Override @@ -32,9 +32,9 @@ public CompletableFuture getPaymentContextDetails // Synchronous methods @Override - public PaymentContextsRequestResponse requestPaymentContextsSync(final PaymentContextsRequest paymentContextsRequest) { + public PaymentContextsRequestResponse requestPaymentContextsSync(final PaymentContextsRequest paymentContextsRequest, final String idempotencyKey) { validatePaymentContextsRequest(paymentContextsRequest); - return apiClient.post(PAYMENT_CONTEXTS_PATH, sdkAuthorization(), PaymentContextsRequestResponse.class, paymentContextsRequest, null); + return apiClient.post(PAYMENT_CONTEXTS_PATH, sdkAuthorization(), PaymentContextsRequestResponse.class, paymentContextsRequest, idempotencyKey); } @Override diff --git a/src/test/java/com/checkout/agenticcommerce/AgenticCommerceClientImplTest.java b/src/test/java/com/checkout/agenticcommerce/AgenticCommerceClientImplTest.java index d54ff66e..b4fbe68f 100644 --- a/src/test/java/com/checkout/agenticcommerce/AgenticCommerceClientImplTest.java +++ b/src/test/java/com/checkout/agenticcommerce/AgenticCommerceClientImplTest.java @@ -74,7 +74,7 @@ void shouldDelegatePayment() throws ExecutionException, InterruptedException { eq(headers))) .thenReturn(CompletableFuture.completedFuture(response)); - final CompletableFuture future = client.delegatePayment(request, headers); + final CompletableFuture future = client.delegatePayment(request, null, headers); assertNotNull(future.get()); assertEquals(response, future.get()); @@ -95,7 +95,49 @@ void shouldDelegatePaymentSync() { eq(headers))) .thenReturn(response); - final DelegatePaymentResponse result = client.delegatePaymentSync(request, headers); + final DelegatePaymentResponse result = client.delegatePaymentSync(request, null, headers); + + assertNotNull(result); + assertEquals(response, result); + } + + @Test + void shouldDelegatePaymentWithIdempotencyKey() throws ExecutionException, InterruptedException { + final DelegatePaymentRequest request = buildDelegatePaymentRequest(); + final DelegatePaymentHeaders headers = buildHeaders(); + final DelegatePaymentResponse response = mock(DelegatePaymentResponse.class); + + when(apiClient.postAsync( + eq("agentic_commerce/delegate_payment"), + eq(authorization), + eq(DelegatePaymentResponse.class), + eq(request), + eq("idempotencyKey"), + eq(headers))) + .thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture future = client.delegatePayment(request, "idempotencyKey", headers); + + assertNotNull(future.get()); + assertEquals(response, future.get()); + } + + @Test + void shouldDelegatePaymentSyncWithIdempotencyKey() { + final DelegatePaymentRequest request = buildDelegatePaymentRequest(); + final DelegatePaymentHeaders headers = buildHeaders(); + final DelegatePaymentResponse response = mock(DelegatePaymentResponse.class); + + when(apiClient.post( + eq("agentic_commerce/delegate_payment"), + eq(authorization), + eq(DelegatePaymentResponse.class), + eq(request), + eq("idempotencyKey"), + eq(headers))) + .thenReturn(response); + + final DelegatePaymentResponse result = client.delegatePaymentSync(request, "idempotencyKey", headers); assertNotNull(result); assertEquals(response, result); @@ -116,7 +158,7 @@ void shouldDelegatePaymentWithMinimalRequest() throws ExecutionException, Interr any(DelegatePaymentHeaders.class))) .thenReturn(CompletableFuture.completedFuture(response)); - final DelegatePaymentResponse result = client.delegatePayment(request, headers).get(); + final DelegatePaymentResponse result = client.delegatePayment(request, null, headers).get(); assertNotNull(result); assertEquals(response, result); diff --git a/src/test/java/com/checkout/agenticcommerce/AgenticCommerceTestIT.java b/src/test/java/com/checkout/agenticcommerce/AgenticCommerceTestIT.java index 3b7ce249..762ace7e 100644 --- a/src/test/java/com/checkout/agenticcommerce/AgenticCommerceTestIT.java +++ b/src/test/java/com/checkout/agenticcommerce/AgenticCommerceTestIT.java @@ -41,7 +41,7 @@ void shouldCreateDelegatePaymentToken() { final DelegatePaymentRequest request = buildFullRequest(); final DelegatePaymentResponse response = - blocking(() -> checkoutApi.agenticCommerceClient().delegatePayment(request, buildHeaders())); + blocking(() -> checkoutApi.agenticCommerceClient().delegatePayment(request, null, buildHeaders())); validateResponse(response); } @@ -68,7 +68,7 @@ void shouldCreateDelegatePaymentTokenWithNetworkToken() { .build(); final DelegatePaymentResponse response = - blocking(() -> checkoutApi.agenticCommerceClient().delegatePayment(request, buildHeaders())); + blocking(() -> checkoutApi.agenticCommerceClient().delegatePayment(request, null, buildHeaders())); validateResponse(response); } @@ -79,7 +79,7 @@ void shouldCreateDelegatePaymentTokenSync() { final DelegatePaymentRequest request = buildFullRequest(); final DelegatePaymentResponse response = - checkoutApi.agenticCommerceClient().delegatePaymentSync(request, buildHeaders()); + checkoutApi.agenticCommerceClient().delegatePaymentSync(request, null, buildHeaders()); validateResponse(response); } diff --git a/src/test/java/com/checkout/issuing/IssuingClientImplTest.java b/src/test/java/com/checkout/issuing/IssuingClientImplTest.java index 09312685..6e8a6ace 100644 --- a/src/test/java/com/checkout/issuing/IssuingClientImplTest.java +++ b/src/test/java/com/checkout/issuing/IssuingClientImplTest.java @@ -864,6 +864,7 @@ void shouldSimulateOobAuthentication() throws ExecutionException, InterruptedExc } } + @Nested @DisplayName("Disputes") class Disputes { @Test @@ -916,6 +917,7 @@ void shouldCancelDispute() throws ExecutionException, InterruptedException { validateVoidResponse(response, future.get()); } + @Test void shouldEscalateDispute() throws ExecutionException, InterruptedException { final EscalateDisputeRequest request = createEscalateDisputeRequest(); final VoidResponse response = createVoidResponse(); @@ -1704,6 +1706,7 @@ void shouldSimulateOobAuthenticationSync() { } } + @Nested @DisplayName("Disputes Sync") class DisputesSync { @Test @@ -1756,6 +1759,7 @@ void shouldCancelDisputeSync() { validateVoidResponse(expectedResponse, actualResponse); } + @Test void shouldEscalateDisputeSync() { final EscalateDisputeRequest request = createEscalateDisputeRequest(); final VoidResponse expectedResponse = createVoidResponse(); diff --git a/src/test/java/com/checkout/payments/contexts/PaymentContextsClientImplTest.java b/src/test/java/com/checkout/payments/contexts/PaymentContextsClientImplTest.java index 8bb5e83a..7a3756bf 100644 --- a/src/test/java/com/checkout/payments/contexts/PaymentContextsClientImplTest.java +++ b/src/test/java/com/checkout/payments/contexts/PaymentContextsClientImplTest.java @@ -54,7 +54,7 @@ void shouldRequestPaymentContexts() throws ExecutionException, InterruptedExcept eq(request), isNull())) .thenReturn(CompletableFuture.completedFuture(expectedResponse)); - final CompletableFuture future = client.requestPaymentContexts(request); + final CompletableFuture future = client.requestPaymentContexts(request, null); final PaymentContextsRequestResponse actualResponse = future.get(); validateResponse(expectedResponse, actualResponse); @@ -86,11 +86,40 @@ void shouldRequestPaymentContextsSync() { eq(request), isNull())) .thenReturn(expectedResponse); - final PaymentContextsRequestResponse actualResponse = client.requestPaymentContextsSync(request); + final PaymentContextsRequestResponse actualResponse = client.requestPaymentContextsSync(request, null); validateResponse(expectedResponse, actualResponse); } + @Test + void shouldRequestPaymentContextsWithIdempotencyKey() throws ExecutionException, InterruptedException { + final PaymentContextsRequest request = createMockPaymentContextsRequest(); + final PaymentContextsRequestResponse expectedResponse = mock(PaymentContextsRequestResponse.class); + + when(apiClient.postAsync(eq("payment-contexts"), eq(authorization), eq(PaymentContextsRequestResponse.class), + eq(request), eq("idempotencyKey"))) + .thenReturn(CompletableFuture.completedFuture(expectedResponse)); + + final CompletableFuture future = client.requestPaymentContexts(request, "idempotencyKey"); + final PaymentContextsRequestResponse actualResponse = future.get(); + + validateResponse(expectedResponse, actualResponse); + } + + @Test + void shouldRequestPaymentContextsWithIdempotencyKeySync() { + final PaymentContextsRequest request = createMockPaymentContextsRequest(); + final PaymentContextsRequestResponse expectedResponse = mock(PaymentContextsRequestResponse.class); + + when(apiClient.post(eq("payment-contexts"), eq(authorization), eq(PaymentContextsRequestResponse.class), + eq(request), eq("idempotencyKey"))) + .thenReturn(expectedResponse); + + final PaymentContextsRequestResponse actualResponse = client.requestPaymentContextsSync(request, "idempotencyKey"); + + validateResponse(expectedResponse, actualResponse); + } + @Test void shouldGetAPaymentContextSync() { final PaymentContextDetailsResponse expectedResponse = mock(PaymentContextDetailsResponse.class); diff --git a/src/test/java/com/checkout/payments/contexts/PaymentContextsTestIT.java b/src/test/java/com/checkout/payments/contexts/PaymentContextsTestIT.java index 6bcf5990..37e81fd1 100644 --- a/src/test/java/com/checkout/payments/contexts/PaymentContextsTestIT.java +++ b/src/test/java/com/checkout/payments/contexts/PaymentContextsTestIT.java @@ -21,7 +21,7 @@ class PaymentContextsTestIT extends SandboxTestFixture { @Test void shouldMakeAPaymentContextPayPalRequest() { final PaymentContextsRequest request = TestHelper.createPaymentContextsPayPalRequest(); - final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request)); + final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request, null)); validatePayPalResponse(response); } @@ -29,7 +29,7 @@ void shouldMakeAPaymentContextPayPalRequest() { @Test void shouldMakeAPaymentContextKlarnaRequest() { final PaymentContextsRequest request = TestHelper.createPaymentContextsKlarnaRequest(); - final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request)); + final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request, null)); validateKlarnaResponse(response); } @@ -38,7 +38,7 @@ void shouldMakeAPaymentContextKlarnaRequest() { @Test void shouldMakeAPaymentContextStcpayRequest() { final PaymentContextsRequest request = TestHelper.createPaymentContextsStcpayRequest(); - final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request)); + final PaymentContextsRequestResponse response = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request, null)); validateStcpayResponse(response); } @@ -46,13 +46,13 @@ void shouldMakeAPaymentContextStcpayRequest() { @Test void shouldMakeAPaymentContextTabbyRequest() { final PaymentContextsRequest request = TestHelper.createPaymentContextsTabbyRequest(); - checkErrorItem(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request), APM_SERVICE_UNAVAILABLE); + checkErrorItem(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request, null), APM_SERVICE_UNAVAILABLE); } @Test void shouldGetAPaymentContext() { final PaymentContextsRequest request = TestHelper.createPaymentContextsPayPalRequest(); - final PaymentContextsRequestResponse paymentContextsResponse = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request)); + final PaymentContextsRequestResponse paymentContextsResponse = blocking(() -> checkoutApi.paymentContextsClient().requestPaymentContexts(request, null)); final PaymentContextDetailsResponse response = blocking(() -> checkoutApi.paymentContextsClient().getPaymentContextDetails(paymentContextsResponse.getId())); validatePaymentContextDetails(response); @@ -62,7 +62,7 @@ void shouldGetAPaymentContext() { @Test void shouldMakeAPaymentContextPayPalRequestSync() { final PaymentContextsRequest request = TestHelper.createPaymentContextsPayPalRequest(); - final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request); + final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request, null); validatePayPalResponse(response); } @@ -70,7 +70,7 @@ void shouldMakeAPaymentContextPayPalRequestSync() { @Test void shouldMakeAPaymentContextKlarnaRequestSync() { final PaymentContextsRequest request = TestHelper.createPaymentContextsKlarnaRequest(); - final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request); + final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request, null); validateKlarnaResponse(response); } @@ -79,7 +79,7 @@ void shouldMakeAPaymentContextKlarnaRequestSync() { @Test void shouldMakeAPaymentContextStcpayRequestSync() { final PaymentContextsRequest request = TestHelper.createPaymentContextsStcpayRequest(); - final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request); + final PaymentContextsRequestResponse response = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request, null); validateStcpayResponse(response); } @@ -87,13 +87,13 @@ void shouldMakeAPaymentContextStcpayRequestSync() { @Test void shouldMakeAPaymentContextTabbyRequestSync() { final PaymentContextsRequest request = TestHelper.createPaymentContextsTabbyRequest(); - checkErrorItemSync(() -> checkoutApi.paymentContextsClient().requestPaymentContextsSync(request), APM_SERVICE_UNAVAILABLE); + checkErrorItemSync(() -> checkoutApi.paymentContextsClient().requestPaymentContextsSync(request, null), APM_SERVICE_UNAVAILABLE); } @Test void shouldGetAPaymentContextSync() { final PaymentContextsRequest request = TestHelper.createPaymentContextsPayPalRequest(); - final PaymentContextsRequestResponse paymentContextsResponse = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request); + final PaymentContextsRequestResponse paymentContextsResponse = checkoutApi.paymentContextsClient().requestPaymentContextsSync(request, null); final PaymentContextDetailsResponse response = checkoutApi.paymentContextsClient().getPaymentContextDetailsSync(paymentContextsResponse.getId()); validatePaymentContextDetails(response); From cf3b69bd9c93bcb7a8699fa319ded1c660f07795 Mon Sep 17 00:00:00 2001 From: david ruiz Date: Tue, 2 Jun 2026 11:18:24 +0200 Subject: [PATCH 3/4] Keep the original methods without idempotency --- .../AgenticCommerceClient.java | 4 ++++ .../AgenticCommerceClientImpl.java | 10 ++++++++++ .../com/checkout/issuing/IssuingClient.java | 8 ++++++++ .../checkout/issuing/IssuingClientImpl.java | 20 +++++++++++++++++++ .../contexts/PaymentContextsClient.java | 4 ++++ .../contexts/PaymentContextsClientImpl.java | 10 ++++++++++ 6 files changed, 56 insertions(+) diff --git a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java index c7a88f13..535fb28a 100644 --- a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java +++ b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClient.java @@ -8,7 +8,11 @@ public interface AgenticCommerceClient { + CompletableFuture delegatePayment(DelegatePaymentRequest request, DelegatePaymentHeaders headers); + CompletableFuture delegatePayment(DelegatePaymentRequest request, String idempotencyKey, DelegatePaymentHeaders headers); + DelegatePaymentResponse delegatePaymentSync(DelegatePaymentRequest request, DelegatePaymentHeaders headers); + DelegatePaymentResponse delegatePaymentSync(DelegatePaymentRequest request, String idempotencyKey, DelegatePaymentHeaders headers); } diff --git a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java index b0151716..971c2558 100644 --- a/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java +++ b/src/main/java/com/checkout/agenticcommerce/AgenticCommerceClientImpl.java @@ -20,6 +20,11 @@ public AgenticCommerceClientImpl(final ApiClient apiClient, final CheckoutConfig super(apiClient, configuration, SdkAuthorizationType.SECRET_KEY_OR_OAUTH); } + @Override + public CompletableFuture delegatePayment(final DelegatePaymentRequest request, final DelegatePaymentHeaders headers) { + return delegatePayment(request, null, headers); + } + @Override public CompletableFuture delegatePayment(final DelegatePaymentRequest request, final String idempotencyKey, final DelegatePaymentHeaders headers) { CheckoutUtils.validateParams("request", request, "headers", headers); @@ -32,6 +37,11 @@ public CompletableFuture delegatePayment(final Delegate headers); } + @Override + public DelegatePaymentResponse delegatePaymentSync(final DelegatePaymentRequest request, final DelegatePaymentHeaders headers) { + return delegatePaymentSync(request, null, headers); + } + @Override public DelegatePaymentResponse delegatePaymentSync(final DelegatePaymentRequest request, final String idempotencyKey, final DelegatePaymentHeaders headers) { CheckoutUtils.validateParams("request", request, "headers", headers); diff --git a/src/main/java/com/checkout/issuing/IssuingClient.java b/src/main/java/com/checkout/issuing/IssuingClient.java index 3e46a3a6..25665672 100644 --- a/src/main/java/com/checkout/issuing/IssuingClient.java +++ b/src/main/java/com/checkout/issuing/IssuingClient.java @@ -74,6 +74,8 @@ public interface IssuingClient { CompletableFuture getCardholderCards(String cardholderId); + CompletableFuture createCard(CardRequest cardRequest); + CompletableFuture createCard(CardRequest cardRequest, String idempotencyKey); CompletableFuture getCardDetails(String cardId); @@ -92,6 +94,8 @@ public interface IssuingClient { CompletableFuture suspendCard(final String cardId, final SuspendCardRequest suspendCardRequest); + CompletableFuture createControl(final CardControlRequest cardControlRequest); + CompletableFuture createControl(final CardControlRequest cardControlRequest, final String idempotencyKey); CompletableFuture getCardControls(final CardControlsQuery queryFilter); @@ -200,6 +204,8 @@ CompletableFuture simulateReversal( CardholderCardsResponse getCardholderCardsSync(String cardholderId); + CardResponse createCardSync(CardRequest cardRequest); + CardResponse createCardSync(CardRequest cardRequest, String idempotencyKey); CardDetailsResponse getCardDetailsSync(String cardId); @@ -218,6 +224,8 @@ CompletableFuture simulateReversal( VoidResponse suspendCardSync(String cardId, SuspendCardRequest suspendCardRequest); + CardControlResponse createControlSync(CardControlRequest cardControlRequest); + CardControlResponse createControlSync(CardControlRequest cardControlRequest, String idempotencyKey); CardControlsQueryResponse getCardControlsSync(CardControlsQuery queryFilter); diff --git a/src/main/java/com/checkout/issuing/IssuingClientImpl.java b/src/main/java/com/checkout/issuing/IssuingClientImpl.java index 5767bd2a..7d2c7ebf 100644 --- a/src/main/java/com/checkout/issuing/IssuingClientImpl.java +++ b/src/main/java/com/checkout/issuing/IssuingClientImpl.java @@ -185,6 +185,11 @@ public CompletableFuture getCardholderCards(final Strin ); } + @Override + public CompletableFuture createCard(final CardRequest cardRequest) { + return createCard(cardRequest, null); + } + @Override public CompletableFuture createCard(final CardRequest cardRequest, final String idempotencyKey) { validateParams("cardRequest", cardRequest); @@ -299,6 +304,11 @@ public CompletableFuture suspendCard( ); } + @Override + public CompletableFuture createControl(final CardControlRequest cardControlRequest) { + return createControl(cardControlRequest, null); + } + @Override public CompletableFuture createControl( final CardControlRequest cardControlRequest, @@ -743,6 +753,11 @@ public CardholderCardsResponse getCardholderCardsSync(final String cardholderId) ); } + @Override + public CardResponse createCardSync(final CardRequest cardRequest) { + return createCardSync(cardRequest, null); + } + @Override public CardResponse createCardSync(final CardRequest cardRequest, final String idempotencyKey) { validateCardRequest(cardRequest); @@ -857,6 +872,11 @@ public VoidResponse suspendCardSync( ); } + @Override + public CardControlResponse createControlSync(final CardControlRequest cardControlRequest) { + return createControlSync(cardControlRequest, null); + } + @Override public CardControlResponse createControlSync( final CardControlRequest cardControlRequest, diff --git a/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java b/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java index 29e6392b..24fac51b 100644 --- a/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java +++ b/src/main/java/com/checkout/payments/contexts/PaymentContextsClient.java @@ -4,11 +4,15 @@ public interface PaymentContextsClient { + CompletableFuture requestPaymentContexts(PaymentContextsRequest paymentContextsRequest); + CompletableFuture requestPaymentContexts(PaymentContextsRequest paymentContextsRequest, String idempotencyKey); CompletableFuture getPaymentContextDetails(String paymentContextId); // Synchronous methods + PaymentContextsRequestResponse requestPaymentContextsSync(PaymentContextsRequest paymentContextsRequest); + PaymentContextsRequestResponse requestPaymentContextsSync(PaymentContextsRequest paymentContextsRequest, String idempotencyKey); PaymentContextDetailsResponse getPaymentContextDetailsSync(String paymentContextId); diff --git a/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java b/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java index 1e2fa979..622c7f7b 100644 --- a/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java +++ b/src/main/java/com/checkout/payments/contexts/PaymentContextsClientImpl.java @@ -17,6 +17,11 @@ public PaymentContextsClientImpl(final ApiClient apiClient, final CheckoutConfig super(apiClient, configuration, SdkAuthorizationType.SECRET_KEY_OR_OAUTH); } + @Override + public CompletableFuture requestPaymentContexts(final PaymentContextsRequest paymentContextsRequest) { + return requestPaymentContexts(paymentContextsRequest, null); + } + @Override public CompletableFuture requestPaymentContexts(final PaymentContextsRequest paymentContextsRequest, final String idempotencyKey) { validatePaymentContextsRequest(paymentContextsRequest); @@ -31,6 +36,11 @@ public CompletableFuture getPaymentContextDetails } // Synchronous methods + @Override + public PaymentContextsRequestResponse requestPaymentContextsSync(final PaymentContextsRequest paymentContextsRequest) { + return requestPaymentContextsSync(paymentContextsRequest, null); + } + @Override public PaymentContextsRequestResponse requestPaymentContextsSync(final PaymentContextsRequest paymentContextsRequest, final String idempotencyKey) { validatePaymentContextsRequest(paymentContextsRequest); From 8d271950f484aad601c723085b1634a439ed95a4 Mon Sep 17 00:00:00 2001 From: david ruiz Date: Tue, 2 Jun 2026 11:57:49 +0200 Subject: [PATCH 4/4] Deprecated message for SubmitDisputeRequest --- .../issuing/disputes/requests/SubmitDisputeRequest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/checkout/issuing/disputes/requests/SubmitDisputeRequest.java b/src/main/java/com/checkout/issuing/disputes/requests/SubmitDisputeRequest.java index 596e52b4..b04669a9 100644 --- a/src/main/java/com/checkout/issuing/disputes/requests/SubmitDisputeRequest.java +++ b/src/main/java/com/checkout/issuing/disputes/requests/SubmitDisputeRequest.java @@ -13,7 +13,9 @@ /** * Request to submit an Issuing dispute to the card scheme for processing + * @deprecated POST /issuing/disputes/{disputeId}/submit was removed from the API on 2026-04-15. */ +@Deprecated @Data @Builder @NoArgsConstructor