All notable changes to this project will be documented in this file.

This project adheres to Semantic Versioning.

Publishing note: The last version published to Hex.pm was 1.1.0 (2026-04-14). Sections 1.4.0 through 1.6.0 below are milestone checkpoints shipped together in 1.7.0 — they were not published as separate Hex releases. Install: {:lattice_stripe, "~> 1.7"}.

[Unreleased]

No unreleased changes.

1.7.0 (2026-05-27)

Highlights

This release publishes 1.7.0 to Hex — the first package since 1.1.0, bundling v1.4 adoption closure, v1.5 thin-event webhooks, v1.6 Tax, and v1.7 Charge expansion plus operator playbooks. Adopters on ~> 1.1 resolve to 1.7.0.

v1.x scope and maintenance posture: see README and User Flows & JTBD.

Upgrading from 1.1.x or 1.3.x: Update your mix.exs dependency to {:lattice_stripe, "~> 1.7"}. Review the milestone sections below for additive surfaces (Tax, thin events, Charge list/search/update/capture) and the WEBFIX-01 migration under 1.5.0 if you use tolerance: 0 in tests.

Added

  • Charge surface expansionLatticeStripe.Charge gains list/3, list!/3, stream!/3, search/3, search!/3, search_stream!/3, update/4, update!/4, capture/4, and capture!/4 for support, audit, and Connect reconciliation. PaymentIntent remains the payment-initiation path (create/cancel intentionally omitted). See Charge moduledoc.
  • Operator playbooksguides/production-checklist.md (pre-launch boundaries) and guides/event-debugging.md (webhook diagnostic ladder from delivery boundary inward).
  • Install and docs-truth lockstep — All public install surfaces and docs_truth_test.exs derive the canonical {:lattice_stripe, "~> 1.7"} snippet from mix.exs (SSOT contract).

[1.6.0] — Tax

Milestone included in 1.7.0. Not published separately to Hex.

Added

  • Tax.Calculationcreate/3, retrieve/3, list_line_items/3 for standalone tax calculation (90-day expiry documented in moduledoc).
  • Tax.Transactioncreate_from_calculation/3, create_reversal/3, retrieve/3, list_line_items/3 for recording and reversing tax liability.
  • Tax.Settings — singleton retrieve/update for account-level tax configuration.
  • Tax.Registration — jurisdiction registration CRUDL with stream!/3.
  • TaxId — dual-path customer and account tax ID management.
  • guides/tax.md — canonical Tax adoption guide with scope boundary vs Invoice.AutomaticTax.

[1.5.0] — Thin-Event Webhooks

Milestone included in 1.7.0. Not published separately to Hex.

Fixed

  • WEBFIX-01 — Webhook.check_tolerance/2 tolerance: 0 semantics reconciled. Before this release, tolerance: 0 returned {:error, :timestamp_expired} on every call — directly contradicting the verify_signature/4 docstring which has always documented 0 as "disable staleness check". The code clause has been corrected to match the docstring (and every canonical Stripe SDK: stripe-node's if (tolerance > 0 && ...) gate, stripe-go's IgnoreTolerance flag, stripe-ruby's if tolerance && ... guard).
  • WEBFIX-01 — Webhook.Plug NimbleOptions :tolerance schema relaxed. Changed from :pos_integer to :non_neg_integer so the documented "Set 0 to disable" lever is reachable through the public Plug surface. Negative tolerances are still rejected at init/1 time. Testing only — never set tolerance: 0 in production; it removes replay-attack protection. See guides/webhooks-thin-events.md for the canonical thin-event path.

Added

  • Thin-event SDK surfaceWebhook.parse_event_notification/4, fetch_event/3, fetch_related_object/3 with typed EventNotification struct and Event extensions for related_object and context.
  • guides/webhooks-thin-events.md — canonical Phoenix thin-event guide: fetch-after-verify idempotency on event.id, verification-vs-payload-shape failure boundary, Stripe 100 req/s rate-limit ceiling, Connect routing via event.context.
  • Testing helpers — thin-event payload builders in LatticeStripe.Testing for signed wire-format fixtures.

[1.4.0] — Adoption Closure

Milestone included in 1.7.0. Not published separately to Hex.

Added

  • Flagship recipesguides/checkout-signup-and-portal.md, guides/connect-platform-flow.md, guides/metering-runtime-and-reconciliation.md, guides/quote-to-billing-operator.md with cross-linked discovery ladder.
  • Docs-truth baselinedocs_truth_test.exs regression locks onboarding install lines, ExDoc extras, and guide cross-link graph (Phase 43).
  • Guide discovery — JTBD routing layer, cheatsheet, and README docs ladder aligned to shipped 1.3.x surface before capstone version flip.

1.3.0 (2026-05-25)

Changed

  • Expand deserialization — When you pass expand: ["customer"] (or any expandable field), the response struct now contains a fully typed struct (e.g., %Customer{}) instead of a raw map. Fields that are not expanded remain as string IDs, unchanged. This applies to all resource modules.

    Migration note: If your code pattern-matches on expanded fields expecting a raw map, update to match on the typed struct:

    # Before (v1.1):
    {:ok, %PaymentIntent{customer: %{"id" => id}}} = PaymentIntent.retrieve(client, id, expand: ["customer"])
    
    # After (v1.2):
    {:ok, %PaymentIntent{customer: %Customer{id: id}}} = PaymentIntent.retrieve(client, id, expand: ["customer"])

    If you were not passing expand:, your code is unaffected — unexpanded fields are still string IDs.

  • Status atomization — All resource modules with a documented finite status field now return atoms (e.g., :active, :succeeded) instead of strings from from_map/1. Unknown or future status values pass through as raw strings for forward-compatibility.

    Migration note: If your code compares status as a string, update to atom comparison:

    # Before (v1.1):
    if pi.status == "succeeded" do ...
    
    # After (v1.2):
    if pi.status == :succeeded do ...

    Affected modules: PaymentIntent, Subscription, SubscriptionSchedule, Charge, Refund, SetupIntent, Payout, BalanceTransaction, BankAccount, Checkout.Session, Billing.Meter, Account.Capability.

  • Deprecated Billing.Meter.status_atom/1 and Account.Capability.status_atom/1 — status is now automatically atomized in from_map/1/cast/1. Access .status directly on the struct.

  • Docs/package truth — README, ExDoc extras, and public guide discovery align with the shipped 1.3.x surface instead of presenting the line as unreleased.

Added

  • v1.3 surface — adds File/FileLink upload/download support, Disputes, Credit Notes, Mandates, SetupAttempts, Quotes, public testing fixture builders, a compact recipes guide, and a canonical Phoenix webhook quickstart.

  • Docs: User Flows & JTBD guide — Added a new conceptual guide aimed at experienced Elixir/Phoenix SaaS integrators. It explains LatticeStripe through real product jobs and end-to-end flow choices, including when to use Checkout vs direct APIs, how subscriptions, invoices, portal sessions, metering, and webhooks fit together, and where current roadmap gaps still exist.

  • Internal object-type dispatch module for expandable Stripe resources (not part of public API).

  • Union type specs (Customer.t() | String.t() | nil) on all expandable fields across all resource modules.

Fixed

  • Getting Started guide version drift — Updated the install snippet to {:lattice_stripe, "~> 1.3"} and aligned the first PaymentIntent example output with atomized status values.

1.1.0 (2026-04-14)

Highlights

The first post-1.0 minor release. Adds the two downstream unblockers needed by Accrue: usage-based billing (Billing Metering) and customer self-service (Customer Portal). Full phase history is in PR #9.

What's new:

  • Billing Metering. Billing.Meter CRUDL plus deactivate/3 and reactivate/3, usage event ingestion via MeterEvent.create/3, and late corrections via MeterEventAdjustment.create/3. A pre-flight guard (GUARD-03) raises ArgumentError on malformed value_settings before the network call, preventing Stripe's silent-zero trap for sum/last aggregation formulas.
  • Customer Portal. BillingPortal.Session.create/3 returns a short-lived portal URL for a given customer. Full deep-link flow support (subscription_cancel, subscription_update, subscription_update_confirm, payment_method_update) via a 5-module nested FlowData struct tree. A pre-flight guard raises ArgumentError with actionable messages for missing required flow sub-fields, so malformed requests fail before they hit Stripe. The Inspect protocol masks the portal URL and flow to keep short-lived secrets out of log output.
  • Docs. New guides/metering.md (usage-reporting idiom, idempotency two-layer explainer, reconciliation, backdating window, aggregation semantics) and guides/customer-portal.md (all 4 flow types with required sub-fields, Accrue-style Phoenix controller example, Inspect masking security teaching). New ExDoc groups: "Billing Metering" and "Customer Portal". Reciprocal cross-links from existing guides/subscriptions.md and guides/webhooks.md.

Verification. 1488 tests passing. Integration tests run against stripe-mock. mix compile --warnings-as-errors, mix credo --strict, and mix docs --warnings-as-errors all clean. Phase 20 and Phase 21 verification reports: passed.

Upgrading from 1.0.x. No breaking changes. Additive only — Billing.Meter, Billing.MeterEvent, Billing.MeterEventAdjustment, and BillingPortal.Session are new public modules. Existing code keeps working unchanged.

Features

  • Billing.Meter: create/3, retrieve/3, update/4, list/2, deactivate/3, reactivate/3
  • Billing.Meter.ValueSettings, DefaultAggregation, CustomerMapping, StatusTransitions: nested typed structs with :extra forward-compat
  • Billing.MeterEvent: create/3 with two-layer idempotency (identifier vs idempotency_key:)
  • Billing.MeterEventAdjustment: create/3 with nested Cancel struct for late corrections
  • Billing.Guards.check_meter_value_settings!/1: pre-flight shape guard for value_settings (GUARD-03, prevents silent-zero trap)
  • BillingPortal.Session: create/3 returns {:ok, %Session{url: ..., flow: ...}}
  • BillingPortal.Session.FlowData: 5-module nested struct tree — FlowData, AfterCompletion, SubscriptionCancel, SubscriptionUpdate, SubscriptionUpdateConfirm
  • BillingPortal Guards: pre-flight check_flow_data!/1 raises ArgumentError for missing flow sub-fields, enumerating valid flow types on unknown input
  • Inspect masking for BillingPortal.Session: hides :url and :flow fields via explicit allowlist to keep short-lived portal URLs out of logs
  • guides/metering.md: usage-reporting idiom, idempotency layers, reconciliation, aggregation semantics
  • guides/customer-portal.md: all 4 flow types, Accrue-style Phoenix controller example, Inspect masking security teaching
  • mix.exs: groups_for_modules entries for "Billing Metering" and "Customer Portal"; both guides added to extras

1.0.0 (2026-04-13)

Highlights

LatticeStripe 1.0 marks our commitment to API stability for the Elixir + Stripe integration story. The 0.2 → 1.0 journey spans four major milestones: a solid foundation of transport, retries, pagination, and observability (Phases 1-11); full Billing coverage for Invoices, Subscriptions, SubscriptionItems, and Subscription Schedules (Phases 14-16); end-to-end Connect support including accounts, onboarding links, external accounts, transfers, payouts, balance, and balance transactions (Phases 17-18); and a formalized public API surface with @moduledoc false internals and an explicit semver contract (Phase 19). Starting with 1.0.0, LatticeStripe follows standard semver: patch releases for bug fixes, minor releases for additive features, major releases for breaking public API changes — see API Stability for the full contract.

What's in the box:

  • Payments. Customers, PaymentIntents, SetupIntents, PaymentMethods, Refunds, Checkout Sessions.
  • Billing. Invoices (create, finalize, pay, void, send, search), Subscriptions with lifecycle verbs and pause helpers, Subscription Schedules with proration guards, Invoice Items.
  • Connect. Accounts (Standard/Express/Custom), Account Links, Login Links, External Accounts (BankAccount/Card), Transfers + TransferReversals, Payouts (with TraceId), Balance + BalanceTransactions, Charge retrieve for fee reconciliation.
  • Webhooks. Timing-safe signature verification, Event struct, Phoenix Webhook.Plug, Webhook.Handler behaviour.
  • Operational glue. Pluggable Transport/Json/RetryStrategy behaviours, Telemetry events for every request, LatticeStripe.Testing helpers with TestClock support.

Upgrading from 0.2.x. No breaking API changes from 0.2. The public surface has been frozen; previously-visible internal modules (FormEncoder, Request, Resource, Transport.Finch, Json.Jason, RetryStrategy.Default, Webhook.CacheBodyReader, Billing.Guards) are now documented as private via @moduledoc false and are excluded from the semver contract.

Supported versions. Elixir 1.15+ on OTP 26+, tested up to Elixir 1.19 on OTP 28.

Features

  • 17-01: add canonical Account/AccountLink/LoginLink fixtures (a1a101c)
  • 17-01: add stripe-mock reject probe script and record result in VALIDATION.md (e3539e9)
  • 17-02: Account.Capability (D-02) with safe status_atom/1 (3a80de4)
  • 17-02: PII-safe nested structs — TosAcceptance, Company, Individual (fddb864)
  • 17-02: plain nested structs — BusinessProfile, Requirements, Settings (4bd03c9)
  • 17-03: LatticeStripe.Account resource module — CRUD + reject + stream + from_map (92747d0)
  • 17-04: LatticeStripe.AccountLink — create/3, create!/3, from_map/1 + tests (7161f34)
  • 17-04: LatticeStripe.LoginLink — create/4, create!/4, from_map/1 + tests (0bd48d7)
  • 17-05: Account full-lifecycle integration test + fix cast_capabilities for stripe-mock (e1364a6)
  • 17-05: AccountLink + LoginLink integration tests (9 tests each) (ecb7494)
  • 17-06: add guides/connect.md — Connect onboarding narrative (874dda9)
  • 18-01: add BankAccount + Card structs with F-001 and PII Inspect (f775aff)
  • 18-01: add ExternalAccount polymorphic dispatcher + Unknown fallback (91148ac)
  • 18-02: add LatticeStripe.Charge retrieve-only resource (44a0adb)
  • 18-03: add LatticeStripe.Transfer CRUDL with embedded reversals decoding (90b1234)
  • 18-03: add LatticeStripe.TransferReversal standalone module (5cddcb9)
  • 18-04: add Payout CRUDL + cancel + reverse with TraceId integration (79605ae)
  • 18-04: add Payout.TraceId nested typed struct (52f6d11)
  • 18-05: add Balance singleton with Amount and SourceTypes nested structs (5304b80)
  • 18-05: add BalanceTransaction retrieve/list/stream + FeeDetail struct (6873c5f)
  • 19-01: rewrite mix.exs groups_for_modules to nine-group D-19 layout (c66223b)

Bug Fixes

  • 17-02: align nested struct tests with 17-01 canonical fixture values (025082a)
  • 18: IN-01 correct BankAccount docstring account_number reference (b720afa)
  • 18: IN-02 normalize nil/empty id guards to 'id in [nil, ""]' style (542fc1b)
  • 18: IN-03 derive ExternalAccount.Unknown.cast drop list from @known_fields (00d618e)
  • 18: IN-04 add is_map(params) guard to Payout.update/update! (bdc4ab8)
  • 18: IN-05 preserve unexpected Transfer reversals shape in extra (ae1c85e)
  • 18: WR-01 add map() to Transfer expandable typespecs (772795e)
  • 18: WR-01 add map() to TransferReversal expandable typespecs (fe9bbdd)
  • 18: WR-02 add map() to Charge destination/source_transfer typespecs (c26187d)
  • 18: WR-03 add nil/empty id guards to BalanceTransaction.retrieve/3 and retrieve!/3 (e60f220)
  • 18: WR-03 add nil/empty id guards to Payout.update/4 and update!/4 (4614b1c)
  • 18: WR-03 restore balance_transaction id error message for test contract (10a8827)

0.2.0 (2026-04-04)

Features

  • 01-01: configure test infrastructure with Mox mocks, formatter, and Credo (d75666e)
  • 01-01: scaffold Elixir project with Phase 1 dependencies (2e4ae58)
  • 01-02: implement JSON codec behaviour and Jason adapter with tests (bb63aac)
  • 01-02: implement recursive Stripe-compatible form encoder with tests (2c232e4)
  • 01-03: implement Error struct with Stripe error response parsing and tests (8438a4c)
  • 01-03: implement Transport behaviour and Request struct with tests (192ddc9)
  • 01-04: implement Finch transport adapter with tests (b0951e3)
  • 01-04: implement NimbleOptions config schema and validation with tests (9441d19)
  • 01-05: implement Client struct with new!/1, new/1, and request/2 (8c384d8)
  • 02-01: add non-bang decode/1 and encode/1 to Json behaviour and Jason adapter (1666da4)
  • 02-01: enrich Error struct with new fields, idempotency_error, String.Chars (33da331)
  • 02-02: implement RetryStrategy behaviour and Default implementation (f2394e7)
  • 02-02: update Config and Client with retry_strategy field and max_retries default 2 (f3df360)
  • 02-03: wire retry loop, auto-idempotency, bang variant, non-JSON handling into Client (9501f91)
  • 03-01: add List struct, api_version/0, update Config/Client defaults and User-Agent (f7b30af)
  • 03-01: add Response struct with Access behaviour, get_header/2, custom Inspect (8a97dc8)
  • 03-02: wrap responses in %Response{} with list auto-detection (9051f8c)
  • 03-03: implement stream!/2 and stream/2 auto-pagination on List (dc2b01a)
  • 04-01: implement LatticeStripe.Customer resource module (420f4a2)
  • 04-02: implement LatticeStripe.PaymentIntent resource module (30b55c8)
  • 05-01: build SetupIntent resource module with full CRUD, lifecycle actions, list/stream, and tests (7908ede)
  • 05-01: extract Resource helpers, refactor Customer/PaymentIntent, add PI search, shared test helpers (0a85316)
  • 05-02: implement PaymentMethod resource with CRUD, attach/detach, validated list, stream, and tests (ec48dca)
  • 06-01: extract Phase 4/5 test fixtures into dedicated fixture modules (bd69567)
  • 06-01: implement Refund resource with CRUD, cancel, list, stream, and tests (8e4ecad)
  • 06-02: implement Checkout.Session and LineItem with all endpoints and tests (99dbadd)
  • 07-01: add Event struct, Handler behaviour, SignatureVerificationError, deps (1c04f4b)
  • 07-01: implement LatticeStripe.Webhook with HMAC-SHA256 verification (b524010)
  • 07-02: add CacheBodyReader and Webhook.Plug with NimbleOptions, path matching, handler dispatch, MFA secrets (08eed78)
  • 08-01: create LatticeStripe.Telemetry module with event catalog and span helpers (c8e514e)
  • 08-02: implement webhook_verify_span, attach_default_logger, integrate webhook telemetry (63de0a4)
  • 09-01: add 6 resource integration test files (87cb6ab)
  • 09-01: add integration test infrastructure (c37a9ec)
  • 09-02: add mix ci alias, Credo strict mode, and fix all violations (152eacc)
  • 09-02: implement LatticeStripe.Testing public module (60506ed)
  • 10-01: complete cheatsheet with two-column layout (52368ea)
  • 10-01: ExDoc config, README quickstart, CHANGELOG, guide stubs (677b034)
  • 10-02: add @typedoc and Stripe API reference links to resource modules (70ab5f4)
  • 10-02: add @moduledoc/@doc/@typedoc to core and internal modules (32b1917)
  • 10-03: write checkout and webhooks guides (3b04b13)
  • 10-03: write getting-started, client-configuration, and payments guides (781f10e)
  • 11-02: add Dependabot config and auto-merge workflow (12078f6)
  • 11-02: add Release Please workflow and manifest config (a478928)
  • 11-03: add community files — CONTRIBUTING, SECURITY, issue templates, PR template (36d6a7a)

Bug Fixes

  • 01: resolve verification gaps — update REQUIREMENTS.md traceability and fix flaky test (4edc9ad)
  • 01: revise plans based on checker feedback (3226334)
  • 03: remove deferred requirements EXPD-02, EXPD-03, EXPD-05 from Plan 02 (ca8372e)
  • 04: Customer Inspect uses Inspect.Algebra to prevent PII field name leakage (63ae62e)
  • 04: remove unused aliases in test files (9780bdf)
  • 09: revise plans based on checker feedback (9a59458)
  • remove deprecated 'command' input from release-please-action v4 (3ff8a12)
  • skip invalid-id integration tests — stripe-mock returns stubs for any ID (e986f1b)
  • update GitHub org from lattice-stripe to szTheory (ad46956)