Skip to content

Add offer selection API for subscriptions #2

Description

@proggeramlug

Today `js_play_billing_purchase(productId)` automatically picks the first `SubscriptionOfferDetails` returned by Play, which is typically "the cheapest available offer." That's the right default for the simple case but loses information for apps that want to show users a choice between offers — intro pricing, free trials, developer-defined promotional codes.

Current behavior

`PlayBillingBridge.purchase` (Kotlin):

```kotlin
val offer = product.subscriptionOfferDetails?.firstOrNull()
if (offer != null) builder.setOfferToken(offer.offerToken)
```

The TS surface already exposes `subscriptionOffers: SubscriptionOffer[]` per Product, including each offer's `offerToken`, `basePlanId`, `offerId`, `offerTags`, and `pricingPhases`. The data is there; the purchase entry point just doesn't accept it.

Proposed API

Add an optional second parameter:

```typescript
export declare function js_play_billing_purchase(
productId: string,
offerToken?: string,
): Promise;
```

When omitted, current behavior (cheapest auto-selected). When passed, the Kotlin side calls `setOfferToken(offerToken)` directly without inspecting the offer list.

Why deferred

The v0.1.x surface is a faithful port of issue #537's sketch (`purchase(productId): Promise`) and matches what the apps that triggered the issue actually need today. Offer selection is a real-world need but most apps don't expose it in their UI for v1; this can land independently when there's a real consumer.

Work

  • Add `offerToken` param to the FFI declaration in `package.json` + `src/index.ts`.
  • Add second parameter to the Rust `js_play_billing_purchase` export + JNI signature `(JLjava/lang/String;Ljava/lang/String;)V`.
  • Update `PlayBillingBridge.purchase` to accept `offerToken: String?` and use it when non-null.
  • Document the offer-selection flow in README.

Notes

  • Compatible with Apple's StoreKit 2 sibling (`@perryts/storekit`): StoreKit doesn't have a comparable offer concept, so the cross-platform API stays the same on the iOS side.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions