FloPay Backend Changelog

Client-facing updates for FloPay backend and API releases.

v1.0.3 - Traceable Stripe objects with flo_* metadata #

Stripe customers, subscriptions, payments, products, and coupons now carry flo_* identifiers so dashboard and webhook events trace back to platform records without extra lookups.

16 May 2026

Improvement
Stripe
Webhooks
Observability

Every Stripe object the platform creates or updates is now stamped with a consistent set of flo_* metadata keys. Support staff inspecting Stripe in the dashboard, and webhook consumers reacting to events, can map each Stripe record back to its originating client, user, checkout session, subscription, product, coupon, or invoice without an additional API call or database lookup.

What changed

  • Standardized metadata keys — Stripe Customer, Subscription, PaymentIntent, SetupIntent, Product, and Coupon create/update calls now include flo_client, flo_user, flo_checkout_session, flo_subscription, flo_product, flo_coupon, and flo_invoice whenever the corresponding identifier is known. Keys are omitted entirely when no value applies, so metadata payloads remain clean.
  • Single-source subscription tagging — Subscriptions are tagged with flo_product only for single-product subscriptions and with flo_coupon only when exactly one coupon is applied, keeping the metadata unambiguous for dashboard filtering and downstream reporting.
  • Webhook resolution improvements — Stripe webhook handlers (payment_intent.succeeded, payment_intent.payment_failed, and the outbox/persistence pipeline) now prefer the canonical flo_checkout_session, flo_product, and flo_coupon keys when reconciling events to platform records, with a fallback to the previous checkoutSessionId / initialCheckoutSessionId keys for objects created before this release.

Why it matters

Operators and developers can now jump directly from any Stripe object — in the dashboard, in a webhook payload, or in an exported report — to the matching platform entity. This shortens incident triage, simplifies reconciliation, and reduces the number of round-trip lookups required to answer "which Flo record produced this Stripe object?"

Developer notes

  • No action is required for objects created before this release. Webhook handlers transparently fall back to the legacy metadata keys, so historical Stripe records continue to resolve correctly.
  • New Stripe objects created after upgrading will carry the flo_* keys going forward. Custom integrations that read Stripe metadata can begin relying on the canonical key names immediately.

v1.0.2 - Checkout now runs on the local catalog #

Checkout sessions validate against the platform's own products and coupons and stream that catalog data through to Stripe, removing runtime price lookups.

15 May 2026

Feature
Checkout
Catalog
Subscriptions
Stripe

Checkout now resolves products, prices, and coupons against the local catalog introduced in v1.0.1 instead of looking them up in Stripe at request time. Sessions are validated up-front, pricing is sent inline to Stripe, and every checkout, subscription, and invoice is linked back to the catalog records that produced it.

What changed

  • Catalog-validated checkout sessionsPOST /checkout/sessions now resolves every submitted product and coupon code against the client's local catalog before a session is created. Unknown, soft-deleted, or non-applicable entries are rejected with a 422 response carrying machine-readable codes (UnknownProduct, DeletedProduct, UnknownCoupon, DeletedCoupon, CouponNotApplicable).
  • Inline pricing to Stripe — Stripe subscription and one-off charge calls now send price_data/product_data built from the local catalog, including trial days and price overrides. Stripe no longer needs a pre-existing Price for each checkout item.
  • Persistent checkout-to-catalog links — New checkout_product and checkout_coupon records capture which catalog entries were used for each session. Resulting subscription and invoice rows are populated with the corresponding product_id and coupon_id, including from incoming Stripe webhooks.
  • Coupon guarantor — Stripe coupons are retrieved-or-created on demand per currency from the local coupon definition, with race handling for concurrent creates.

Why it matters

Merchants get a single source of truth for what they sell. Pricing, trial windows, and discount rules live in the platform catalog and are enforced consistently at checkout, on the resulting Stripe charge, and on the persisted invoice and subscription — which makes reporting, refunds, and reconciliation line up cleanly across the lifecycle.

Developer notes

  • Checkout request bodies must reference product and coupon code values that exist (and are not soft-deleted) in the local catalog for the authenticated client. Invalid references now return 422 with a typed error code instead of being passed through to the gateway.

v1.0.1 - Local product catalog foundation #

New gateway-independent APIs for managing products, prices, coupons, and collections directly on the platform.

14 May 2026

Feature
Catalog
Products
Coupons
Collections
API

Merchants can now manage their own products, prices, coupons, and collections through the platform API without relying on a payment gateway's catalog. This release adds the data layer and CRUD endpoints that future checkout and subscription flows will build on.

What changed

  • Products — Create, list, retrieve, update, and soft-delete products scoped to the authenticated client. Each product supports one-time or recurring pricing with multiple currencies via nested prices.
  • Coupons — Manage percentage or fixed-amount discounts with duration controls (once, repeating, forever), per-currency amounts, and optional product associations.
  • Collections — Group products into named collections for catalog organization, with associations managed in the same create or update request.
  • Consistent list queries — All new list endpoints (GET /products, GET /coupons, GET /collections) accept the standard page, limit, sort, filter, and relation-inclusion parameters introduced in v1.0.0.
  • Unique codes — Product, coupon, and collection code values are enforced as unique per client at the database level.

Why it matters

This is the catalog foundation that lets merchants define their offerings once and reuse them across checkout, subscriptions, and reporting — independent of which payment gateway ultimately processes a transaction. Soft-delete semantics preserve historical references on existing invoices and subscriptions even after a product or coupon is retired.

Developer notes

  • All catalog endpoints are guarded by client authentication; client_id is derived from the authenticated client and is never read from the request body.
  • Nested prices and product associations are upserted in the same request, so a single POST or PATCH call is sufficient to persist a product with its prices or a coupon with its applicable products.
  • No checkout or Stripe flows change in this release. Wiring the catalog into checkout and subscription creation will follow in subsequent releases.

v1.0.0 - Expand list query support across API list endpoints #

Payments, invoices, and webhook event listing endpoints now support pagination, sorting, filtering, and related-record expansion through a unified query contract.

13 May 2026

Improvement
Payments
Invoices
Webhooks
API

List endpoints across the API now accept a consistent set of query parameters for pagination, sorting, filtering, and relation inclusion. This replaces previous per-endpoint, ad-hoc query handling with a single shared contract, giving developers a predictable and documented interface for all list operations.

What changed

  • Payments, invoices, and webhook events listing endpoints accept standardized page, limit, sort and filter query parameters.
  • Filtering supports typed, operator-driven expressions (e.g. equality, range) so results can be narrowed without custom endpoints.
  • Relation inclusion allows callers to request parent and original-delivery records alongside webhook events in a single response.
  • Malformed or unsupported query parameters now return a clear 400 Bad Request response rather than silently ignoring or mishandling the input.
  • OpenAPI / Swagger documentation reflects the new query contract; docs now derive the API version and title from the package version automatically.

Why it matters

Developers building merchant dashboards, reconciliation tools, or operational integrations can now paginate and filter results reliably across all major list endpoints using the same parameter names and semantics — reducing the need for client-side post-processing and extra round trips.

Developer notes

  • The per-endpoint query DTOs for payments (PaymentsQueryDto), invoices (InvoiceListQueryDto), and webhook events (ListClientWebhookEventsQueryDto) have been replaced by the shared list-query parser. Update any code that constructed or validated those DTOs directly.
  • Unsupported or malformed filter/sort expressions that were previously silently ignored will now return 400. Review any existing queries that relied on lenient handling.
  • No database migrations are required.
  • API documents are available from here.