node-behind-api-client 2.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/.gitlab-ci.yml +20 -0
  2. package/README.md +65 -0
  3. package/docs/behind-api-client/easyjob/JobDescriptions/README.md +654 -0
  4. package/docs/behind-api-client/easyjob/README.md +647 -0
  5. package/docs/behind-api-client/easyjob/applicants/README.md +494 -0
  6. package/docs/behind-api-client/easyjob/applications/README.md +754 -0
  7. package/docs/behind-api-client/easyjob/candidateProfiles/README.md +940 -0
  8. package/docs/behind-api-client/easyjob/jd-candidate-questions/README.md +372 -0
  9. package/docs/behind-api-client/payments/payture/README.21.md +901 -0
  10. package/docs/behind-api-client/payments/payture/README.cards.md +1497 -0
  11. package/docs/behind-api-client/payments/payture/README.md +1497 -0
  12. package/docs/behind-api-client/payments/payture/README.rukitchen.md +396 -0
  13. package/docs/behind-api-client/payments/payture/README.subscriptions.md +1266 -0
  14. package/docs/behind-api-client/payments/stripe/README.flow.md +254 -0
  15. package/docs/behind-api-client/rag/storage/README.md +519 -0
  16. package/example.js +35 -0
  17. package/index.cjs +14 -0
  18. package/index.js +15 -0
  19. package/lib/behind-api-auth-client/BehindApiAuthClient.js +91 -0
  20. package/lib/behind-api-auth-client/authorisation/AuthorisationApp.js +9 -0
  21. package/lib/behind-api-auth-client/authorisation/AuthorisationV10.js +9 -0
  22. package/lib/behind-api-auth-client/authorisation/AuthorisationV10Code.js +30 -0
  23. package/lib/behind-api-auth-client/example.js +47 -0
  24. package/lib/behind-api-auth-client/package.json +9 -0
  25. package/lib/behind-api-client/BehindApiClient.js +137 -0
  26. package/lib/behind-api-client/chat/ChatApp.js +11 -0
  27. package/lib/behind-api-client/chat/ChatV10.js +13 -0
  28. package/lib/behind-api-client/chat/ChatV10Chat.js +87 -0
  29. package/lib/behind-api-client/chat/ChatV10Chats.js +14 -0
  30. package/lib/behind-api-client/chat/ChatV10Message.js +57 -0
  31. package/lib/behind-api-client/chat/ChatV20.js +11 -0
  32. package/lib/behind-api-client/chat/ChatV20Chat.js +14 -0
  33. package/lib/behind-api-client/chat/ChatV20Message.js +27 -0
  34. package/lib/behind-api-client/easyjob/EasyjobApp.js +9 -0
  35. package/lib/behind-api-client/easyjob/EasyjobV10.js +31 -0
  36. package/lib/behind-api-client/easyjob/EasyjobV10Answers.js +16 -0
  37. package/lib/behind-api-client/easyjob/EasyjobV10Applicants.js +29 -0
  38. package/lib/behind-api-client/easyjob/EasyjobV10Applications.js +39 -0
  39. package/lib/behind-api-client/easyjob/EasyjobV10CandidateProfileArtifacts.js +31 -0
  40. package/lib/behind-api-client/easyjob/EasyjobV10CandidateProfiles.js +99 -0
  41. package/lib/behind-api-client/easyjob/EasyjobV10Companies.js +36 -0
  42. package/lib/behind-api-client/easyjob/EasyjobV10Cv.js +15 -0
  43. package/lib/behind-api-client/easyjob/EasyjobV10Departments.js +37 -0
  44. package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptionArtifacts.js +29 -0
  45. package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptionCandidateQuestions.js +63 -0
  46. package/lib/behind-api-client/easyjob/EasyjobV10JobDescriptions.js +93 -0
  47. package/lib/behind-api-client/easyjob/EasyjobV10Reports.js +35 -0
  48. package/lib/behind-api-client/example.js +47 -0
  49. package/lib/behind-api-client/global/GlobalApp.js +9 -0
  50. package/lib/behind-api-client/global/GlobalV10.js +11 -0
  51. package/lib/behind-api-client/global/GlobalV10Sockets.js +16 -0
  52. package/lib/behind-api-client/global/GlobalV10Storage.js +29 -0
  53. package/lib/behind-api-client/gpt/GptApp.js +15 -0
  54. package/lib/behind-api-client/gpt/GptV10.js +15 -0
  55. package/lib/behind-api-client/gpt/GptV10Prompt.js +17 -0
  56. package/lib/behind-api-client/gpt/GptV10Request.js +16 -0
  57. package/lib/behind-api-client/gpt/GptV10Storedprompts.js +14 -0
  58. package/lib/behind-api-client/gpt/GptV10Whisper.js +23 -0
  59. package/lib/behind-api-client/gpt/GptV20.js +9 -0
  60. package/lib/behind-api-client/gpt/GptV20Prompt.js +15 -0
  61. package/lib/behind-api-client/gpt/GptV30.js +13 -0
  62. package/lib/behind-api-client/gpt/GptV30Chat.js +19 -0
  63. package/lib/behind-api-client/gpt/GptV30Prompt.js +41 -0
  64. package/lib/behind-api-client/gpt/GptV30Prompts.js +32 -0
  65. package/lib/behind-api-client/gpt/GptV40.js +11 -0
  66. package/lib/behind-api-client/gpt/GptV40Prompt.js +24 -0
  67. package/lib/behind-api-client/gpt/GptV40Prompts.js +30 -0
  68. package/lib/behind-api-client/mailer/MailerApp.js +11 -0
  69. package/lib/behind-api-client/mailer/MailerV10.js +15 -0
  70. package/lib/behind-api-client/mailer/MailerV10Bulk.js +21 -0
  71. package/lib/behind-api-client/mailer/MailerV10Message.js +83 -0
  72. package/lib/behind-api-client/mailer/MailerV10Settings.js +44 -0
  73. package/lib/behind-api-client/mailer/MailerV10Template.js +23 -0
  74. package/lib/behind-api-client/mailer/MailerV20.js +9 -0
  75. package/lib/behind-api-client/mailer/MailerV20Message.js +21 -0
  76. package/lib/behind-api-client/mastogram/MastogramApp.js +9 -0
  77. package/lib/behind-api-client/mastogram/MastogramV10.js +13 -0
  78. package/lib/behind-api-client/mastogram/MastogramV10Bluesky.js +42 -0
  79. package/lib/behind-api-client/mastogram/MastogramV10Mastodon.js +45 -0
  80. package/lib/behind-api-client/mastogram/MastogramV10Telegram.js +39 -0
  81. package/lib/behind-api-client/monitor/MonitorApp.js +9 -0
  82. package/lib/behind-api-client/monitor/MonitorV10.js +13 -0
  83. package/lib/behind-api-client/monitor/MonitorV10Finances.js +39 -0
  84. package/lib/behind-api-client/monitor/MonitorV10Record.js +15 -0
  85. package/lib/behind-api-client/monitor/MonitorV10Records.js +22 -0
  86. package/lib/behind-api-client/oauth/OauthApp.js +9 -0
  87. package/lib/behind-api-client/oauth/OauthV10.js +9 -0
  88. package/lib/behind-api-client/oauth/OauthV10Authorisation.js +15 -0
  89. package/lib/behind-api-client/package.json +9 -0
  90. package/lib/behind-api-client/payments/PaymentsApp.js +13 -0
  91. package/lib/behind-api-client/payments/PaymentsV10.js +15 -0
  92. package/lib/behind-api-client/payments/PaymentsV10Gift.js +32 -0
  93. package/lib/behind-api-client/payments/PaymentsV10Payture.js +30 -0
  94. package/lib/behind-api-client/payments/PaymentsV10Product.js +15 -0
  95. package/lib/behind-api-client/payments/PaymentsV10Telegram.js +44 -0
  96. package/lib/behind-api-client/payments/PaymentsV20.js +9 -0
  97. package/lib/behind-api-client/payments/PaymentsV20Payture.js +32 -0
  98. package/lib/behind-api-client/payments/PaymentsV21.js +15 -0
  99. package/lib/behind-api-client/payments/PaymentsV21Cards.js +14 -0
  100. package/lib/behind-api-client/payments/PaymentsV21Payture.js +29 -0
  101. package/lib/behind-api-client/payments/PaymentsV21Stripe.js +28 -0
  102. package/lib/behind-api-client/payments/PaymentsV21Subscriptions.js +21 -0
  103. package/lib/behind-api-client/questionnaire/QuestionnaireApp.js +9 -0
  104. package/lib/behind-api-client/questionnaire/QuestionnaireV10.js +9 -0
  105. package/lib/behind-api-client/questionnaire/QuestionnaireV10Form.js +22 -0
  106. package/lib/behind-api-client/raet/RaetApp.js +11 -0
  107. package/lib/behind-api-client/raet/RaetV10.js +21 -0
  108. package/lib/behind-api-client/raet/RaetV10Cv.js +87 -0
  109. package/lib/behind-api-client/raet/RaetV10Individual.js +43 -0
  110. package/lib/behind-api-client/raet/RaetV10Individuals.js +38 -0
  111. package/lib/behind-api-client/raet/RaetV10Jd.js +47 -0
  112. package/lib/behind-api-client/raet/RaetV10Project.js +61 -0
  113. package/lib/behind-api-client/raet/RaetV10Projects.js +14 -0
  114. package/lib/behind-api-client/raet/RaetV10Report.js +39 -0
  115. package/lib/behind-api-client/raet/RaetV20.js +11 -0
  116. package/lib/behind-api-client/raet/RaetV20Cv.js +31 -0
  117. package/lib/behind-api-client/raet/RaetV20Individuals.js +25 -0
  118. package/lib/behind-api-client/rag/RagApp.js +9 -0
  119. package/lib/behind-api-client/rag/RagV10.js +9 -0
  120. package/lib/behind-api-client/rag/RagV10Storage.js +27 -0
  121. package/lib/behind-api-client/ruKitchen/RuKitchenApp.js +9 -0
  122. package/lib/behind-api-client/ruKitchen/RuKitchenV10.js +11 -0
  123. package/lib/behind-api-client/ruKitchen/RuKitchenV10Importer.js +29 -0
  124. package/lib/behind-api-client/ruKitchen/RuKitchenV10SeoArticle.js +14 -0
  125. package/lib/behind-api-client/sales/SalesApp.js +11 -0
  126. package/lib/behind-api-client/sales/SalesV10.js +23 -0
  127. package/lib/behind-api-client/sales/SalesV10Catalogue.js +58 -0
  128. package/lib/behind-api-client/sales/SalesV10Categories.js +15 -0
  129. package/lib/behind-api-client/sales/SalesV10Companies.js +55 -0
  130. package/lib/behind-api-client/sales/SalesV10Company.js +120 -0
  131. package/lib/behind-api-client/sales/SalesV10Group.js +70 -0
  132. package/lib/behind-api-client/sales/SalesV10Groups.js +21 -0
  133. package/lib/behind-api-client/sales/SalesV10Logs.js +14 -0
  134. package/lib/behind-api-client/sales/SalesV10Notes.js +38 -0
  135. package/lib/behind-api-client/sales/SalesV20.js +11 -0
  136. package/lib/behind-api-client/sales/SalesV20Companies.js +26 -0
  137. package/lib/behind-api-client/sales/SalesV20Notes.js +17 -0
  138. package/lib/behind-api-client/sip/SipApp.js +9 -0
  139. package/lib/behind-api-client/sip/SipV10.js +15 -0
  140. package/lib/behind-api-client/sip/SipV10Call.js +83 -0
  141. package/lib/behind-api-client/sip/SipV10Phone.js +44 -0
  142. package/lib/behind-api-client/sip/SipV10Transcript.js +21 -0
  143. package/lib/behind-api-client/sip/SipV10Transcripts.js +21 -0
  144. package/lib/behind-api-client/storage/StorageApp.js +9 -0
  145. package/lib/behind-api-client/storage/StorageV10.js +11 -0
  146. package/lib/behind-api-client/storage/StorageV10File.js +35 -0
  147. package/lib/behind-api-client/storage/StorageV10Upload.js +21 -0
  148. package/lib/behind-api-client/tests/TestsApp.js +9 -0
  149. package/lib/behind-api-client/tests/TestsV10.js +15 -0
  150. package/lib/behind-api-client/tests/TestsV10Cases.js +29 -0
  151. package/lib/behind-api-client/tests/TestsV10CasesExtended.js +14 -0
  152. package/lib/behind-api-client/tests/TestsV10Core.js +14 -0
  153. package/lib/behind-api-client/tests/TestsV10Mail.js +14 -0
  154. package/lib/behind-api-client/tools/ToolsApp.js +9 -0
  155. package/lib/behind-api-client/tools/ToolsV10.js +9 -0
  156. package/lib/behind-api-client/tools/ToolsV10Pdf.js +30 -0
  157. package/package.json +25 -0
@@ -0,0 +1,1497 @@
1
+ # Payments API - Payture Extension
2
+
3
+ This document extends the main EasyJob JavaScript API Client Documentation with detailed information about the Payture payment gateway integration methods.
4
+
5
+ ## Overview
6
+
7
+ The Payture Payments API provides methods for creating and managing payment bills through the Payture payment gateway. This includes creating bills for authorized and unauthorized users, checking bill status, and handling payment workflows for subscriptions and gift purchases.
8
+
9
+ ---
10
+
11
+ ## Payments API - Payture
12
+
13
+ ### behindAPI.V20.payments.payture.billCreate(subscriptionId)
14
+ Creates a payment bill for an authorized user subscribing to a product.
15
+
16
+ **Parameters:**
17
+ - `subscriptionId` (string, required) - The subscription product UUID to create a bill for
18
+
19
+ **Usage:**
20
+ ```javascript
21
+ const result = await behindAPI.V20.payments.payture.billCreate(
22
+ "550e8400-e29b-41d4-a716-446655440001"
23
+ );
24
+
25
+ // Response:
26
+ {
27
+ success: true,
28
+ data: {
29
+ bill_id: "cc0e8400-e29b-41d4-a716-446655440009",
30
+ bill: {
31
+ payUrl: "https://payture.com/apim/Pay?SessionId=abc123xyz"
32
+ }
33
+ }
34
+ }
35
+
36
+ // Error Response:
37
+ {
38
+ success: false,
39
+ message: "Can't finish request"
40
+ }
41
+ ```
42
+
43
+ ### behindAPI.V20.payments.payture.billCreateUnauthorised(subscriptionId, userId, redirectUrl, extended)
44
+ Creates a payment bill for an unauthorized user or allows specifying custom parameters. This method is useful for guest checkouts or when you need to pass additional data with the payment.
45
+
46
+ **Parameters:**
47
+ - `subscriptionId` (string, required) - The subscription product UUID to create a bill for
48
+ - `userId` (string, required) - The user UUID who is making the purchase
49
+ - `redirectUrl` (string, optional) - Custom URL to redirect after payment completion. Must be a valid HTTP/HTTPS URL
50
+ - `extended` (object, optional) - Additional data to store with the bill (e.g., gift recipient info, page access details)
51
+
52
+ **Usage:**
53
+ ```javascript
54
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
55
+ "550e8400-e29b-41d4-a716-446655440001", // subscription_id
56
+ "aa0e8400-e29b-41d4-a716-446655440005", // user_id
57
+ "https://example.com/payment-complete", // redirect_url
58
+ {
59
+ pageId: "ck4jrtawdA3Ed4",
60
+ giftRecipient: "john@example.com",
61
+ customNote: "Holiday special"
62
+ } // extended
63
+ );
64
+
65
+ // Response:
66
+ {
67
+ success: true,
68
+ data: {
69
+ bill_id: "cc0e8400-e29b-41d4-a716-446655440009",
70
+ bill: {
71
+ payUrl: "https://payture.com/apim/Pay?SessionId=abc123xyz"
72
+ }
73
+ }
74
+ }
75
+
76
+ // Error Response:
77
+ {
78
+ success: false,
79
+ message: "Can't finish request"
80
+ }
81
+ ```
82
+
83
+ ### behindAPI.V20.payments.payture.billStatus(billId)
84
+ Retrieves the current status of a payment bill and processes completed payments. This method checks the bill status with Payture and updates the local database accordingly.
85
+
86
+ **Parameters:**
87
+ - `billId` (string, required) - The bill UUID to check status for
88
+
89
+ **Usage:**
90
+ ```javascript
91
+ const result = await behindAPI.V20.payments.payture.billStatus(
92
+ "cc0e8400-e29b-41d4-a716-446655440009"
93
+ );
94
+
95
+ // Response (pending payment):
96
+ {
97
+ success: true,
98
+ data: {
99
+ bill_info: {
100
+ bill_status: "PENDING",
101
+ amount: 99900
102
+ },
103
+ status: "PENDING"
104
+ }
105
+ }
106
+
107
+ // Response (successful payment):
108
+ {
109
+ success: true,
110
+ data: {
111
+ bill_info: {
112
+ bill_status: "PAID",
113
+ amount: 99900
114
+ },
115
+ status: "PAID"
116
+ }
117
+ }
118
+
119
+ // Response (gift purchase - includes gift code):
120
+ {
121
+ success: true,
122
+ data: {
123
+ bill_info: {
124
+ bill_status: "PAID",
125
+ amount: 99900,
126
+ gift: {
127
+ code: "GIFT-ABC123"
128
+ }
129
+ },
130
+ status: "PAID"
131
+ }
132
+ }
133
+
134
+ // Error Response (empty bill_id):
135
+ {
136
+ success: false,
137
+ message: "bill_id can not be empty"
138
+ }
139
+
140
+ // Error Response (amount mismatch):
141
+ {
142
+ success: false,
143
+ data: {
144
+ bill_info: {
145
+ bill_status: "PAID",
146
+ amount: 99900
147
+ },
148
+ status: "AMOUNT_MISMATCH"
149
+ }
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Data Structure Reference
156
+
157
+ ### Bill Creation Response
158
+ The `billCreate()` and `billCreateUnauthorised()` methods return:
159
+
160
+ **Success Response:**
161
+ - `success` (boolean) - Always `true` for successful requests
162
+ - `data` (object) - Container for response data
163
+ - `bill_id` (UUID) - The newly created bill's unique identifier
164
+ - `bill` (object) - Bill details
165
+ - `payUrl` (string) - URL to redirect user for payment
166
+
167
+ **Error Response:**
168
+ - `success` (boolean) - Always `false` for failed requests
169
+ - `message` (string) - Error description
170
+
171
+ ### Bill Status Response
172
+ The `billStatus()` method returns:
173
+
174
+ **Success Response:**
175
+ - `success` (boolean) - Always `true` for successful requests
176
+ - `data` (object) - Container for response data
177
+ - `bill_info` (object) - Payment information from Payture
178
+ - `bill_status` (string) - Current status: "PENDING", "PAID"
179
+ - `amount` (number) - Payment amount in kopecks (cents)
180
+ - `gift` (object, optional) - Only present for gift purchases after payment
181
+ - `code` (string) - Gift activation code
182
+ - `status` (string) - Current bill status: "PENDING", "PAID", "DONE", "AMOUNT_MISMATCH"
183
+
184
+ **Special Status Values:**
185
+ - `PENDING` - Payment not yet completed
186
+ - `PAID` - Payment completed on Payture side
187
+ - `DONE` - Payment processed and subscription/gift activated
188
+ - `AMOUNT_MISMATCH` - Payment amount doesn't match expected amount
189
+
190
+ ---
191
+
192
+ ## Complete Usage Examples
193
+
194
+ ### Basic Payment Flow for Authorized Users
195
+
196
+ ```javascript
197
+ // Example: Create payment and redirect user
198
+ async function createPaymentForUser(subscriptionId) {
199
+ try {
200
+ console.log("Creating payment bill...");
201
+
202
+ const billResult = await behindAPI.V20.payments.payture.billCreate(
203
+ subscriptionId
204
+ );
205
+
206
+ if (billResult.success) {
207
+ console.log("✓ Bill created successfully!");
208
+ console.log(`Bill ID: ${billResult.data.bill_id}`);
209
+ console.log(`Payment URL: ${billResult.data.bill.payUrl}`);
210
+
211
+ // Redirect user to payment page
212
+ window.location.href = billResult.data.bill.payUrl;
213
+
214
+ return billResult.data;
215
+ } else {
216
+ console.log(`✗ Failed to create bill: ${billResult.message}`);
217
+ return null;
218
+ }
219
+ } catch (error) {
220
+ console.error("Error creating payment:", error);
221
+ return null;
222
+ }
223
+ }
224
+
225
+ // Usage
226
+ const paymentData = await createPaymentForUser(
227
+ "550e8400-e29b-41d4-a716-446655440001"
228
+ );
229
+ ```
230
+
231
+ ### Guest Checkout with Custom Redirect
232
+
233
+ ```javascript
234
+ // Example: Create payment for guest user with custom redirect
235
+ async function createGuestPayment(subscriptionId, userId, returnUrl) {
236
+ try {
237
+ console.log("Creating guest payment bill...");
238
+
239
+ const billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
240
+ subscriptionId,
241
+ userId,
242
+ returnUrl,
243
+ {
244
+ source: "landing_page",
245
+ campaign: "spring_sale_2024"
246
+ }
247
+ );
248
+
249
+ if (billResult.success) {
250
+ console.log("✓ Guest bill created successfully!");
251
+ console.log(`Bill ID: ${billResult.data.bill_id}`);
252
+ console.log(`Payment URL: ${billResult.data.bill.payUrl}`);
253
+
254
+ // Store bill_id in session for later status checking
255
+ sessionStorage.setItem('pending_bill_id', billResult.data.bill_id);
256
+
257
+ // Redirect to payment
258
+ window.location.href = billResult.data.bill.payUrl;
259
+
260
+ return billResult.data;
261
+ } else {
262
+ console.log(`✗ Failed to create guest bill: ${billResult.message}`);
263
+ return null;
264
+ }
265
+ } catch (error) {
266
+ console.error("Error creating guest payment:", error);
267
+ return null;
268
+ }
269
+ }
270
+
271
+ // Usage
272
+ const guestPayment = await createGuestPayment(
273
+ "550e8400-e29b-41d4-a716-446655440001",
274
+ "aa0e8400-e29b-41d4-a716-446655440005",
275
+ "https://mysite.com/thank-you"
276
+ );
277
+ ```
278
+
279
+ ### Page Access Purchase with Extended Data
280
+
281
+ ```javascript
282
+ // Example: Purchase subscription with page access
283
+ async function purchasePageAccess(subscriptionId, userId, pageId) {
284
+ try {
285
+ console.log("Creating page access purchase...");
286
+
287
+ // Create bill with page access information
288
+ const billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
289
+ subscriptionId,
290
+ userId,
291
+ "https://mysite.com/access-granted",
292
+ {
293
+ pageId: "ck4jrtawdA3Ed4"
294
+ }
295
+ );
296
+
297
+ if (!billResult.success) {
298
+ console.log(`✗ Failed to create bill: ${billResult.message}`);
299
+ return { success: false, error: billResult.message };
300
+ }
301
+
302
+ console.log("✓ Bill created with page access!");
303
+ console.log(`Bill ID: ${billResult.data.bill_id}`);
304
+ console.log(`Page ID: ck4jrtawdA3Ed4`);
305
+
306
+ // Store for later verification
307
+ sessionStorage.setItem('pending_bill_id', billResult.data.bill_id);
308
+ sessionStorage.setItem('pending_page_id', 'ck4jrtawdA3Ed4');
309
+
310
+ // Redirect to payment
311
+ window.location.href = billResult.data.bill.payUrl;
312
+
313
+ return {
314
+ success: true,
315
+ billId: billResult.data.bill_id,
316
+ pageId: 'ck4jrtawdA3Ed4',
317
+ paymentUrl: billResult.data.bill.payUrl
318
+ };
319
+
320
+ } catch (error) {
321
+ console.error("Error purchasing page access:", error);
322
+ return { success: false, error: error.message };
323
+ }
324
+ }
325
+
326
+ // Usage
327
+ const pageAccessPurchase = await purchasePageAccess(
328
+ "550e8400-e29b-41d4-a716-446655440001",
329
+ "aa0e8400-e29b-41d4-a716-446655440005",
330
+ "ck4jrtawdA3Ed4"
331
+ );
332
+ ```
333
+
334
+ ### Gift Purchase Workflow
335
+
336
+ ```javascript
337
+ // Example: Purchase a gift subscription
338
+ async function purchaseGift(giftSubscriptionId, buyerId, recipientEmail) {
339
+ try {
340
+ console.log("Creating gift purchase...");
341
+
342
+ // Create bill with gift recipient information
343
+ const billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
344
+ giftSubscriptionId,
345
+ buyerId,
346
+ "https://mysite.com/gift-complete",
347
+ {
348
+ giftRecipient: recipientEmail,
349
+ giftType: "subscription",
350
+ giftMessage: "Enjoy your subscription!"
351
+ }
352
+ );
353
+
354
+ if (!billResult.success) {
355
+ console.log(`✗ Failed to create gift bill: ${billResult.message}`);
356
+ return { success: false, error: billResult.message };
357
+ }
358
+
359
+ console.log("✓ Gift bill created!");
360
+ console.log(`Bill ID: ${billResult.data.bill_id}`);
361
+
362
+ // Redirect to payment
363
+ window.location.href = billResult.data.bill.payUrl;
364
+
365
+ return {
366
+ success: true,
367
+ billId: billResult.data.bill_id,
368
+ paymentUrl: billResult.data.bill.payUrl
369
+ };
370
+
371
+ } catch (error) {
372
+ console.error("Error purchasing gift:", error);
373
+ return { success: false, error: error.message };
374
+ }
375
+ }
376
+
377
+ // Usage
378
+ const giftPurchase = await purchaseGift(
379
+ "550e8400-e29b-41d4-a716-446655440001",
380
+ "aa0e8400-e29b-41d4-a716-446655440005",
381
+ "recipient@example.com"
382
+ );
383
+ ```
384
+
385
+ ### Payment Status Monitoring
386
+
387
+ ```javascript
388
+ // Example: Check payment status with polling
389
+ async function monitorPaymentStatus(billId, maxAttempts = 10, intervalMs = 3000) {
390
+ let attempts = 0;
391
+
392
+ const checkStatus = async () => {
393
+ try {
394
+ console.log(`Checking payment status (attempt ${attempts + 1}/${maxAttempts})...`);
395
+
396
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(billId);
397
+
398
+ if (!statusResult.success) {
399
+ console.log(`✗ Status check failed: ${statusResult.message}`);
400
+ return { success: false, error: statusResult.message };
401
+ }
402
+
403
+ const status = statusResult.data.status;
404
+ console.log(`Current status: ${status}`);
405
+
406
+ if (status === "PAID" || status === "DONE") {
407
+ console.log("✓ Payment completed successfully!");
408
+
409
+ // Check for gift code
410
+ if (statusResult.data.bill_info.gift) {
411
+ console.log(`Gift code: ${statusResult.data.bill_info.gift.code}`);
412
+ }
413
+
414
+ return {
415
+ success: true,
416
+ status: status,
417
+ billInfo: statusResult.data.bill_info
418
+ };
419
+ }
420
+
421
+ if (status === "AMOUNT_MISMATCH") {
422
+ console.log("✗ Payment amount mismatch detected!");
423
+ return {
424
+ success: false,
425
+ error: "Amount mismatch",
426
+ status: status
427
+ };
428
+ }
429
+
430
+ // Still pending, continue polling
431
+ attempts++;
432
+ if (attempts < maxAttempts) {
433
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
434
+ return checkStatus();
435
+ } else {
436
+ console.log("⚠ Maximum attempts reached, payment still pending");
437
+ return {
438
+ success: false,
439
+ error: "Timeout",
440
+ status: "PENDING"
441
+ };
442
+ }
443
+
444
+ } catch (error) {
445
+ console.error("Error checking payment status:", error);
446
+ return { success: false, error: error.message };
447
+ }
448
+ };
449
+
450
+ return checkStatus();
451
+ }
452
+
453
+ // Usage
454
+ const billId = "cc0e8400-e29b-41d4-a716-446655440009";
455
+ const paymentResult = await monitorPaymentStatus(billId);
456
+
457
+ if (paymentResult.success) {
458
+ console.log("Payment confirmed!");
459
+ if (paymentResult.billInfo.gift) {
460
+ console.log(`Gift code: ${paymentResult.billInfo.gift.code}`);
461
+ }
462
+ } else {
463
+ console.log(`Payment not completed: ${paymentResult.error}`);
464
+ }
465
+ ```
466
+
467
+ ### Payment Return Handler with Page Access
468
+
469
+ ```javascript
470
+ // Example: Handle user return from payment gateway
471
+ async function handlePaymentReturn() {
472
+ try {
473
+ // Get bill_id from URL or session
474
+ const urlParams = new URLSearchParams(window.location.search);
475
+ const billId = urlParams.get('bill_id') ||
476
+ sessionStorage.getItem('pending_bill_id');
477
+ const pageId = sessionStorage.getItem('pending_page_id');
478
+
479
+ if (!billId) {
480
+ console.log("No bill ID found");
481
+ return { success: false, error: "No bill ID" };
482
+ }
483
+
484
+ console.log("Checking payment status for return...");
485
+
486
+ // Check the bill status
487
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(billId);
488
+
489
+ if (!statusResult.success) {
490
+ console.log(`✗ Failed to check status: ${statusResult.message}`);
491
+ return {
492
+ success: false,
493
+ error: statusResult.message
494
+ };
495
+ }
496
+
497
+ const status = statusResult.data.status;
498
+ const billInfo = statusResult.data.bill_info;
499
+
500
+ // Clear stored data
501
+ sessionStorage.removeItem('pending_bill_id');
502
+ sessionStorage.removeItem('pending_page_id');
503
+
504
+ if (status === "PAID" || status === "DONE") {
505
+ console.log("✓ Payment successful!");
506
+
507
+ // Handle gift code if present
508
+ if (billInfo.gift) {
509
+ return {
510
+ success: true,
511
+ status: status,
512
+ paymentType: "gift",
513
+ giftCode: billInfo.gift.code,
514
+ message: "Payment successful! Your gift code is ready."
515
+ };
516
+ }
517
+
518
+ // Handle page access if present
519
+ if (pageId) {
520
+ return {
521
+ success: true,
522
+ status: status,
523
+ paymentType: "page_access",
524
+ pageId: pageId,
525
+ message: "Payment successful! Your page access has been granted."
526
+ };
527
+ }
528
+
529
+ return {
530
+ success: true,
531
+ status: status,
532
+ paymentType: "subscription",
533
+ message: "Payment successful! Your subscription is now active."
534
+ };
535
+ } else if (status === "PENDING") {
536
+ console.log("⚠ Payment still pending");
537
+ return {
538
+ success: false,
539
+ status: "PENDING",
540
+ message: "Payment is still being processed. Please wait..."
541
+ };
542
+ } else if (status === "AMOUNT_MISMATCH") {
543
+ console.log("✗ Payment amount mismatch");
544
+ return {
545
+ success: false,
546
+ status: status,
547
+ message: "Payment amount doesn't match. Please contact support."
548
+ };
549
+ } else {
550
+ console.log(`⚠ Unknown status: ${status}`);
551
+ return {
552
+ success: false,
553
+ status: status,
554
+ message: "Unknown payment status. Please contact support."
555
+ };
556
+ }
557
+
558
+ } catch (error) {
559
+ console.error("Error handling payment return:", error);
560
+ return {
561
+ success: false,
562
+ error: error.message
563
+ };
564
+ }
565
+ }
566
+
567
+ // Usage on return page
568
+ window.addEventListener('load', async () => {
569
+ const result = await handlePaymentReturn();
570
+
571
+ if (result.success) {
572
+ document.getElementById('status').textContent = result.message;
573
+
574
+ if (result.paymentType === "gift" && result.giftCode) {
575
+ document.getElementById('gift-code').textContent = result.giftCode;
576
+ document.getElementById('gift-section').style.display = 'block';
577
+ } else if (result.paymentType === "page_access" && result.pageId) {
578
+ document.getElementById('page-info').textContent =
579
+ `You now have access to page: ${result.pageId}`;
580
+ document.getElementById('page-section').style.display = 'block';
581
+ }
582
+ } else {
583
+ document.getElementById('status').textContent =
584
+ result.message || "Payment not completed";
585
+ }
586
+ });
587
+ ```
588
+
589
+ ### Complete Purchase Flow with Error Handling
590
+
591
+ ```javascript
592
+ // Example: Complete payment flow from creation to confirmation
593
+ async function completePurchaseFlow(subscriptionId, userId, options = {}) {
594
+ const flow = {
595
+ billId: null,
596
+ paymentUrl: null,
597
+ status: null,
598
+ error: null
599
+ };
600
+
601
+ try {
602
+ console.log("=== STARTING PURCHASE FLOW ===");
603
+
604
+ // Step 1: Prepare extended data
605
+ const extendedData = {};
606
+ if (options.pageId) {
607
+ extendedData.pageId = options.pageId;
608
+ }
609
+ if (options.giftRecipient) {
610
+ extendedData.giftRecipient = options.giftRecipient;
611
+ }
612
+ if (options.customData) {
613
+ Object.assign(extendedData, options.customData);
614
+ }
615
+
616
+ // Step 2: Create bill
617
+ console.log("\n1. Creating payment bill...");
618
+ let billResult;
619
+
620
+ if (options.isGuest) {
621
+ billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
622
+ subscriptionId,
623
+ userId,
624
+ options.redirectUrl || "https://mysite.com/payment-return",
625
+ extendedData
626
+ );
627
+ } else {
628
+ billResult = await behindAPI.V20.payments.payture.billCreate(
629
+ subscriptionId
630
+ );
631
+ }
632
+
633
+ if (!billResult.success) {
634
+ console.log(`✗ Bill creation failed: ${billResult.message}`);
635
+ flow.error = billResult.message;
636
+ return flow;
637
+ }
638
+
639
+ flow.billId = billResult.data.bill_id;
640
+ flow.paymentUrl = billResult.data.bill.payUrl;
641
+
642
+ console.log(`✓ Bill created: ${flow.billId}`);
643
+ console.log(`Payment URL: ${flow.paymentUrl}`);
644
+
645
+ // Step 3: Store bill_id for later verification
646
+ sessionStorage.setItem('current_bill_id', flow.billId);
647
+ sessionStorage.setItem('bill_created_at', Date.now());
648
+
649
+ if (options.pageId) {
650
+ sessionStorage.setItem('pending_page_id', options.pageId);
651
+ }
652
+
653
+ // Step 4: Open payment in new window or redirect
654
+ console.log("\n2. Opening payment gateway...");
655
+ const paymentWindow = window.open(flow.paymentUrl, '_blank');
656
+
657
+ if (!paymentWindow) {
658
+ console.log("⚠ Popup blocked, redirecting in current window...");
659
+ window.location.href = flow.paymentUrl;
660
+ return flow;
661
+ }
662
+
663
+ // Step 5: Monitor payment status
664
+ console.log("\n3. Monitoring payment status...");
665
+ const monitoringResult = await monitorPaymentWindow(
666
+ flow.billId,
667
+ paymentWindow
668
+ );
669
+
670
+ flow.status = monitoringResult.status;
671
+
672
+ if (monitoringResult.success) {
673
+ console.log("✓ Payment completed successfully!");
674
+ sessionStorage.removeItem('current_bill_id');
675
+ sessionStorage.removeItem('bill_created_at');
676
+ sessionStorage.removeItem('pending_page_id');
677
+ } else {
678
+ console.log(`✗ Payment not completed: ${monitoringResult.error}`);
679
+ flow.error = monitoringResult.error;
680
+ }
681
+
682
+ return flow;
683
+
684
+ } catch (error) {
685
+ console.error("Error in purchase flow:", error);
686
+ flow.error = error.message;
687
+ return flow;
688
+ }
689
+ }
690
+
691
+ // Helper function to monitor payment window
692
+ async function monitorPaymentWindow(billId, paymentWindow) {
693
+ return new Promise((resolve) => {
694
+ let attempts = 0;
695
+ const maxAttempts = 60;
696
+
697
+ const interval = setInterval(async () => {
698
+ attempts++;
699
+
700
+ if (paymentWindow.closed) {
701
+ clearInterval(interval);
702
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(billId);
703
+
704
+ if (statusResult.success &&
705
+ (statusResult.data.status === "PAID" || statusResult.data.status === "DONE")) {
706
+ resolve({
707
+ success: true,
708
+ status: statusResult.data.status,
709
+ billInfo: statusResult.data.bill_info
710
+ });
711
+ } else {
712
+ resolve({
713
+ success: false,
714
+ error: "Payment window closed without completion",
715
+ status: statusResult.data?.status || "UNKNOWN"
716
+ });
717
+ }
718
+ return;
719
+ }
720
+
721
+ if (attempts % 2 === 0) {
722
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(billId);
723
+
724
+ if (statusResult.success &&
725
+ (statusResult.data.status === "PAID" || statusResult.data.status === "DONE")) {
726
+ clearInterval(interval);
727
+ paymentWindow.close();
728
+ resolve({
729
+ success: true,
730
+ status: statusResult.data.status,
731
+ billInfo: statusResult.data.bill_info
732
+ });
733
+ return;
734
+ }
735
+ }
736
+
737
+ if (attempts >= maxAttempts) {
738
+ clearInterval(interval);
739
+ resolve({
740
+ success: false,
741
+ error: "Payment monitoring timeout",
742
+ status: "PENDING"
743
+ });
744
+ }
745
+ }, 5000);
746
+ });
747
+ }
748
+
749
+ // Usage examples
750
+
751
+ // Standard purchase
752
+ const standardPurchase = await completePurchaseFlow(
753
+ "550e8400-e29b-41d4-a716-446655440001",
754
+ "aa0e8400-e29b-41d4-a716-446655440005",
755
+ {
756
+ isGuest: true
757
+ }
758
+ );
759
+
760
+ // Purchase with page access
761
+ const pageAccessPurchase = await completePurchaseFlow(
762
+ "550e8400-e29b-41d4-a716-446655440001",
763
+ "aa0e8400-e29b-41d4-a716-446655440005",
764
+ {
765
+ isGuest: true,
766
+ pageId: "ck4jrtawdA3Ed4",
767
+ redirectUrl: "https://mysite.com/access-granted"
768
+ }
769
+ );
770
+
771
+ // Gift purchase
772
+ const giftPurchase = await completePurchaseFlow(
773
+ "550e8400-e29b-41d4-a716-446655440001",
774
+ "aa0e8400-e29b-41d4-a716-446655440005",
775
+ {
776
+ isGuest: false,
777
+ giftRecipient: "recipient@example.com",
778
+ redirectUrl: "https://mysite.com/gift-sent"
779
+ }
780
+ );
781
+
782
+ console.log("=== PURCHASE RESULT ===");
783
+ console.log(pageAccessPurchase);
784
+ ```
785
+
786
+ ---
787
+
788
+ ## Best Practices
789
+
790
+ 1. **Bill ID Storage**: Always store the bill_id after creation for status verification and troubleshooting.
791
+
792
+ 2. **Status Polling**: Implement reasonable polling intervals (3-5 seconds) when monitoring payment status to avoid overwhelming the API.
793
+
794
+ 3. **Error Handling**: Always check the `success` property and handle various status values (PENDING, PAID, DONE, AMOUNT_MISMATCH).
795
+
796
+ 4. **Redirect URLs**: When using custom redirect URLs with `billCreateUnauthorised`, ensure they are properly formatted and accessible.
797
+
798
+ 5. **Extended Data**: Use the `extended` parameter to store additional context about the purchase:
799
+ - `pageId` (e.g., "ck4jrtawdA3Ed4") for granting page access after payment
800
+ - Gift recipient information for gift purchases
801
+ - Source tracking and campaign data
802
+ - Any custom metadata needed for your business logic
803
+
804
+ 6. **Amount Verification**: Always verify the payment amount matches your expected amount to prevent fraudulent transactions.
805
+
806
+ 7. **Gift Codes**: For gift purchases, ensure proper handling of the gift code returned after successful payment.
807
+
808
+ 8. **Page Access**: When including `pageId` in extended data, the system automatically grants user access to the specified page upon successful payment (for direct subscription types).
809
+
810
+ 9. **Session Management**: Clear stored bill IDs and session data after successful payment completion.
811
+
812
+ 10. **User Experience**: Provide clear feedback during payment processing and handle popup blockers gracefully.
813
+
814
+ 11. **Security**: Never store sensitive payment information locally. Always use the Payture gateway for payment processing.
815
+
816
+ ---
817
+
818
+ ## Payment Status Flow
819
+
820
+ ```
821
+ PENDING → PAID → DONE
822
+
823
+ AMOUNT_MISMATCH
824
+ ```
825
+
826
+ - **PENDING**: Initial state after bill creation, payment not completed
827
+ - **PAID**: Payment completed on Payture side, amount verified
828
+ - **DONE**: Payment processed and subscription/gift activated
829
+ - **AMOUNT_MISMATCH**: Payment completed but amount doesn't match expected value
830
+
831
+ ---
832
+
833
+ ## Extended Data Use Cases
834
+
835
+ The `extended` parameter in `billCreateUnauthorised` supports various use cases:
836
+
837
+ ### Page Access Purchase
838
+
839
+ ```javascript
840
+ // Grant access to specific page after payment
841
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
842
+ subscriptionId,
843
+ userId,
844
+ redirectUrl,
845
+ {
846
+ pageId: "ck4jrtawdA3Ed4"
847
+ }
848
+ );
849
+ ```
850
+
851
+ ### Gift Purchase with Recipient Info
852
+
853
+ ```javascript
854
+ // Store gift recipient information
855
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
856
+ subscriptionId,
857
+ userId,
858
+ redirectUrl,
859
+ {
860
+ giftRecipient: "friend@example.com",
861
+ giftMessage: "Happy Birthday!",
862
+ giftOccasion: "birthday"
863
+ }
864
+ );
865
+ ```
866
+
867
+ ### Marketing Campaign Tracking
868
+
869
+ ```javascript
870
+ // Track purchase source and campaign
871
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
872
+ subscriptionId,
873
+ userId,
874
+ redirectUrl,
875
+ {
876
+ source: "facebook_ad",
877
+ campaign: "spring_sale_2024",
878
+ referrer: "influencer_abc",
879
+ utm_source: "social",
880
+ utm_medium: "paid",
881
+ utm_campaign: "spring24"
882
+ }
883
+ );
884
+ ```
885
+
886
+ ---
887
+
888
+ ## Authorization Requirements
889
+
890
+ - `billCreate`: Requires valid user session (`need_authorization: true`)
891
+ - `billCreateUnauthorised`: No authorization required (`need_authorization: false`)
892
+ - `billStatus`: No authorization required (`need_authorization: false`)
893
+
894
+ The `billCreateUnauthorised` and `billStatus` methods can be called without user authentication, making them suitable for guest checkouts and status verification.
895
+
896
+ ---
897
+
898
+ ## Integration Notes
899
+
900
+ The Payture Payments API integrates with:
901
+
902
+ - **Subscription System**: Bills are created for subscription products and activate subscriptions upon payment
903
+ - **Gift System**: Supports gift purchases with automatic code generation and email notifications
904
+ - **Email System**: Sends invoices and gift notifications through the mailer API
905
+ - **Woololo API**: Can grant page access for specific purchase types when `pageId` is provided in extended data
906
+ - **Database**: Stores bill records, tracks status, and manages payment history
907
+
908
+ ### Page Access Integration
909
+
910
+ When creating a bill with `pageId` in the extended data:
911
+ 1. The bill is created with the page access information stored
912
+ 2. Upon successful payment (PAID status)
913
+ 3. For "direct" subscription product types, the system automatically grants user access to the specified page
914
+ 4. Access is granted using the Woololo API with access_type 'ALL_USERS'
915
+
916
+ ---
917
+
918
+ ## Error Handling
919
+
920
+ All methods return a response object with a `success` boolean property. When `success` is `false`, a `message` property contains the error description.
921
+
922
+ ```javascript
923
+ // Comprehensive error handling example
924
+ async function safePaymentOperation(subscriptionId, userId, pageId = null) {
925
+ try {
926
+ // Validate input parameters
927
+ if (!subscriptionId || !userId) {
928
+ return {
929
+ success: false,
930
+ error: "Missing required parameters"
931
+ };
932
+ }
933
+
934
+ // Validate UUID format
935
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
936
+ if (!uuidRegex.test(subscriptionId) || !uuidRegex.test(userId)) {
937
+ return {
938
+ success: false,
939
+ error: "Invalid UUID format"
940
+ };
941
+ }
942
+
943
+ // Prepare extended data
944
+ const extendedData = {};
945
+ if (pageId) {
946
+ extendedData.pageId = pageId;
947
+ }
948
+
949
+ // Create bill
950
+ const billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
951
+ subscriptionId,
952
+ userId,
953
+ "https://mysite.com/return",
954
+ extendedData
955
+ );
956
+
957
+ if (!billResult.success) {
958
+ console.error("API Error:", billResult.message);
959
+ return {
960
+ success: false,
961
+ error: billResult.message
962
+ };
963
+ }
964
+
965
+ return {
966
+ success: true,
967
+ billId: billResult.data.bill_id,
968
+ paymentUrl: billResult.data.bill.payUrl,
969
+ pageId: pageId
970
+ };
971
+
972
+ } catch (error) {
973
+ console.error("Unexpected error:", error);
974
+ return {
975
+ success: false,
976
+ error: "An unexpected error occurred"
977
+ };
978
+ }
979
+ }
980
+
981
+ // Usage with comprehensive error handling
982
+ const result = await safePaymentOperation(
983
+ "550e8400-e29b-41d4-a716-446655440001",
984
+ "aa0e8400-e29b-41d4-a716-446655440005",
985
+ "ck4jrtawdA3Ed4"
986
+ );
987
+
988
+ if (result.success) {
989
+ console.log("Bill created:", result.billId);
990
+ if (result.pageId) {
991
+ console.log("Page access will be granted:", result.pageId);
992
+ }
993
+ window.location.href = result.paymentUrl;
994
+ } else {
995
+ console.error("Operation failed:", result.error);
996
+ // Show user-friendly error message
997
+ alert("Unable to create payment. Please try again.");
998
+ }
999
+ ```
1000
+
1001
+ ---
1002
+
1003
+ ## Common Error Scenarios
1004
+
1005
+ ### Empty Bill ID
1006
+ ```javascript
1007
+ const result = await behindAPI.V20.payments.payture.billStatus("");
1008
+
1009
+ // Response:
1010
+ {
1011
+ success: false,
1012
+ message: "bill_id can not be empty"
1013
+ }
1014
+ ```
1015
+
1016
+ ### Invalid UUID Format
1017
+ ```javascript
1018
+ // Always validate UUIDs before making API calls
1019
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1020
+
1021
+ if (!uuidRegex.test(subscriptionId)) {
1022
+ console.error("Invalid subscription ID format");
1023
+ return { success: false, error: "Invalid UUID format" };
1024
+ }
1025
+ ```
1026
+
1027
+ ### Payment Amount Mismatch
1028
+ ```javascript
1029
+ // The system detects when payment amount doesn't match expected amount
1030
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(billId);
1031
+
1032
+ if (statusResult.data?.status === "AMOUNT_MISMATCH") {
1033
+ console.error("Payment amount verification failed");
1034
+ // Contact support or retry payment
1035
+ }
1036
+ ```
1037
+
1038
+ ### Network Timeout
1039
+ ```javascript
1040
+ // Implement timeout handling for API calls
1041
+ async function createBillWithTimeout(subscriptionId, userId, timeoutMs = 30000) {
1042
+ const timeoutPromise = new Promise((_, reject) => {
1043
+ setTimeout(() => reject(new Error("Request timeout")), timeoutMs);
1044
+ });
1045
+
1046
+ const billPromise = behindAPI.V20.payments.payture.billCreateUnauthorised(
1047
+ subscriptionId,
1048
+ userId,
1049
+ "https://mysite.com/return"
1050
+ );
1051
+
1052
+ try {
1053
+ const result = await Promise.race([billPromise, timeoutPromise]);
1054
+ return result;
1055
+ } catch (error) {
1056
+ console.error("Timeout or error:", error);
1057
+ return { success: false, error: error.message };
1058
+ }
1059
+ }
1060
+ ```
1061
+
1062
+ ---
1063
+
1064
+ ## Advanced Usage Patterns
1065
+
1066
+ ### Multi-Currency Support
1067
+ ```javascript
1068
+ // Handle different currencies based on user location
1069
+ async function createInternationalPayment(subscriptionId, userId, userCountry) {
1070
+ const currencyMap = {
1071
+ 'RU': { currency: 'RUB', redirectUrl: 'https://mysite.ru/return' },
1072
+ 'US': { currency: 'USD', redirectUrl: 'https://mysite.com/return' },
1073
+ 'EU': { currency: 'EUR', redirectUrl: 'https://mysite.eu/return' }
1074
+ };
1075
+
1076
+ const config = currencyMap[userCountry] || currencyMap['RU'];
1077
+
1078
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
1079
+ subscriptionId,
1080
+ userId,
1081
+ config.redirectUrl,
1082
+ {
1083
+ currency: config.currency,
1084
+ country: userCountry
1085
+ }
1086
+ );
1087
+
1088
+ return result;
1089
+ }
1090
+ ```
1091
+
1092
+ ### Retry Logic for Failed Payments
1093
+ ```javascript
1094
+ // Implement retry mechanism with exponential backoff
1095
+ async function createBillWithRetry(subscriptionId, userId, maxRetries = 3) {
1096
+ let lastError;
1097
+
1098
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1099
+ try {
1100
+ console.log(`Payment creation attempt ${attempt}/${maxRetries}`);
1101
+
1102
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
1103
+ subscriptionId,
1104
+ userId,
1105
+ "https://mysite.com/return"
1106
+ );
1107
+
1108
+ if (result.success) {
1109
+ console.log("✓ Payment created successfully");
1110
+ return result;
1111
+ }
1112
+
1113
+ lastError = result.message;
1114
+
1115
+ } catch (error) {
1116
+ lastError = error.message;
1117
+ console.error(`Attempt ${attempt} failed:`, error);
1118
+ }
1119
+
1120
+ // Wait before retrying (exponential backoff)
1121
+ if (attempt < maxRetries) {
1122
+ const waitTime = Math.pow(2, attempt) * 1000;
1123
+ console.log(`Waiting ${waitTime}ms before retry...`);
1124
+ await new Promise(resolve => setTimeout(resolve, waitTime));
1125
+ }
1126
+ }
1127
+
1128
+ return {
1129
+ success: false,
1130
+ error: `Failed after ${maxRetries} attempts: ${lastError}`
1131
+ };
1132
+ }
1133
+ ```
1134
+
1135
+ ### Payment Analytics Tracking
1136
+ ```javascript
1137
+ // Track payment events for analytics
1138
+ async function createTrackedPayment(subscriptionId, userId, analyticsData) {
1139
+ const startTime = Date.now();
1140
+
1141
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
1142
+ subscriptionId,
1143
+ userId,
1144
+ "https://mysite.com/return",
1145
+ {
1146
+ ...analyticsData,
1147
+ sessionId: generateSessionId(),
1148
+ deviceType: getDeviceType(),
1149
+ referrer: document.referrer
1150
+ }
1151
+ );
1152
+
1153
+ const duration = Date.now() - startTime;
1154
+
1155
+ // Send analytics event
1156
+ trackEvent('payment_initiated', {
1157
+ billId: result.data?.bill_id,
1158
+ subscriptionId: subscriptionId,
1159
+ success: result.success,
1160
+ duration: duration,
1161
+ ...analyticsData
1162
+ });
1163
+
1164
+ return result;
1165
+ }
1166
+
1167
+ function trackEvent(eventName, eventData) {
1168
+ // Your analytics implementation
1169
+ console.log(`Analytics: ${eventName}`, eventData);
1170
+ }
1171
+
1172
+ function generateSessionId() {
1173
+ return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1174
+ }
1175
+
1176
+ function getDeviceType() {
1177
+ const ua = navigator.userAgent;
1178
+ if (/mobile/i.test(ua)) return 'mobile';
1179
+ if (/tablet/i.test(ua)) return 'tablet';
1180
+ return 'desktop';
1181
+ }
1182
+ ```
1183
+
1184
+ ### Webhook Handler for Payment Notifications
1185
+ ```javascript
1186
+ // Server-side webhook handler example (Node.js/Express)
1187
+ app.post('/webhooks/payture', async (req, res) => {
1188
+ try {
1189
+ const { bill_id, status, amount } = req.body;
1190
+
1191
+ // Verify webhook authenticity (implement your verification logic)
1192
+ if (!verifyWebhookSignature(req)) {
1193
+ return res.status(401).json({ error: 'Invalid signature' });
1194
+ }
1195
+
1196
+ // Check payment status
1197
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(bill_id);
1198
+
1199
+ if (statusResult.success && statusResult.data.status === "DONE") {
1200
+ // Payment completed, update your systems
1201
+ await updateUserSubscription(bill_id);
1202
+
1203
+ // Send confirmation email
1204
+ await sendPaymentConfirmation(bill_id);
1205
+
1206
+ res.status(200).json({ success: true });
1207
+ } else {
1208
+ res.status(200).json({ success: false, status: statusResult.data?.status });
1209
+ }
1210
+
1211
+ } catch (error) {
1212
+ console.error('Webhook error:', error);
1213
+ res.status(500).json({ error: 'Internal server error' });
1214
+ }
1215
+ });
1216
+ ```
1217
+
1218
+ ### Subscription Management Dashboard
1219
+ ```javascript
1220
+ // Build a dashboard showing all user payments
1221
+ async function buildPaymentDashboard(userId) {
1222
+ const dashboard = {
1223
+ activeSubscriptions: [],
1224
+ pendingPayments: [],
1225
+ completedPayments: [],
1226
+ giftCodes: [],
1227
+ totalSpent: 0
1228
+ };
1229
+
1230
+ try {
1231
+ // Fetch user's bills from your database
1232
+ const userBills = await fetchUserBills(userId);
1233
+
1234
+ for (const bill of userBills) {
1235
+ const statusResult = await behindAPI.V20.payments.payture.billStatus(
1236
+ bill.bill_id
1237
+ );
1238
+
1239
+ if (!statusResult.success) continue;
1240
+
1241
+ const billData = {
1242
+ billId: bill.bill_id,
1243
+ amount: statusResult.data.bill_info.amount / 100,
1244
+ status: statusResult.data.status,
1245
+ createdAt: bill.created_at
1246
+ };
1247
+
1248
+ switch (statusResult.data.status) {
1249
+ case "PENDING":
1250
+ dashboard.pendingPayments.push(billData);
1251
+ break;
1252
+ case "DONE":
1253
+ case "PAID":
1254
+ dashboard.completedPayments.push(billData);
1255
+ dashboard.totalSpent += billData.amount;
1256
+
1257
+ if (statusResult.data.bill_info.gift) {
1258
+ dashboard.giftCodes.push({
1259
+ ...billData,
1260
+ giftCode: statusResult.data.bill_info.gift.code
1261
+ });
1262
+ } else {
1263
+ dashboard.activeSubscriptions.push(billData);
1264
+ }
1265
+ break;
1266
+ }
1267
+ }
1268
+
1269
+ return dashboard;
1270
+
1271
+ } catch (error) {
1272
+ console.error("Error building dashboard:", error);
1273
+ return dashboard;
1274
+ }
1275
+ }
1276
+
1277
+ // Usage
1278
+ const dashboard = await buildPaymentDashboard("aa0e8400-e29b-41d4-a716-446655440005");
1279
+ console.log("Payment Dashboard:", dashboard);
1280
+ ```
1281
+
1282
+ ---
1283
+
1284
+ ## Testing
1285
+
1286
+ ### Test Environment Setup
1287
+ ```javascript
1288
+ // Configure test environment
1289
+ const TEST_CONFIG = {
1290
+ subscriptionId: "550e8400-e29b-41d4-a716-446655440001",
1291
+ testUserId: "test-user-000000000000000000000001",
1292
+ testPageId: "ck4jrtawdA3Ed4",
1293
+ testRedirectUrl: "https://test.mysite.com/return"
1294
+ };
1295
+
1296
+ // Run payment flow test
1297
+ async function testPaymentFlow() {
1298
+ console.log("=== TESTING PAYMENT FLOW ===\n");
1299
+
1300
+ // Test 1: Create bill
1301
+ console.log("Test 1: Creating test bill...");
1302
+ const billResult = await behindAPI.V20.payments.payture.billCreateUnauthorised(
1303
+ TEST_CONFIG.subscriptionId,
1304
+ TEST_CONFIG.testUserId,
1305
+ TEST_CONFIG.testRedirectUrl,
1306
+ {
1307
+ pageId: TEST_CONFIG.testPageId,
1308
+ test: true
1309
+ }
1310
+ );
1311
+
1312
+ console.log(billResult.success ? "✓ PASS" : "✗ FAIL");
1313
+ if (!billResult.success) return;
1314
+
1315
+ const billId = billResult.data.bill_id;
1316
+ console.log(`Bill ID: ${billId}\n`);
1317
+
1318
+ // Test 2: Check initial status
1319
+ console.log("Test 2: Checking initial bill status...");
1320
+ const initialStatus = await behindAPI.V20.payments.payture.billStatus(billId);
1321
+ console.log(initialStatus.success ? "✓ PASS" : "✗ FAIL");
1322
+ console.log(`Status: ${initialStatus.data?.status}\n`);
1323
+
1324
+ // Test 3: Check with empty bill_id
1325
+ console.log("Test 3: Testing empty bill_id validation...");
1326
+ const emptyTest = await behindAPI.V20.payments.payture.billStatus("");
1327
+ console.log(!emptyTest.success ? "✓ PASS" : "✗ FAIL");
1328
+ console.log(`Error message: ${emptyTest.message}\n`);
1329
+
1330
+ console.log("=== TEST COMPLETE ===");
1331
+ }
1332
+
1333
+ // Run tests
1334
+ testPaymentFlow();
1335
+ ```
1336
+
1337
+ ---
1338
+
1339
+ ## Troubleshooting
1340
+
1341
+ ### Common Issues and Solutions
1342
+
1343
+ **Issue: Payment window blocked by popup blocker**
1344
+ ```javascript
1345
+ // Solution: Provide fallback to direct redirect
1346
+ const paymentWindow = window.open(paymentUrl, '_blank');
1347
+
1348
+ if (!paymentWindow || paymentWindow.closed) {
1349
+ alert("Please allow popups for this site to complete payment");
1350
+ // Fallback to same-window redirect
1351
+ window.location.href = paymentUrl;
1352
+ }
1353
+ ```
1354
+
1355
+ **Issue: Payment status remains PENDING after successful payment**
1356
+ ```javascript
1357
+ // Solution: Implement proper status polling with logging
1358
+ async function debugPaymentStatus(billId) {
1359
+ console.log(`Debugging bill: ${billId}`);
1360
+
1361
+ const result = await behindAPI.V20.payments.payture.billStatus(billId);
1362
+
1363
+ console.log("API Response:", JSON.stringify(result, null, 2));
1364
+ console.log("Status:", result.data?.status);
1365
+ console.log("Bill Status:", result.data?.bill_info?.bill_status);
1366
+ console.log("Amount:", result.data?.bill_info?.amount);
1367
+
1368
+ return result;
1369
+ }
1370
+ ```
1371
+
1372
+ **Issue: Amount mismatch errors**
1373
+ ```javascript
1374
+ // Solution: Log and verify amounts at each step
1375
+ async function verifyPaymentAmount(billId, expectedAmount) {
1376
+ const result = await behindAPI.V20.payments.payture.billStatus(billId);
1377
+
1378
+ if (result.success) {
1379
+ const actualAmount = result.data.bill_info.amount / 100; // Convert from kopecks
1380
+ console.log(`Expected: ${expectedAmount}, Actual: ${actualAmount}`);
1381
+
1382
+ if (Math.abs(actualAmount - expectedAmount) > 0.01) {
1383
+ console.error("Amount mismatch detected!");
1384
+ return false;
1385
+ }
1386
+ }
1387
+
1388
+ return true;
1389
+ }
1390
+ ```
1391
+
1392
+ **Issue: Lost bill_id after page refresh**
1393
+ ```javascript
1394
+ // Solution: Implement persistent storage
1395
+ function saveBillId(billId) {
1396
+ // Store in multiple places for redundancy
1397
+ sessionStorage.setItem('pending_bill_id', billId);
1398
+ localStorage.setItem('last_bill_id', billId);
1399
+
1400
+ // Store with timestamp for cleanup
1401
+ const billData = {
1402
+ billId: billId,
1403
+ timestamp: Date.now()
1404
+ };
1405
+ localStorage.setItem('bill_data', JSON.stringify(billData));
1406
+ }
1407
+
1408
+ function retrieveBillId() {
1409
+ // Try session storage first
1410
+ let billId = sessionStorage.getItem('pending_bill_id');
1411
+
1412
+ // Fallback to local storage
1413
+ if (!billId) {
1414
+ billId = localStorage.getItem('last_bill_id');
1415
+ }
1416
+
1417
+ // Check if bill is recent (within 24 hours)
1418
+ const billData = JSON.parse(localStorage.getItem('bill_data') || '{}');
1419
+ const hoursSinceCreation = (Date.now() - billData.timestamp) / (1000 * 60 * 60);
1420
+
1421
+ if (hoursSinceCreation > 24) {
1422
+ console.warn("Bill ID is more than 24 hours old");
1423
+ }
1424
+
1425
+ return billId;
1426
+ }
1427
+ ```
1428
+
1429
+ ---
1430
+
1431
+ ## Security Considerations
1432
+
1433
+ 1. **Never expose sensitive data**: Don't log or store payment card details
1434
+ 2. **Validate all inputs**: Always validate UUIDs and URLs before API calls
1435
+ 3. **Use HTTPS**: Ensure all redirect URLs use HTTPS protocol
1436
+ 4. **Implement CSRF protection**: Use tokens for payment initiation
1437
+ 5. **Rate limiting**: Implement rate limiting to prevent abuse
1438
+ 6. **Verify webhooks**: Always verify webhook signatures
1439
+ 7. **Session security**: Use secure session storage mechanisms
1440
+ 8. **Audit logging**: Log all payment operations for security audits
1441
+
1442
+ ```javascript
1443
+ // Example: Secure payment initiation
1444
+ async function securePaymentInit(subscriptionId, userId, csrfToken) {
1445
+ // Verify CSRF token
1446
+ if (!verifyCsrfToken(csrfToken)) {
1447
+ return { success: false, error: "Invalid security token" };
1448
+ }
1449
+
1450
+ // Sanitize inputs
1451
+ const sanitizedSubId = sanitizeUuid(subscriptionId);
1452
+ const sanitizedUserId = sanitizeUuid(userId);
1453
+
1454
+ // Check rate limit
1455
+ if (isRateLimited(userId)) {
1456
+ return { success: false, error: "Too many requests. Please try again later." };
1457
+ }
1458
+
1459
+ // Create bill with audit log
1460
+ const result = await behindAPI.V20.payments.payture.billCreateUnauthorised(
1461
+ sanitizedSubId,
1462
+ sanitizedUserId,
1463
+ "https://secure.mysite.com/return"
1464
+ );
1465
+
1466
+ // Log the operation
1467
+ auditLog({
1468
+ action: 'payment_initiated',
1469
+ userId: sanitizedUserId,
1470
+ billId: result.data?.bill_id,
1471
+ success: result.success,
1472
+ timestamp: new Date().toISOString()
1473
+ });
1474
+
1475
+ return result;
1476
+ }
1477
+ ```
1478
+
1479
+ ---
1480
+
1481
+ ## API Reference Summary
1482
+
1483
+ | Method | Authorization Required | Parameters | Returns |
1484
+ |--------|----------------------|------------|---------|
1485
+ | `billCreate` | Yes | subscriptionId | bill_id, payUrl |
1486
+ | `billCreateUnauthorised` | No | subscriptionId, userId, redirectUrl, extended | bill_id, payUrl |
1487
+ | `billStatus` | No | billId | bill_info, status |
1488
+
1489
+ ---
1490
+
1491
+ ## Support and Resources
1492
+
1493
+ For additional help:
1494
+ - **API Documentation**: Refer to the main EasyJob API documentation
1495
+ - **Error Codes**: Check Payture's official error code documentation
1496
+ - **Support**: Contact your technical support team for integration assistance
1497
+ - **Testing**: Use test environment before production deployment