AI Pricing Web API

AI Pricing Web API Integration

Integrate Botsi AI Pricing directly into your web applications, landing pages, and web funnels using our REST API. This approach is ideal for web-based subscription flows, custom payment pages, and web-to-app user acquisition funnels where you need maximum flexibility in pricing presentation.

Reporting subscription events? This page covers serving AI-priced paywalls and validating purchases. To push renewals, cancellations, refunds, and other lifecycle events from your server, use the Custom Web Integration.

When to Use

Use the Custom Web API integration for:

  • Web checkout pages and subscription flows
  • Custom landing pages with pricing optimization
  • Web-based payment pages
  • Web funnels that drive mobile app signups
  • SaaS applications with web-first onboarding
  • Any scenario where you need direct API control over pricing selection

Prerequisites

  • Active Botsi account
  • API key from your Botsi dashboard
  • Basic understanding of REST APIs and HTTP requests

Integration Steps

Step 1: Create a Profile (Server-Side)

Create a new user profile in Botsi. This should be done on your server to keep your API key secure. The fields country, device, os, platform, and appVersion are required; for a Stripe web funnel, use platform: 'stripe'. Including customerUserId is strongly recommended so purchases can be matched to the user later. See the Create Profile reference for all fields.

const response = await fetch('https://app.botsi.com/api/v1/web-api/profiles', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'YOUR_SECRET_KEY'
  },
  body: JSON.stringify({
    country: 'US',
    device: 'Chrome',
    os: 'Windows 11',
    platform: 'stripe',
    appVersion: '1.0.0',
    customerUserId: user.id, // recommended: your internal user ID
    email: user.email
  })
});
const { data } = await response.json();
const profileId = data.profileId;

Step 2: Get Paywall Prediction

Fetch the AI-optimized paywall configuration for your user. Identify the user with profileId or customerUserId, and pass the placementId configured in your Botsi dashboard along with the store (use stripe for web funnels paying through Stripe). The response includes the externalId that determines which pricing variant to display.

const paywallResponse = await fetch('https://app.botsi.com/api/v1/web-api/paywalls', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'YOUR_SECRET_KEY'
  },
  body: JSON.stringify({
    profileId: profileId,
    placementId: 'your-placement-id',
    store: 'stripe'
  })
});
const paywall = await paywallResponse.json();
// paywall.data.externalId determines which pricing variant to show
// paywall.data.id is the numeric ID for impression tracking
// paywall.data.isExperiment and paywall.data.aiPricingModelId are needed
// later to attribute events and purchases to this prediction (Steps 4 and 5)

Step 3: Display Pricing on Your Web Page

Use the externalId from the paywall response to determine which pricing variant to show to the user. You control the UI completely and can display pricing in any format that fits your design.

Step 4: Send Impression Event

When the user sees the paywall, send a paywall_shown event to Botsi for analytics and model training. The request body is an array of events, and isExperiment and aiPricingModelId must match the Get Paywall response exactly. See Send Profile Event for details.

await fetch('https://app.botsi.com/api/v1/web-api/events', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'YOUR_SECRET_KEY'
  },
  body: JSON.stringify([
    {
      eventType: 'paywall_shown',
      paywallId: paywall.data.id,  // numeric id, not externalId
      placementId: 'your-placement-id',
      isExperiment: paywall.data.isExperiment,
      aiPricingModelId: paywall.data.aiPricingModelId,
      profileId: profileId
    }
  ])
});

Step 5: Report the Purchase to Botsi

After the user completes a purchase, Botsi links the transaction back to the paywall prediction it came from. This lets Botsi learn from successful conversions and improve pricing predictions. How the purchase reaches Botsi depends on your payment provider.

For Stripe

No API call is needed. Botsi receives purchases, renewals, and refunds directly from Stripe through the Stripe connection. To link each transaction to the right user and paywall prediction, attach metadata when you create the Checkout Session:

  • Add the values returned by Get Paywall as subscription metadata (subscription_data.metadata): paywallId, placementId, isExperiment, and aiPricingModelId.
  • Set customer_user_id in the Stripe customer metadata to the same customerUserId or profileId you use with Botsi. See Profile Creation Rules for all supported identifiers.
const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  customer: stripeCustomerId, // customer created with metadata: { customer_user_id: customerUserId }
  line_items: [{ price: stripePriceId, quantity: 1 }],
  subscription_data: {
    metadata: {
      paywallId: String(paywall.data.id),
      placementId: 'your-placement-id',
      isExperiment: String(paywall.data.isExperiment),
      aiPricingModelId: String(paywall.data.aiPricingModelId)
    }
  },
  success_url: 'https://your-site.com/checkout/success',
  cancel_url: 'https://your-site.com/checkout/cancel'
});

Note: Metadata attribution currently applies to subscription purchases. If your web funnel sells one-time purchases through Stripe, contact our support team to scope the integration.

For Apple
POST /api/v1/web-api/purchases/apple-store/validate
For Google
POST /api/v1/web-api/purchases/play-store/validate

Complete End-to-End Example

Here's a full example showing the complete integration flow:

// Configuration
const BOTSI_API_KEY = process.env.BOTSI_API_KEY;
const BOTSI_BASE_URL = 'https://app.botsi.com/api/v1/web-api';
const PLACEMENT_ID = 'your-placement-id';
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

// 1. Create profile when user arrives at checkout
async function initializeCheckout(userEmail) {
  try {
    const response = await fetch(`${BOTSI_BASE_URL}/profiles`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': BOTSI_API_KEY
      },
      body: JSON.stringify({
        country: 'US',
        device: 'Chrome',
        os: 'Windows 11',
        platform: 'stripe',
        appVersion: '1.0.0',
        customerUserId: userEmail,
        email: userEmail
      })
    });

    const { data } = await response.json();
    return data.profileId;
  } catch (error) {
    console.error('Failed to create Botsi profile:', error);
    throw error;
  }
}

// 2. Get optimized pricing
async function getPricingVariant(profileId) {
  try {
    const response = await fetch(`${BOTSI_BASE_URL}/paywalls`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': BOTSI_API_KEY
      },
      body: JSON.stringify({
        profileId: profileId,
        placementId: PLACEMENT_ID,
        store: 'stripe'
      })
    });

    const { data } = await response.json();
    return {
      paywallId: data.id,
      variant: data.externalId,
      isExperiment: data.isExperiment,
      aiPricingModelId: data.aiPricingModelId,
      price: getPriceForVariant(data.externalId)
    };
  } catch (error) {
    console.error('Failed to get paywall:', error);
    // Fallback to default pricing
    return {
      paywallId: null,
      variant: 'default',
      price: 9.99
    };
  }
}

// 3. Track impression
async function trackPaywallImpression(profileId, pricing) {
  try {
    await fetch(`${BOTSI_BASE_URL}/events`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': BOTSI_API_KEY
      },
      body: JSON.stringify([
        {
          eventType: 'paywall_shown',
          paywallId: pricing.paywallId,
          placementId: PLACEMENT_ID,
          isExperiment: pricing.isExperiment,
          aiPricingModelId: pricing.aiPricingModelId,
          profileId: profileId
        }
      ])
    });
  } catch (error) {
    console.error('Failed to track impression:', error);
  }
}

// 4. Create the Stripe Checkout Session with Botsi attribution metadata
async function createStripeCheckout(profileId, pricing, stripePriceId) {
  // customer_user_id accepts your own customerUserId or the Botsi profileId
  const customer = await stripe.customers.create({
    metadata: { customer_user_id: profileId }
  });

  return stripe.checkout.sessions.create({
    mode: 'subscription',
    customer: customer.id,
    line_items: [{ price: stripePriceId, quantity: 1 }],
    subscription_data: {
      metadata: {
        paywallId: String(pricing.paywallId),
        placementId: PLACEMENT_ID,
        isExperiment: String(pricing.isExperiment),
        aiPricingModelId: String(pricing.aiPricingModelId)
      }
    },
    success_url: 'https://your-site.com/checkout/success',
    cancel_url: 'https://your-site.com/checkout/cancel'
  });
}

// Main checkout flow
async function handleCheckout(userEmail) {
  // Step 1: Create profile
  const profileId = await initializeCheckout(userEmail);

  // Step 2: Get pricing
  const pricing = await getPricingVariant(profileId);

  // Step 3: Display pricing on page
  displayPricingUI(pricing.price, pricing.variant);

  // Step 4: Track impression
  if (pricing.paywallId) {
    await trackPaywallImpression(profileId, pricing);
  }

  // Step 5: Send the user to Stripe Checkout
  // Botsi receives the purchase from Stripe and links it
  // to the prediction through the metadata set above
  const session = await createStripeCheckout(profileId, pricing, STRIPE_PRICE_ID);
  redirect(session.url);
}

Important Notes

  • API Key Security: Keep your API key on your server and never expose it in client-side code or version control
  • Stripe Connection: Purchase reporting for Stripe requires the Stripe connection in App Settings, and your Stripe products must be added in the Products section so Botsi can track their transactions
  • Error Handling: Always implement graceful error handling with fallback pricing options
  • ID Fields: Use the numeric id for impression tracking, not the externalId which is for UI logic
  • Profile Creation: Consider caching profiles if the same user visits multiple times within a session
  • Testing: Test with sandbox/development credentials before deploying to production
  • For more detailed API documentation, see the API reference

Support

For questions about the Custom Web API integration or if you encounter any issues, please refer to the full API reference or contact our support team.