Skip to content

Add decimal_string coercion for v1 and v2 API fields#1769

Merged
jar-stripe merged 7 commits intomasterfrom
jar/decimal-tier2-python
Mar 25, 2026
Merged

Add decimal_string coercion for v1 and v2 API fields#1769
jar-stripe merged 7 commits intomasterfrom
jar/decimal-tier2-python

Conversation

@jar-stripe
Copy link
Contributor

@jar-stripe jar-stripe commented Mar 20, 2026

Why?

The Stripe API uses decimal_string fields — high-precision decimal values that travel as JSON strings on the wire (e.g. "9.99") to avoid floating-point loss. This PR adds bidirectional coercion so these fields are transparent to SDK users: pass a Decimal in, get a Decimal back.

Coercion fires for both v1 and v2 resources. The codegen-emitted _field_encodings metadata drives which fields get coerced; resources without decimal fields are unaffected. This matches other SDK behavior (Java, Go, .NET).

What?

Runtime (hand-written):

  • stripe/_encode.py: Adds _coerce_decimal_string(value, *, encode) helper and handles "decimal_string" in _coerce_value (request path via _coerce_v2_params).
  • stripe/_stripe_object.py: Imports _coerce_decimal_string; adds "decimal_string" case to _coerce_field_value (response path via _field_encodings).
  • tests/test_decimal_string.py: 34 tests covering encode/decode, precision round-trips, nested objects, arrays, _coerce_v2_params integration, response coercion via _field_encodings, and v1 non-regression.

Generated:

  • All resources with decimal_string fields (v1 and v2) now emit _field_encodings = {"field_name": "decimal_string", ...}.
  • primitiveDecimalType changed from str to Decimal (stdlib decimal.Decimal), so response types and TypedDicts use Decimal | str instead of str.

See Also

Changelog

  • ⚠️ Breaking change: All decimal_string fields changed type from str to decimal.Decimal in both request params and response objects. Code that reads or writes these fields as str will need to use Decimal instead. Affected fields across v1 and v2 APIs:
    • checkout.Session: fx_rate
    • climate.Order: metric_tons; climate.Product: metric_tons_available
    • CreditNoteLineItem: unit_amount_decimal
    • InvoiceItem: quantity_decimal, unit_amount_decimal
    • InvoiceLineItem: quantity_decimal, unit_amount_decimal
    • issuing.Authorization / issuing.Transaction (and TestHelpers): quantity_decimal, unit_cost_decimal, gross_amount_decimal, local_amount_decimal, national_amount_decimal
    • Plan: amount_decimal, flat_amount_decimal, unit_amount_decimal
    • Price: unit_amount_decimal, flat_amount_decimal (including currency_options and tiers)
    • v2.core.Account / v2.core.AccountPerson: percent_ownership
    • Request params on Invoice, Product, Quote, Subscription, SubscriptionItem, SubscriptionSchedule, PaymentLink: unit_amount_decimal, flat_amount_decimal, quantity_decimal (where applicable)

Adds bidirectional coercion for decimal_string fields, following the
same pattern as int64_string:
- Encode: Decimal/int/float → str on request serialization
- Decode: str → decimal.Decimal on response hydration

_coerce_decimal_string added to _encode.py; decimal_string case added
to _coerce_value (request path) and _coerce_field_value (response path).
Precision is fully preserved through round-trips.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
@jar-stripe jar-stripe requested a review from a team as a code owner March 20, 2026 23:08
@jar-stripe jar-stripe requested review from prathmesh-stripe and removed request for a team March 20, 2026 23:08
…d v2 resources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
@jar-stripe jar-stripe changed the title Add decimal_string coercion for V2 API fields Add decimal_string coercion for v1 and v2 API fields Mar 21, 2026
The json.dumps() default callback only handled datetime, causing
"Circular reference detected" when sending Decimal values in V2
request params. Add Decimal → str conversion, matching the wire
format (decimal fields serialize as JSON strings).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
Copy link
Member

@xavdid-stripe xavdid-stripe left a comment

Choose a reason for hiding this comment

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

Similar to the thing Michal fixed for int64, the generated examples need updated types

jar-stripe and others added 4 commits March 24, 2026 15:36
Addresses PR feedback: list handling now recurses into the same
function per-element instead of duplicating isinstance checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Committed-By-Agent: claude
@jar-stripe jar-stripe enabled auto-merge (squash) March 25, 2026 00:40
@jar-stripe jar-stripe merged commit 618d3b3 into master Mar 25, 2026
16 checks passed
@jar-stripe jar-stripe deleted the jar/decimal-tier2-python branch March 25, 2026 00:44
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.

3 participants