> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flokitai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Release notes and updates for FloKit.

FloKit is in private beta. This changelog tracks significant releases, integration changes, and breaking changes to the API and data model.

For early access to the private beta, visit [flokitai.com](https://flokitai.com) or contact the FloKit team.

***

## August 12, 2026 — Paddle-hosted checkout (optional surface)

**Flows / Payments** — additive. The same-origin `@flokitai/checkout-js` overlay is unchanged and
remains the default checkout experience.

* Apps whose Paddle connection requires Paddle's own hosted checkout page now redirect through two
  Flow-gateway routes, `GET /pc/paddle-hosted/launch` and `GET /pc/paddle-hosted/return`. Both are
  same-origin with the Flow page; the launch id is single-use and the bridge record expires.
* Whether a given app uses this path depends on its per-connection checkout configuration, not on a
  global setting.
* Confirmation still comes from the Paddle webhook, never from the browser return — a return hit
  alone never grants an entitlement.

***

## August 5, 2026 — Custom delivery domains and clean Flow URLs

**Flows** — additive; no existing URL stopped working.

* **Custom delivery domains.** You can now serve Flows from your own subdomain. Point a `CNAME` at
  `edge.flokitai.com` and add the `_flokit-verification.<host>` `TXT` record, then verify and
  promote the domain from the dashboard's **Domains** tab. Until a custom domain is primary, Flows
  keep serving from their `*.funnels.flokitai.com` fallback host. See
  [Custom subdomain setup](/guides/custom-subdomain).
* **Clean public Flow URLs.** Generated Flows are now published at a single-segment path,
  `https://<your-host>/<slug>`. The older `/f/<flowId>/<frozenSlug>` form still resolves and issues
  a `308` redirect to the clean URL, so existing links and ad destinations keep working. Retired
  paths answer `410` rather than `404`, so a removed Flow is distinguishable from a typo.
* A slug is reserved once used: reusing it for a different Flow is rejected rather than silently
  repointing an existing public URL.

***

## July 30, 2026 — Canonical subscription domain (SDK v2.0.0)

<Warning>
  **Breaking — entitlement reads, receipt submission, and the `Entitlement` shape all changed.**

  * Entitlement read: `GET /api/paywall/entitlement` → **`GET /api/entitlements/current`**. The old
    path was deleted and now `404`s.
  * Receipts: `POST /api/paywall/receipt` → **`POST /api/iap/receipts`**. The body schema is unchanged.
  * `Entitlement.product_id` → **`entitlement_key`**, and it is now **opaque** — the store product id
    for native purchases, the Package key for web. Do not parse it.
  * `expires_at` is now `string | null`; `null` means open-ended.
  * New fields on `Entitlement`: `state`, `source_event_id`, `updated_at`.
  * `EntitlementProvider` widened to `apple` | `google` | `paddle` | `lemon_squeezy` |
    `stripe_direct` | `stripe_managed_payments` | `custom`.
</Warning>

**Payments gateway**

* `GET /api/paywall/config` now returns `410` with `{"code": "PAYWALL_CONFIG_REMOVED"}`. Remote
  paywall configuration no longer exists — paywalls are Flow-owned and served with the Flow page.
  The path is still proxied so older SDK builds get an honest `410` rather than a `404`.
* `GET /api/monetization/provider-profile` was **deleted**.
* `POST /api/providers/generic-subscription/webhook` was **deleted**. Third-party subscription
  events must arrive through a per-connection provider receiver.

See [Entitlements API](/api-reference/entitlements), [Paywall API](/api-reference/paywall), and
[SDKs](/sdks/overview#migrating-to-v2-0).

***

## July 28, 2026 — SDK v1.3.1

**Breaking — Subscriptions SDK**

* `startWebCheckout()` now **always** throws `CheckoutUnavailableError` with
  `code: 'WEB_CHECKOUT_MIGRATED'`. Web checkout moved to the Flow page, driven same-origin by
  `@flokitai/checkout-js`.
* `previewOfferPrice()` and the `PricePreview` type were **removed**.
* `trackPaywallEvent({ offerId })` was retired.

***

## July 27, 2026 — RevenueCat and Adapty webhook receivers removed

**Payments gateway** — breaking for anyone who configured these URLs.

* `POST /api/providers/revenuecat/webhook` and `POST /api/providers/adapty/webhook` no longer
  exist. There is no RevenueCat or Adapty adapter in the platform; the endpoints were documented
  but are not served. Deliveries to either URL are dropped.
* Route third-party subscription events through a per-connection provider receiver instead.
  Apple, Google Play, Paddle, Stripe, and Lemon Squeezy receivers are unchanged.

<Note>
  Superseded by the July 30, 2026 entry above. The generic-subscription receiver named in the
  original version of this entry (`POST /api/providers/generic-subscription/webhook`) has since
  been deleted, as has `GET /api/monetization/provider-profile`.
</Note>

The v1 REST API preview pages no longer print a base URL. That API is not served on a public
host yet — see [Authentication](/api-reference/authentication).

***

## July 20, 2026 — Daily activity and entitlement telemetry (SDK v1.3.0)

**Subscriptions SDK** — additive.

* `day_active` — emitted once per **local** calendar day on that day's first foreground.
  The DAU spine: counting distinct users off `app_open` works, but it leaves the
  definition of "active today" duplicated in every query that asks.
* `entitlement_granted` / `entitlement_revoked` — access-state transitions, distinct from
  the commercial events. `convert` is "they paid"; `entitlement_granted` is "they can use
  it". A restore, a web checkout completing, or a server-side grant produces one without
  the other. First observation carries `first_observation: true`.
* Entitlement is revalidated on foreground (60s TTL), so a trial that lapsed or a
  cancellation that took effect overnight is caught instead of served stale from cache.

***

## July 20, 2026 — Package renamed, SDK becomes the measurement client (SDK v1.2.0)

<Warning>
  **Breaking — the package was renamed.** `@flokit/subscriptions-sdk` is no longer published
  anywhere. Distribution moved to GitHub Packages, whose registry requires the package scope to
  match the repository owner. Re-pin to `@flokitai/subscriptions-sdk` and add
  `@flokitai:registry=https://npm.pkg.github.com` to your `.npmrc`. See [SDKs](/sdks/overview).
</Warning>

**Breaking — Subscriptions SDK**

* `purchase()` now owns its whole funnel: `purchase_start` on entry, then exactly one
  terminal event (`convert`, `trial_start`, `cancel`, or `purchase_failed`).
  **Hosts must delete their own emissions of these** — hand-rolling them is what produced
  double-counted `purchase_start`, `trial_start` recorded against failed purchases, and
  every error filed as a user cancellation.
* `resolveSdkMarket()` / `ResolveSdkMarketOptions` **removed**. They were the sole consumer
  of a private `file:` dependency that an external consumer could not resolve, which blocked
  publishing outright. They shipped only in 1.1.0, which was never released, so nothing can
  depend on them. `previewOfferPrice()` is unaffected.

**Added — Subscriptions SDK**

* `track(eventName, properties?)` for general-purpose funnel events, drawn from a canonical
  vocabulary shared verbatim with the hosted web funnel, so a web session and an app session
  describe one journey.
* Sessions and lifecycle: `session_id` on every event, plus `first_open`, `app_open`,
  `session_start`, `session_end`. Pass `appState` at init to get transitions and a flush when
  the app backgrounds.
* Device/app context on every event (`sdk_version`, `app_version`, `build_number`,
  `os_version`, `device_model`, `locale`), all host-supplied.
* Campaign attribution now survives: handoff-supplied `campaignId` /
  `campaignCreationSessionId` were previously discarded, and are now persisted and stamped on
  every later event across restarts.
* Revenue on conversions — `purchase({ priceUsdCents, currency })` stamps `revenue` on the
  terminal event only, never on `purchase_start`.
* `getDiagnostics()` gains `droppedEvents` and `sessionId`.

**API**

* `POST /api/paywall/events` accepts the full vocabulary — 31 event types across paywall
  render, app lifecycle, entitlement transitions, the shared web-funnel moments, and
  checkout/identity. `purchase_failed` and `paywall_dismiss` do not require
  `paywall_id`/`variant_id`.

***

## July 12, 2026 — Localized pricing (SDK v1.1.0, never released)

<Note>
  v1.1.0 was superseded by v1.2.0 and never released. `resolveSdkMarket()`, announced here
  originally, was removed before release — see the v1.2.0 entry above. `previewOfferPrice()`
  shipped in v1.2.0 and was removed in v1.3.1 — see the July 28, 2026 entry.
</Note>

**Subscriptions SDK**

* `previewOfferPrice()` returns a localized `PricePreview` (currency, formatted
  subtotal / tax / total, and per-price line items) before checkout.

**API**

* `POST /api/billing/offers/:offerId/price-preview` returns a country-localized price
  breakdown for a published offer.

***

## July 12, 2026 — Subscriptions SDK v1.0 (placement-first)

**Breaking — Subscriptions SDK**

* `@flokit/subscriptions-sdk` **v1.0** is a clean break with no 0.x compatibility.
  Paywalls are now addressed by **placement**: apps register a placement name
  (`onboarding_complete`) and the dashboard maps it to a published paywall and A/B
  variant, so which paywall shows where — and which experiment runs — changes with
  no app release.
* **Context-first API.** `initSubscriptionsSdk()` is required for the main surface;
  every function resolves `baseUrl` / `appId` / user / credentials from the context.
  `getPaywall(placement)` replaces `fetchPaywallConfig`; `<RemotePaywall placement>`
  replaces the per-prop form. Identity is anonymous-first (`userId` optional at init).
* **New:** `onEntitlementChange()` listener, automatic app-session token mint +
  refresh (no manual `fetchAppToken`), and `identify()` now also posts the
  server-side identity alias edge.

**API**

* `GET /api/paywall/config` accepts `placement_id` (resolved to a published paywall)
  as an alternative to `paywall_id`; the response echoes `placement_id`. An unmapped
  placement returns the empty fallback, never a 404.
* Paywall funnel events accept an optional top-level `placement_id`, surfaced in
  reporting via the `paywall_funnel_events` warehouse view.

***

## July 8, 2026 — Customer onboarding guide

**Docs**

* Added [Customer onboarding](/getting-started/onboarding), a production rollout
  guide from workspace setup through app identity, revenue, attribution, events,
  identity validation, first payback report review, guardrails, and
  recommendations.
* Added the onboarding guide to the **Start here** navigation area.
* Refreshed the changelog with a dated entry for the onboarding docs update.

***

## July 2026 — Subscriptions SDK hardening (v0.3.0, v0.4.0)

**Subscriptions SDK**

* `@flokit/subscriptions-sdk` **v0.3.0** — app-session tokens: `fetchAppToken()`
  mints a short-lived token via `POST /api/paywall/token`; every call and the
  `RemotePaywall` prop now accept `appToken`, sent as `x-app-token` (takes
  precedence over `appKey`). Optional and backwards compatible.
* `@flokit/subscriptions-sdk` **v0.4.0** — optional `initSubscriptionsSdk()`
  wires a persisted, retrying funnel-event queue (`EventQueue` + injectable
  `StorageAdapter`), on-device identity (`identify` / `resetIdentity` with a
  persisted `anonymous_ref`), a stale-while-revalidate entitlement cache
  (`getEntitlement` / `restore`), the web→app handoff bridge
  (`exchangeHandoffCode`), the hosted Paddle web-checkout bridge
  (`startWebCheckout`), and diagnostics (`getDiagnostics` / `setDebugLogger`).
  Fully additive — existing standalone calls are unchanged. See [SDKs](/sdks/overview).

**Live gateway endpoints**

* Web→app handoff — `POST /api/paywall/handoff/exchange` redeems a one-time
  handoff code and returns the flow-session context.
* Web checkout — `POST /api/paywall/checkout` opens a hosted Paddle checkout for
  the web-to-app funnel.

***

## June–July 2026 — Remote paywalls, live gateway endpoints, measurement ingest

**Subscriptions SDK**

* `@flokit/subscriptions-sdk` v0.2.0 (React Native, TypeScript) — remote paywall rendering via `RemotePaywall` / `Paywall` / `fetchPaywallConfig`, native purchase support (`purchase`, `submitReceipt` with an injected StoreKit 2 / Play Billing adapter), entitlement gate (`fetchEntitlement`), paywall funnel events (`trackPaywallEvent`), and the app-scoped publishable key credential (`appKey` → `x-app-key`). See [SDKs](/sdks/overview).

**Live gateway endpoints**

* Paywall config — `GET /api/paywall/config` with deterministic A/B variant selection and a safe fallback response. See [Paywall API](/api-reference/paywall).
* Receipt verification — `POST /api/paywall/receipt` for Apple StoreKit 2 (JWS) and Google Play receipts.
* Entitlements — `GET /api/paywall/entitlement` and alias `GET /api/entitlements/current`. See [Entitlements API](/api-reference/entitlements).
* Paywall funnel analytics — `POST /api/paywall/events` accepting `impression`, `offer_tap`, `purchase_start`, `trial_start`, `convert`, and `cancel` events (1–50 per request) with edge-side country resolution.
* Provider webhook passthrough — raw-body receiver endpoints for Stripe, Apple, Google, RevenueCat, Adapty, generic subscription providers, and MMP attribution callbacks.

**Measurement ingest**

* MMP server-callback ingestion at `GET/POST /ingest/:vendor` with per-vendor secret auth, event deduplication (30-day window), and a `{ received, written, duplicate, dropped }` outcome — Adjust is the first supported vendor. See [Measurement ingest](/api-reference/measurement-ingest).

**Docs**

* New live-endpoint reference section (paywall, entitlements, measurement ingest).
* Architecture, flow, and lifecycle diagrams across getting-started, integrations, send-data, product, recipes, and API reference pages.
* Examples and SDKs sections added to the navigation.
* v1 REST API pages labeled as design-partner preview.

***

## June 2025 — Private Beta Launch

**Integrations**

* RevenueCat integration — connect via API key and optional webhook for real-time subscription events.
* Adapty integration — connect via API key and webhook for subscription and paywall events.
* AppsFlyer integration — connect via V2.0 API token for install and attribution data.
* Adjust integration — connect via API token and app token for install and attribution data.

**Reports**

* Payback reports with cohort windows at 30, 60, 90, 180, and 365 days.
* CAC, trial conversion rate, renewal rate, ROAS, and projected LTV by campaign, channel, country, creative, and offer.
* Action outcomes report — track performance impact of approved actions.

**Actions**

* Action queue with budget shift and creative pause recommendation types.
* Action lifecycle: draft → ready\_for\_approval → approved → running → completed | rolled\_back.
* Guardrails configuration — spend caps, confidence thresholds, excluded entities, rollback triggers.
* Manual approval required for all action types in beta.

**API**

* Events API — send server-side subscription and lifecycle events directly to FloKit (`POST https://YOUR-FLOKIT-API-HOST/v1/events`).
* Reports API — query payback and cohort data programmatically (`GET https://YOUR-FLOKIT-API-HOST/v1/reports/payback`).
* Actions API — approve and rollback actions via API (`POST https://YOUR-FLOKIT-API-HOST/v1/actions/{id}/approve`).

**Webhooks**

* `action.status_changed` — fired when an action moves between lifecycle states.
* `guardrail.triggered` — fired when a guardrail prevents an action from entering the approval queue or triggers a rollback.

See [Webhooks](/api-reference/webhooks) for payload schemas and delivery configuration.
