Native Mobile Paywall Display

Native Mobile Paywall Display

Build your own custom paywall UI without relying on third-party paywall SDKs. This integration allows you to call Botsi's API directly and render your own native paywall interface using SwiftUI, Jetpack Compose, or any other native UI framework.

This approach gives you complete control over the user experience while still leveraging Botsi's AI-powered pricing optimization. You handle the payment processing through native StoreKit (iOS) or Google Play Billing (Android), and report the results back to Botsi for validation and learning.

Prerequisites

  • Botsi AI Pricing configured in your account
  • Store connections set up (Apple App Store and/or Google Play Store)
  • API key from your Botsi dashboard
  • Basic knowledge of StoreKit 2 (iOS) or Google Play Billing Library (Android)

Integration Flow

  1. Create a Botsi Profile (POST /api/v1/web-api/profiles)
  2. Get Paywall prediction (POST /api/v1/web-api/profiles/{profileId}/get-paywall)
  3. Display your native paywall using the returned paywall data
  4. Send paywall impression event (POST /api/v1/web-api/profiles/{profileId}/events)
  5. Handle purchase through native StoreKit/Google Play Billing
  6. Validate purchase with Botsi

Code Examples

Swift Example

import Foundation

// 1. Create profile
func createBotsiProfile(apiKey: String) async throws -> String {
    var request = URLRequest(url: URL(string: "https://api.botsi.com/api/v1/web-api/profiles")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
    let (data, _) = try await URLSession.shared.data(for: request)
    let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
    let profileData = json["data"] as! [String: Any]
    return profileData["profileId"] as! String
}

// 2. Get paywall prediction
func getPaywall(profileId: String, apiKey: String) async throws -> [String: Any] {
    var request = URLRequest(url: URL(string: "https://api.botsi.com/api/v1/web-api/profiles/\(profileId)/get-paywall")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
    let (data, _) = try await URLSession.shared.data(for: request)
    return try JSONSerialization.jsonObject(with: data) as! [String: Any]
}

// 3. Send impression event
func sendImpression(profileId: String, paywallId: Int, apiKey: String) async throws {
    var request = URLRequest(url: URL(string: "https://api.botsi.com/api/v1/web-api/profiles/\(profileId)/events")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
    let body: [String: Any] = ["paywallId": paywallId, "event": "paywall_impression"]
    request.httpBody = try JSONSerialization.data(withJSONObject: body)
    let (_, _) = try await URLSession.shared.data(for: request)
}

Kotlin Example

import okhttp3.*
import org.json.JSONObject

// 1. Create profile
suspend fun createBotsiProfile(apiKey: String): String {
    val client = OkHttpClient()
    val request = Request.Builder()
        .url("https://api.botsi.com/api/v1/web-api/profiles")
        .post(RequestBody.create(null, ""))
        .addHeader("Content-Type", "application/json")
        .addHeader("X-API-Key", apiKey)
        .build()
    val response = client.newCall(request).execute()
    val json = JSONObject(response.body?.string() ?: "")
    return json.getJSONObject("data").getString("profileId")
}

// 2. Get paywall
suspend fun getPaywall(profileId: String, apiKey: String): JSONObject {
    val client = OkHttpClient()
    val request = Request.Builder()
        .url("https://api.botsi.com/api/v1/web-api/profiles/$profileId/get-paywall")
        .post(RequestBody.create(null, ""))
        .addHeader("Content-Type", "application/json")
        .addHeader("X-API-Key", apiKey)
        .build()
    val response = client.newCall(request).execute()
    return JSONObject(response.body?.string() ?: "")
}

Java Example

import java.net.HttpURLConnection;
import java.net.URL;

// 1. Create profile
public String createBotsiProfile(String apiKey) throws Exception {
    URL url = new URL("https://api.botsi.com/api/v1/web-api/profiles");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type", "application/json");
    conn.setRequestProperty("X-API-Key", apiKey);
    // Read response and parse profileId
    return profileId;
}

React Native Example

// 1. Create profile
const createProfile = async (apiKey) => {
  const response = await fetch('https://api.botsi.com/api/v1/web-api/profiles', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey }
  });
  const { data } = await response.json();
  return data.profileId;
};

// 2. Get paywall
const getPaywall = async (profileId, apiKey) => {
  const response = await fetch(`https://api.botsi.com/api/v1/web-api/profiles/${profileId}/get-paywall`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey }
  });
  return response.json();
};

Flutter Example

import 'dart:convert';
import 'package:http/http.dart' as http;

// 1. Create profile
Future<String> createBotsiProfile(String apiKey) async {
  final response = await http.post(
    Uri.parse('https://api.botsi.com/api/v1/web-api/profiles'),
    headers: {'Content-Type': 'application/json', 'X-API-Key': apiKey},
  );
  final data = jsonDecode(response.body)['data'];
  return data['profileId'];
}

Unity (C#) Example

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

IEnumerator CreateBotsiProfile(string apiKey) {
    var request = new UnityWebRequest("https://api.botsi.com/api/v1/web-api/profiles", "POST");
    request.SetRequestHeader("Content-Type", "application/json");
    request.SetRequestHeader("X-API-Key", apiKey);
    request.downloadHandler = new DownloadHandlerBuffer();
    yield return request.SendWebRequest();
    var json = JsonUtility.FromJson<ProfileResponse>(request.downloadHandler.text);
    string profileId = json.data.profileId;
}

Implementation Notes

  • Keep your API key secure on the server side; never expose it in client-side code
  • Use the externalID from the paywall response to determine which pricing variant to display
  • Use the numeric id from the paywall response when sending impression events
  • Handle network errors gracefully and provide fallback pricing options
  • Test thoroughly in sandbox mode before releasing to production
  • For more detailed API information, see the API reference