Repository navigation
fix(payments): align retry and customer retry types with the spec - #701
Conversation
🟢 Risk Classification: LOWApproval route: AI Auto-Approval Classification reasons
Operational gates
Files analysed: 17 wall-e 2026.06.19-02 · policy |
🔬 Debug — why this classification?Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.
Kinds:
See issue #3 for the proposal to formalise this map as Appendix A of the standards doc. wall-e 2026.06.19-02 · debug |
🟡 Risk Classification: MINORApproval route: AI Review + Human Approval Classification reasons
Operational gates
Files analysed: 19 wall-e 2026.06.19-02 · policy |
🔬 Debug — why this classification?Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.
Kinds:
See issue #3 for the proposal to formalise this map as Appendix A of the standards doc. wall-e 2026.06.19-02 · debug |
🟠 Advisory review: Concerns worth a lookThis PR needs a human approval. Before you give it, these are the things I'd want resolved. The PR aligns retry/customer-retry SDK types with the API spec, adding CustomerRetry to hosted payments and payment links, fixing PaymentRetryResponse, and removing the spurious default of 6 on Retry.maxAttempts. The changes are largely correct and well-tested, but there is one concrete bug in the deprecated compatibility path and one subtle correctness issue with the CustomerRetry default. Concerns
This is not an approval. wall-e cannot auto-approve this PR — it is an opinion to help whoever does. Advisory review · us.anthropic.claude-sonnet-4-6 · wall-e 2026.06.19-02 |
🟡 Risk Classification: MINORApproval route: AI Review + Human Approval Classification reasons
Operational gates
Files analysed: 19 wall-e 2026.06.19-02 · policy |
🔬 Debug — why this classification?Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.
Kinds:
See issue #3 for the proposal to formalise this map as Appendix A of the standards doc. wall-e 2026.06.19-02 · debug |
customer_retry on POST /hosted-payments and POST /payment-links only accepts max_attempts (0 to 5), so it now uses CustomerRetry instead of PaymentRetryRequest. PaymentRetryRequest.enabled is no longer deprecated: it is the required switch for asynchronous retries on POST /payments. The payment retry response gains attemptsMade, and the request payment retry response no longer reports a max_attempts the API did not return.
Code scanning flags calls to deprecated members from non-deprecated code. The private converter only serves the deprecated PaymentRetryRequest overloads, and the tests exercise those overloads on purpose, so both are marked deprecated instead of suppressing the warning.
2c216b3 to
48b757f
Compare
🟡 Risk Classification: MINORApproval route: AI Review + Human Approval Classification reasons
Operational gates
Files analysed: 19 wall-e 2026.06.19-02 · policy |
🔬 Debug — why this classification?Each reason code emitted by the classifier, its source clause in the AI in SDLC Control Framework, and what it means.
Kinds:
See issue #3 for the proposal to formalise this map as Appendix A of the standards doc. wall-e 2026.06.19-02 · debug |
|
…suing This release adds the Payment Setup payment type, the risk settings on the Payment Setup confirm response and the Tamara risk assessment fields. It also adds the subscription details and the retry attempt count to payment responses, and lets you revoke and suspend Issuing cards without a request body. Customer retries on hosted payments and payment links now use the type the API accepts, and the update card headers the API no longer documents are deprecated. Every deprecated member keeps working and will be removed in the next major version. **Added** Issuing (#697) * `IssuingClient#revokeCard(String cardId)`, `#suspendCard(String cardId)`, `#revokeCardSync(String cardId)` and `#suspendCardSync(String cardId)`. The existing overloads that take a `RevokeCardRequest` or `SuspendCardRequest` now accept `null`, because the request body is optional in the API. Payment Setups (#700) * `PaymentSetupPaymentType` with the values of the Payment Setups API: `REGULAR` (`regular`), `RECURRING` (`recurring`), `MOTO` (`moto`), `INSTALLMENT` (`installment`), `PAY_LATER` (`pay_later`), `UNSCHEDULED` (`unscheduled`). * `PaymentSetupsConfirmResponse#risk` (`PaymentSetupRisk`). * `Tamara#initialization` (`PaymentMethodInitialization`, default `DISABLED`) and `Tamara#riskAssessment`, with the new `TamaraRiskAssessment` (`premiumCustomer`, `riskScore`, `orderCountLast24h`, `linkedDeviceCount`). Payments (#701) * `PaymentResponse#subscription` (`PaymentSubscription`). * `PaymentRetryResponse#attemptsMade`, returned by get payment details. **Changed** * `PaymentRetryRequest#enabled` is no longer deprecated. It is the required switch for asynchronous retries on payment requests (#701). * Request and response fields of payments, payment retries, hosted payments, payment links, payment sessions and Payment Setups now document whether they are required or optional, with the limits, defaults and enum values of the API reference (#700, #701). * Payment Setup payment methods document that an update replaces the payment methods, so `initialization` must be sent as `ENABLED` again to keep a method enabled (#700). **Fixed** * The `Retry` response of a payment request no longer reports `maxAttempts` as 6 when the API did not return it (#701). **Deprecated** All deprecated members keep working and will be removed in the next major version. * `CardUpdateHeaders` and the `IssuingClient#updateCard` and `#updateCardSync` overloads that take it: the API no longer documents the `return-encrypted-cvv` and `Encryption-Key` headers. Headers that are set are still sent. Use `updateCard(String, UpdateCardRequest)` or `updateCardSync(String, UpdateCardRequest)` (#697). * `HostedPaymentRequest#setCustomerRetry(PaymentRetryRequest)` and `HostedPaymentRequestBuilder#customerRetry(PaymentRetryRequest)`: customer retries only accept `max_attempts`, so only that value is kept. Use the `CustomerRetry` overloads (#701). * `PaymentLinkRequest#setCustomerRetry(PaymentRetryRequest)` and `PaymentLinkRequestBuilder#customerRetry(PaymentRetryRequest)`: same reason. Use the `CustomerRetry` overloads (#701). **Breaking changes required by the API**⚠️ * `PaymentSetupsRequest#paymentType`, `PaymentSetupsResponse#paymentType` and `PaymentSetupsConfirmResponse#paymentType` change from `com.checkout.payments.PaymentType` to `PaymentSetupPaymentType`. The Payment Setups API only accepts the lowercase values; the old type sent `PayLater`, which the API rejects with a 422, and read every value except `regular` as null. Migration: replace `PaymentType.X` with `PaymentSetupPaymentType.X` (#700). * `MerchantAccount#lastPaymentAmount` (Payment Setups customer) changes from `Long` to `Double`, because the API defines it as a number (for example `55.99`). Migration: pass a `Double` (for example `500d`) and read the getter as `Double` (#700). * `HostedPaymentRequest#customerRetry` and `PaymentLinkRequest#customerRetry` change from `PaymentRetryRequest` to `CustomerRetry`, because customer retries only accept `max_attempts` (0 to 5). Code that sets the field keeps compiling through the deprecated overloads; code that reads `getCustomerRetry()` now gets a `CustomerRetry`. Migration: `CustomerRetry.builder().maxAttempts(n).build()` (#701). **Dependencies** * gson 2.14.0, slf4j-api 2.0.18 and commons-codec 1.22.1, all still compatible with Java 8 (#702).
This release adds the Payment Setup payment type, the risk settings on the Payment Setup confirm response and the Tamara risk assessment fields. It also adds the subscription details and the retry attempt count to payment responses, and lets you revoke and suspend Issuing cards without a request body. Customer retries on hosted payments and payment links now use the type the API accepts, and the update card headers the API no longer documents are deprecated. Every deprecated member keeps working and will be removed in the next major version. **Added** Issuing (#697) * `IssuingClient#revokeCard(String cardId)`, `#suspendCard(String cardId)`, `#revokeCardSync(String cardId)` and `#suspendCardSync(String cardId)`. The existing overloads that take a `RevokeCardRequest` or `SuspendCardRequest` now accept `null`, because the request body is optional in the API. Payment Setups (#700) * `PaymentSetupPaymentType` with the values of the Payment Setups API: `REGULAR` (`regular`), `RECURRING` (`recurring`), `MOTO` (`moto`), `INSTALLMENT` (`installment`), `PAY_LATER` (`pay_later`), `UNSCHEDULED` (`unscheduled`). * `PaymentSetupsConfirmResponse#risk` (`PaymentSetupRisk`). * `Tamara#initialization` (`PaymentMethodInitialization`, default `DISABLED`) and `Tamara#riskAssessment`, with the new `TamaraRiskAssessment` (`premiumCustomer`, `riskScore`, `orderCountLast24h`, `linkedDeviceCount`). Payments (#701) * `PaymentResponse#subscription` (`PaymentSubscription`). * `PaymentRetryResponse#attemptsMade`, returned by get payment details. **Changed** * `PaymentRetryRequest#enabled` is no longer deprecated. It is the required switch for asynchronous retries on payment requests (#701). * Request and response fields of payments, payment retries, hosted payments, payment links, payment sessions and Payment Setups now document whether they are required or optional, with the limits, defaults and enum values of the API reference (#700, #701). * Payment Setup payment methods document that an update replaces the payment methods, so `initialization` must be sent as `ENABLED` again to keep a method enabled (#700). **Fixed** * The `Retry` response of a payment request no longer reports `maxAttempts` as 6 when the API did not return it (#701). **Deprecated** All deprecated members keep working and will be removed in the next major version. * `CardUpdateHeaders` and the `IssuingClient#updateCard` and `#updateCardSync` overloads that take it: the API no longer documents the `return-encrypted-cvv` and `Encryption-Key` headers. Headers that are set are still sent. Use `updateCard(String, UpdateCardRequest)` or `updateCardSync(String, UpdateCardRequest)` (#697). * `HostedPaymentRequest#setCustomerRetry(PaymentRetryRequest)` and `HostedPaymentRequestBuilder#customerRetry(PaymentRetryRequest)`: customer retries only accept `max_attempts`, so only that value is kept. Use the `CustomerRetry` overloads (#701). * `PaymentLinkRequest#setCustomerRetry(PaymentRetryRequest)` and `PaymentLinkRequestBuilder#customerRetry(PaymentRetryRequest)`: same reason. Use the `CustomerRetry` overloads (#701). **Breaking changes required by the API**⚠️ * `PaymentSetupsRequest#paymentType`, `PaymentSetupsResponse#paymentType` and `PaymentSetupsConfirmResponse#paymentType` change from `com.checkout.payments.PaymentType` to `PaymentSetupPaymentType`. The Payment Setups API only accepts the lowercase values; the old type sent `PayLater`, which the API rejects with a 422, and read every value except `regular` as null. Migration: replace `PaymentType.X` with `PaymentSetupPaymentType.X` (#700). * `MerchantAccount#lastPaymentAmount` (Payment Setups customer) changes from `Long` to `Double`, because the API defines it as a number (for example `55.99`). Migration: pass a `Double` (for example `500d`) and read the getter as `Double` (#700). * `HostedPaymentRequest#customerRetry` and `PaymentLinkRequest#customerRetry` change from `PaymentRetryRequest` to `CustomerRetry`, because customer retries only accept `max_attempts` (0 to 5). Code that sets the field keeps compiling through the deprecated overloads; code that reads `getCustomerRetry()` now gets a `CustomerRetry`. Migration: `CustomerRetry.builder().maxAttempts(n).build()` (#701). **Dependencies** * gson 2.14.0, slf4j-api 2.0.18 and commons-codec 1.22.1, all still compatible with Java 8 (#702).
This release adds the Payment Setup payment type, the risk settings on the Payment Setup confirm response and the Tamara risk assessment fields. It also adds the subscription details and the retry attempt count to payment responses, and lets you revoke and suspend Issuing cards without a request body. Customer retries on hosted payments and payment links now use the type the API accepts, and the update card headers the API no longer documents are deprecated. Every deprecated member keeps working and will be removed in the next major version. **Added** Issuing (#697) * `IssuingClient#revokeCard(String cardId)`, `#suspendCard(String cardId)`, `#revokeCardSync(String cardId)` and `#suspendCardSync(String cardId)`. The existing overloads that take a `RevokeCardRequest` or `SuspendCardRequest` now accept `null`, because the request body is optional in the API. Payment Setups (#700) * `PaymentSetupPaymentType` with the values of the Payment Setups API: `REGULAR` (`regular`), `RECURRING` (`recurring`), `MOTO` (`moto`), `INSTALLMENT` (`installment`), `PAY_LATER` (`pay_later`), `UNSCHEDULED` (`unscheduled`). * `PaymentSetupsConfirmResponse#risk` (`PaymentSetupRisk`). * `Tamara#initialization` (`PaymentMethodInitialization`, default `DISABLED`) and `Tamara#riskAssessment`, with the new `TamaraRiskAssessment` (`premiumCustomer`, `riskScore`, `orderCountLast24h`, `linkedDeviceCount`). Payments (#701) * `PaymentResponse#subscription` (`PaymentSubscription`). * `PaymentRetryResponse#attemptsMade`, returned by get payment details. **Changed** * `PaymentRetryRequest#enabled` is no longer deprecated. It is the required switch for asynchronous retries on payment requests (#701). * Request and response fields of payments, payment retries, hosted payments, payment links, payment sessions and Payment Setups now document whether they are required or optional, with the limits, defaults and enum values of the API reference (#700, #701). * Payment Setup payment methods document that an update replaces the payment methods, so `initialization` must be sent as `ENABLED` again to keep a method enabled (#700). **Fixed** * The `Retry` response of a payment request no longer reports `maxAttempts` as 6 when the API did not return it (#701). **Deprecated** All deprecated members keep working and will be removed in the next major version. * `CardUpdateHeaders` and the `IssuingClient#updateCard` and `#updateCardSync` overloads that take it: the API no longer documents the `return-encrypted-cvv` and `Encryption-Key` headers. Headers that are set are still sent. Use `updateCard(String, UpdateCardRequest)` or `updateCardSync(String, UpdateCardRequest)` (#697). * `HostedPaymentRequest#setCustomerRetry(PaymentRetryRequest)` and `HostedPaymentRequestBuilder#customerRetry(PaymentRetryRequest)`: customer retries only accept `max_attempts`, so only that value is kept. Use the `CustomerRetry` overloads (#701). * `PaymentLinkRequest#setCustomerRetry(PaymentRetryRequest)` and `PaymentLinkRequestBuilder#customerRetry(PaymentRetryRequest)`: same reason. Use the `CustomerRetry` overloads (#701). **Breaking changes required by the API**⚠️ * `PaymentSetupsRequest#paymentType`, `PaymentSetupsResponse#paymentType` and `PaymentSetupsConfirmResponse#paymentType` change from `com.checkout.payments.PaymentType` to `PaymentSetupPaymentType`. The Payment Setups API only accepts the lowercase values; the old type sent `PayLater`, which the API rejects with a 422, and read every value except `regular` as null. Migration: replace `PaymentType.X` with `PaymentSetupPaymentType.X` (#700). * `MerchantAccount#lastPaymentAmount` (Payment Setups customer) changes from `Long` to `Double`, because the API defines it as a number (for example `55.99`). Migration: pass a `Double` (for example `500d`) and read the getter as `Double` (#700). * `HostedPaymentRequest#customerRetry` and `PaymentLinkRequest#customerRetry` change from `PaymentRetryRequest` to `CustomerRetry`, because customer retries only accept `max_attempts` (0 to 5). Code that sets the field keeps compiling through the deprecated overloads; code that reads `getCustomerRetry()` now gets a `CustomerRetry`. Migration: `CustomerRetry.builder().maxAttempts(n).build()` (#701). **Dependencies** * gson 2.14.0, slf4j-api 2.0.18 and commons-codec 1.22.1, all still compatible with Java 8 (#702).



Summary
Aligns the payment retry types with the API.
customerRetryon hosted payments and payment links only acceptsmax_attempts(0 to 5) but usedPaymentRetryRequest, theretryobject ofPOST /payments. It now usesCustomerRetry, and the old builder and setter calls still compile through deprecated overloads.PaymentRetryRequest.enabledwas deprecated although it is the required switch for asynchronous retries. The retry responses were missingattempts_made, and one of them reported amax_attemptsthe API did not return.Changes
payments/hosted/HostedPaymentRequest.java,payments/links/PaymentLinkRequest.java:customerRetrynow usesCustomerRetry. The builder keepscustomerRetry(PaymentRetryRequest)and the class keepssetCustomerRetry(PaymentRetryRequest), both@Deprecated; they convertmaxAttemptstoCustomerRetry(a request withoutmaxAttemptssends the default of 5, null clears it).handlepaymentsandpayouts/flow/entities/CustomerRetry.java,flow/requests/PaymentSessionCreateRequest.java: docs aligned with the spec.payments/request/PaymentRetryRequest.java:enabledis no longer deprecated.maxAttemptsandendAfterDaysstay deprecated and now point toCustomerRetry.maxAttempts(customer_retry) orDunningRetryRequestviadunning(retry).payments/request/DunningRetryRequest.java,DowntimeRetryRequest.java,PaymentRequest.java: docs, required markers and ranges from the spec.payments/response/PaymentRetryResponse.java:attemptsMadeadded, every field documented.payments/response/PaymentResponse.java: every property documented,subscription(PaymentSubscription) added.payments/response/GetPaymentResponse.java: every property documented.postpayments/.../retry/Retry.java:maxAttemptsno longer defaults to 6 when the API leaves it out.CustomerRetrySerializationTest,PaymentRetryResponseSerializationTest(alsoPaymentResponse.subscription) andRetrySerializationTest;PaymentRetryRequestSerializationTestrewritten with exact JSON assertions;HostedPaymentRequestSerializationTestandPaymentLinkRequestSerializationTestcheck that both builder overloads and both setters send the samecustomer_retry.API Reference
POST /payments(retry, responsesubscription): https://api-reference.checkout.com/tag/payments/POST/payments.body.retryGET /payments/{id}(retry): https://api-reference.checkout.com/tag/payments/GET/payments/%7Bid%7DPOST /hosted-payments(customer_retry): https://api-reference.checkout.com/tag/hosted-payments-page/POST/hosted-payments.body.customer_retryPOST /payment-links(customer_retry): https://api-reference.checkout.com/tag/payment-links/POST/payment-links.body.customer_retryPOST /payment-sessions(customer_retry): https://api-reference.checkout.com/tag/flow/POST/payment-sessions.body.customer_retryBreaking changes
Forced by the API, released as a minor.
HostedPaymentRequest.getCustomerRetry()andPaymentLinkRequest.getCustomerRetry()now returnCustomerRetryinstead ofPaymentRetryRequest: a source break for code that reads it into aPaymentRetryRequest, and a binary break (recompile).customerRetry(PaymentRetryRequest)andsetCustomerRetry(PaymentRetryRequest)still work, deprecated. Migration:CustomerRetry.builder().maxAttempts(n).build(), readgetCustomerRetry().getMaxAttempts().Retry.getMaxAttempts()on the request a payment response returns null when the API omits the field, instead of 6;Retry.builder().build()also gives null. Migration: treat null as "not returned".README
Not affected: the README does not document these types.