@hypay/typescript-sdk 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +735 -0
- package/dist/chunk-LKIXYEBZ.mjs +103 -0
- package/dist/helpers-T6ONVODW.mjs +30 -0
- package/dist/index.d.mts +1363 -0
- package/dist/index.d.ts +1363 -0
- package/dist/index.js +1227 -0
- package/dist/index.mjs +1067 -0
- package/package.json +52 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1067 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildItemsString,
|
|
3
|
+
calculateItemsTotal,
|
|
4
|
+
isTestMasof,
|
|
5
|
+
isValidEmail,
|
|
6
|
+
isValidIsraeliId,
|
|
7
|
+
isValidMasof,
|
|
8
|
+
isValidToken,
|
|
9
|
+
parsePaymentPageResponse,
|
|
10
|
+
parseQueryString,
|
|
11
|
+
parseRedirectUrl,
|
|
12
|
+
parseTokef,
|
|
13
|
+
serializeParams,
|
|
14
|
+
toQueryString
|
|
15
|
+
} from "./chunk-LKIXYEBZ.mjs";
|
|
16
|
+
|
|
17
|
+
// src/types.ts
|
|
18
|
+
var Coin = /* @__PURE__ */ ((Coin2) => {
|
|
19
|
+
Coin2[Coin2["ILS"] = 1] = "ILS";
|
|
20
|
+
Coin2[Coin2["USD"] = 2] = "USD";
|
|
21
|
+
Coin2[Coin2["EUR"] = 3] = "EUR";
|
|
22
|
+
Coin2[Coin2["GBP"] = 4] = "GBP";
|
|
23
|
+
return Coin2;
|
|
24
|
+
})(Coin || {});
|
|
25
|
+
var PageLang = /* @__PURE__ */ ((PageLang2) => {
|
|
26
|
+
PageLang2["HEB"] = "HEB";
|
|
27
|
+
PageLang2["ENG"] = "ENG";
|
|
28
|
+
return PageLang2;
|
|
29
|
+
})(PageLang || {});
|
|
30
|
+
var TashType = /* @__PURE__ */ ((TashType2) => {
|
|
31
|
+
TashType2[TashType2["Regular"] = 1] = "Regular";
|
|
32
|
+
TashType2[TashType2["Credit"] = 6] = "Credit";
|
|
33
|
+
return TashType2;
|
|
34
|
+
})(TashType || {});
|
|
35
|
+
var Bank = /* @__PURE__ */ ((Bank2) => {
|
|
36
|
+
Bank2[Bank2["Isracard"] = 1] = "Isracard";
|
|
37
|
+
Bank2[Bank2["VisaCal"] = 2] = "VisaCal";
|
|
38
|
+
Bank2[Bank2["Diners"] = 3] = "Diners";
|
|
39
|
+
Bank2[Bank2["Amex"] = 4] = "Amex";
|
|
40
|
+
Bank2[Bank2["MAX"] = 6] = "MAX";
|
|
41
|
+
Bank2[Bank2["BIT"] = 99] = "BIT";
|
|
42
|
+
return Bank2;
|
|
43
|
+
})(Bank || {});
|
|
44
|
+
var Brand = /* @__PURE__ */ ((Brand2) => {
|
|
45
|
+
Brand2[Brand2["PL"] = 0] = "PL";
|
|
46
|
+
Brand2[Brand2["MasterCard"] = 1] = "MasterCard";
|
|
47
|
+
Brand2[Brand2["Visa"] = 2] = "Visa";
|
|
48
|
+
Brand2[Brand2["Diners"] = 3] = "Diners";
|
|
49
|
+
Brand2[Brand2["Amex"] = 4] = "Amex";
|
|
50
|
+
Brand2[Brand2["Isracard"] = 5] = "Isracard";
|
|
51
|
+
return Brand2;
|
|
52
|
+
})(Brand || {});
|
|
53
|
+
var Issuer = /* @__PURE__ */ ((Issuer2) => {
|
|
54
|
+
Issuer2[Issuer2["Foreign"] = 0] = "Foreign";
|
|
55
|
+
Issuer2[Issuer2["Isracard"] = 1] = "Isracard";
|
|
56
|
+
Issuer2[Issuer2["VisaCal"] = 2] = "VisaCal";
|
|
57
|
+
Issuer2[Issuer2["JCB"] = 5] = "JCB";
|
|
58
|
+
Issuer2[Issuer2["MAX"] = 6] = "MAX";
|
|
59
|
+
return Issuer2;
|
|
60
|
+
})(Issuer || {});
|
|
61
|
+
var HKNewStatus = /* @__PURE__ */ ((HKNewStatus2) => {
|
|
62
|
+
HKNewStatus2[HKNewStatus2["Terminate"] = 1] = "Terminate";
|
|
63
|
+
HKNewStatus2[HKNewStatus2["Activate"] = 2] = "Activate";
|
|
64
|
+
return HKNewStatus2;
|
|
65
|
+
})(HKNewStatus || {});
|
|
66
|
+
var SpecialCardType = /* @__PURE__ */ ((SpecialCardType2) => {
|
|
67
|
+
SpecialCardType2["Default"] = "00";
|
|
68
|
+
SpecialCardType2["Immediate"] = "01";
|
|
69
|
+
SpecialCardType2["Club"] = "70";
|
|
70
|
+
SpecialCardType2["PetrolCard"] = "03";
|
|
71
|
+
SpecialCardType2["DualCard"] = "04";
|
|
72
|
+
SpecialCardType2["DualClub"] = "74";
|
|
73
|
+
SpecialCardType2["PetrolClub"] = "75";
|
|
74
|
+
SpecialCardType2["Chargeable"] = "06";
|
|
75
|
+
SpecialCardType2["Petrol"] = "08";
|
|
76
|
+
SpecialCardType2["Tourist"] = "99";
|
|
77
|
+
return SpecialCardType2;
|
|
78
|
+
})(SpecialCardType || {});
|
|
79
|
+
var HypayError = class extends Error {
|
|
80
|
+
constructor(message, code, raw, params) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "HypayError";
|
|
83
|
+
this.code = code;
|
|
84
|
+
this.raw = raw;
|
|
85
|
+
this.params = params;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var HypayNetworkError = class extends Error {
|
|
89
|
+
constructor(message, cause) {
|
|
90
|
+
super(message);
|
|
91
|
+
this.name = "HypayNetworkError";
|
|
92
|
+
this.cause = cause;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var HypayTimeoutError = class extends Error {
|
|
96
|
+
constructor(timeoutMs) {
|
|
97
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
98
|
+
this.name = "HypayTimeoutError";
|
|
99
|
+
this.timeoutMs = timeoutMs;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/errors.ts
|
|
104
|
+
var HYPAY_ERROR_CODES = {
|
|
105
|
+
"33": "Refund amount is greater than the original transaction amount",
|
|
106
|
+
"250": "Deal does not exist or already committed",
|
|
107
|
+
"400": "Sum of items differs from transaction amount",
|
|
108
|
+
"401": "First or last name is required",
|
|
109
|
+
"402": "Transaction information (Info) is required",
|
|
110
|
+
"600": "Checking card number (J2)",
|
|
111
|
+
"700": "Approved without charge (J5 credit line reservation)",
|
|
112
|
+
"800": "Postpone transaction (delayed charge)",
|
|
113
|
+
"901": "Terminal is not permitted to work in this method",
|
|
114
|
+
"902": "Authentication error \u2014 reference differs from configured method",
|
|
115
|
+
"903": "Number of payments exceeds terminal configuration",
|
|
116
|
+
"905": "Wrong parameter value",
|
|
117
|
+
"906": "Agreement does not exist",
|
|
118
|
+
"910": "Token request from invalid transaction \u2014 add allowFalse=True",
|
|
119
|
+
"920": "Deal does not exist or already committed/cancelled",
|
|
120
|
+
"990": "Card details not fully readable",
|
|
121
|
+
"996": "Terminal is not permitted to use token",
|
|
122
|
+
"997": "Token is not valid",
|
|
123
|
+
"998": "Deal cancelled",
|
|
124
|
+
"999": "Communication error"
|
|
125
|
+
};
|
|
126
|
+
var SHVA_ERROR_CODES = {
|
|
127
|
+
"0": "Approved",
|
|
128
|
+
"000": "Approved",
|
|
129
|
+
"1": "Card blocked \u2014 confiscate card",
|
|
130
|
+
"001": "Card blocked",
|
|
131
|
+
"2": "Stolen card \u2014 confiscate card",
|
|
132
|
+
"002": "Stolen card \u2014 confiscate card",
|
|
133
|
+
"3": "Call credit card company",
|
|
134
|
+
"003": "Call credit card company",
|
|
135
|
+
"4": "Transaction not approved",
|
|
136
|
+
"004": "Transaction not approved",
|
|
137
|
+
"5": "Forged card \u2014 confiscate card",
|
|
138
|
+
"005": "Forged card \u2014 confiscate card",
|
|
139
|
+
"6": "Incorrect ID or CVV",
|
|
140
|
+
"006": "Rejected: incorrect CVV2",
|
|
141
|
+
"7": "Must call credit card company",
|
|
142
|
+
"007": "Rejected: incorrect CAVV/UCAF",
|
|
143
|
+
"8": "Error building encryption key for blocked file",
|
|
144
|
+
"008": "Rejected: incorrect AVS",
|
|
145
|
+
"9": "Could not connect \u2014 call credit card company",
|
|
146
|
+
"009": "Rejection \u2014 communication disconnect",
|
|
147
|
+
"010": "Partial approval",
|
|
148
|
+
"011": "Rejected: insufficient points/stars/miles/benefit",
|
|
149
|
+
"012": "Card not authorized at this terminal",
|
|
150
|
+
"013": "Rejected: incorrect balance code",
|
|
151
|
+
"014": "Rejected: card not associated with network",
|
|
152
|
+
"015": "Rejected: card not valid (expired)",
|
|
153
|
+
"016": "Rejected: currency not authorized",
|
|
154
|
+
"017": "Rejected: credit type not authorized for transaction",
|
|
155
|
+
"026": "Rejected: incorrect ID",
|
|
156
|
+
"033": "Invalid card",
|
|
157
|
+
"036": "Expired card",
|
|
158
|
+
"041": "Must query due to ceiling only for J2 transaction",
|
|
159
|
+
"042": "Must query (not ceiling-only) for J2 transaction",
|
|
160
|
+
"173": "Duplicate transaction"
|
|
161
|
+
};
|
|
162
|
+
var ALL_ERROR_CODES = {
|
|
163
|
+
...SHVA_ERROR_CODES,
|
|
164
|
+
...HYPAY_ERROR_CODES
|
|
165
|
+
};
|
|
166
|
+
function getErrorMessage(ccode) {
|
|
167
|
+
return ALL_ERROR_CODES[ccode] ?? `Unknown error (CCode=${ccode})`;
|
|
168
|
+
}
|
|
169
|
+
function isSuccessCode(ccode) {
|
|
170
|
+
return ccode === "0" || ccode === "600" || ccode === "700" || ccode === "800";
|
|
171
|
+
}
|
|
172
|
+
function isShvaError(ccode) {
|
|
173
|
+
const num = parseInt(ccode, 10);
|
|
174
|
+
return !isNaN(num) && num >= 1 && num <= 200;
|
|
175
|
+
}
|
|
176
|
+
function isHypayError(ccode) {
|
|
177
|
+
const num = parseInt(ccode, 10);
|
|
178
|
+
if (isNaN(num)) return false;
|
|
179
|
+
if (num === 600 || num === 700 || num === 800) return false;
|
|
180
|
+
return num >= 201 && num <= 999;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/client.ts
|
|
184
|
+
var DEFAULT_BASE_URL = "https://pay.hyp.co.il/p/";
|
|
185
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
186
|
+
var HypayClient = class {
|
|
187
|
+
constructor(config) {
|
|
188
|
+
this.masof = config.masof;
|
|
189
|
+
this.apiKey = config.apiKey;
|
|
190
|
+
this.passP = config.passP;
|
|
191
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/?$/, "/");
|
|
192
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
193
|
+
this.fetchFn = config.fetch ?? globalThis.fetch;
|
|
194
|
+
this.hooks = config.hooks ?? {};
|
|
195
|
+
}
|
|
196
|
+
// ─── Low-level HTTP ──────────────────────────────────────────────────────
|
|
197
|
+
/**
|
|
198
|
+
* Make a GET request to the Hypay API.
|
|
199
|
+
* All API calls use GET by default, which is the most common method for Hypay.
|
|
200
|
+
*/
|
|
201
|
+
async requestGet(action, params) {
|
|
202
|
+
const serialized = serializeParams(params);
|
|
203
|
+
const qs = toQueryString(serialized);
|
|
204
|
+
const url = `${this.baseUrl}?${qs}`;
|
|
205
|
+
const context = {
|
|
206
|
+
action,
|
|
207
|
+
method: "GET",
|
|
208
|
+
url,
|
|
209
|
+
params: Object.fromEntries(
|
|
210
|
+
Object.entries(serialized).filter(([, v]) => v !== void 0).map(([k, v]) => [k, String(v)])
|
|
211
|
+
)
|
|
212
|
+
};
|
|
213
|
+
await this.hooks.onRequest?.(context);
|
|
214
|
+
const start = Date.now();
|
|
215
|
+
let response;
|
|
216
|
+
try {
|
|
217
|
+
const controller = new AbortController();
|
|
218
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
219
|
+
try {
|
|
220
|
+
response = await this.fetchFn(url, { signal: controller.signal });
|
|
221
|
+
} finally {
|
|
222
|
+
clearTimeout(timer);
|
|
223
|
+
}
|
|
224
|
+
} catch (err) {
|
|
225
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
226
|
+
throw new HypayTimeoutError(this.timeout);
|
|
227
|
+
}
|
|
228
|
+
throw new HypayNetworkError(
|
|
229
|
+
`Network error while calling Hypay API: ${err instanceof Error ? err.message : String(err)}`,
|
|
230
|
+
err
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const text = await response.text();
|
|
234
|
+
const parsed = parseQueryString(text);
|
|
235
|
+
const durationMs = Date.now() - start;
|
|
236
|
+
await this.hooks.onResponse?.({
|
|
237
|
+
...context,
|
|
238
|
+
statusCode: response.status,
|
|
239
|
+
raw: text,
|
|
240
|
+
parsedParams: parsed,
|
|
241
|
+
durationMs
|
|
242
|
+
});
|
|
243
|
+
return { raw: text, params: parsed };
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Make a POST request to the Hypay API.
|
|
247
|
+
* Use for actions that send large payloads (e.g., WalletToken with Apple Pay).
|
|
248
|
+
*/
|
|
249
|
+
async requestPost(action, params) {
|
|
250
|
+
const serialized = serializeParams(params);
|
|
251
|
+
const body = toQueryString(serialized);
|
|
252
|
+
const context = {
|
|
253
|
+
action,
|
|
254
|
+
method: "POST",
|
|
255
|
+
url: this.baseUrl,
|
|
256
|
+
params: Object.fromEntries(
|
|
257
|
+
Object.entries(serialized).filter(([, v]) => v !== void 0).map(([k, v]) => [k, String(v)])
|
|
258
|
+
)
|
|
259
|
+
};
|
|
260
|
+
await this.hooks.onRequest?.(context);
|
|
261
|
+
const start = Date.now();
|
|
262
|
+
let response;
|
|
263
|
+
try {
|
|
264
|
+
const controller = new AbortController();
|
|
265
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
266
|
+
try {
|
|
267
|
+
response = await this.fetchFn(this.baseUrl, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
270
|
+
body,
|
|
271
|
+
signal: controller.signal
|
|
272
|
+
});
|
|
273
|
+
} finally {
|
|
274
|
+
clearTimeout(timer);
|
|
275
|
+
}
|
|
276
|
+
} catch (err) {
|
|
277
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
278
|
+
throw new HypayTimeoutError(this.timeout);
|
|
279
|
+
}
|
|
280
|
+
throw new HypayNetworkError(
|
|
281
|
+
`Network error while calling Hypay API: ${err instanceof Error ? err.message : String(err)}`,
|
|
282
|
+
err
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
const text = await response.text();
|
|
286
|
+
const parsed = parseQueryString(text);
|
|
287
|
+
const durationMs = Date.now() - start;
|
|
288
|
+
await this.hooks.onResponse?.({
|
|
289
|
+
...context,
|
|
290
|
+
statusCode: response.status,
|
|
291
|
+
raw: text,
|
|
292
|
+
parsedParams: parsed,
|
|
293
|
+
durationMs
|
|
294
|
+
});
|
|
295
|
+
return { raw: text, params: parsed };
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Unified request method. Defaults to GET, uses POST for wallet/large payloads.
|
|
299
|
+
*/
|
|
300
|
+
async request(action, params, method = "GET") {
|
|
301
|
+
return method === "POST" ? this.requestPost(action, params) : this.requestGet(action, params);
|
|
302
|
+
}
|
|
303
|
+
authParams() {
|
|
304
|
+
return {
|
|
305
|
+
Masof: this.masof,
|
|
306
|
+
PassP: this.passP
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
throwIfError(parsed, raw, context) {
|
|
310
|
+
if (parsed.CCode && !isSuccessCode(parsed.CCode)) {
|
|
311
|
+
const error = new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
312
|
+
if (context) {
|
|
313
|
+
this.hooks.onError?.(error, context);
|
|
314
|
+
}
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
319
|
+
// PAY PROTOCOL — Payment Page
|
|
320
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
321
|
+
/**
|
|
322
|
+
* **Step 1** — Sign payment page parameters (APISign + What=SIGN).
|
|
323
|
+
*
|
|
324
|
+
* This generates a `signature` that must be appended to the payment page URL.
|
|
325
|
+
* The signature prevents parameter tampering on the client side.
|
|
326
|
+
*
|
|
327
|
+
* Requires "Verify by signature in the payment page" enabled in terminal settings.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* const result = await client.sign({
|
|
332
|
+
* Info: "Order #123",
|
|
333
|
+
* Amount: 100,
|
|
334
|
+
* UserId: "203269535",
|
|
335
|
+
* ClientName: "Israel",
|
|
336
|
+
* Coin: Coin.ILS,
|
|
337
|
+
* Sign: true,
|
|
338
|
+
* UTF8: true,
|
|
339
|
+
* UTF8out: true,
|
|
340
|
+
* MoreData: true,
|
|
341
|
+
* });
|
|
342
|
+
* console.log(result.signature);
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
async sign(params) {
|
|
346
|
+
const allParams = {
|
|
347
|
+
action: "APISign",
|
|
348
|
+
What: "SIGN",
|
|
349
|
+
KEY: this.apiKey,
|
|
350
|
+
...this.authParams(),
|
|
351
|
+
...params
|
|
352
|
+
};
|
|
353
|
+
const { raw, params: parsed } = await this.request("APISign", allParams);
|
|
354
|
+
return {
|
|
355
|
+
raw,
|
|
356
|
+
signature: parsed.signature ?? "",
|
|
357
|
+
params: parsed
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* **Step 2** — Build the full payment page URL from a signed query string.
|
|
362
|
+
*
|
|
363
|
+
* @param signedQueryString - The raw result from `sign()`.
|
|
364
|
+
*/
|
|
365
|
+
buildPaymentPageUrl(signedQueryString) {
|
|
366
|
+
return `${this.baseUrl}?${signedQueryString}`;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* **Steps 1 + 2 combined** — Sign parameters and return the full payment page URL.
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```ts
|
|
373
|
+
* const url = await client.createPaymentPageUrl({
|
|
374
|
+
* Info: "Order #123",
|
|
375
|
+
* Amount: 100,
|
|
376
|
+
* UserId: "203269535",
|
|
377
|
+
* ClientName: "Israel",
|
|
378
|
+
* Coin: Coin.ILS,
|
|
379
|
+
* Sign: true,
|
|
380
|
+
* UTF8: true,
|
|
381
|
+
* UTF8out: true,
|
|
382
|
+
* });
|
|
383
|
+
* // Redirect the customer to `url`
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
async createPaymentPageUrl(params) {
|
|
387
|
+
const signResult = await this.sign(params);
|
|
388
|
+
return this.buildPaymentPageUrl(signResult.raw);
|
|
389
|
+
}
|
|
390
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
391
|
+
// VERIFICATION — Verify transaction signature
|
|
392
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
393
|
+
/**
|
|
394
|
+
* **Step 4** — Verify a transaction using parameters from the success page.
|
|
395
|
+
*
|
|
396
|
+
* Takes the query parameters from the success/failure redirect URL and verifies
|
|
397
|
+
* them against the Hypay server. Returns `verified: true` when `CCode === "0"`,
|
|
398
|
+
* `CCode === "902"` means verification failed.
|
|
399
|
+
*
|
|
400
|
+
* Requires "Verify by signature in the payment page" enabled in terminal settings.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* import { parseRedirectUrl } from "@hypay/typescript-sdk";
|
|
405
|
+
*
|
|
406
|
+
* const successParams = parseRedirectUrl(req.url);
|
|
407
|
+
* const result = await client.verify(successParams);
|
|
408
|
+
*
|
|
409
|
+
* if (result.verified) {
|
|
410
|
+
* // Transaction is legitimate — process the order
|
|
411
|
+
* } else {
|
|
412
|
+
* // Verification failed — do not process
|
|
413
|
+
* }
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
async verify(params) {
|
|
417
|
+
const allParams = {
|
|
418
|
+
action: "APISign",
|
|
419
|
+
What: "VERIFY",
|
|
420
|
+
KEY: this.apiKey,
|
|
421
|
+
...this.authParams(),
|
|
422
|
+
...params
|
|
423
|
+
};
|
|
424
|
+
const { raw, params: parsed } = await this.request("APISign-VERIFY", allParams);
|
|
425
|
+
return {
|
|
426
|
+
verified: parsed.CCode === "0",
|
|
427
|
+
CCode: parsed.CCode ?? "",
|
|
428
|
+
raw,
|
|
429
|
+
params: parsed
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Convenience method: parse a success page URL and verify it in one call.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```ts
|
|
437
|
+
* const result = await client.verifyRedirectUrl(
|
|
438
|
+
* "https://yoursite.com/success?Id=123&CCode=0&Amount=10&..."
|
|
439
|
+
* );
|
|
440
|
+
* if (result.verified) { /* OK *\/ }
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
async verifyRedirectUrl(redirectUrl) {
|
|
444
|
+
const { parseRedirectUrl: parseRedirectUrl2 } = await import("./helpers-T6ONVODW.mjs");
|
|
445
|
+
const params = parseRedirectUrl2(redirectUrl);
|
|
446
|
+
return this.verify(params);
|
|
447
|
+
}
|
|
448
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
449
|
+
// SOFT PROTOCOL — Server-side transactions
|
|
450
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
451
|
+
/**
|
|
452
|
+
* Execute a server-side transaction using the Soft protocol.
|
|
453
|
+
*
|
|
454
|
+
* Used for:
|
|
455
|
+
* - Token-based charges (after obtaining a token via `getToken()`)
|
|
456
|
+
* - Apple Pay / Google Pay via WalletToken
|
|
457
|
+
* - Direct credit card charges (PCI-compliant environments)
|
|
458
|
+
*
|
|
459
|
+
* Automatically uses POST for WalletToken requests (large payload).
|
|
460
|
+
*
|
|
461
|
+
* @throws {HypayError} When CCode indicates an error
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* // Token-based transaction
|
|
466
|
+
* const result = await client.soft({
|
|
467
|
+
* CC: "1315872608557940000",
|
|
468
|
+
* Tmonth: "04",
|
|
469
|
+
* Tyear: "2025",
|
|
470
|
+
* Amount: 50,
|
|
471
|
+
* Info: "Subscription renewal",
|
|
472
|
+
* UserId: "203269535",
|
|
473
|
+
* ClientName: "Israel",
|
|
474
|
+
* Token: true,
|
|
475
|
+
* MoreData: true,
|
|
476
|
+
* UTF8: true,
|
|
477
|
+
* UTF8out: true,
|
|
478
|
+
* });
|
|
479
|
+
* ```
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* ```ts
|
|
483
|
+
* // Apple Pay / Google Pay
|
|
484
|
+
* const result = await client.soft({
|
|
485
|
+
* WalletToken: walletTokenJson,
|
|
486
|
+
* Amount: 100,
|
|
487
|
+
* Info: "Purchase",
|
|
488
|
+
* UserId: "203269535",
|
|
489
|
+
* ClientName: "Israel",
|
|
490
|
+
* });
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
async soft(params) {
|
|
494
|
+
const allParams = {
|
|
495
|
+
action: "soft",
|
|
496
|
+
...this.authParams(),
|
|
497
|
+
...params
|
|
498
|
+
};
|
|
499
|
+
const method = "WalletToken" in params && params.WalletToken ? "POST" : "GET";
|
|
500
|
+
const { raw, params: parsed } = await this.request("soft", allParams, method);
|
|
501
|
+
if (parsed.CCode && !isSuccessCode(parsed.CCode)) {
|
|
502
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
Id: parsed.Id ?? "",
|
|
506
|
+
CCode: parsed.CCode ?? "",
|
|
507
|
+
Amount: parsed.Amount ?? "",
|
|
508
|
+
ACode: parsed.ACode ?? "",
|
|
509
|
+
Fild1: parsed.Fild1,
|
|
510
|
+
Fild2: parsed.Fild2,
|
|
511
|
+
Fild3: parsed.Fild3,
|
|
512
|
+
Hesh: parsed.Hesh,
|
|
513
|
+
UID: parsed.UID,
|
|
514
|
+
errMsg: parsed.errMsg,
|
|
515
|
+
raw,
|
|
516
|
+
params: parsed
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
520
|
+
// TOKENS — Get and manage tokens
|
|
521
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
522
|
+
/**
|
|
523
|
+
* Obtain a token for a previously completed transaction.
|
|
524
|
+
*
|
|
525
|
+
* The token (19 digits) replaces credit card information for future Soft transactions.
|
|
526
|
+
* The transaction must be in one of these statuses: Approved (0), 600, 700, 800, 998.
|
|
527
|
+
*
|
|
528
|
+
* **Important:** Save the Tokef (card validity) and customer details (UserId, etc.)
|
|
529
|
+
* as they are NOT stored in Hypay servers.
|
|
530
|
+
*
|
|
531
|
+
* The response includes convenience fields `Tmonth` and `Tyear` parsed from `Tokef`.
|
|
532
|
+
*
|
|
533
|
+
* @throws {HypayError} When CCode indicates an error (901, 902, 910, 990)
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```ts
|
|
537
|
+
* const token = await client.getToken({ TransId: "12788261" });
|
|
538
|
+
*
|
|
539
|
+
* // Save for future charges:
|
|
540
|
+
* // token.Token = "1315872608557940000"
|
|
541
|
+
* // token.Tmonth = "04"
|
|
542
|
+
* // token.Tyear = "2025"
|
|
543
|
+
*
|
|
544
|
+
* // Use in a soft transaction:
|
|
545
|
+
* await client.soft({
|
|
546
|
+
* CC: token.Token,
|
|
547
|
+
* Tmonth: token.Tmonth,
|
|
548
|
+
* Tyear: token.Tyear,
|
|
549
|
+
* Token: true,
|
|
550
|
+
* Amount: 50,
|
|
551
|
+
* Info: "Charge via token",
|
|
552
|
+
* UserId: "203269535",
|
|
553
|
+
* ClientName: "Israel",
|
|
554
|
+
* });
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
async getToken(params) {
|
|
558
|
+
const allParams = {
|
|
559
|
+
action: "getToken",
|
|
560
|
+
...this.authParams(),
|
|
561
|
+
TransId: params.TransId,
|
|
562
|
+
Fild1: params.Fild1,
|
|
563
|
+
Fild2: params.Fild2,
|
|
564
|
+
Fild3: params.Fild3,
|
|
565
|
+
allowFalse: params.allowFalse
|
|
566
|
+
};
|
|
567
|
+
const { raw, params: parsed } = await this.request("getToken", allParams);
|
|
568
|
+
if (parsed.CCode && parsed.CCode !== "0") {
|
|
569
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
570
|
+
}
|
|
571
|
+
let Tmonth = "";
|
|
572
|
+
let Tyear = "";
|
|
573
|
+
if (parsed.Tokef && parsed.Tokef.length === 4) {
|
|
574
|
+
const parsed_tokef = parseTokef(parsed.Tokef);
|
|
575
|
+
Tmonth = parsed_tokef.Tmonth;
|
|
576
|
+
Tyear = parsed_tokef.Tyear;
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
Id: parsed.Id ?? "",
|
|
580
|
+
CCode: parsed.CCode ?? "",
|
|
581
|
+
Token: parsed.Token ?? "",
|
|
582
|
+
Tokef: parsed.Tokef ?? "",
|
|
583
|
+
Tmonth,
|
|
584
|
+
Tyear,
|
|
585
|
+
Fild1: parsed.Fild1,
|
|
586
|
+
Fild2: parsed.Fild2,
|
|
587
|
+
Fild3: parsed.Fild3,
|
|
588
|
+
raw,
|
|
589
|
+
params: parsed
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
593
|
+
// TRANSACTION J5 — Charge a J5 reservation
|
|
594
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
595
|
+
/**
|
|
596
|
+
* Charge a J5 (credit line reservation) transaction.
|
|
597
|
+
*
|
|
598
|
+
* When a Pay/Soft request was made with `J5=True` and `MoreData=True`,
|
|
599
|
+
* you can later charge the reserved amount using the UID and ACode from the response.
|
|
600
|
+
*
|
|
601
|
+
* **If charge amount <= original J5 amount:** use this method (soft + additional params).
|
|
602
|
+
* **If charge amount > original J5 amount:** use the regular token flow instead.
|
|
603
|
+
*
|
|
604
|
+
* @param tokenParams - Standard Soft token parameters (CC, Tmonth, Tyear, etc.)
|
|
605
|
+
* @param j5Params - J5-specific parameters (originalUid, originalAmount, AuthNum)
|
|
606
|
+
*
|
|
607
|
+
* @throws {HypayError} When CCode indicates an error
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```ts
|
|
611
|
+
* const result = await client.chargeJ5(
|
|
612
|
+
* {
|
|
613
|
+
* CC: token.Token,
|
|
614
|
+
* Tmonth: token.Tmonth,
|
|
615
|
+
* Tyear: token.Tyear,
|
|
616
|
+
* Token: true,
|
|
617
|
+
* Amount: 50,
|
|
618
|
+
* Info: "J5 charge",
|
|
619
|
+
* UserId: "203269535",
|
|
620
|
+
* ClientName: "Israel",
|
|
621
|
+
* },
|
|
622
|
+
* {
|
|
623
|
+
* "inputObj.originalUid": originalResponse.UID,
|
|
624
|
+
* "inputObj.originalAmount": 5000, // 50 ILS in agorot
|
|
625
|
+
* AuthNum: originalResponse.ACode,
|
|
626
|
+
* "inputObj.authorizationCodeManpik": 7,
|
|
627
|
+
* }
|
|
628
|
+
* );
|
|
629
|
+
* ```
|
|
630
|
+
*/
|
|
631
|
+
async chargeJ5(tokenParams, j5Params) {
|
|
632
|
+
const allParams = {
|
|
633
|
+
action: "soft",
|
|
634
|
+
...this.authParams(),
|
|
635
|
+
...tokenParams,
|
|
636
|
+
...j5Params
|
|
637
|
+
};
|
|
638
|
+
const { raw, params: parsed } = await this.request("soft-J5", allParams);
|
|
639
|
+
if (parsed.CCode && !isSuccessCode(parsed.CCode)) {
|
|
640
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
Id: parsed.Id ?? "",
|
|
644
|
+
CCode: parsed.CCode ?? "",
|
|
645
|
+
Amount: parsed.Amount ?? "",
|
|
646
|
+
ACode: parsed.ACode ?? "",
|
|
647
|
+
Fild1: parsed.Fild1,
|
|
648
|
+
Fild2: parsed.Fild2,
|
|
649
|
+
Fild3: parsed.Fild3,
|
|
650
|
+
Hesh: parsed.Hesh,
|
|
651
|
+
UID: parsed.UID,
|
|
652
|
+
errMsg: parsed.errMsg,
|
|
653
|
+
raw,
|
|
654
|
+
params: parsed
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
658
|
+
// POSTPONE — Commit delayed transactions
|
|
659
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
660
|
+
/**
|
|
661
|
+
* Commit a postponed transaction (CCode 800).
|
|
662
|
+
*
|
|
663
|
+
* Postponed transactions should be committed within 72 hours.
|
|
664
|
+
* If not committed, leave at status 800 (do not cancel).
|
|
665
|
+
*
|
|
666
|
+
* @throws {HypayError} When CCode indicates an error (250 = doesn't exist / already committed)
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```ts
|
|
670
|
+
* const result = await client.commitTransaction({
|
|
671
|
+
* TransId: "5343635",
|
|
672
|
+
* SendHesh: true,
|
|
673
|
+
* heshDesc: "Payment for order 1234",
|
|
674
|
+
* UTF8: true,
|
|
675
|
+
* UTF8out: true,
|
|
676
|
+
* });
|
|
677
|
+
* console.log(result.HeshASM); // Invoice number
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
async commitTransaction(params) {
|
|
681
|
+
const allParams = {
|
|
682
|
+
action: "commitTrans",
|
|
683
|
+
...this.authParams(),
|
|
684
|
+
...params
|
|
685
|
+
};
|
|
686
|
+
const { raw, params: parsed } = await this.request("commitTrans", allParams);
|
|
687
|
+
if (parsed.CCode && parsed.CCode !== "0") {
|
|
688
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
689
|
+
}
|
|
690
|
+
return {
|
|
691
|
+
Id: parsed.Id ?? "",
|
|
692
|
+
CCode: parsed.CCode ?? "",
|
|
693
|
+
HeshASM: parsed.HeshASM,
|
|
694
|
+
Fild1: parsed.Fild1,
|
|
695
|
+
Fild2: parsed.Fild2,
|
|
696
|
+
Fild3: parsed.Fild3,
|
|
697
|
+
raw,
|
|
698
|
+
params: parsed
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
702
|
+
// CANCEL — Cancel a transaction
|
|
703
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
704
|
+
/**
|
|
705
|
+
* Cancel a transaction.
|
|
706
|
+
*
|
|
707
|
+
* **Rules:**
|
|
708
|
+
* - Only on the same day, before 23:20 (before SHVA deposit)
|
|
709
|
+
* - Cancelled transactions CANNOT be restored
|
|
710
|
+
* - No cost to the business (transaction won't be presented to credit card companies)
|
|
711
|
+
* - If invoice module is active, a credit memo will be issued
|
|
712
|
+
*
|
|
713
|
+
* @throws {HypayError} When CCode indicates an error (920 = doesn't exist / already committed)
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```ts
|
|
717
|
+
* const result = await client.cancelTransaction({ TransId: "5890796" });
|
|
718
|
+
* console.log(result.CCode); // "0" = success
|
|
719
|
+
* ```
|
|
720
|
+
*/
|
|
721
|
+
async cancelTransaction(params) {
|
|
722
|
+
const allParams = {
|
|
723
|
+
action: "CancelTrans",
|
|
724
|
+
...this.authParams(),
|
|
725
|
+
TransId: params.TransId
|
|
726
|
+
};
|
|
727
|
+
const { raw, params: parsed } = await this.request("CancelTrans", allParams);
|
|
728
|
+
if (parsed.CCode && parsed.CCode !== "0") {
|
|
729
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
TransId: parsed.TransId ?? "",
|
|
733
|
+
CCode: parsed.CCode ?? "",
|
|
734
|
+
Hesh: parsed.Hesh,
|
|
735
|
+
raw,
|
|
736
|
+
params: parsed
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
740
|
+
// REFUND — Refund transactions
|
|
741
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
742
|
+
/**
|
|
743
|
+
* Refund a transaction by its original transaction ID (zikoyAPI).
|
|
744
|
+
*
|
|
745
|
+
* **Rules:**
|
|
746
|
+
* - Refund amount must not exceed the original transaction amount
|
|
747
|
+
* - Can be done at any stage, even after 23:00
|
|
748
|
+
* - A credit refund is like a new deal for the credit card company
|
|
749
|
+
* - Does NOT require a token or the secret refund password
|
|
750
|
+
*
|
|
751
|
+
* @throws {HypayError} When CCode indicates an error (33 = amount exceeds original)
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```ts
|
|
755
|
+
* const result = await client.refund({
|
|
756
|
+
* TransId: "12290620",
|
|
757
|
+
* Amount: 10,
|
|
758
|
+
* Tash: 1,
|
|
759
|
+
* SendHesh: true,
|
|
760
|
+
* UTF8: true,
|
|
761
|
+
* UTF8out: true,
|
|
762
|
+
* });
|
|
763
|
+
* console.log(`Refund ID: ${result.Id}`);
|
|
764
|
+
* ```
|
|
765
|
+
*/
|
|
766
|
+
async refund(params) {
|
|
767
|
+
const allParams = {
|
|
768
|
+
action: "zikoyAPI",
|
|
769
|
+
...this.authParams(),
|
|
770
|
+
...params
|
|
771
|
+
};
|
|
772
|
+
const { raw, params: parsed } = await this.request("zikoyAPI", allParams);
|
|
773
|
+
if (parsed.CCode && parsed.CCode !== "0") {
|
|
774
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
Id: parsed.Id ?? "",
|
|
778
|
+
CCode: parsed.CCode ?? "",
|
|
779
|
+
ACode: parsed.ACode,
|
|
780
|
+
HeshASM: parsed.HeshASM,
|
|
781
|
+
raw,
|
|
782
|
+
params: parsed
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Refund a transaction using a token and the secret refund password (PAYout).
|
|
787
|
+
*
|
|
788
|
+
* This uses the Soft protocol with the `zPass` parameter.
|
|
789
|
+
* The refund password is sent to the terminal owner's cell phone and is non-interchangeable.
|
|
790
|
+
*
|
|
791
|
+
* @throws {HypayError} When CCode indicates an error
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```ts
|
|
795
|
+
* const result = await client.refundByToken({
|
|
796
|
+
* CC: "6907500685494032346",
|
|
797
|
+
* Tmonth: "04",
|
|
798
|
+
* Tyear: "2023",
|
|
799
|
+
* Amount: 2,
|
|
800
|
+
* Info: "Refund for order 123",
|
|
801
|
+
* zPass: "1234",
|
|
802
|
+
* Token: true,
|
|
803
|
+
* UserId: "000000000",
|
|
804
|
+
* ClientName: "Israel",
|
|
805
|
+
* SendHesh: true,
|
|
806
|
+
* sendemail: true,
|
|
807
|
+
* });
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
async refundByToken(params) {
|
|
811
|
+
return this.soft(params);
|
|
812
|
+
}
|
|
813
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
814
|
+
// HK MODULE — Standing Orders / Subscriptions
|
|
815
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
816
|
+
/**
|
|
817
|
+
* Create a subscription (HK / standing order) payment page URL.
|
|
818
|
+
*
|
|
819
|
+
* This is a convenience wrapper around `createPaymentPageUrl` with HK-specific params.
|
|
820
|
+
*
|
|
821
|
+
* @example
|
|
822
|
+
* ```ts
|
|
823
|
+
* const url = await client.createSubscriptionUrl({
|
|
824
|
+
* Info: "Monthly subscription",
|
|
825
|
+
* Amount: 120,
|
|
826
|
+
* HK: true,
|
|
827
|
+
* Tash: 999, // Unlimited payments
|
|
828
|
+
* freq: 1, // Monthly
|
|
829
|
+
* FirstDate: "2025-06-01",
|
|
830
|
+
* OnlyOnApprove: true,
|
|
831
|
+
* UserId: "203269535",
|
|
832
|
+
* ClientName: "Israel",
|
|
833
|
+
* email: "customer@example.com",
|
|
834
|
+
* Coin: Coin.ILS,
|
|
835
|
+
* UTF8: true,
|
|
836
|
+
* UTF8out: true,
|
|
837
|
+
* Sign: true,
|
|
838
|
+
* MoreData: true,
|
|
839
|
+
* });
|
|
840
|
+
* ```
|
|
841
|
+
*/
|
|
842
|
+
async createSubscriptionUrl(params) {
|
|
843
|
+
return this.createPaymentPageUrl(params);
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Create a subscription with an initial transaction of a different amount.
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```ts
|
|
850
|
+
* const url = await client.createSubscriptionWithInitialPayment({
|
|
851
|
+
* Info: "Plan with setup fee",
|
|
852
|
+
* Amount: 120, // Monthly amount
|
|
853
|
+
* HK: true,
|
|
854
|
+
* Tash: 999,
|
|
855
|
+
* freq: 1,
|
|
856
|
+
* TashFirstPayment: 50, // Setup fee
|
|
857
|
+
* FirstPaymentTash: 3, // Charge setup fee for 3 months
|
|
858
|
+
* FixTash: true,
|
|
859
|
+
* OnlyOnApprove: true,
|
|
860
|
+
* UserId: "203269535",
|
|
861
|
+
* ClientName: "Israel",
|
|
862
|
+
* Coin: Coin.ILS,
|
|
863
|
+
* UTF8: true,
|
|
864
|
+
* UTF8out: true,
|
|
865
|
+
* Sign: true,
|
|
866
|
+
* MoreData: true,
|
|
867
|
+
* });
|
|
868
|
+
* ```
|
|
869
|
+
*/
|
|
870
|
+
async createSubscriptionWithInitialPayment(params) {
|
|
871
|
+
return this.createPaymentPageUrl(params);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Change the status of a standing order (HK) agreement.
|
|
875
|
+
*
|
|
876
|
+
* @throws {HypayError} When CCode indicates an error (905 = wrong param, 906 = not found)
|
|
877
|
+
*
|
|
878
|
+
* @example
|
|
879
|
+
* ```ts
|
|
880
|
+
* // Terminate
|
|
881
|
+
* await client.updateHKStatus({
|
|
882
|
+
* HKId: "64239",
|
|
883
|
+
* NewStat: HKNewStatus.Terminate,
|
|
884
|
+
* });
|
|
885
|
+
*
|
|
886
|
+
* // Reactivate
|
|
887
|
+
* await client.updateHKStatus({
|
|
888
|
+
* HKId: "64239",
|
|
889
|
+
* NewStat: HKNewStatus.Activate,
|
|
890
|
+
* });
|
|
891
|
+
* ```
|
|
892
|
+
*/
|
|
893
|
+
async updateHKStatus(params) {
|
|
894
|
+
const allParams = {
|
|
895
|
+
action: "HKStatus",
|
|
896
|
+
...this.authParams(),
|
|
897
|
+
HKId: params.HKId,
|
|
898
|
+
NewStat: params.NewStat
|
|
899
|
+
};
|
|
900
|
+
const { raw, params: parsed } = await this.request("HKStatus", allParams);
|
|
901
|
+
if (parsed.CCode && parsed.CCode !== "0") {
|
|
902
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
903
|
+
}
|
|
904
|
+
return {
|
|
905
|
+
HKId: parsed.HKId ?? "",
|
|
906
|
+
CCode: parsed.CCode ?? "",
|
|
907
|
+
raw,
|
|
908
|
+
params: parsed
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Terminate a standing order agreement. Shorthand for `updateHKStatus`.
|
|
913
|
+
*/
|
|
914
|
+
async terminateSubscription(hkId) {
|
|
915
|
+
return this.updateHKStatus({ HKId: hkId, NewStat: 1 });
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Activate a standing order agreement. Shorthand for `updateHKStatus`.
|
|
919
|
+
*/
|
|
920
|
+
async activateSubscription(hkId) {
|
|
921
|
+
return this.updateHKStatus({ HKId: hkId, NewStat: 2 });
|
|
922
|
+
}
|
|
923
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
924
|
+
// EZCOUNT INVOICES — Print and manage invoices
|
|
925
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
926
|
+
/**
|
|
927
|
+
* Generate a signed URL for printing/viewing an EzCount invoice.
|
|
928
|
+
*
|
|
929
|
+
* Uses a two-step process:
|
|
930
|
+
* 1. Sign the request with APISign (What=SIGN, ACTION=PrintHesh)
|
|
931
|
+
* 2. Build the final URL from the signed response
|
|
932
|
+
*
|
|
933
|
+
* **Note:** `ACTION=PrintHesh` is uppercase, `action=APISign` is lowercase.
|
|
934
|
+
*
|
|
935
|
+
* @example
|
|
936
|
+
* ```ts
|
|
937
|
+
* const url = await client.getInvoiceUrl({
|
|
938
|
+
* TransId: "55373520",
|
|
939
|
+
* type: "EZCOUNT",
|
|
940
|
+
* });
|
|
941
|
+
* // Redirect user or fetch the invoice PDF
|
|
942
|
+
* ```
|
|
943
|
+
*/
|
|
944
|
+
async getInvoiceUrl(params) {
|
|
945
|
+
const signParams = {
|
|
946
|
+
action: "APISign",
|
|
947
|
+
What: "SIGN",
|
|
948
|
+
Masof: this.masof,
|
|
949
|
+
KEY: this.apiKey,
|
|
950
|
+
PassP: this.passP,
|
|
951
|
+
ACTION: "PrintHesh",
|
|
952
|
+
type: params.type
|
|
953
|
+
};
|
|
954
|
+
if (params.TransId) signParams.TransId = params.TransId;
|
|
955
|
+
if (params.asm) signParams.asm = params.asm;
|
|
956
|
+
if (params.HeshORCopy !== void 0) signParams.HeshORCopy = params.HeshORCopy;
|
|
957
|
+
const { raw } = await this.request("PrintHesh-SIGN", signParams);
|
|
958
|
+
return `${this.baseUrl}?${raw}`;
|
|
959
|
+
}
|
|
960
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
961
|
+
// OFFLINE INVOICES — Cash, Check, Multi
|
|
962
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
963
|
+
/**
|
|
964
|
+
* Create an invoice for an offline transaction (Cash, Check, or Multi-check).
|
|
965
|
+
*
|
|
966
|
+
* Uses the Soft protocol with the `TransType` parameter.
|
|
967
|
+
*
|
|
968
|
+
* @throws {HypayError} When CCode indicates an error
|
|
969
|
+
*
|
|
970
|
+
* @example
|
|
971
|
+
* ```ts
|
|
972
|
+
* // Cash invoice
|
|
973
|
+
* const result = await client.createOfflineInvoice({
|
|
974
|
+
* TransType: "Cash",
|
|
975
|
+
* Info: "Cash payment",
|
|
976
|
+
* Amount: 200,
|
|
977
|
+
* UserId: "203269535",
|
|
978
|
+
* ClientName: "Israel",
|
|
979
|
+
* email: "customer@example.com",
|
|
980
|
+
* Pritim: true,
|
|
981
|
+
* heshDesc: "[001~Product A~2~50][002~Product B~1~100]",
|
|
982
|
+
* SendHesh: true,
|
|
983
|
+
* UTF8: true,
|
|
984
|
+
* UTF8out: true,
|
|
985
|
+
* });
|
|
986
|
+
* ```
|
|
987
|
+
*
|
|
988
|
+
* @example
|
|
989
|
+
* ```ts
|
|
990
|
+
* // Check invoice
|
|
991
|
+
* const result = await client.createOfflineInvoice({
|
|
992
|
+
* TransType: "Check",
|
|
993
|
+
* Info: "Check payment",
|
|
994
|
+
* Amount: 200,
|
|
995
|
+
* Bank: "10",
|
|
996
|
+
* Snif: "912",
|
|
997
|
+
* PAN: "1234456",
|
|
998
|
+
* CheckNum: "11111111",
|
|
999
|
+
* Date: "20250211",
|
|
1000
|
+
* UserId: "203269535",
|
|
1001
|
+
* ClientName: "Israel",
|
|
1002
|
+
* SendHesh: true,
|
|
1003
|
+
* UTF8: true,
|
|
1004
|
+
* UTF8out: true,
|
|
1005
|
+
* });
|
|
1006
|
+
* ```
|
|
1007
|
+
*/
|
|
1008
|
+
async createOfflineInvoice(params) {
|
|
1009
|
+
const allParams = {
|
|
1010
|
+
action: "soft",
|
|
1011
|
+
...this.authParams(),
|
|
1012
|
+
...params
|
|
1013
|
+
};
|
|
1014
|
+
const { raw, params: parsed } = await this.request("soft-offline", allParams);
|
|
1015
|
+
if (parsed.CCode && !isSuccessCode(parsed.CCode)) {
|
|
1016
|
+
throw new HypayError(getErrorMessage(parsed.CCode), parsed.CCode, raw, parsed);
|
|
1017
|
+
}
|
|
1018
|
+
return {
|
|
1019
|
+
Id: parsed.Id ?? "",
|
|
1020
|
+
CCode: parsed.CCode ?? "",
|
|
1021
|
+
Amount: parsed.Amount ?? "",
|
|
1022
|
+
ACode: parsed.ACode ?? "",
|
|
1023
|
+
Fild1: parsed.Fild1,
|
|
1024
|
+
Fild2: parsed.Fild2,
|
|
1025
|
+
Fild3: parsed.Fild3,
|
|
1026
|
+
Hesh: parsed.Hesh,
|
|
1027
|
+
UID: parsed.UID,
|
|
1028
|
+
errMsg: parsed.errMsg,
|
|
1029
|
+
raw,
|
|
1030
|
+
params: parsed
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
export {
|
|
1035
|
+
ALL_ERROR_CODES,
|
|
1036
|
+
Bank,
|
|
1037
|
+
Brand,
|
|
1038
|
+
Coin,
|
|
1039
|
+
HKNewStatus,
|
|
1040
|
+
HYPAY_ERROR_CODES,
|
|
1041
|
+
HypayClient,
|
|
1042
|
+
HypayError,
|
|
1043
|
+
HypayNetworkError,
|
|
1044
|
+
HypayTimeoutError,
|
|
1045
|
+
Issuer,
|
|
1046
|
+
PageLang,
|
|
1047
|
+
SHVA_ERROR_CODES,
|
|
1048
|
+
SpecialCardType,
|
|
1049
|
+
TashType,
|
|
1050
|
+
buildItemsString,
|
|
1051
|
+
calculateItemsTotal,
|
|
1052
|
+
getErrorMessage,
|
|
1053
|
+
isHypayError,
|
|
1054
|
+
isShvaError,
|
|
1055
|
+
isSuccessCode,
|
|
1056
|
+
isTestMasof,
|
|
1057
|
+
isValidEmail,
|
|
1058
|
+
isValidIsraeliId,
|
|
1059
|
+
isValidMasof,
|
|
1060
|
+
isValidToken,
|
|
1061
|
+
parsePaymentPageResponse,
|
|
1062
|
+
parseQueryString,
|
|
1063
|
+
parseRedirectUrl,
|
|
1064
|
+
parseTokef,
|
|
1065
|
+
serializeParams,
|
|
1066
|
+
toQueryString
|
|
1067
|
+
};
|