portalpay-core
v1.0.1
Published
Core payment processing library for PortalPay. Handles configuration fetching, payment intent creation, amount monitoring, and security features for embedding payments into any application.
Readme
PortalPay Core
Core payment processing functionality for the PortalPay SDK. Handles configuration fetching, payment intent creation, and security monitoring.
Overview
portalpay-core is the foundation of the PortalPay SDK ecosystem. It provides the essential logic for:
- 🔧 Configuration Management - Fetch payment provider configurations (always fresh from API)
- 💳 Payment Intents - Create secure payment sessions with checkout URLs
- 🔒 Security Monitoring - Tamper detection and fraud prevention
- 📊 Amount Monitoring - Real-time tracking of payment amounts from DOM or variables
Installation
npm install portalpay-core
# or
yarn add portalpay-core
# or
pnpm add portalpay-coreQuick Start
import { fetchConfig, createIntent, getConfig } from 'portalpay-core';
// Initialize with your publishable key
const publishableKey = 'pk_live_alexpay_xxxxxxxx';
// Fetch configuration from payment provider
await fetchConfig(publishableKey, {
currency: 'GHS', // Optional overrides
narration: 'Order Payment'
});
// Get the loaded configuration
const config = getConfig();
console.log('Payment method:', config.method); // 'card' or 'mobile-money'
// Create a payment intent
// Amount is passed in cents (e.g., 5000 = $50.00), formatted as decimal string internally
const intent = await createIntent(5000, config, 'Product Purchase');
console.log('Checkout URL:', intent.checkout_url);
// Redirect user to: window.location.href = intent.checkout_url;API Reference
Configuration
fetchConfig(key, overrides?)
Fetches configuration from the payment provider's API.
import { fetchConfig } from 'portalpay-core';
await fetchConfig('pk_live_alexpay_xxxxxxxx', {
narration: 'Order Payment', // Override narration
method: 'mobilemoney', // Override payment method ('card' | 'mobilemoney')
redirectSuccessUrl: 'https://yoursite.com/success', // Card success redirect
redirectFailedUrl: 'https://yoursite.com/failed', // Card failure redirect
redirectUrl: 'https://yoursite.com/redirect', // Mobile money redirect
webhookUrl: 'https://yoursite.com/webhook' // Webhook endpoint
});Parameters:
key(string): Publishable key from your payment provideroverrides(object, optional): Configuration overrides (only non-empty values are applied)narration: Payment descriptionmethod: Payment method ('card' | 'mobilemoney')redirectSuccessUrl: Card payment success redirect URLredirectFailedUrl: Card payment failure redirect URLredirectUrl: Mobile money redirect URLwebhookUrl: Webhook endpoint for payment notifications
API-Only Fields (cannot be overridden, come from provider API):
name: Merchant/store namecurrency: Currency code (e.g., 'GHS', 'NGN', 'USD')operator: Card operator (e.g., 'mpgs')
Returns: Promise<void>
getConfig()
Retrieves the currently loaded configuration (fetched fresh from API on each page load).
import { getConfig } from 'portalpay-core';
const config = getConfig();
// Returns: {
// key, name, currency, method, narration, operator, provider,
// redirectUrl, redirectSuccessUrl, redirectFailedUrl, webhookUrl,
// checkoutUrl, ...
// }getState()
Check the current SDK state.
import { getState } from 'portalpay-core';
const state = getState();
// Returns: 'idle' | 'fetching' | 'ready' | 'error' | 'retrying'Payment Intents
createIntent(amount, config, narration?)
Creates a payment intent and returns a checkout URL.
import { createIntent, getConfig } from 'portalpay-core';
const config = getConfig();
// Amount is in cents (e.g., 5000 = $50.00), will be formatted as "50.00" internally
const intent = await createIntent(5000, config, 'Order #123');
// intent.checkout_url - Redirect user here
// intent.session_intent_token - Unique session identifier**Parameters:
amount(number): Payment amount in smallest currency unit (e.g., 5000 for GHS 50.00)config(PortalPayConfig): Configuration object from getConfig()narration(string, optional): Payment description override
Returns: Promise<IntentResponse>
Amount Monitoring
startMonitoring(source)
Monitor payment amount from a DOM element or JavaScript variable.
import { startMonitoring } from 'portalpay-core';
// Monitor a DOM element
startMonitoring({
type: 'dom',
selector: '#total-amount'
});
// Monitor a JavaScript variable
startMonitoring({
type: 'var',
varName: 'cartTotal'
});stopMonitoring()
Stop amount monitoring.
import { stopMonitoring } from 'portalpay-core';
stopMonitoring();getLatest()
Get the latest amount snapshot.
import { getLatest } from 'portalpay-core';
const snapshot = getLatest();
// Returns: { value: number, timestamp: number }Security
arm(getter)
Enable tamper detection security.
import { arm, getLatest } from 'portalpay-core';
// Arm security with amount getter
arm(() => getLatest()?.value ?? 0);disarm()
Disable tamper detection.
import { disarm } from 'portalpay-core';
disarm();assess(amount)
Assess if current amount passes security checks.
import { assess } from 'portalpay-core';
const result = assess(5000);
// Returns: { ok: boolean }Configuration Options
PortalPayConfig Interface
interface PortalPayConfig {
publishableKey: string; // Publishable key
currency: string; // Currency code (GHS, NGN, USD)
narration: string; // Payment description
method: 'card' | 'mobile-money';
callback: string; // Success URL
cancel: string; // Cancel URL
checkoutUrl: string; // Checkout page URL (for mock mode)
provider?: string; // Provider slug
forceMock?: boolean; // Force mock mode
}Error Handling
import { fetchConfig, getState } from 'portalpay-core';
try {
await fetchConfig('pk_live_alexpay_xxxxxxxx');
} catch (error) {
const state = getState();
if (error.message === 'DOMAIN_NOT_AUTHORIZED') {
console.error('This domain is not authorized');
} else if (error.message === 'INVALID_KEY') {
console.error('Invalid publishable key');
} else if (error.message === 'SERVER_ERROR') {
console.error('Payment provider server error');
}
}Mock Mode (Testing)
Enable mock mode for testing without real transactions:
await fetchConfig('pk_test_alexpay_xxxxxxxx', {
forceMock: true,
checkoutUrl: 'https://yoursite.com/checkout'
});Test Credentials:
- Success Card: 4084 0841 2345 6789, Exp: 12/28, CVV: 123
- Declined Card: 4000 0000 0000 0002, Exp: 12/28, CVV: 456
Supported Payment Providers
- AlexPay - Card and Mobile Money (GHS)
- Vesicash - Card and Bank Transfer (NGN)
- Portal - Card and Mobile Money (Multi-currency)
Provider Endpoints
AlexPay
- Live Config:
https://api.alexpay.com/v1/keys/publishable/config/{key} - Live Initiate:
https://api.alexpay.com/v1/embed/session - Test Config:
https://api.staging.alexpay.com/v1/keys/publishable/config/{key} - Test Initiate:
https://api.staging.alexpay.com/v1/embed/session
TypeScript Support
Full TypeScript definitions included:
import type {
PortalPayConfig,
IntentPayload,
IntentResponse,
AmountSource,
SDKState
} from 'portalpay-core';Browser Compatibility
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
Related Packages
portalpay- Browser bundle with UIportalpay-react- React integrationportalpay-vue- Vue integration
Changelog
v1.0.0
PortalPay Launch:
- Complete rebrand from EmbedPay to PortalPay
- New package name:
portalpay-core - All interfaces renamed (e.g.,
PortalPayConfig) - Debug flag changed to
window.__PORTALPAY_DEBUG__ - All internal prefixes changed from
ep_topp_
v3.0.9 (EmbedPay - Deprecated)
Breaking Changes:
- Config Field Names Updated: Old
callback/cancelfields replaced with:redirectSuccessUrl- Card payment success redirect URLredirectFailedUrl- Card payment failure redirect URLredirectUrl- Mobile money redirect URLwebhookUrl- Webhook endpoint
- Amount Format: Now sent as decimal string (e.g.,
"50.00") instead of cents - Payment Method: Use
'mobilemoney'(not'mobile-money')
Improvements:
- No Caching: Config always fetched fresh from API (no localStorage cache)
- Smart Overrides: Empty string overrides are ignored, preserving API values
- Debug Mode: Set
window.__PORTALPAY_DEBUG__ = truefor detailed logs - User-Friendly Errors: Clear error messages for common issues
API-Only Fields (cannot be overridden):
name- Merchant/store namecurrency- Transaction currencyoperator- Card operator (e.g., 'mpgs')
Debug Mode
Enable detailed logging (internal use only):
// Before SDK loads
window.__PORTALPAY_DEBUG__ = true;License
MIT © Vesicash
Support
- 📧 Email: [email protected]
- 🌐 Website: https://vesicash.com/portalpay
- 📖 Documentation: https://docs.vesicash.com/portalpay
Built with ❤️ by the Vesicash team — PortalPay is the evolution of EmbedPay
