Use this page with AI Copy this into your coding assistant and add your request.
Read https://openiap.dev/docs/types/discount-offer and https://openiap.dev/llms.txt. Follow the reading instructions, detailed reference, and linked guides relevant to my task before making changes.
Inspect my existing project and reuse its framework and conventions. Ask me for missing product decisions. Implement the requested behavior and run the applicable checks.
Show the working result, the commands and actual test results, and any remaining limitations. Keep your explanation brief.
My request: [describe what customers should be able to do]See an example request → DiscountOffer DiscountOffer# DiscountOffer is the standardized representation of a Google Play one-time product purchase option or offer. OpenIAP populates ProductAndroid.discountOffers from ProductDetails.getOneTimePurchaseOfferDetailsList() on Google Play Billing Library 8.0+.
Each entry maps to ProductDetails.OneTimePurchaseOfferDetails and has the wire type one-time. Subscription introductory and promotional offers use SubscriptionOffer instead. iOS does not populate DiscountOffer.
Native references: Google · Multiple purchase options and offers for one-time products · ProductDetails.OneTimePurchaseOfferDetails
Common Fields# Field Type Description idIDUnique identifier for the offer displayPriceString!Formatted display price (e.g., "$4.99") priceFloat!Numeric price value currencyString!Currency code (ISO 4217, e.g., "USD") typeDiscountOfferType!Always one-time for DiscountOffer entries. The shared enum's introductory and promotional variants are used by SubscriptionOffer .
Android-Specific Fields# Field Type Description offerTokenAndroidStringRequired for purchase. Pass to requestPurchase()offerTagsAndroid[String!]Tags associated with this offer fullPriceMicrosAndroidStringOriginal price in micro-units (divide by 1,000,000) percentageDiscountAndroidIntPercentage discount (e.g., 33 for 33% off) discountAmountMicrosAndroidStringFixed discount amount in micro-units formattedDiscountAmountAndroidStringLocalized discount amount including the currency symbol (e.g., "$5.00") validTimeWindowAndroidValidTimeWindowAndroidTime window for limited-time offers limitedQuantityInfoAndroidLimitedQuantityInfoAndroidQuantity limits for the offer preorderDetailsAndroidPreorderDetailsAndroidPre-order details (Billing Library 8.1.0+) rentalDetailsAndroidRentalDetailsAndroidRental offer details purchaseOptionIdAndroidStringPurchase option ID for identifying which purchase option was selected (8.0+)
Type Definition# struct DiscountOffer: Codable {
// Common fields
let id: String?
let displayPrice: String
let price: Double
let currency: String
let type: DiscountOfferType
// Android-specific fields
let offerTokenAndroid: String?
let offerTagsAndroid: [String]?
let fullPriceMicrosAndroid: String?
let percentageDiscountAndroid: Int?
let discountAmountMicrosAndroid: String?
let formattedDiscountAmountAndroid: String?
let validTimeWindowAndroid: ValidTimeWindowAndroid?
let limitedQuantityInfoAndroid: LimitedQuantityInfoAndroid?
let preorderDetailsAndroid: PreorderDetailsAndroid?
let rentalDetailsAndroid: RentalDetailsAndroid?
let purchaseOptionIdAndroid: String?
}
enum DiscountOfferType: String, Codable {
case introductory = "introductory"
case promotional = "promotional"
case oneTime = "one-time"
}Kotlin example data class DiscountOffer(
// Common fields
val id: String? = null,
val displayPrice: String,
val price: Double,
val currency: String,
val type: DiscountOfferType,
// Android-specific fields
val offerTokenAndroid: String? = null,
val offerTagsAndroid: List<String>? = null,
val fullPriceMicrosAndroid: String? = null,
val percentageDiscountAndroid: Int? = null,
val discountAmountMicrosAndroid: String? = null,
val formattedDiscountAmountAndroid: String? = null,
val validTimeWindowAndroid: ValidTimeWindowAndroid? = null,
val limitedQuantityInfoAndroid: LimitedQuantityInfoAndroid? = null,
val preorderDetailsAndroid: PreorderDetailsAndroid? = null,
val rentalDetailsAndroid: RentalDetailsAndroid? = null,
val purchaseOptionIdAndroid: String? = null
)
enum class DiscountOfferType(val rawValue: String) {
Introductory("introductory"),
Promotional("promotional"),
OneTime("one-time")
}TypeScript example interface DiscountOffer {
// Common fields
id?: string | null;
displayPrice: string;
price: number;
currency: string;
type: DiscountOfferType;
// Android-specific fields
offerTokenAndroid?: string | null;
offerTagsAndroid?: string[] | null;
fullPriceMicrosAndroid?: string | null;
percentageDiscountAndroid?: number | null;
discountAmountMicrosAndroid?: string | null;
formattedDiscountAmountAndroid?: string | null;
validTimeWindowAndroid?: ValidTimeWindowAndroid | null;
limitedQuantityInfoAndroid?: LimitedQuantityInfoAndroid | null;
preorderDetailsAndroid?: PreorderDetailsAndroid | null;
rentalDetailsAndroid?: RentalDetailsAndroid | null;
purchaseOptionIdAndroid?: string | null;
}
type DiscountOfferType = 'introductory' | 'promotional' | 'one-time';
// DiscountOffer instances currently use only 'one-time'.Dart example class DiscountOffer {
// Common fields
final String? id;
final String displayPrice;
final double price;
final String currency;
final DiscountOfferType type;
// Android-specific fields
final String? offerTokenAndroid;
final List<String>? offerTagsAndroid;
final String? fullPriceMicrosAndroid;
final int? percentageDiscountAndroid;
final String? discountAmountMicrosAndroid;
final String? formattedDiscountAmountAndroid;
final ValidTimeWindowAndroid? validTimeWindowAndroid;
final LimitedQuantityInfoAndroid? limitedQuantityInfoAndroid;
final PreorderDetailsAndroid? preorderDetailsAndroid;
final RentalDetailsAndroid? rentalDetailsAndroid;
final String? purchaseOptionIdAndroid;
DiscountOffer({
this.id,
required this.displayPrice,
required this.price,
required this.currency,
required this.type,
this.offerTokenAndroid,
this.offerTagsAndroid,
this.fullPriceMicrosAndroid,
this.percentageDiscountAndroid,
this.discountAmountMicrosAndroid,
this.formattedDiscountAmountAndroid,
this.validTimeWindowAndroid,
this.limitedQuantityInfoAndroid,
this.preorderDetailsAndroid,
this.rentalDetailsAndroid,
this.purchaseOptionIdAndroid,
});
}
enum DiscountOfferType {
Introductory('introductory'),
Promotional('promotional'),
OneTime('one-time');
const DiscountOfferType(this.value);
final String value;
}C# (MAUI) example using OpenIap;
using OpenIap.Maui;
using System.Collections.Generic;
public sealed record DiscountOffer
{
// Common fields
public string? Id { get; init; }
public required string DisplayPrice { get; init; }
public required double Price { get; init; }
public required string Currency { get; init; }
public required DiscountOfferType Type { get; init; }
// Android-specific fields
public string? OfferTokenAndroid { get; init; }
public IReadOnlyList<string>? OfferTagsAndroid { get; init; }
public string? FullPriceMicrosAndroid { get; init; }
public int? PercentageDiscountAndroid { get; init; }
public string? DiscountAmountMicrosAndroid { get; init; }
public string? FormattedDiscountAmountAndroid { get; init; }
public ValidTimeWindowAndroid? ValidTimeWindowAndroid { get; init; }
public LimitedQuantityInfoAndroid? LimitedQuantityInfoAndroid { get; init; }
public PreorderDetailsAndroid? PreorderDetailsAndroid { get; init; }
public RentalDetailsAndroid? RentalDetailsAndroid { get; init; }
public string? PurchaseOptionIdAndroid { get; init; }
}
public enum DiscountOfferType
{
Introductory,
Promotional,
OneTime
}GDScript example class_name DiscountOffer
# Common fields
var id: Variant = null
var display_price: String = ""
var price: float = 0.0
var currency: String = ""
var type: DiscountOfferType
# Android-specific fields
var offer_token_android: Variant = null
var offer_tags_android: Array[String] = []
var full_price_micros_android: Variant = null
var percentage_discount_android: Variant = null
var discount_amount_micros_android: Variant = null
var formatted_discount_amount_android: Variant = null
var valid_time_window_android: ValidTimeWindowAndroid
var limited_quantity_info_android: LimitedQuantityInfoAndroid
var preorder_details_android: PreorderDetailsAndroid
var rental_details_android: RentalDetailsAndroid
var purchase_option_id_android: Variant = null
enum DiscountOfferType {
INTRODUCTORY,
PROMOTIONAL,
ONE_TIME
}