Bridge library for VK Mini Apps to communicate with VK clients across iOS, Android, and Web platforms
—
Payment processing and e-commerce functionality for monetizing VK Mini Apps through VK Pay integration.
Process payments through VK Pay system with support for various payment methods and transaction types.
/**
* Open VK Pay payment form
* @param props - Payment configuration with action and parameters
*/
function send(method: 'VKWebAppOpenPayForm', props: VKPayProps<VKPayActionType>): Promise<
TransactionResult | { result: TransactionResult }
>;
interface VKPayProps<T extends VKPayActionType> {
/** VK application ID */
app_id: number;
/** Payment action type */
action: T;
/** Action-specific parameters */
params: VKPayActionParamsMap[T];
}
type VKPayActionType = 'pay-to-service' | 'pay-to-user' | 'pay-to-group';
interface VKPayActionParamsMap {
'pay-to-service': {
/** Merchant ID */
merchant_id: number;
/** Payment amount */
amount: number;
/** Payment description */
description: string;
/** Unique transaction ID */
order_id: string;
/** Additional data */
data?: string;
};
'pay-to-user': {
/** Recipient user ID */
user_id: number;
/** Payment amount */
amount: number;
/** Payment description */
description: string;
};
'pay-to-group': {
/** Recipient group ID */
group_id: number;
/** Payment amount */
amount: number;
/** Payment description */
description: string;
};
}
interface TransactionResult {
/** Transaction status */
status: 'success' | 'cancel' | 'fail';
/** Transaction ID */
transaction_id?: string;
/** Payment amount */
amount?: number;
/** Additional transaction data */
extra?: any;
}Usage Examples:
// Service payment (in-app purchase)
const servicePayment = await bridge.send('VKWebAppOpenPayForm', {
app_id: 51665960,
action: 'pay-to-service',
params: {
merchant_id: 12345,
amount: 100, // Amount in kopecks (1 ruble = 100 kopecks)
description: 'Premium features unlock',
order_id: `order_${Date.now()}`,
data: JSON.stringify({
feature: 'premium',
duration: '1month'
})
}
});
if (servicePayment.status === 'success') {
console.log('Payment successful:', servicePayment.transaction_id);
// Unlock premium features
await unlockPremiumFeatures();
} else if (servicePayment.status === 'cancel') {
console.log('Payment cancelled by user');
} else {
console.log('Payment failed');
}
// User-to-user payment
const userPayment = await bridge.send('VKWebAppOpenPayForm', {
app_id: 51665960,
action: 'pay-to-user',
params: {
user_id: 12345,
amount: 500, // 5 rubles
description: 'Gift from friend'
}
});
// Group payment (donation)
const groupPayment = await bridge.send('VKWebAppOpenPayForm', {
app_id: 51665960,
action: 'pay-to-group',
params: {
group_id: 123456789,
amount: 1000, // 10 rubles
description: 'Support our community'
}
});interface Product {
id: string;
name: string;
description: string;
price: number; // in kopecks
category: 'consumable' | 'non-consumable' | 'subscription';
}
class PaymentManager {
private appId: number;
private merchantId: number;
constructor(appId: number, merchantId: number) {
this.appId = appId;
this.merchantId = merchantId;
}
async purchaseProduct(product: Product, userId: number): Promise<boolean> {
try {
const result = await bridge.send('VKWebAppOpenPayForm', {
app_id: this.appId,
action: 'pay-to-service',
params: {
merchant_id: this.merchantId,
amount: product.price,
description: product.description,
order_id: `${product.id}_${userId}_${Date.now()}`,
data: JSON.stringify({
product_id: product.id,
user_id: userId,
category: product.category
})
}
});
if (result.status === 'success') {
// Record successful purchase
await this.recordPurchase(product, userId, result.transaction_id!);
return true;
}
return false;
} catch (error) {
console.error('Purchase failed:', error);
return false;
}
}
private async recordPurchase(product: Product, userId: number, transactionId: string): Promise<void> {
// Send purchase info to your server for validation and fulfillment
await fetch('/api/purchases', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
product_id: product.id,
user_id: userId,
transaction_id: transactionId,
amount: product.price,
timestamp: Date.now()
})
});
}
}
// Usage
const paymentManager = new PaymentManager(51665960, 12345);
const premiumProduct: Product = {
id: 'premium_month',
name: 'Premium Subscription',
description: '1 month premium access',
price: 29900, // 299 rubles
category: 'subscription'
};
const success = await paymentManager.purchaseProduct(premiumProduct, currentUserId);
if (success) {
console.log('Premium subscription activated!');
}async function handlePayment(paymentParams: VKPayProps<VKPayActionType>) {
try {
const result = await bridge.send('VKWebAppOpenPayForm', paymentParams);
switch (result.status) {
case 'success':
console.log('Payment successful');
// Process successful payment
await processSuccessfulPayment(result);
break;
case 'cancel':
console.log('Payment cancelled by user');
// Handle cancellation (maybe show retry option)
showPaymentCancelledMessage();
break;
case 'fail':
console.log('Payment failed');
// Handle payment failure
showPaymentFailedMessage();
break;
}
return result;
} catch (error) {
console.error('Payment error:', error);
if (error.error_type === 'client_error') {
switch (error.error_data.error_code) {
case 1:
console.log('Payment method not supported');
break;
case 2:
console.log('Insufficient funds');
break;
default:
console.log('Payment client error:', error.error_data.error_reason);
}
}
throw error;
}
}// Always validate payments on your server
async function validatePayment(transactionId: string, expectedAmount: number): Promise<boolean> {
try {
const response = await fetch('/api/validate-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
transaction_id: transactionId,
expected_amount: expectedAmount
})
});
const validation = await response.json();
return validation.valid === true;
} catch (error) {
console.error('Payment validation failed:', error);
return false;
}
}
// Use validation in payment flow
const paymentResult = await bridge.send('VKWebAppOpenPayForm', paymentParams);
if (paymentResult.status === 'success') {
const isValid = await validatePayment(
paymentResult.transaction_id!,
paymentParams.params.amount
);
if (isValid) {
// Safe to fulfill the purchase
await fulfillPurchase(paymentResult);
} else {
console.error('Payment validation failed');
// Handle invalid payment
}
}Install with Tessl CLI
npx tessl i tessl/npm-vkontakte--vk-bridge