0
# Payments & Commerce
1
2
Payment processing and e-commerce functionality for monetizing VK Mini Apps through VK Pay integration.
3
4
## Capabilities
5
6
### Payment Processing
7
8
Process payments through VK Pay system with support for various payment methods and transaction types.
9
10
```typescript { .api }
11
/**
12
* Open VK Pay payment form
13
* @param props - Payment configuration with action and parameters
14
*/
15
function send(method: 'VKWebAppOpenPayForm', props: VKPayProps<VKPayActionType>): Promise<
16
TransactionResult | { result: TransactionResult }
17
>;
18
19
interface VKPayProps<T extends VKPayActionType> {
20
/** VK application ID */
21
app_id: number;
22
/** Payment action type */
23
action: T;
24
/** Action-specific parameters */
25
params: VKPayActionParamsMap[T];
26
}
27
28
type VKPayActionType = 'pay-to-service' | 'pay-to-user' | 'pay-to-group';
29
30
interface VKPayActionParamsMap {
31
'pay-to-service': {
32
/** Merchant ID */
33
merchant_id: number;
34
/** Payment amount */
35
amount: number;
36
/** Payment description */
37
description: string;
38
/** Unique transaction ID */
39
order_id: string;
40
/** Additional data */
41
data?: string;
42
};
43
'pay-to-user': {
44
/** Recipient user ID */
45
user_id: number;
46
/** Payment amount */
47
amount: number;
48
/** Payment description */
49
description: string;
50
};
51
'pay-to-group': {
52
/** Recipient group ID */
53
group_id: number;
54
/** Payment amount */
55
amount: number;
56
/** Payment description */
57
description: string;
58
};
59
}
60
61
interface TransactionResult {
62
/** Transaction status */
63
status: 'success' | 'cancel' | 'fail';
64
/** Transaction ID */
65
transaction_id?: string;
66
/** Payment amount */
67
amount?: number;
68
/** Additional transaction data */
69
extra?: any;
70
}
71
```
72
73
**Usage Examples:**
74
75
```typescript
76
// Service payment (in-app purchase)
77
const servicePayment = await bridge.send('VKWebAppOpenPayForm', {
78
app_id: 51665960,
79
action: 'pay-to-service',
80
params: {
81
merchant_id: 12345,
82
amount: 100, // Amount in kopecks (1 ruble = 100 kopecks)
83
description: 'Premium features unlock',
84
order_id: `order_${Date.now()}`,
85
data: JSON.stringify({
86
feature: 'premium',
87
duration: '1month'
88
})
89
}
90
});
91
92
if (servicePayment.status === 'success') {
93
console.log('Payment successful:', servicePayment.transaction_id);
94
// Unlock premium features
95
await unlockPremiumFeatures();
96
} else if (servicePayment.status === 'cancel') {
97
console.log('Payment cancelled by user');
98
} else {
99
console.log('Payment failed');
100
}
101
102
// User-to-user payment
103
const userPayment = await bridge.send('VKWebAppOpenPayForm', {
104
app_id: 51665960,
105
action: 'pay-to-user',
106
params: {
107
user_id: 12345,
108
amount: 500, // 5 rubles
109
description: 'Gift from friend'
110
}
111
});
112
113
// Group payment (donation)
114
const groupPayment = await bridge.send('VKWebAppOpenPayForm', {
115
app_id: 51665960,
116
action: 'pay-to-group',
117
params: {
118
group_id: 123456789,
119
amount: 1000, // 10 rubles
120
description: 'Support our community'
121
}
122
});
123
```
124
125
## Payment Flow Patterns
126
127
### In-App Purchases
128
129
```typescript
130
interface Product {
131
id: string;
132
name: string;
133
description: string;
134
price: number; // in kopecks
135
category: 'consumable' | 'non-consumable' | 'subscription';
136
}
137
138
class PaymentManager {
139
private appId: number;
140
private merchantId: number;
141
142
constructor(appId: number, merchantId: number) {
143
this.appId = appId;
144
this.merchantId = merchantId;
145
}
146
147
async purchaseProduct(product: Product, userId: number): Promise<boolean> {
148
try {
149
const result = await bridge.send('VKWebAppOpenPayForm', {
150
app_id: this.appId,
151
action: 'pay-to-service',
152
params: {
153
merchant_id: this.merchantId,
154
amount: product.price,
155
description: product.description,
156
order_id: `${product.id}_${userId}_${Date.now()}`,
157
data: JSON.stringify({
158
product_id: product.id,
159
user_id: userId,
160
category: product.category
161
})
162
}
163
});
164
165
if (result.status === 'success') {
166
// Record successful purchase
167
await this.recordPurchase(product, userId, result.transaction_id!);
168
return true;
169
}
170
171
return false;
172
} catch (error) {
173
console.error('Purchase failed:', error);
174
return false;
175
}
176
}
177
178
private async recordPurchase(product: Product, userId: number, transactionId: string): Promise<void> {
179
// Send purchase info to your server for validation and fulfillment
180
await fetch('/api/purchases', {
181
method: 'POST',
182
headers: { 'Content-Type': 'application/json' },
183
body: JSON.stringify({
184
product_id: product.id,
185
user_id: userId,
186
transaction_id: transactionId,
187
amount: product.price,
188
timestamp: Date.now()
189
})
190
});
191
}
192
}
193
194
// Usage
195
const paymentManager = new PaymentManager(51665960, 12345);
196
197
const premiumProduct: Product = {
198
id: 'premium_month',
199
name: 'Premium Subscription',
200
description: '1 month premium access',
201
price: 29900, // 299 rubles
202
category: 'subscription'
203
};
204
205
const success = await paymentManager.purchaseProduct(premiumProduct, currentUserId);
206
if (success) {
207
console.log('Premium subscription activated!');
208
}
209
```
210
211
### Error Handling
212
213
```typescript
214
async function handlePayment(paymentParams: VKPayProps<VKPayActionType>) {
215
try {
216
const result = await bridge.send('VKWebAppOpenPayForm', paymentParams);
217
218
switch (result.status) {
219
case 'success':
220
console.log('Payment successful');
221
// Process successful payment
222
await processSuccessfulPayment(result);
223
break;
224
225
case 'cancel':
226
console.log('Payment cancelled by user');
227
// Handle cancellation (maybe show retry option)
228
showPaymentCancelledMessage();
229
break;
230
231
case 'fail':
232
console.log('Payment failed');
233
// Handle payment failure
234
showPaymentFailedMessage();
235
break;
236
}
237
238
return result;
239
} catch (error) {
240
console.error('Payment error:', error);
241
242
if (error.error_type === 'client_error') {
243
switch (error.error_data.error_code) {
244
case 1:
245
console.log('Payment method not supported');
246
break;
247
case 2:
248
console.log('Insufficient funds');
249
break;
250
default:
251
console.log('Payment client error:', error.error_data.error_reason);
252
}
253
}
254
255
throw error;
256
}
257
}
258
```
259
260
### Security Considerations
261
262
```typescript
263
// Always validate payments on your server
264
async function validatePayment(transactionId: string, expectedAmount: number): Promise<boolean> {
265
try {
266
const response = await fetch('/api/validate-payment', {
267
method: 'POST',
268
headers: { 'Content-Type': 'application/json' },
269
body: JSON.stringify({
270
transaction_id: transactionId,
271
expected_amount: expectedAmount
272
})
273
});
274
275
const validation = await response.json();
276
return validation.valid === true;
277
} catch (error) {
278
console.error('Payment validation failed:', error);
279
return false;
280
}
281
}
282
283
// Use validation in payment flow
284
const paymentResult = await bridge.send('VKWebAppOpenPayForm', paymentParams);
285
286
if (paymentResult.status === 'success') {
287
const isValid = await validatePayment(
288
paymentResult.transaction_id!,
289
paymentParams.params.amount
290
);
291
292
if (isValid) {
293
// Safe to fulfill the purchase
294
await fulfillPurchase(paymentResult);
295
} else {
296
console.error('Payment validation failed');
297
// Handle invalid payment
298
}
299
}
300
```