Skip to content

feat(api): add customer blocklist and manual payment retry - #149

Merged
aagarwal1012 merged 1 commit into
mainfrom
stlc-generated-33521978397
Sep 1, 2026
Merged

aagarwal1012 merged 1 commit into
mainfrom
stlc-generated-33521978397

Conversation

@aagarwal1012

Copy link
Copy Markdown
Member

Spec 1.113.6 -> 1.113.13 (+5 paths, +12 schemas, none removed).

Adds a new blocklist resource exposing blocklist.customers with
list/create/retrieve/delete and a nested notes subresource (create/update),
plus two manual retry methods on payments (retry, retrieve_retry_state).

Generated by stlc run 33521978397 from dodopayments-sdk-config@ae64a0b.

Spec 1.113.6 -> 1.113.13 (+5 paths, +12 schemas, none removed).

Adds a new blocklist resource exposing blocklist.customers with
list/create/retrieve/delete and a nested notes subresource (create/update),
plus two manual retry methods on payments (retry, retrieve_retry_state).

The blocklist list endpoint takes page_number/page_size and returns an items
array, matching default_page_number_pagination, so it auto-detects like the
other page-number lists and needs no explicit paginated flag.

SubscriptionWebhookPayload is reachable through OutgoingWebhookData and the
subscription.* webhooks, so it needs no explicit model mapping.

Validated: 148 configured endpoints all resolve against the spec, 113 config
schema refs resolve, and all 295 distinct spec $refs resolve with none
dangling. The 18 uncovered spec paths are the pre-existing intentional
exclusions (Swagger UI /docs routes, internal connectors and discount-customer
endpoints); no newly added path is uncovered.

Stainless-Generated-From: cb8f543
@aagarwal1012
aagarwal1012 merged commit 585359e into main Sep 1, 2026
7 checks passed
@aagarwal1012
aagarwal1012 deleted the stlc-generated-33521978397 branch September 1, 2026 15:06

@dodo-squirrels dodo-squirrels Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: generated SDK update for spec 1.113.6 → 1.113.13

I verified the generated output against the OpenAPI spec embedded in scripts/mock (decoded and diffed old vs. new). The spec delta is exactly +5 paths / +12 schemas, none removed, and configured_endpoints: 137 → 145 matches the 8 new operations (4 blocklist customer + 2 notes + 2 payment retry).

Verification performed

  • Compiled dodo-payments-java-core (main + test) cleanly on JDK 21.
  • Ran the suite against the Steady mock server: 1,889 tests, 1,860 passing. The 29 failures are all Could not initialize plugin: org.mockito.plugins.MockMaker in ClientOptionsTest, AutoPagerAsyncTest and AsyncStreamResponseTest — I reproduced them on main, so they are a sandbox self-attach limitation, unrelated to this PR. All 426 tests covering files touched by this PR pass.
  • Upstream CI build and lint are both green.

What checks out

  • Paths, HTTP verbs and path-parameter ordering match the spec for every new operation, including the two-segment PATCH /blocklist/customers/{entry_id}/notes/{note_id}.
  • Required vs. optional fields on BlockedCustomer, BlockedCustomerNote, ManualRetry, ManualRetryState and CustomerListPageResponse match the spec exactly, and numeric widths are right (retry_attempt int32 → Int; sends_used/sends_allowed/total int64 → Long).
  • The allOf(BlockIdentifier, {reason, source}) request body flattens correctly into two union variants that each carry reason and source, and the deserializer tries customer_id first, matching the spec's stated "customer_id wins" tie-break.
  • All six list query parameters are serialized with the correct wire names and ISO-8601 date-time formatting; pagination is consistent with every other paginated resource in the SDK.
  • Sync/async method parity holds for all three new services, client wiring and the ProGuard smoke test are updated, and the scripts/mock change is confined to the embedded spec blob (the script logic is byte-identical).

Main concern: an undisclosed breaking change rides along with this PR

The 12th new schema, SubscriptionWebhookPayload (= SubscriptionResponse + past_due_ends_at), is not mentioned in the PR description, but it is responsible for most of the 38.6k-line diff and it breaks source and binary compatibility for webhook consumers.

Across 12 event classes (SubscriptionActiveWebhookEvent, …Cancelled, …Expired, …Failed, …OnHold, …PastDue, …Paused, …PlanChanged, …Renewed, …Unpaused, …UpdatePaymentMethod, …Updated), the data field changes type:

- fun data(): Subscription   // com.dodopayments.api.models.subscriptions.Subscription
+ fun data(): Data           // a new class nested inside each event

Any code doing Subscription s = event.data();, or builder().data(subscription), stops compiling — and pre-compiled callers break at runtime. Two consequences worth deciding on before merge:

  1. Release type. The commit is feat(api):, which release-please turns into a minor bump (1.114.0 → 1.115.0) with no breaking-change note in the changelog. A compile break shipping silently in a minor release is likely to surprise users. Please either add a BREAKING CHANGE: footer / ! so the bump and changelog reflect reality, or call it out prominently in the release notes.

  2. Code duplication. The generator inlined SubscriptionWebhookPayload once per event rather than emitting a shared model. I confirmed the 12 nested Data classes are byte-for-byte identical after normalizing the enclosing class name — 26,460 lines of exact duplication for a single schema, roughly 2,200 lines each. Beyond review burden, this inflates jar size, compile time, and R8/ProGuard output for Android consumers, and it means the 12 payload types are mutually incompatible even though they represent the same thing (you can't write one helper that accepts the payload from any subscription event).

    Adding SubscriptionWebhookPayload to the shared models section of the Stainless config would collapse these into one type. That is still a type change relative to Subscription, but it is a much smaller diff, keeps a single shared payload type, and mirrors how Subscription itself was previously shared. Note WebhookPayload.kt already handles the same spec change additively on its existing nested Subscription class, so only the standalone event classes are affected.

Everything else in the change is additive and backward compatible: new past_due / subscription.past_due enum members, optional Customer.blocked_at / blocklist_entry_id, and optional BalanceLedgerEntry.payout_id.


Minor notes (non-blocking)

  • models/blocklist/customers/BlockIdentifier.kt is generated but referenced nowhere in the SDK — the request body uses the flattened CreateBlockedCustomerRequest variants instead. It is dead public API surface that will need to be supported forever; consider dropping it from the config unless it is intentionally exported.
  • UnwrapWebhookEvent.Visitor gains visitSubscriptionPastDue with no default implementation, so anyone implementing that interface directly must update. This is the established pattern in this SDK for new union variants, just worth a changelog mention alongside the data change.

I'd suggest REQUEST_CHANGES only on the release-metadata point — the generated code itself is correct and faithful to the spec. Happy to approve once the breaking change is either reflected in the version bump/changelog or the shared-model config change is made.

*
* @throws DodoPaymentsInvalidDataException if the JSON field has an unexpected type or is
* unexpectedly missing or null (e.g. if the server responded with an unexpected value).
*/
fun data(): Subscription = data.getRequired("data")
fun data(): Data = data.getRequired("data")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data changes from the shared com.dodopayments.api.models.subscriptions.Subscription to this per-event nested Data class. This is source- and binary-incompatible for anyone calling event.data() or builder().data(subscription), and it repeats identically across 12 subscription event classes.

The underlying spec change is legitimate (SubscriptionWebhookPayload = SubscriptionResponse + past_due_ends_at), but promoting it to a shared model in the Stainless config would keep a single payload type across all 12 events instead of 12 mutually incompatible copies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant