Skip to content

Asia-Digital/PayVia-SDK

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PayVia SDK

A lightweight JavaScript SDK for connecting your Chrome Extension / SaaS app to PayVia, for accepting PayPal payments and managing subscriptions, license validation, tier-based feature gating, trial management and monthly / yearly / lifetime plans.

Quick Start

The sample-extension comes pre-configured with a shared demo project and works out of the box:

  1. Open chrome://extensions/
  2. Enable "Developer mode"
  3. Click "Load unpacked" and select the sample-extension folder
  4. Click the extension icon — everything works!

Note: The demo project is shared across all users and is meant for testing only. To accept real payments, create your own project at PayVia Dashboard.

Installation

Option 1: Copy directly

Copy payvia.js into your extension folder.

Option 2: npm

npm install @payvia-sdk/sdk

Basic Usage

1. Add to manifest.json

{
  "manifest_version": 3,
  "name": "Your Extension",
  "permissions": ["storage"],
  "host_permissions": [
    "https://api.payvia.site/*",
    "https://payvia.site/*"
  ],
  "background": {
    "service_worker": "background.js"
  }
}

If using Google Identity for automatic user detection, also add:

{
  "permissions": ["storage", "identity", "identity.email"]
}

2. Initialize in background.js

import PayVia from './payvia.js';

const payvia = PayVia('YOUR_API_KEY');

// Check if user has paid
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'checkPaid') {
    payvia.getUser().then(user => {
      sendResponse({ paid: user.paid });
    });
    return true; // async response
  }
});

3. Check payment status

const user = await payvia.getUser();

if (user.paid) {
  enablePremiumFeatures();
} else {
  showUpgradeButton();
}

4. Open payment page

// Option 1: Pricing page — shows all plans (recommended)
await payvia.openPaymentPage({ mode: 'pricing', email: userEmail });

// Option 2: Hosted checkout — specific plan
await payvia.openPaymentPage({ mode: 'hosted', planId: 'your-plan-id', email: userEmail });

// Option 3: Direct PayPal — no PayVia UI
await payvia.openPaymentPage({ mode: 'direct', planId: 'your-plan-id', email: userEmail });

5. Listen for payment changes

const unsubscribe = payvia.onPaid((user) => {
  console.log('User just paid!', user);
  enablePremiumFeatures();
});

// Call unsubscribe() to stop listening

Checkout Modes

Mode Description When to use
pricing PayVia plan selection page Default — when you have multiple plans
hosted PayVia checkout for a specific plan When you have one plan or want to skip selection
direct Straight to PayPal, no PayVia UI For developers who want full UI control

User Identity

The SDK automatically identifies users:

  1. Google Identity — if the extension has the identity permission, uses the user's Google email
  2. Random ID fallback — generates a persistent pv_-prefixed UUID, synced via chrome.storage.sync
const identity = await payvia.getIdentity();
// { id: "user@gmail.com", email: "user@gmail.com", source: "google" }
// or: { id: "pv_abc123...", email: null, source: "random" }

Tier-Based Feature Gating

Tiers define feature sets (Free/Pro/Super). Plans are pricing options within tiers.

// Check tier level (0=Free, 1=Pro, 2=Super)
const hasPro = await payvia.hasTierLevel(1); // Pro or above

// Check specific feature
const canExport = await payvia.hasFeature('export_pdf');

// Get full tier info
const tier = await payvia.getTier();
// { id: "...", name: "Pro", level: 1, features: ["export_pdf", "api_access"] }

// Or via user object
const user = await payvia.getUser();
// user.tier — tier object
// user.features — shortcut to user.tier.features

Trial Support

// Start trial on first use (idempotent — safe to call multiple times)
if (await payvia.isFirstRun()) {
  const trial = await payvia.startTrial();
  if (trial) {
    console.log(`Trial started! ${trial.daysRemaining} days remaining`);
    // { subscriptionId, status, planId, planName, trialExpiresAt, daysRemaining }
  }
  await payvia.markFirstRunDone();
}

// Check trial status
const status = await payvia.getTrialStatus();
// { status, trialExpiresAt, daysRemaining, canConvert, planIds }

Trial info is also available on the user object:

const user = await payvia.getUser();
// user.isTrial — boolean
// user.trialExpiresAt — Date or null
// user.daysRemaining — number or null

License Caching

The SDK caches license data for offline resilience. No setup required — it works automatically.

  • TTL: 7 days (server-controlled)
  • Grace period: 30 days (allows offline access after TTL expires)
  • Storage: chrome.storage.local (extension) or localStorage (web)
  • Anti-tamper: HMAC-SHA256 signature verification
// Refresh cache in background (e.g., service worker startup)
chrome.runtime.onStartup.addListener(async () => {
  await payvia.refreshLicenseCache();
});

// Check if data came from cache
const user = await payvia.getUser();
if (user.fromCache) {
  // Using cached data — works offline
}

API Reference

PayVia(apiKey)

Creates a new PayVia instance.

Parameter Type Description
apiKey string API key from the PayVia dashboard

payvia.getUser(options?)

Returns the user's payment status and subscription info. Uses cache automatically.

Options: { forceRefresh: boolean }

Returns: Promise<PayViaUser>

interface PayViaUser {
  id: string;                          // Unique user identifier
  email: string | null;                // User email (if available)
  identitySource: 'google' | 'random'; // Identity source
  paid: boolean;                       // true if ACTIVE or TRIAL
  status: 'ACTIVE' | 'TRIAL' | 'INACTIVE'; // Subscription status
  tier: {                              // Current tier (or null)
    id: string;
    name: string;
    level: number;                     // 0=Free, 1=Pro, 2=Super
    features: string[];
  } | null;
  features: string[];                  // Shortcut to tier.features
  planIds: string[];                   // Purchased plan IDs
  isTrial: boolean;                    // Whether on trial
  trialExpiresAt: Date | null;         // Trial expiration date
  daysRemaining: number | null;        // Trial days remaining
  fromCache: boolean;                  // true if data came from cache
  checkedAt: number | null;            // Unix timestamp (ms)
  ttl: number | null;                  // Cache TTL in ms
  signature: string | null;            // HMAC anti-tamper signature
}

payvia.refresh()

Force-refreshes user status from the server (bypasses cache).

Returns: Promise<PayViaUser>


payvia.refreshLicenseCache()

Refreshes the license cache if expired. Ideal for background service worker startup.

Returns: Promise<void>


payvia.openPaymentPage(options)

Opens the payment page in a new tab.

Option Type Required Description
mode 'pricing' | 'hosted' | 'direct' No Checkout mode (default: pricing)
planId string For hosted/direct Plan ID to purchase
email string No Customer email
successUrl string For direct Redirect URL after successful payment
cancelUrl string For direct Redirect URL if user cancels

Returns: Promise<{ mode, pricingUrl? | checkoutUrl? }>


payvia.onPaid(callback)

Listens for payment status changes (polls every 5 seconds).

Returns: Function — call it to stop listening


payvia.hasFeature(name)

Checks if the user's tier includes a specific feature.

Returns: Promise<boolean>


payvia.hasTierLevel(level)

Checks if the user's tier is at or above the required level.

Returns: Promise<boolean>


payvia.getTier()

Returns the user's current tier info.

Returns: Promise<{ id, name, level, features } | null>


payvia.getIdentity()

Returns the current user identity.

Returns: Promise<{ id: string, email: string | null, source: 'google' | 'random' }>


payvia.needsEmailForPayment()

Checks if an email prompt is needed (user has no Google identity).

Returns: Promise<boolean>


payvia.getPlans()

Returns available plans for the project.

Returns: Promise<Plan[]>


payvia.startTrial()

Starts a trial for the current user. Idempotent — safe to call multiple times.

Returns: Promise<{ subscriptionId, status, planId, planName, trialExpiresAt, daysRemaining } | null>


payvia.getTrialStatus()

Returns the trial status for the current user.

Returns: Promise<{ status, trialExpiresAt, daysRemaining, canConvert, planIds }>


payvia.isFirstRun()

Checks if the extension is being used for the first time.

Returns: Promise<boolean>


payvia.markFirstRunDone()

Marks the first run as complete.


payvia.cancelSubscription(options?)

Cancels the user's subscription.

Option Type Required Description
planId string No Specific plan to cancel
reason string No Cancellation reason

Returns: Promise<{ success, message, canceledPlanId }>


payvia.resetLicense()

Resets the user's license (for testing/demo purposes). Deletes all subscriptions for the current user.

Returns: Promise<{ message }>


Plan Description Format

In the PayVia Dashboard, you can write plan descriptions with feature lists:

Everything in Free, plus:
+++Unlimited access
+++Priority support
+++Custom features
Contact us for enterprise plans

Lines starting with +++ are displayed with a green checkmark on checkout pages.


Sample Extension

See the sample-extension/ folder for a working example that demonstrates:

  1. Payment status check — automatic user detection
  2. Three checkout modes — Pricing Page, Hosted Checkout, Direct PayPal
  3. Feature-per-Plan — each plan unlocks different features
  4. Smart identity — Google Identity and Random ID support
  5. Reset demo — button to reset license for repeated testing

Running the sample:

  1. Open chrome://extensions/
  2. Enable Developer mode
  3. Click "Load unpacked"
  4. Select the sdk/sample-extension/ folder
  5. Click the extension icon

FAQ

How is the user identified?

PayVia uses chrome.storage.sync to create a unique ID that persists even if the user uninstalls the extension. If the user is signed into Chrome and you have the identity permission, identification uses their Google email instead.

What happens offline?

The SDK uses cached license data with a 7-day TTL and 30-day grace period. During network outages within the grace period, the cached status is returned. If no valid cache exists, getUser() returns { paid: false, status: 'INACTIVE' }.

What's the difference between checkout modes?

  • pricing — user sees all plans and picks one
  • hosted — user sees a styled checkout page for a specific plan
  • direct — user is sent straight to PayPal with no PayVia UI

How do I test in development?

Use PayPal Sandbox credentials and PayPal Sandbox accounts.


Resources

About

A Lightweight JavaScript SDK for connecting you chrome extension / SaaS app to PayVia, for accepting PayPal payments and managing subscriptions, license validation, tier-based feature gating, trial management and monthly / yearly / lifetime plans

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors