Add UnsetFields for clearing field values in v1 and v2 API requests#2322
Merged
jar-stripe merged 12 commits intomasterfrom Mar 24, 2026
Merged
Add UnsetFields for clearing field values in v1 and v2 API requests#2322jar-stripe merged 12 commits intomasterfrom
jar-stripe merged 12 commits intomasterfrom
Conversation
For v2 APIs (JSON-encoded POST), null has semantic meaning — it clears
a field. Previously, nil pointer fields with omitempty were always
omitted from JSON, making it impossible to send explicit null.
Adds NullFields []string to the Params struct and a marshalV2JSON
helper that patches explicit null entries into the marshaled JSON for
any field names listed in NullFields. This is fully additive — existing
code is unaffected, and v1 requests ignore NullFields entirely.
Usage:
params := &stripe.V2SomeUpdateParams{Name: stripe.String("new")}
params.AddNullField("description")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
EmptyFields works across both v1 and v2 APIs: - v2 JSON: sends "field": null to clear a field - v1 form: sends field= (empty string) to clear a field Renamed from NullFields since the semantic is "empty/clear this field" regardless of API version, and the wire encoding differs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Add collectAllEmptyFields() which walks params structs via reflection
to find EmptyFields entries at all nesting levels. Update marshalV2JSON
and v1 form encoding to use recursive collection, so nested params
structs can declare emptyable fields independently.
For v2 JSON: nested nulls are injected at the correct depth
(e.g. {"details": {"comment": null}}).
For v1 form: nested empty fields use bracket notation
(e.g. details[comment]=).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
Rename the field clearing mechanism from EmptyFields/AddEmptyField to UnsetFields/AddUnsetField for clarity. Regenerate all codegen output with the updated naming: per-struct UnsetField enum types, AddUnsetField methods, and UnsetFields []string on nested params. Skip EmptyableField generation for list/search params structs since they embed ListParams (not Params) and clearing fields on GET requests is not meaningful. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
There was a problem hiding this comment.
Pull request overview
This PR adds an UnsetFields mechanism to Stripe Go params to let callers explicitly clear fields in API requests (v1 form: field=, v2 JSON: "field": null), including support for nested params structs, and updates generated params types plus tests accordingly.
Changes:
- Added
Params.UnsetFields []stringandParams.AddUnsetField(string)for explicit field clearing. - Updated request encoding in
stripe.goto emit empty form fields for v1 and inject JSON nulls for v2, collecting nestedUnsetFieldsvia reflection. - Regenerated many params structs to include type-safe
UnsetFieldenums +AddUnsetFieldhelpers; added tests for root and nested behavior.
Reviewed changes
Copilot reviewed 62 out of 63 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| webhookendpoint.go | Adds type-safe unset-field enums + AddUnsetField helpers for webhook endpoint params. |
| treasury_outboundtransfer.go | Adds UnsetFields support to nested destination payment method options params. |
| treasury_outboundpayment.go | Adds UnsetFields support to billing details/options nested params. |
| treasury_financialaccount.go | Adds type-safe unset-field enums + AddUnsetField helpers for financial account params. |
| transferreversal.go | Adds type-safe unset-field enums + AddUnsetField helpers for transfer reversal params. |
| transfer.go | Adds type-safe unset-field enums + AddUnsetField helpers for transfer params. |
| topup.go | Adds type-safe unset-field enums + AddUnsetField helpers for topup params. |
| testhelpers_confirmationtoken.go | Adds UnsetFields + enums/helpers to testhelpers confirmation token nested params. |
| terminal_reader.go | Adds type-safe unset-field enums + AddUnsetField helpers for terminal reader params. |
| terminal_location.go | Adds type-safe unset-field enums + AddUnsetField helpers for terminal location params. |
| terminal_configuration.go | Adds UnsetFields across multiple nested terminal configuration structs + enums/helpers. |
| taxrate.go | Adds type-safe unset-field enums + AddUnsetField helpers for tax rate params. |
| tax_registration.go | Adds type-safe unset-field enums + AddUnsetField helpers for tax registration params. |
| subscriptionschedule.go | Adds UnsetFields support across many nested subscription schedule structs + enums/helpers. |
| subscriptionitem.go | Adds UnsetFields support across subscription item params + enums/helpers. |
| stripe_test.go | Adds tests covering v1/v2 root and nested UnsetFields behavior. |
| stripe.go | Implements recursive collection of UnsetFields + v1/v2 encoding behavior (marshalV2JSON). |
| source.go | Adds UnsetFields support and enums/helpers for source and mandate params. |
| shippingrate.go | Adds type-safe unset-field enums + AddUnsetField helpers for shipping rate params. |
| refund.go | Adds type-safe unset-field enums + AddUnsetField helpers for refund params. |
| quote.go | Adds UnsetFields support across quote + line item/subscription nested params + enums/helpers. |
| promotioncode.go | Adds type-safe unset-field enums + AddUnsetField helpers for promotion code params. |
| product.go | Adds type-safe unset-field enums + AddUnsetField helpers for product params. |
| price.go | Adds type-safe unset-field enums + AddUnsetField helpers for price params. |
| plan.go | Adds type-safe unset-field enums + AddUnsetField helpers for plan params. |
| person.go | Adds UnsetFields support across person nested params + enums/helpers. |
| payout.go | Adds type-safe unset-field enums + AddUnsetField helpers for payout params. |
| paymentsource.go | Adds type-safe unset-field enums + AddUnsetField helpers for payment source params. |
| paymentrecord.go | Adds type-safe unset-field enums + AddUnsetField helpers for payment record report params. |
| paymentmethod.go | Adds UnsetFields support across payment method billing details/network nested params + enums/helpers. |
| paymentlink.go | Adds UnsetFields support across payment link nested params + enums/helpers. |
| params.go | Adds Params.UnsetFields and Params.AddUnsetField. |
| issuing_transaction.go | Adds type-safe unset-field enums + AddUnsetField helpers for issuing transaction params. |
| issuing_personalizationdesign.go | Adds UnsetFields support across issuing personalization design nested params + enums/helpers. |
| issuing_cardholder.go | Adds UnsetFields support for issuing cardholder terms acceptance nested params + enums/helpers. |
| issuing_card.go | Adds type-safe unset-field enums + AddUnsetField helpers for issuing card params. |
| issuing_authorization.go | Adds type-safe unset-field enums + AddUnsetField helpers for issuing authorization params. |
| invoicelineitem.go | Adds UnsetFields support for invoice line item params + enums/helpers. |
| invoiceitem.go | Adds UnsetFields support for invoice item params + enums/helpers. |
| identity_verificationsession.go | Adds UnsetFields support for identity verification session options nested params + enums/helpers. |
| filelink.go | Adds type-safe unset-field enums + AddUnsetField helpers for file link params. |
| file.go | Adds UnsetFields support for file link data nested params + enums/helpers. |
| feerefund.go | Adds type-safe unset-field enums + AddUnsetField helpers for fee refund params. |
| entitlements_feature.go | Adds type-safe unset-field enums + AddUnsetField helpers for entitlements feature params. |
| dispute.go | Adds UnsetFields support across dispute evidence nested params + enums/helpers. |
| customerbalancetransaction.go | Adds type-safe unset-field enums + AddUnsetField helpers for customer balance transaction params. |
| customer.go | Adds UnsetFields support across customer nested params + enums/helpers. |
| creditnote.go | Adds UnsetFields support for credit note line params + enums/helpers. |
| coupon.go | Adds type-safe unset-field enums + AddUnsetField helpers for coupon params. |
| climate_order.go | Adds UnsetFields support for climate order beneficiary nested params + enums/helpers. |
| charge.go | Adds UnsetFields support for charge fraud details nested params + enums/helpers. |
| card.go | Adds type-safe unset-field enums + AddUnsetField helpers for card params. |
| billingportal_configuration.go | Adds UnsetFields support across billing portal configuration nested params + enums/helpers. |
| billing_creditgrant.go | Adds type-safe unset-field enums + AddUnsetField helpers for billing credit grant params. |
| bankaccount.go | Adds type-safe unset-field enums + AddUnsetField helpers for bank account params. |
| balancesettings.go | Adds UnsetFields support in balance settings nested params; also changes map value type for MinimumBalanceByCurrency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address review feedback: - Nested params structs now use typed UnsetFields slices (e.g. []AccountBusinessProfileParamsUnsetField) instead of []string, so callers don't need to cast. Root structs still use []string via the embedded Params struct. - Add BenchmarkCollectAllUnsetFields (~880ns/op, 3 allocs on M3 Pro). - Fix misleading test name: UnsetFields overrides set values, not "does not override." Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Add a deeply_nested sub-benchmark that populates PaymentMethodOptions, PaymentMethodData, and Shipping with multiple levels of nesting to stress-test the recursive reflection walk. Results on M3 Pro: minimal: ~900ns/op, 64 B/op, 3 allocs deeply_nested: ~4.5µs/op, 224 B/op, 13 allocs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
mbroshi-stripe
approved these changes
Mar 24, 2026
Contributor
mbroshi-stripe
left a comment
There was a problem hiding this comment.
Looks great! Thanks for taking this on! Please link to #1556 also, which I believe this resolves.
Remove UnsetFields []string and AddUnsetField from the base Params struct. Every params struct (root and nested) now has its own typed UnsetFields field and AddUnsetField method, generated by codegen. This eliminates the untyped []string on Params and makes the API consistent across root and nested structs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Extend collectAllUnsetFields to recurse into slice/array elements, using numeric indices as path segments. Update setNestedNull to handle array indices when patching nulls into v2 JSON output. For v1 form, form.FormatKey already handles numeric path segments with bracket notation (e.g. line_items[1][tax_rates]=). Add tests for slice element UnsetFields: - Unit test (marshalV2JSON with slice element unset) - v1 form integration test (bracket notation encoding) - v2 JSON integration test (null in array element) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why?
Go's pointer types with
omitemptycannot distinguish "user never set this field" (nil pointer) from "user explicitly wants to clear this field." This affects both API versions:field=(empty string), but the form encoder skips nil pointers"field": null, butjson.Marshalomits nil pointers entirelyThis was identified as part of DEVSDK-2926 (cross-SDK emptyable field audit). Go was one of three languages needing runtime changes.
What?
In params.go + stripe.go:
UnsetFields []stringfield toParams— a list of API field names that should be explicitly cleared in requestsAddUnsetField(field string)convenience method onParamsCall()addsfield=entries for all listed fieldsmarshalV2JSON()marshals params normally, then patches in null entries for any fields listed inUnsetFieldsIn stripe.go:
collectAllUnsetFields()which recursively walks params structs via reflection to findUnsetFieldsentries at all nesting levelscancellation_details[comment]=){"cancellation_details": {"comment": null}})UnsetFields []stringfield (generated by codegen)Tests: 11 tests covering root and nested UnsetFields for both v1 form and v2 JSON encoding, including deep nesting.
See Also
Changelog
UnsetFieldsfield andAddUnsetFieldmethod toParamsfor explicitly clearing field values in API requests. For v2 JSON requests, listed fields are sent as"field": null. For v1 form requests, listed fields are sent asfield=(empty string).UnsetFieldsslice, enabling clearing of nested fields (e.g.params.CancellationDetails.AddUnsetField(...)).UnsetFieldstring enum types provide type-safe constants for each clearable field (e.g.SubscriptionUpdateParamsUnsetFieldDescription).