API Reference

Step 1. Get API key from project settings


Step 2. Add your deeplink in project settings

  1. Go to Deeplink tab
  2. Click on help icon on the right to the field to launch Helper
  3. Add base deeplink
    1. https://YYYYY.onelink.me/XXXXXX?af_xp=custom&pid=web2wave&deep_link_value=
  4. Add user properties you want to include
    1. Usually just user_id
  5. Final link will be inserted
    1. https://YYYYY.onelink.me/XXXXXX?af_xp=custom&pid=web2wave&deep_link_value=%7B%22user_id%22%3A%22{user_id}%22%7D&user_id={user_id}

After the purchase of a subscription on web, user will get this deeplink to install the app.


3. Read deeplink value and use "user_id" param to request web2wave API to get Subscription status

Here is an example for AppsFlyer:

  1. Read user_id from deeplink value using AppsFlyer

  2. Store user_id locally on the device

  3. Request web2wave API

    1. https://web2-tfsv.readme.io/reference/get_user-subscriptions
  4. If "subscriptions" array contains subscription with (subscription.status = active || subscription.status = trialing)

    • then don't show paywalls and give the user paid content
  5. Update subscription status on every app launch, if no result returned - use previous value

  6. In Subscription management section in the app show the user button with "manage_link" URL

  7. Use SDK to simplify requests

    iOS SDK – https://github.com/web2wave/web2wave_swift

    Flutter SDK – https://github.com/web2wave/web2wave_flutter

    Kotlin SDK – https://github.com/web2wave/web2wave_kotlin

    Java SDK – https://github.com/web2wave/web2wave_java


Sample code:

import UIKit
import AppsFlyerLib
import Adapty
import Web2Wave

class ViewController: UIViewController, DeepLinkDelegate {
    var userId: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        Adapty.activate("your_adapty_public_sdk_key")
        AppsFlyerLib.shared().deepLinkDelegate = self
        AppsFlyerLib.shared().start()
        
        if let userId = UserDefaults.standard.string(forKey: "userId") {
            fetchSubscriptionStatus(userId: userId)
        }
    }
    
    func didResolveDeepLink(_ result: DeepLinkResult) {
        guard case .found = result.status, let deepLink = result.deepLink else { return }
        handleDeepLink(deepLink: deepLink)
    }
    
    private func handleDeepLink(deepLink: DeepLink) {
        guard let deepLinkValue = deepLink["deep_link_value"] as? String,
              let data = deepLinkValue.data(using: .utf8),
              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let extractedUserId = json["user_id"] as? String else { return }
        
        self.userId = extractedUserId
        UserDefaults.standard.set(extractedUserId, forKey: "userId")
        fetchSubscriptionStatus(userId: extractedUserId)
    }
    
    private func fetchSubscriptionStatus(userId: String) async {
        // Fetch user subscriptions
        let isActive = await Web2Wave.shared.hasActiveSubscription(userID: userId)
        DispatchQueue.main.async {
            isActive ? self.providePaidContent() : self.showPaywall()
        }
    }
    
    private func providePaidContent() {
        print("User has an active subscription. Providing access to paid content.")
    }
    
    private func showPaywall() {
        print("No active subscription. Displaying paywall.")
    }
    
    // Example usage of Web2Wave library methods
    private func web2WaveExamples() async {
        guard let userId = userId else { return }
        
        // Fetch all user properties
        let properties = await Web2Wave.shared.fetchUserProperties(userID: userId)
        print("User properties: \(String(describing: properties))")
        
        // Update a user property
        let updateResult = await Web2Wave.shared.updateUserProperty(
            userID: userId,
            property: "theme",
            value: "dark"
        )
        if case .failure(let error) = updateResult {
            print("Failed to update user property: \(error)")
        }
        
        // Set Adapty Profile ID
        let adaptyResult = await Web2Wave.shared.setAdaptyProfileID(
            appUserID: userId,
            adaptyProfileID: "example_adapty_id"
        )
        if case .failure(let error) = adaptyResult {
            print("Failed to save Adapty profile ID: \(error)")
        }
    }
}
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.appsflyer.AppsFlyerLib
import com.appsflyer.deeplink.DeepLink
import com.appsflyer.deeplink.DeepLinkListener
import kotlinx.coroutines.*
import web2wave.Web2Wave
import org.json.JSONObject

class MainActivity : AppCompatActivity() {

    private val scope = CoroutineScope(Dispatchers.IO)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Web2Wave.initWith("YOUR_API_KEY_TO_WEB2WAVE")
        AppsFlyerLib.getInstance().apply {
            init("yourAppsFlyerDevKey", null, this@MainActivity)
            start(this@MainActivity)
            registerConversionListener(this@MainActivity, object : DeepLinkListener {
                override fun onDeepLinking(deepLink: DeepLink?) {
                    deepLink?.deepLinkValue?.let { handleDeepLink(it) }
                }
                override fun onAttributionFailure(error: String?) {
                    println("Failed deep link: $error")
                }
            })
        }
        getSharedPreferences("prefs", Context.MODE_PRIVATE)
            .getString("userId", null)?.let { fetchSubscriptionStatus(it) }
    }

    private fun handleDeepLink(deepLinkValue: String) {
        runCatching {
            JSONObject(deepLinkValue).getString("user_id").also {
                getSharedPreferences("prefs", Context.MODE_PRIVATE).edit().putString("userId", it).apply()
                fetchSubscriptionStatus(it)
            }
        }.onFailure { println("Failed to parse deep link: ${it.message}") }
    }

    private fun fetchSubscriptionStatus(userId: String) {
        scope.launch {
            val isActive = runCatching { Web2Wave.hasActiveSubscription(userId) }.getOrDefault(false)
            runOnUiThread { if (isActive) providePaidContent() else showPaywall() }
        }
    }

    private fun providePaidContent() = println("Access granted to paid content.")
    private fun showPaywall() = println("Displaying paywall.")
}
import 'package:flutter/material.dart';
import 'package:web2wave/web2wave.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Web2Wave.shared.initialize(apiKey: 'your-api-key');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String? userId;

  @override
  void initState() {
    super.initState();
    _initializeUser();
  }

  Future<void> _initializeUser() async {
    final prefs = await SharedPreferences.getInstance();
    final storedUserId = prefs.getString('userId');
    if (storedUserId != null) {
      setState(() {
        userId = storedUserId;
      });
      _fetchSubscriptionStatus(storedUserId);
    }
  }

  Future<void> _handleDeepLink(String deepLinkValue) async {
    try {
      final Map<String, dynamic> json = deepLinkValue as Map<String, dynamic>;
      final extractedUserId = json['user_id'] as String?;
      if (extractedUserId != null) {
        final prefs = await SharedPreferences.getInstance();
        await prefs.setString('userId', extractedUserId);
        setState(() {
          userId = extractedUserId;
        });
        _fetchSubscriptionStatus(extractedUserId);
      }
    } catch (e) {
      print('Failed to parse deep link: $e');
    }
  }

  Future<void> _fetchSubscriptionStatus(String userId) async {
    final isActive = await Web2Wave.shared.hasActiveSubscription(web2waveUserId: userId);
    if (isActive) {
      _providePaidContent();
    } else {
      _showPaywall();
    }
  }

  void _providePaidContent() {
    print("User has an active subscription. Providing access to paid content.");
  }

  void _showPaywall() {
    print("No active subscription. Displaying paywall.");
  }

  Future<void> _web2WaveExamples() async {
    if (userId == null) return;

    // Fetch user properties
    final properties = await Web2Wave.shared.fetchUserProperties(web2waveUserId: userId!);
    print("User properties: ${properties.toString()}");

    // Update a user property
    final updateResult = await Web2Wave.shared.updateUserProperty(
      web2waveUserId: userId!,
      property: "theme",
      value: "dark",
    );
    if (!updateResult.isSuccess) {
      print("Failed to update user property: ${updateResult.errorMessage}");
    }

    // Set Adapty Profile ID
    final adaptyResult = await Web2Wave.shared.setAdaptyProfileID(
      web2waveUserId: userId!,
      adaptyProfileId: "example_adapty_id",
    );
    if (!adaptyResult.isSuccess) {
      print("Failed to save Adapty profile ID: ${adaptyResult.errorMessage}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Web2Wave Example")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(userId != null ? "User ID: $userId" : "No User ID"),
            ElevatedButton(
              onPressed: _web2WaveExamples,
              child: Text("Test Web2Wave"),
            ),
          ],
        ),
      ),
    );
  }
}