Skip to main content

Quick Start Integration Guide

N.B: The documentation is still undergoing standardization, please report any issues you had while following the guide.

SolydFlow is the revenue infrastructure for African mobile/web apps.

It unifies app stores (Apple App Store and Google Play), local African payment gateways (Paystack and Flutterwave), and Stripe for global coverage and portability into a single API.

Beyond payment aggregation, SolydFlow includes Smart Payment Routing, allowing transactions to be automatically routed to the payment rail most likely to succeed based on the customer's region, currency, and available payment methods.

Built for the realities of emerging markets, SolydFlow provides:

  • Offline entitlement access, so users can continue accessing paid features even when connectivity is unstable.
  • Transaction recovery, ensuring successful payments are restored even if the app closes before completion.
  • Churn protection tools that help recover subscribers before they cancel or expire.
  • A single dashboard for managing products, pricing, entitlements, and payment providers.

This guide walks you through setting up your project, connecting payment providers, configuring products, and integrating the SolydFlow SDK into your Flutter application.


How SolydFlow Works

At a high level, SolydFlow sits between your application and your payment providers.

Customer

Your App

SolydFlow SDK

SolydFlow Platform

Paystack / Flutterwave / Stripe

Payment Verified

Entitlement Activated

Premium Features Unlocked

What Happens During a Purchase?

  1. A customer selects a product in your application.
  2. SolydFlow initiates the payment with the configured payment provider.
  3. The payment provider confirms the transaction.
  4. SolydFlow verifies the payment and activates the associated entitlement.
  5. The SDK updates the customer's access locally and remotely.
  6. Premium content or features become immediately available.

Why Entitlements Matter

An entitlement represents access, not a product.

For example:

PackageEntitlement
gold_monthlygold_access
gold_yearlygold_access

Although the customer purchased different packages, both unlock the same entitlement (gold_access).

This allows you to manage access consistently regardless of billing period, currency, or payment provider.


Smart Payment Routing

SolydFlow can automatically route payments to the most appropriate payment provider based on currency, geography, and configured routing rules.

This helps improve conversion rates by reducing failed card transactions and directing users to payment methods that are commonly used in their region.

Example Routing Flow

Customer (NGN)

SolydFlow Smart Router

Monnify Virtual Account
Customer (KES)

SolydFlow Smart Router

M-Pesa STK Push
Customer (USD)

SolydFlow Smart Router

Stripe

Supported Payment Rails

Payment RailBest For
PaystackGeneral African card payments
FlutterwaveGeneral African card payments
MonnifyNigerian virtual accounts
M-Pesa / DarajaKenyan mobile money payments
StripeGlobal card payments

Routing rules are configured from the SolydFlow Console and require no application code changes.


Prerequisites


Step 1: Configure Your Project in the SolydFlow Console

Before writing code, you need to configure your project in the SolydFlow Console.

1. Create a Project

Log in to the SolydFlow Console and click New Project.

Enter your application's name and create the project.

After creation, you'll receive:

  • Public Key (sf_pk_...): Used by your mobile application.
  • Secret Key (sf_sk_...): Used only by your backend services.

Keep your Secret Key private and never expose it inside your mobile application.


2. Connect Your Payment Providers

SolydFlow follows a secure Bring Your Own Keys (BYOK) model. This ensures you maintain direct ownership of your merchant accounts, payouts, and compliance, while SolydFlow orchestrates the intelligence and routing.

Navigate to SolydFlow Console → Projects → Configuration (Settings Icon) to access your API Credentials Vault and connect the payment providers you want to use.

Depending on your target markets, configure the following providers:

(Click any provider above to view their specific key and webhook setup guide).

Production-ready providers

  • Paystack
  • Flutterwave
  • Stripe

Currently in testing

  • Apple In-App Purchases
  • Google Play Billing

Overview for each provider:

  1. Paste your provider's Secret Key.
  2. Save the configuration.
  3. Copy the SolydFlow Webhook URL displayed in the dashboard.
  4. Add the webhook URL to your payment provider's dashboard.

Webhook integration enables:

  • Automatic payment verification
  • Transaction recovery
  • Background subscription synchronization
  • Restoration of interrupted purchases

Connecting Paystack to SolydFlow

Connect your Paystack account to enable payment monitoring, transaction recovery, and financial consensus across your revenue infrastructure.

By integrating Paystack, SolydFlow's Consensus Engine, Sweeper, and Immutable Ledger continuously monitor transaction states and eliminate revenue uncertainty.

Prerequisites

  • An active Paystack account (Live or Test mode).
  • A SolydFlow project.

Step 1: Add Your Paystack Secret Keys to SolydFlow

SolydFlow requires your Paystack Secret Keys to initialize payments and independently verify transaction states directly from Paystack's API.

  1. Log in to your Paystack Dashboard.
  2. Navigate to Settings → API Keys & Webhooks.
  3. Copy your Secret Key (sk_live_... and sk_test_...).
  4. Log in to the SolydFlow Console.
  5. Open your Project settings.
  6. Navigate to API Credentials Vault.
  7. Paste your Paystack Secret Keys into the Paystack section.
  8. Click Save Configuration.

Security Note: All gateway credentials are encrypted using AES-256-GCM and are never exposed to client applications.


Step 2: Configure the Inbound Webhook

Paystack must notify SolydFlow when payment activity occurs.

  1. In the SolydFlow Console, open Inbound Gateway Webhook Configurations.
  2. Copy your Paystack Webhook URL:
https://api.solydflow.com/api/v1/webhook/paystack/{your_solydflow_api_key}
  1. Log in to Paystack.
  2. Navigate to Settings → API Keys & Webhooks.
  3. Paste the SolydFlow URL into the Webhook URL field.
  4. Save your configuration.

How SolydFlow Secures Paystack Events

SolydFlow never grants access based solely on a webhook payload.

When Paystack sends an event:

  1. SolydFlow intercepts the webhook.
  2. The Consensus Engine pauses entitlement activation.
  3. SolydFlow securely queries Paystack's Verify Transaction API using your encrypted Secret Key.
  4. The returned transaction state is compared against the webhook payload.
  5. If both states agree, SolydFlow records a SETTLED_CONSENSUS event in the Immutable Ledger.
  6. Access is granted.

This prevents:

  • Webhook spoofing
  • Replay attacks
  • State manipulation
  • False payment confirmations

What SolydFlow Monitors

Once connected, SolydFlow continuously tracks:

  • Successful transactions
  • Delayed callbacks
  • Missing webhooks
  • Abandoned checkouts
  • Zombie transactions
  • State mismatches

These signals power Recover, Truth, and Enforce across your payment infrastructure.


Connecting Flutterwave to SolydFlow

Connect your Flutterwave account to enable transaction recovery, payment verification, and financial consensus across your revenue stack.

By integrating Flutterwave, SolydFlow's Consensus Engine continuously verifies transaction states before access is granted to customers.

Prerequisites

  • An active Flutterwave account (Live or Test mode).
  • A SolydFlow project.

Step 1: Add Your Flutterwave Secret Keys to SolydFlow

SolydFlow requires your Flutterwave Secret Keys to independently verify transactions and eliminate trust in client-side responses.

  1. Log in to your Flutterwave Dashboard.
  2. Navigate to Settings → API Keys.
  3. Copy your Secret Key (FLWSECK_TEST... and FLWSECK_LIVE...).
  4. Log in to the SolydFlow Console.
  5. Open your Project settings.
  6. Navigate to API Credentials Vault.
  7. Paste your Flutterwave Secret Keys into the Flutterwave section.
  8. Click Save Configuration.

Security Note: SolydFlow encrypts all gateway credentials using AES-256-GCM before storage.


Step 2: Configure the Inbound Webhook

Flutterwave must notify SolydFlow whenever transaction activity occurs.

  1. In the SolydFlow Console, open Inbound Gateway Webhook Configurations.
  2. Copy your Flutterwave Webhook URL:
https://api.solydflow.com/api/v1/webhook/flutterwave/{your_solydflow_api_key}
  1. Log in to Flutterwave.
  2. Navigate to Settings → Webhooks.
  3. Paste the SolydFlow URL.
  4. Save your webhook configuration.

How SolydFlow Secures Flutterwave Events

Unlike traditional integrations, SolydFlow does not blindly trust incoming webhooks.

When Flutterwave sends a payment event:

  1. SolydFlow receives the webhook.
  2. The Consensus Engine pauses entitlement activation.
  3. SolydFlow queries Flutterwave's transaction verification API using your encrypted Secret Key.
  4. The API response is compared against the webhook payload.
  5. If consensus is reached, a SETTLED_CONSENSUS record is written to the Immutable Ledger.
  6. User access is activated.

This guarantees financial truth even when:

  • Webhooks arrive late
  • Duplicate events are received
  • Client responses are manipulated
  • Network interruptions occur

What SolydFlow Monitors

After connection, SolydFlow actively monitors:

  • Successful payments
  • Pending transactions
  • Failed callbacks
  • Missing webhooks
  • Delayed settlements
  • Zombie transactions
  • Ledger conflicts

These signals feed SolydFlow Recover, Truth, and Enforce to ensure every payment reaches a final and correct state.


Connecting Stripe to SolydFlow

Connect your Stripe account to enable global card processing. By integrating Stripe, SolydFlow's Consensus Engine and Sweeper can actively monitor your international transactions, resolve state mismatches, and automate recovery workflows.

Prerequisites

  • An active Stripe account (Live or Test mode).
  • A SolydFlow project.

Step 1: Add Your Stripe Keys to SolydFlow

SolydFlow requires your Stripe Secret Keys to securely initialize payments and verify transaction status directly with the Stripe API (bypassing client-side spoofing).

  1. Log in to your Stripe Dashboard.
  2. Navigate to Developers → API Keys.
  3. Copy your Secret Key (sk_live_... and sk_test_...).
  4. Log in to the SolydFlow Console.
  5. Go to your Project settings and open the API Credentials Vault.
  6. Paste your Stripe Secret Keys into the Stripe section and click Save Configuration.

Security Note: SolydFlow uses military-grade AES-256-GCM encryption to store your Secret Keys at rest.


Step 2: Configure the Inbound Webhook

Stripe must notify SolydFlow whenever a payment completes. SolydFlow uses a cryptographically secure webhook endpoint unique to your project.

  1. In the SolydFlow Console, scroll down to Inbound Gateway Webhook Configurations.
  2. Copy your unique Stripe Webhook URL: https://api.solydflow.com/api/v1/webhook/stripe/{your_solydflow_api_key}
  3. In your Stripe Dashboard, navigate to Developers → Webhooks → Add Endpoint.
  4. Paste the SolydFlow URL.
  5. Under Select Events, add payment_intent.succeeded. (SolydFlow's Consensus Engine will automatically query the API for the rest of the required data).
  6. Click Add Endpoint.

How SolydFlow Secures Stripe Events

Unlike standard integrations, SolydFlow does not blindly trust incoming webhooks.

When Stripe fires a webhook to SolydFlow, our Layer 2 Consensus Engine activates:

  1. We intercept the webhook.
  2. We pause the entitlement grant.
  3. We securely query the Stripe REST API using your encrypted sk_live_... key.
  4. If the live API confirms the webhook payload, we log a SETTLED_CONSENSUS event to your Immutable Ledger and grant the user access.

This completely eliminates Webhook Replay attacks and guarantees Absolute Financial Truth.

3. Create Entitlements

Entitlements represent the access level a customer receives after a successful purchase.

Examples:

  • pro_access
  • gold_access
  • enterprise_access

Think of an entitlement as the permission that unlocks premium features inside your application.


4. Create Packages

Packages are the products customers actually purchase.

Examples:

  • gold_monthly
  • gold_yearly
  • pro_monthly
  • pro_annual

Each package should be mapped to an entitlement.

Example:

PackageEntitlement
gold_monthlygold_access
gold_yearlygold_access

Both subscriptions unlock the same access level even though they have different billing periods.


5. Configure Regional Pricing

When creating packages, SolydFlow can automatically suggest localized pricing across supported regions using Smart Suggestions.

This helps maintain purchasing-power parity across currencies such as:

  • NGN
  • KES
  • GHS
  • ZAR
  • USD
  • EUR

You can accept the suggested pricing or customize prices manually for each market.

6. Configure Payment Routing Rules

SolydFlow allows you to define routing rules that determine which payment provider should be used for specific currencies or markets.

Navigate to:

Settings → Payment Routing Rules

Configure:

  • A default payment provider.
  • Currency-specific routing overrides.
  • Local payment rail preferences.

Example:

CurrencyRoute To
NGNMonnify
KESM-Pesa
USDStripe
OtherPaystack

These rules can be updated without releasing a new version of your application.


Step 2: Install the SDK

Add SolydFlow to your Flutter project's pubspec.yaml.

dependencies:
flutter:
sdk: flutter

solydflow_flutter:
git:
url: https://github.com/solydflow/solydflow_flutter.git
path: sdk_flutter
ref: v0.8.0

After updating your dependencies, run:

flutter pub get

Platform Requirements

Android

SolydFlow requires Android API Level 21 (Android 5.0) or higher.

Open:

android/app/build.gradle

or

android/app/build.gradle.kts

and ensure:

defaultConfig {
minSdkVersion = 21
}

iOS

If you are participating in Apple In-App Purchase testing, enable the In-App Purchase capability in Xcode.

  1. Open:
ios/Runner.xcworkspace
  1. Navigate to:
Signing & Capabilities
  1. Click:
+ Capability
  1. Add:
In-App Purchase

Apple In-App Purchase support is currently in testing. Most Paystack and Flutterwave integrations do not require this step.


Step 3: Initialize SolydFlow

Initialize SolydFlow as early as possible in your application's lifecycle, ideally before rendering your first screen.

import 'package:flutter/material.dart';
import 'package:solydflow_flutter/solydflow_flutter.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();

await SolydFlow.configure(
apiKey: "sf_pk_your_public_key",
userID: "unique_user_id",
userPhone: "2348012345678",
userEmamil: "user@mail.com"
);

runApp(const MyApp());
}

Configuration Parameters

apiKey

Your project's public API key.

You can find this in your SolydFlow project dashboard.

Example:

sf_pk_xxxxxxxxxxxxxxxxx

userID

A unique identifier for the currently authenticated user in your application.

Examples:

  • Firebase UID
  • Supabase User ID
  • Internal database user ID

This value is used to:

  • Track purchases
  • Restore access across devices
  • Sync entitlements
  • Recover interrupted transactions

Example:

user_12345

The user's phone number in international format.

Example:

2348012345678

Providing a phone number enables SolydFlow features such as:

  • Subscription recovery campaigns
  • Churn prevention messaging
  • Customer re-engagement workflows
  • and local payment rails such as M-Pesa.

If a phone number is not available, M-Pesa can not be used, you can then pass empty string for the phone number field and SolydFlow will continue to function normally.


When Should Initialization Happen?

Initialize SolydFlow:

  • After the user has authenticated.
  • Before checking entitlements.
  • Before displaying a paywall.
  • Before making purchases.

If your application supports guest users, initialize SolydFlow with a temporary identifier and reconfigure it once the user signs in.


Step 4: Choose Your Integration Strategy

SolydFlow supports two different integration approaches.

Choose the one that best matches your team's workflow and product requirements.

OptionBest For
Custom UITeams that want complete control over the paywall experience and design.
No-Code PaywallTeams that want to design, update, and publish paywalls directly from the SolydFlow Console without releasing a new app version.

Option A: Custom UI

With the Custom UI approach, your application fetches products from SolydFlow and renders them using your own Flutter widgets and layouts.

This gives you complete control over:

  • Design
  • User experience
  • Layout
  • Product presentation

Fetch your available packages:

Future<void> loadProducts() async {
List<SolydPackage> offerings = await SolydFlow.getOfferings();

for (var pkg in offerings) {
if (pkg.isUpgrade) {
print(
"Upgrade Price: ${pkg.currency} ${pkg.calculatedAmountKobo / 100}"
);
} else {
print(
"Base Price: ${pkg.currency} ${pkg.amountKobo / 100}"
);
}
}
}

The returned packages can be displayed in any UI design you choose.


Purchase a Package

When a user selects a package, initiate the purchase flow:

Future<void> buyPlan(
BuildContext context,
String packageID,
) async {
try {
final CustomerInfo? info =
await SolydFlow.purchasePackage(
context,
packageID,
);

if (info == null) {
return;
}

if (info.activeEntitlements["gold_access"] == true) {
Navigator.pop(context);
print("Purchase successful!");
}
} catch (e) {
print("Purchase failed: $e");
}
}

The SDK automatically handles:

  • Payment processing
  • Verification
  • Entitlement updates
  • Transaction recovery
  • Customer synchronization

Option B: No-Code Paywall

With the No-Code Paywall, you design and manage your paywall directly from the SolydFlow Console.

Changes can be published without requiring users to update your application.

Display the paywall with:

void showPaywall(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (ctx) => SolydPaywall(
onPurchaseSuccess: (CustomerInfo info) {
Navigator.pop(ctx);

ScaffoldMessenger.of(ctx).showSnackBar(
const SnackBar(
content: Text(
"Subscription Unlocked! 🚀",
),
),
);
},
onClose: () => Navigator.pop(ctx),
),
);
}

The paywall automatically:

  • Displays products configured in your dashboard
  • Uses your published paywall design
  • Handles purchases
  • Tracks conversion events
  • Updates customer entitlements after successful payment

Which Option Should You Choose?

Choose Custom UI if:

  • You need full control over the user experience.
  • Your design system is highly customized.
  • You want to build your own paywall components.

Choose No-Code Paywall if:

  • You want faster implementation.
  • Product teams need to update paywalls without app releases.
  • You want dashboard-managed paywall experiences.

Step 5: Checking Entitlements and Customer State

SolydFlow provides two ways to check a user's access level depending on your needs.


Use this when you only need to quickly determine whether a user has access to a feature.

Future<void> checkAccess() async {
bool isPro = await SolydFlow.hasEntitlement("pro_tier");

if (isPro) {
// Unlock premium features
print("User has access");
} else {
// Show paywall or restrict access
print("User does not have access");
}
}

Why use this method?

  • Fast ( < 5ms )
  • Works offline using encrypted local cache
  • Ideal for UI gating and navigation decisions

Option B: Full Customer State (Advanced)

Use this when you need complete information about a user's subscriptions, expiry dates, or entitlement history.

Future<void> getCustomerState() async {
CustomerInfo info = await SolydFlow.getCustomerInfo();

// Check active entitlement
if (info.activeEntitlements["pro_tier"] == true) {
print("User is Pro");
}

// Get entitlement expiry
DateTime? expiry = info.allEntitlements["pro_tier"];
if (expiry != null) {
print("Expires on: $expiry");
}
}

What CustomerInfo Contains

The CustomerInfo object includes:

  • activeEntitlements → A map of currently active access levels

  • allEntitlements → All entitlements with their expiration dates

  • Cached local state (instant access even offline)

  • Synchronized server state (updated in background when connection is restored)


Offline-First Behavior

SolydFlow is designed to work in unstable network conditions.

When calling getCustomerInfo():

  1. The SDK first checks encrypted local storage (instant response).
  2. If available, it returns immediately.
  3. It then syncs with the server in the background.
  4. Any updates are automatically merged.

This ensures:

  • No blocked UI
  • No dependency on constant internet connectivity
  • Reliable entitlement restoration after interruptions

When to Use Which

ScenarioRecommended Method
Show/hide premium UIhasEntitlement()
Route navigation decisionshasEntitlement()
Show subscription detailsgetCustomerInfo()
Analytics / billing insightsgetCustomerInfo()
Debugging user access issuesgetCustomerInfo()

Step 6: Display Products and Process Purchases

Before a customer can make a purchase, your application needs to retrieve the products configured in your SolydFlow dashboard.


Fetch Available Packages

Use getOfferings() to retrieve the packages associated with your project.

Future<void> loadProducts() async {
List<SolydPackage> offerings =
await SolydFlow.getOfferings();

for (var pkg in offerings) {
print(
"${pkg.name} - ${pkg.currency} ${pkg.amountKobo / 100}"
);
}
}

Example output:

Gold Monthly - NGN 1000
Gold Yearly - NGN 10000

The returned packages can be displayed using your own UI or through the SolydFlow No-Code Paywall.


Upgrade Pricing and Smart Credits

When a customer is upgrading from one plan to another, SolydFlow can return adjusted pricing information.

for (var pkg in offerings) {
if (pkg.isUpgrade) {
print(
"Upgrade Price: ${pkg.currency} ${pkg.calculatedAmountKobo / 100}"
);
}
}

When isUpgrade is true, the package contains upgrade-adjusted pricing that can be displayed to the customer.


Initiate a Purchase

When a customer selects a package, call purchasePackage().

Future<void> buyPlan(
BuildContext context,
String packageID,
) async {
try {
final CustomerInfo? info =
await SolydFlow.purchasePackage(
context,
packageID,
);

if (info == null) {
// User cancelled purchase
return;
}

if (info.activeEntitlements["gold_access"] == true) {
print("Purchase successful!");
}
} catch (e) {
print("Purchase failed: $e");
}
}

What Happens During a Purchase?

The SDK automatically handles:

  • Payment initialization
  • Payment provider communication
  • Transaction verification
  • Entitlement activation
  • Customer synchronization
  • Transaction recovery

After a successful purchase, the updated CustomerInfo object is returned immediately.

This allows your application to unlock features without requiring another API call.


Handling Purchase Results

Successful Purchase

if (info.activeEntitlements["gold_access"] == true) {
// Unlock premium features
}

User Cancelled

if (info == null) {
return;
}

Failed Purchase

catch (e) {
print("Purchase failed: $e");
}

Always handle all three scenarios to provide a smooth user experience.


  1. Fetch offerings using getOfferings().
  2. Display products to the user.
  3. User selects a package.
  4. Call purchasePackage().
  5. Verify access using the returned CustomerInfo.
  6. Unlock premium functionality immediately.

Checkout Experience

Depending on the configured routing rules, the customer may experience different payment flows.

Examples include:

  • Hosted checkout pages (Paystack, Flutterwave, Stripe)
  • Virtual account payments (Monnify)
  • Native mobile money prompts (M-Pesa)

The SDK automatically selects and manages the appropriate flow.

No additional application logic is required.


Step 7: Test Transaction Recovery

One of SolydFlow's core capabilities is transaction recovery.

In regions with unstable networks, users may successfully complete a payment but lose connectivity before the application receives confirmation. This can result in paid customers temporarily losing access.

SolydFlow automatically reconciles these transactions using webhook events, entitlement synchronization, and secure local caching.


The "Zombie Transaction" Test

Use this test to verify that transaction recovery is working correctly.

Test Steps

  1. Start a purchase on a physical device.
  2. Complete the payment process.
  3. Before the payment flow returns to your application, immediately force-close the app.
  4. Wait approximately 15 to 30 seconds.
  5. Re-open the application.
  6. Check the user's entitlement status.

Expected Result

The user should automatically regain access to the purchased entitlement even though the application was closed before the purchase flow completed.

For example:

bool hasAccess =
await SolydFlow.hasEntitlement(
"gold_access",
);

The result should return:

true

What This Test Validates

A successful recovery test confirms:

  • Webhooks are configured correctly.
  • Payment verification is working.
  • Entitlement synchronization is active.
  • Customer state recovery is functioning properly.
  • Interrupted purchases can be restored automatically.

Common Issues

Purchase Not Restored

Verify:

  • Gateway credentials are correct.
  • Webhook URLs are configured.
  • The webhook endpoint is reachable.
  • The payment was successfully completed on the provider side.

Entitlement Not Activated

Verify:

  • The package is mapped to the correct entitlement.
  • The entitlement exists in the SolydFlow Console.
  • The application is checking the correct entitlement identifier.

Example:

await SolydFlow.hasEntitlement(
"gold_access",
);

Recovery Takes Longer Than Expected

Recovery timing depends on:

  • Payment provider webhook delivery
  • Network conditions
  • Application reconnect timing

In most cases, recovery should occur automatically within a short period after the payment provider confirms the transaction.


Web Integration (JavaScript & TypeScript)

SolydFlow provides a lightweight, framework-agnostic JavaScript SDK for web applications (React, Vue, Next.js, or Vanilla JS).

The JavaScript SDK provides the same core capabilities available on mobile, including:

  • Dynamic pricing
  • Purchasing Power Parity (PPP)
  • Smart Upgrade Credits
  • Entitlement management
  • Subscription lifecycle tracking

It allows you to use the same pricing logic, entitlement system, and upgrade rules as your mobile applications while maintaining a separate web checkout flow. This allows customers to purchase and manage subscriptions from your website while maintaining a single source of truth across platforms.

Mobile vs Web Purchase Flow

The purchase experience differs slightly between mobile and web platforms.

Mobile SDK

User

In-App Purchase Flow

Payment Completed

CustomerInfo Returned

Entitlement Activated

The SDK waits for the purchase flow to complete and returns an updated CustomerInfo object immediately.

Web SDK

User

Hosted Checkout Page

Payment Completed

Webhook Sent

Backend Updated

Entitlement Activated

Because the browser is redirected to a hosted checkout page, the web application cannot wait for payment completion.

Instead, SolydFlow notifies your backend using webhooks after the transaction has been verified.


1. Installation

Install directly from GitHub:

npm install solydflow-js

or:

yarn add solydflow-js

or

pnpm add solydflow-js

2. Initialization

Initialize the SDK as early as possible in your web application.

import { SolydFlow } from "solydflow-js";

await SolydFlow.configure(
"sf_pk_live_YOUR_PUBLIC_KEY",
"user_12345",
"user@mail.com"
);

3. Choose Your Integration Strategy

The SolydFlow JavaScript SDK supports two integration approaches.

OptionBest For
Drop-In PaywallTeams that want the fastest integration and dashboard-managed pricing experiences.
Custom UITeams that want complete control over their website's pricing and checkout experience.

Option A: Drop-In Paywall

Instead of spending days building your own pricing page, SolydFlow provides a fully responsive, high-converting Drop-In Paywall that automatically stays synchronized with the design, colors, copy, products, and pricing configured in your SolydFlow Console.

The paywall automatically handles:

  • Purchasing Power Parity (Geo-IP pricing)
  • Smart Upgrade Credits
  • Payment routing rules
  • Checkout initiation
  • Product rendering

Step 1: Create a Container

Add a container element to your page:

<div id="solydflow-paywall-container"></div>

Step 2: Render the Paywall

import { SolydFlow } from "solydflow-js";

async function showPricing() {
await SolydFlow.configure(
"sf_pk_live_YOUR_PUBLIC_KEY",
"user_12345",
"user@mail.com"
);

await SolydFlow.renderPaywall(
"solydflow-paywall-container"
);
}

That's all that's required.

The SDK automatically loads and renders the paywall you designed in the SolydFlow Console.

When Should You Use This?

Choose the Drop-In Paywall if:

  • You want the fastest implementation.
  • Product teams manage pricing and promotions.
  • You want paywall updates without deploying new website code.
  • You want built-in optimization and localization.

Option B: Custom UI (Advanced)

If you prefer to build your own pricing experience, you can fetch package information directly and render your own components.

SolydFlow will still calculate:

  • Purchasing Power Parity pricing
  • Smart Upgrade Credits
  • Regional pricing adjustments
async function fetchRawPackages() {
const offerings = await SolydFlow.getOfferings();

offerings.forEach(pkg => {
if (pkg.is_upgrade) {
console.log(
`Upgrade for ${pkg.currency} ${pkg.calculated_amount_kobo / 100}`
);
} else {
console.log(
`Standard Price: ${pkg.currency} ${pkg.amount_kobo / 100}`
);
}
});
}

You are responsible for rendering the UI, while SolydFlow remains responsible for pricing logic, checkout routing, and entitlement management.


4. Checking Access

Check whether the current user has an active entitlement.

async function checkAccess() {
const isGold = await SolydFlow.hasEntitlement("gold_access");

if (isGold) {
console.log("Welcome to the premium dashboard!");
} else {
// Redirect to pricing page
}
}

5. Making a Purchase (Web Redirect Flow)

When a user initiates a purchase, they are redirected to a secure hosted checkout page.

⚠️ Web Flow Difference: Unlike the mobile SDK (which returns CustomerInfo directly), the web SDK redirects the user to a hosted payment page. Your application does not wait for completion.

async function handleCheckout(packageId) {
try {
await SolydFlow.purchasePackage(
packageId,
"2348012345678"
);

// Redirect occurs automatically.
// Code below will not execute immediately.
} catch (error) {
console.error("Checkout failed:", error.message);
}
}

6. Fulfilling the Purchase (Webhooks)

Unlike the mobile SDK, web applications cannot wait for a payment to complete because the customer is redirected to a hosted checkout experience.

To unlock subscriptions, grant entitlements, and synchronize customer access, you must configure a backend webhook endpoint.

Configure Your Webhook Endpoint

  1. Log in to the SolydFlow Console.
  2. Navigate to Projects.
  3. Click Manage Connection.
  4. Under Your Backend Webhook.
  5. Enter your backend endpoint URL (for example, a Node.js API, Laravel endpoint, Django view, or Supabase Edge Function).
  6. Save the configuration.

When subscription activity occurs, SolydFlow securely delivers signed webhook events to your backend.

The 4 Webhook Events

To keep your integration incredibly simple while still supporting powerful marketing analytics, SolydFlow consolidates all billing complexity into just four specific events.

1. subscription_started

When it fires: A user successfully pays for an entitlement for the very first time, or they purchase it again after their previous subscription completely expired. What to do: Grant the user access to the entitlement until the expires_at date. Tip: This is the perfect event to trigger a "Welcome to Premium" onboarding email!

{
"event": "subscription_started",
"event_id": "evt_110e8400-e29b-41d4-a716-446655440001",
"environment": "live",
"is_test": false,
"user_id": "user_12345",
"package_id": "gold_monthly",
"entitlement": "gold_access",
"provider": "paystack",
"expires_at": "2026-07-27T18:33:00Z"
}

2. subscription_renewed

When it fires: A user's active subscription is renewed, upgraded, or a dropped payment is rescued by the SolydFlow Sweeper. Time is added to their current access. What to do: Silently extend the user's access in your database to the new expires_at date.

{
"event": "subscription_renewed",
"event_id": "evt_550e8400-e29b-41d4-a716-446655440000",
"environment": "live",
"is_test": false,
"user_id": "user_12345",
"package_id": "gold_monthly",
"entitlement": "gold_access",
"provider": "paystack",
"expires_at": "2026-08-27T18:33:00Z"
}

3. subscription_revoked

When it fires: A user's access is forcefully killed before their natural expiration date (e.g., a card chargeback, an Apple refund, or a manual Admin rejection in the dashboard). What to do: Immediately revoke the user's access to the entitlement and pause their services.

{
"event": "subscription_revoked",
"event_id": "evt_991f8400-e29b-41d4-a716-446655440001",
"environment": "live",
"is_test": false,
"user_id": "user_12345",
"package_id": "gold_monthly",
"entitlement": "gold_access",
"reason": "chargeback",
"revoked_at": "2026-06-27T18:33:00Z"
}

4. test_event

When it fires: You click "Send Test Webhook" in the SolydFlow Console API Vault. What to do: Use this to verify your HMAC SHA-256 cryptographic signature logic is working correctly before going live.

{
"event": "test_event",
"user_id": "sf_test_user_999",
"package_id": "test_monthly_gold",
"entitlement": "gold_access",
"provider": "solydflow_test",
"expires_at": "2026-07-27T18:33:00Z"
}

Your backend should use these events to update customer records, synchronize subscriptions, and unlock application features.


Securing Your Webhooks

Because webhook endpoints are publicly accessible, every incoming request must be verified before processing.

SolydFlow protects webhook deliveries using:

  • Cryptographic request signatures
  • Timestamp validation
  • Replay attack protection

The Signature Header

Every webhook request includes the following header:

X-SolydFlow-Signature: t=1687263530,v1=9b1d2e3f4a5b6c7d8e9f...

The header contains two values:

FieldDescription
tUNIX timestamp of when the webhook was generated
v1HMAC SHA-256 cryptographic signature

Verification Process

Your backend should perform three verification steps before processing any webhook.

Step 1: Extract the Timestamp and Signature

Parse the X-SolydFlow-Signature header and extract:

  • Timestamp (t)
  • Signature (v1)

Step 2: Prevent Replay Attacks

Compare the supplied timestamp against your server's current UNIX timestamp.

Reject requests older than 300 seconds (5 minutes).

This prevents attackers from intercepting a valid webhook and replaying it later.

Step 3: Verify the Signature

Construct the payload using:

timestamp.raw_body

Example:

1687263530.{"event":"subscription_renewed"}

Generate an HMAC SHA-256 hash using your SolydFlow Webhook Secret and compare it against the supplied v1 signature.

Only process the webhook if both signatures match.


Node.js / Express Verification Example

The example below demonstrates a complete webhook verification implementation.

const express = require('express');
const crypto = require('crypto');

const app = express();

// Preserve the raw request body for signature verification
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString();
}
}));

const SOLYDFLOW_WEBHOOK_SECRET =
process.env.SOLYDFLOW_WEBHOOK_SECRET;

app.post('/webhook/solydflow', (req, res) => {
const signatureHeader =
req.headers['x-solydflow-signature'];

if (!signatureHeader) {
return res
.status(401)
.send('Missing SolydFlow signature');
}

// Extract timestamp and signature
const parsedHeader = signatureHeader
.split(',')
.reduce((acc, pair) => {
const [key, value] = pair.split('=');
acc[key] = value;
return acc;
}, {});

const timestamp = parsedHeader['t'];
const providedSignature = parsedHeader['v1'];

if (!timestamp || !providedSignature) {
return res
.status(401)
.send('Invalid signature format');
}

// Replay attack protection
const currentTimestamp =
Math.floor(Date.now() / 1000);

const webhookAge =
currentTimestamp - parseInt(timestamp, 10);

if (webhookAge > 300) {
return res
.status(401)
.send(
'Webhook timestamp is too old'
);
}

// Compute expected signature
const payloadToSign =
`${timestamp}.${req.rawBody}`;

const expectedSignature = crypto
.createHmac(
'sha256',
SOLYDFLOW_WEBHOOK_SECRET
)
.update(payloadToSign)
.digest('hex');

const isValid =
crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(providedSignature)
);

if (!isValid) {
return res
.status(401)
.send(
'Cryptographic signature mismatch'
);
}

// Webhook verified
const payload = req.body;

console.log(
'Verified SolydFlow Event:',
payload.event
);

switch (payload.event) {
case 'subscription_started':
// Create subscription
break;

case 'subscription_renewed':
// Extend subscription
break;

case 'subscription_revoked':
// Revoke access
break;

default:
console.log(
'Unhandled event:',
payload.event
);
}

// Acknowledge receipt
return res.status(200).json({
received: true
});
});

app.listen(3000, () => {
console.log(
'Server listening on port 3000'
);
});

Production Best Practices

Before updating customer records, your backend should:

  1. Verify the webhook signature.
  2. Verify the timestamp.
  3. Reject duplicate events (idempotency).
  4. Update customer subscription records.
  5. Synchronize entitlement access.
  6. Return a successful response immediately.

A successful webhook response should return:

res.status(200).json({
received: true
});

This confirms to SolydFlow that the event was successfully delivered and processed.


Need Help?

Documentation

Visit the SolydFlow Console documentation for detailed guides, SDK references, and platform-specific integration examples.

Support

For technical assistance, contact:

support@solydflow.com

When contacting support, include:

  • Project name
  • SDK version
  • Platform (Android or iOS)
  • Relevant error messages
  • Steps to reproduce the issue

This helps the team resolve issues more quickly.