Custom Web API

Custom 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.

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.

const response = await fetch('https://api.botsi.com/api/v1/web-api/profiles', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    // Optional: pass any known user data
    customAttributes: {
      email: user.email,
      source: 'web_funnel'
    }
  })
});
const { data } = await response.json();
const profileId = data.profileId;

Step 2: Get Paywall Prediction

Fetch the AI-optimized paywall configuration for your user. The response includes the externalID that determines which pricing variant to display.

const paywallResponse = await fetch(`https://api.botsi.com/api/v1/web-api/profiles/${profileId}/get-paywall`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'YOUR_API_KEY'
  }
});
const paywall = await paywallResponse.json();
// paywall.data.externalID — use to determine which pricing to show
// paywall.data.id — numeric ID for impression tracking

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 an impression event to Botsi for analytics and model training.

await fetch(`https://api.botsi.com/api/v1/web-api/profiles/${profileId}/events`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    paywallId: paywall.data.id,  // Use numeric id, not externalID
    event: 'paywall_impression'
  })
});

Step 5: After Purchase — Validate with Botsi

After the user completes a purchase through your payment processor, validate the transaction with Botsi. This helps Botsi learn from successful conversions and improve pricing predictions.

For Stripe
POST /api/v1/web-api/purchases/stripe/validate
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://api.botsi.com/api/v1/web-api';

// 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',
        'X-API-Key': BOTSI_API_KEY
      },
      body: JSON.stringify({
        customAttributes: {
          email: userEmail,
          source: 'web_checkout',
          timestamp: new Date().toISOString()
        }
      })
    });

    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}/profiles/${profileId}/get-paywall`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': BOTSI_API_KEY
      }
    });

    const { data } = await response.json();
    return {
      paywallId: data.id,
      variant: data.externalID,
      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, paywallId) {
  try {
    await fetch(`${BOTSI_BASE_URL}/profiles/${profileId}/events`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': BOTSI_API_KEY
      },
      body: JSON.stringify({
        paywallId: paywallId,
        event: 'paywall_impression',
        timestamp: new Date().toISOString()
      })
    });
  } catch (error) {
    console.error('Failed to track impression:', error);
  }
}

// 4. Validate purchase after Stripe payment
async function validateStripePurchase(profileId, chargeId, amount) {
  try {
    const response = await fetch(`${BOTSI_BASE_URL}/purchases/stripe/validate`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': BOTSI_API_KEY
      },
      body: JSON.stringify({
        profileId: profileId,
        transactionId: chargeId,
        amount: amount,
        currency: 'usd'
      })
    });

    return await response.json();
  } catch (error) {
    console.error('Failed to validate purchase:', error);
    throw error;
  }
}

// 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.paywallId);
  }

  // Step 5: After user completes Stripe payment
  try {
    await validateStripePurchase(profileId, stripeChargeId, pricing.price);
  } catch (error) {
    console.error('Purchase validation failed:', error);
  }
}

Important Notes

  • API Key Security: Keep your API key on your server and never expose it in client-side code or version control
  • 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.