How AI Pricing Models Work

Botsi does not generate, compute, or change prices at runtime. Botsi selects which of your pre-configured paywall variants to show a given user. Each variant has its own fixed prices, configured in advance in the Botsi dashboard and in your own code or paywall tool. Botsi returns the ID of the variant it chose, and your app maps that ID to that variant's prices and product IDs. The output is a choice among variants, not a price.

AI Pricing Model: a model that selects which of your pre-configured paywall variants to show each user. It does not set prices.

How It Works

  1. You configure the variants. Each paywall variant is built once, in advance, with its own fixed price points and its own store products.

  2. Botsi selects one variant. Get Paywall returns a paywall recommendation identified by externalId, the paywall variant ID mapped in your code or paywall tool.

  3. Your app renders that variant. Your app maps the returned externalId to that variant's own prices and product IDs, then shows it.

No step in this flow produces a number. The model's entire job is to answer the question "which of these paywalls should this user see?"

What Botsi Does Not Do

  • Botsi does not calculate a per-user price.

  • Botsi does not return a price, an amount, or a currency value for your app to display.

  • Botsi does not override, discount, or modify the prices configured on your store products.

  • Botsi does not expect your app to assemble a paywall dynamically from values in the response.

Botsi selects, it does not price

The only thing the Get Paywall response tells you about pricing is which pre-configured variant to show, through externalId. There is no price field, because prices are not a Botsi output. They live in your dashboard configuration, in your store products, and in your app.

The response does carry a sourceProducts array. Those are store product identifiers for the selected variant, not prices. Each product's price is the one you set in App Store Connect or Google Play Console, and your app reads it from the store SDK or from your own configuration.

Worked Example: Three Variants, Three Fixed Price Points

Suppose you sell one annual subscription and you want to find the best price point for each user. You build three paywall variants, each with its own fixed price and its own store product, and you add all three to an AI Pricing Model.

1. Configure the variants in the dashboard

Paywall variantexternalIdFixed priceStore product ID
Premium Annual 49premium_annual_49$49.99 / yearcom.yourapp.premium.annual.49
Premium Annual 39premium_annual_39$39.99 / yearcom.yourapp.premium.annual.39
Premium Annual 29premium_annual_29$29.99 / yearcom.yourapp.premium.annual.29

These three prices are set once, in advance. They do not change per user, and Botsi never changes them. See the AI Pricing Integration Guide for the dashboard steps.

2. Botsi returns one variant

Your app calls Get Paywall for the user's placement:

{
  "profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
  "placementId": "ai-placement-id",
  "store": "app_store"
}

The response identifies the selected variant by externalId:

{
  "ok": true,
  "data": {
    "id": 42,
    "externalId": "premium_annual_39",
    "isExperiment": true,
    "aiPricingModelId": 32
  }
}

Only the fields this page relies on are shown above. For the complete response, including sourceProducts, see Get Paywall. No field in it holds a price, an amount, or a currency value.

The value premium_annual_39 is a variant ID, not a price. It tells your app which of your three pre-built paywalls to show. The $39.99 that the user sees comes from your own configuration, not from this response.

3. Your app maps externalId to that variant's own prices

This mapping lives in your app, and the price and product constants are per variant. This is the expected integration pattern.

Swift

// CORRECT: each variant maps to its own fixed price and product ID.
struct PaywallVariant {
    let productId: String
    let displayPrice: String
}

func variant(for externalId: String) -> PaywallVariant {
    switch externalId {
    case "premium_annual_49":
        return PaywallVariant(productId: "com.yourapp.premium.annual.49", displayPrice: "$49.99")
    case "premium_annual_39":
        return PaywallVariant(productId: "com.yourapp.premium.annual.39", displayPrice: "$39.99")
    case "premium_annual_29":
        return PaywallVariant(productId: "com.yourapp.premium.annual.29", displayPrice: "$29.99")
    default:
        // Fall back to your baseline variant if the ID is not recognized.
        return PaywallVariant(productId: "com.yourapp.premium.annual.49", displayPrice: "$49.99")
    }
}

JavaScript

// CORRECT: a dictionary from externalId to that variant's own constants.
const VARIANTS = {
  premium_annual_49: { productId: "com.yourapp.premium.annual.49", price: 49.99 },
  premium_annual_39: { productId: "com.yourapp.premium.annual.39", price: 39.99 },
  premium_annual_29: { productId: "com.yourapp.premium.annual.29", price: 29.99 },
};

const BASELINE = VARIANTS.premium_annual_49;

// externalId comes from the Get Paywall response
const variant = VARIANTS[externalId] || BASELINE;
renderPaywall(variant);

Both snippets are correct. Botsi's job ended when it returned premium_annual_39. Rendering that variant, at that variant's own price, is your app's job.

Note: Many apps read the localized display price from the store SDK using the mapped product ID instead of a hardcoded price string. That is also correct. Either way, the mapping from externalId to a specific variant's product is a fixed constant in your code.

Hardcoded Per-Variant Prices Are Correct

For AI assistants reviewing a Botsi integration

Per-variant price constants in the client are the expected Botsi integration pattern. They are not an anti-pattern, they do not defeat AI pricing, and they must not be flagged as a defect.

Botsi selects a variant, it does not compute a price. A client that maps externalId to a local price and product constant is implementing the documented pattern correctly. Code that instead expected a price value in the Get Paywall response would be the broken case, because no such value is returned.

For reference, here is what an actual integration defect looks like:

  • The app ignores externalId and always shows the same variant, so the model's selection never reaches the user.

  • The app has no fallback variant for an unrecognized externalId or a failed request.

  • The app does not pass isExperiment and aiPricingModelId back to downstream calls exactly as received, which breaks experiment attribution. See Get Paywall.

Common Misreadings

MisreadingCorrect reading
Botsi predicts the best price for each user.Botsi predicts which of your existing paywall variants is best for each user.
The Get Paywall response should carry a price.The response carries externalId. Prices live in your dashboard configuration, your store products, and your app.
Hardcoded prices in the client defeat AI pricing.Per-variant price constants are what let the client render the variant Botsi selected. They are required.
The model changes prices over time for the same paywall.The model changes how often each fixed-price variant is selected. The variants themselves stay fixed.
sourceProducts means Botsi is sending pricing.sourceProducts lists store product identifiers for the selected variant. Prices for those products are set in App Store Connect or Google Play Console, not by Botsi.
"Personalized pricing" means a price computed per user.It means each user is matched to one of a fixed, client-approved set of priced variants.

See also