@veryfi/veryfi-sdk 1.1.5 → 1.2.1

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/README.md CHANGED
@@ -41,7 +41,7 @@ If you don't have an account with Veryfi, please go ahead and register here: [ht
41
41
 
42
42
  ### Node.js API Client Library
43
43
 
44
- The **veryfi** library can be used to communicate with Veryfi API. All available functionality is described here: <https://veryfi.github.io/veryfi-nodejs/Client.html>
44
+ The **veryfi** library can be used to communicate with Veryfi API. All available functionality is described here: <https://veryfi.github.io/veryfi-nodejs/>
45
45
 
46
46
  Below is a sample script using **Veryfi** for OCR and extracting data from a document:
47
47
 
@@ -251,4 +251,4 @@ If you found a bug in this library or would like new features added, then open a
251
251
 
252
252
  ## Tutorial Video
253
253
 
254
- [![Veryfi Tutorial](https://img.youtube.com/vi/PcJdgnvyfBc/maxresdefault.jpg)](https://www.youtube.com/watch?v=PcJdgnvyfBc)
254
+ [![Veryfi Tutorial](https://img.youtube.com/vi/PcJdgnvyfBc/maxresdefault.jpg)](https://www.youtube.com/watch?v=PcJdgnvyfBc)
package/lib/main.js CHANGED
@@ -2,7 +2,6 @@ const {createHmac} = require('crypto');
2
2
  const axios = require('axios').default;
3
3
  const path = require('path');
4
4
  const fs = require('fs');
5
- const VeryfiClientError = require('./errors');
6
5
 
7
6
  /**
8
7
  * Create instance of a Client
@@ -11,18 +10,18 @@ const VeryfiClientError = require('./errors');
11
10
  * @param {string} client_secret Your Veryfi client secret
12
11
  * @param {string} username Your Veryfi username
13
12
  * @param {string} api_key Your Veryfi API key
14
- * @param {string} base_url
15
- * @param {string} api_version
16
- * @param {Number} timeout
13
+ * @param {string} base_url
14
+ * @param {string} api_version
15
+ * @param {Number} timeout
17
16
  */
18
17
  function Client(
19
- client_id,
20
- client_secret,
21
- username,
22
- api_key,
23
- base_url="https://api.veryfi.com/api/",
24
- api_version="v7",
25
- timeout=120,) {
18
+ client_id,
19
+ client_secret,
20
+ username,
21
+ api_key,
22
+ base_url = "https://api.veryfi.com/",
23
+ api_version = "v8",
24
+ timeout = 120,) {
26
25
  this.client_id = client_id;
27
26
  this.client_secret = client_secret;
28
27
  this.username = username;
@@ -48,6 +47,14 @@ function Client(
48
47
  ];
49
48
  }
50
49
 
50
+ /**
51
+ * Check api version for w2 documents
52
+ * @private
53
+ * @throws if api_version is different to v8
54
+ */
55
+ Client.prototype._check_w2_version = function () {
56
+ if (this.api_version !== "v8") throw Error("w2 is only supported on v8")
57
+ }
51
58
 
52
59
  /**
53
60
  * Prepares the headers needed for a request.
@@ -55,15 +62,15 @@ function Client(
55
62
  * @param {Boolean} has_files Are there any files to be submitted as binary
56
63
  * @return {Object} Dictionary with headers
57
64
  */
58
- Client.prototype._get_headers = function (has_files=false){
65
+ Client.prototype._get_headers = function (has_files = false) {
59
66
  let final_headers = {
60
- "User-Agent": "Node.js Veryfi-Nodejs/1.1.4",
67
+ "User-Agent": "Node.js Veryfi-Nodejs/1.2.0",
61
68
  "Accept": "application/json",
62
69
  "Content-Type": "application/json",
63
70
  "Client-Id": this.client_id,
64
71
  "Authorization": `apikey ${this.username}:${this.api_key}`,
65
72
  };
66
- if (has_files){
73
+ if (has_files) {
67
74
  final_headers["Content-Type"] = "application/x-www-form-urlencoded";
68
75
  }
69
76
  return final_headers;
@@ -74,8 +81,8 @@ Client.prototype._get_headers = function (has_files=false){
74
81
  * @private
75
82
  * @returns {string} Base URL to Veryfi API
76
83
  */
77
- Client.prototype._get_url = function (){
78
- return this.base_url + this.api_version;
84
+ Client.prototype._get_url = function () {
85
+ return this.base_url + "api/" + this.api_version;
79
86
  }
80
87
 
81
88
  /**
@@ -85,9 +92,9 @@ Client.prototype._get_url = function (){
85
92
  * @param {Number} timestamp Unix Long timestamp
86
93
  * @returns {string} Unique signature generated using the client_secret and the payload
87
94
  */
88
- Client.prototype._generate_signature = function (payload_params, timestamp){
95
+ Client.prototype._generate_signature = function (payload_params, timestamp) {
89
96
  let payload = `timestamp:${timestamp}`;
90
- for (let i=0; i<Object.keys(payload_params).length; i++){
97
+ for (let i = 0; i < Object.keys(payload_params).length; i++) {
91
98
  let key = Object.keys(payload_params)[i];
92
99
  let value = payload_params[key];
93
100
  payload = `${payload},${key}:${value}`;
@@ -109,25 +116,28 @@ Client.prototype._generate_signature = function (payload_params, timestamp){
109
116
  * @param {string} http_verb HTTP Method
110
117
  * @param {string} endpoint_name Endpoint name such as 'documents', 'users', etc.
111
118
  * @param {{}} request_arguments JSON payload to send to Veryfi
119
+ * @param params {{}} query params.
112
120
  * @param file_stream file stream of the document
113
121
  * @returns {JSON} A JSON of the response data.
114
122
  */
115
- Client.prototype._request = async function (http_verb, endpoint_name, request_arguments, file_stream=null){
123
+ Client.prototype._request = async function (http_verb, endpoint_name, request_arguments, params = {}, file_stream = null) {
116
124
  let has_files = (Boolean(file_stream));
117
125
  let headers = this._get_headers(has_files);
118
126
  let api_url = `${this._get_url()}/partner${endpoint_name}`;
119
127
 
120
- if (this.client_secret){
128
+ if (this.client_secret) {
121
129
  let timestamp = Date.now();
122
130
  let signature = this._generate_signature(request_arguments, timestamp);
123
- headers = Object.assign(headers,{"X-Veryfi-Request-Timestamp": timestamp,
124
- "X-Veryfi-Request-Signature": signature});
131
+ headers = Object.assign(headers, {
132
+ "X-Veryfi-Request-Timestamp": timestamp,
133
+ "X-Veryfi-Request-Signature": signature
134
+ });
125
135
  }
126
136
 
127
137
  if (has_files === false) {
128
138
  request_arguments = JSON.stringify(request_arguments);
129
139
  } else {
130
- Object.assign(headers,{...request_arguments});
140
+ Object.assign(headers, {...request_arguments});
131
141
  }
132
142
 
133
143
  try {
@@ -136,12 +146,13 @@ Client.prototype._request = async function (http_verb, endpoint_name, request_ar
136
146
  url: api_url,
137
147
  headers: headers,
138
148
  data: request_arguments,
139
- timeout: this.timeout * 1000
149
+ timeout: this.timeout * 1000,
150
+ params: params
140
151
  });
141
152
  } catch (response) {
142
- let Err = new VeryfiClientError(response,response['response']['data']);
143
- let err_msg = Err.from_response(response['response']);
144
- throw new Error(err_msg['status'] + err_msg['error']);
153
+ let errorStatus = response['response']['status'];
154
+ let errorInfo = response['response']['data']['error'];
155
+ throw new Error(errorStatus + errorInfo);
145
156
  }
146
157
  }
147
158
 
@@ -151,12 +162,12 @@ Client.prototype._request = async function (http_verb, endpoint_name, request_ar
151
162
  * @memberof Client
152
163
  * @returns {JSON} JSON object of previously processed documents
153
164
  */
154
- Client.prototype.get_documents = async function (){
165
+ Client.prototype.get_documents = async function () {
155
166
  let endpoint_name = "/documents/";
156
167
  let request_arguments = {};
157
168
  let documents = await this._request("GET", endpoint_name, request_arguments);
158
- if ("data" in documents){
159
- return documents["data"];
169
+ if ("data" in documents) {
170
+ documents = documents["data"];
160
171
  }
161
172
  return documents;
162
173
  }
@@ -178,10 +189,10 @@ Client.prototype.get_document = async function (document_id) {
178
189
  * Process a document and extract all the fields from it
179
190
  * @example
180
191
  * veryfi_client.process_document('file/path',
181
- * ['Entertainment','Food'],
182
- * true,
192
+ * ['Entertainment','Food'],
193
+ * true,
183
194
  * {"extra":"parameters"})
184
- *
195
+ *
185
196
  * @memberof Client
186
197
  * @param {String} file_path Path on disk to a file to submit for data extraction
187
198
  * @param {Array} categories List of categories Veryfi can use to categorize the document
@@ -190,14 +201,14 @@ Client.prototype.get_document = async function (document_id) {
190
201
  * @returns {JSON} Data extracted from the document
191
202
  */
192
203
  Client.prototype.process_document = async function (
193
- file_path,
194
- categories = null,
195
- delete_after_processing = false,
196
- {...kwargs} = {}
197
- ) {
198
-
204
+ file_path,
205
+ categories = null,
206
+ delete_after_processing = false,
207
+ {...kwargs} = {}
208
+ ) {
209
+
199
210
  let endpoint_name = "/documents/";
200
- if (!categories){
211
+ if (!categories) {
201
212
  categories = this.CATEGORIES;
202
213
  }
203
214
  let file_name = path.basename(file_path)
@@ -209,7 +220,7 @@ Client.prototype.process_document = async function (
209
220
  "categories": categories,
210
221
  "auto_delete": delete_after_processing,
211
222
  };
212
- request_arguments = Object.assign(request_arguments,kwargs)
223
+ request_arguments = Object.assign(request_arguments, kwargs)
213
224
  let document = await this._request("POST", endpoint_name, request_arguments)
214
225
  return document['data'];
215
226
  }
@@ -219,10 +230,10 @@ Client.prototype.process_document = async function (
219
230
  * @example
220
231
  * veryfi_client.process_document_buffer('base64_encoded_string',
221
232
  * 'receipt.png',
222
- * ['Entertainment','Food'],
223
- * true,
233
+ * ['Entertainment','Food'],
234
+ * true,
224
235
  * {'extra': 'parameters'})
225
- *
236
+ *
226
237
  * @memberof Client
227
238
  * @param {String} base64_encoded_string Buffer of a file to submit for data extraction
228
239
  * @param {String} file_name The file name including the extension
@@ -232,15 +243,15 @@ Client.prototype.process_document = async function (
232
243
  * @returns {JSON} Data extracted from the document
233
244
  */
234
245
  Client.prototype.process_document_buffer = async function (
235
- base64_encoded_string,
236
- file_name,
237
- categories = null,
238
- delete_after_processing = false,
239
- {...kwargs} = {}
240
- ) {
241
-
246
+ base64_encoded_string,
247
+ file_name,
248
+ categories = null,
249
+ delete_after_processing = false,
250
+ {...kwargs} = {}
251
+ ) {
252
+
242
253
  let endpoint_name = "/documents/";
243
- if (!categories){
254
+ if (!categories) {
244
255
  categories = this.CATEGORIES;
245
256
  }
246
257
  let request_arguments = {
@@ -249,7 +260,7 @@ Client.prototype.process_document_buffer = async function (
249
260
  "categories": categories,
250
261
  "auto_delete": delete_after_processing,
251
262
  };
252
- request_arguments = Object.assign(request_arguments,kwargs)
263
+ request_arguments = Object.assign(request_arguments, kwargs)
253
264
  let document = await this._request("POST", endpoint_name, request_arguments)
254
265
  return document['data'];
255
266
  }
@@ -271,17 +282,17 @@ Client.prototype.process_document_buffer = async function (
271
282
  * @return {JSON} Data extracted from the document.
272
283
  */
273
284
  Client.prototype.process_document_url = async function (
274
- file_url = "",
275
- file_urls = null,
276
- categories = null,
277
- delete_after_processing = false,
278
- boost_mode = 0,
279
- external_id = "",
280
- max_pages_to_process = 1,
281
- {...kwargs} = {},
282
- ) {
285
+ file_url = "",
286
+ file_urls = null,
287
+ categories = null,
288
+ delete_after_processing = false,
289
+ boost_mode = 0,
290
+ external_id = "",
291
+ max_pages_to_process = 1,
292
+ {...kwargs} = {},
293
+ ) {
283
294
  let endpoint_name = "/documents/";
284
- if (!categories){
295
+ if (!categories) {
285
296
  categories = this.CATEGORIES;
286
297
  }
287
298
  let request_arguments = {
@@ -293,40 +304,163 @@ Client.prototype.process_document_url = async function (
293
304
  "file_urls": file_urls,
294
305
  "max_pages_to_process": max_pages_to_process,
295
306
  };
296
- request_arguments = Object.assign(request_arguments,kwargs)
307
+ request_arguments = Object.assign(request_arguments, kwargs)
297
308
  let response = await this._request("POST", endpoint_name, request_arguments);
298
309
  return response['data'];
299
310
  }
300
311
 
301
312
  /**
302
313
  * Delete document from Veryfi
303
- *
314
+ *
304
315
  * @memberof Client
305
316
  * @param {string} document_id ID of the document you'd like to delete
306
317
  */
307
- Client.prototype.delete_document = async function (document_id){
318
+ Client.prototype.delete_document = async function (document_id) {
308
319
  let endpoint_name = `/documents/${document_id}/`;
309
320
  let request_arguments = {"id": document_id};
310
- let response = await this._request("DELETE", endpoint_name, request_arguments);
311
- return response;
321
+ return this._request("DELETE", endpoint_name, request_arguments);
312
322
  }
313
323
 
314
324
  /**
315
325
  * Update data for a previously processed document, including almost any field like `vendor`, `date`, `notes` and etc.
316
326
  * @example
317
327
  * veryfi_client.update_document(id, {date:"2021-01-01", notes:"look what I did"})
318
- *
328
+ *
319
329
  * @memberof Client
320
330
  * @param {string} document_id ID of the document you'd like to update
321
331
  * @param {Object} kwargs fields to update
322
332
  * @return {JSON} A document json with updated fields, if fields are writable. Otherwise a document with unchanged fields.
323
333
  */
324
- Client.prototype.update_document = async function (document_id, {...kwargs} = {}){
334
+ Client.prototype.update_document = async function (document_id, {...kwargs} = {}) {
325
335
  let endpoint_name = `/documents/${document_id}/`;
326
336
  let response = await this._request("PUT", endpoint_name, kwargs);
327
337
  return response['data'];
328
338
  }
329
339
 
340
+ /**
341
+ * Get all w2 documents.
342
+ * @memberOf Client
343
+ * @param {int} page number, response is capped to maximum of 50 results per page.
344
+ * @return {Array} An array of JSON with all w2 documents.
345
+ */
346
+ Client.prototype.get_w2_documents = async function (page = null) {
347
+ this._check_w2_version()
348
+ let endpoint_name = "/w2s/"
349
+ let request_arguments = {}
350
+ let params = {}
351
+ if (page !== null) {
352
+ params = {"page": page}
353
+ }
354
+ let response = await this._request("GET", endpoint_name, request_arguments, params)
355
+ return response['data']['results']
356
+ }
357
+
358
+ /**
359
+ * Get a w2 document
360
+ * @memberOf Client
361
+ * @param {string} document_id ID of the document you'd like to retrieve
362
+ * @returns {JSON} Data extracted from the Document
363
+ */
364
+ Client.prototype.get_w2_document = async function (
365
+ document_id,
366
+ ) {
367
+ this._check_w2_version()
368
+ let endpoint_name = `/w2s/${document_id}/`
369
+ let request_arguments = {"id": document_id}
370
+ let response = await this._request("GET", endpoint_name, request_arguments)
371
+ return response['data']
372
+ }
373
+
374
+ /**
375
+ * Upload a document from a buffer.
376
+ * @memberOf Client
377
+ * @param {String} file_name The file name including the extension
378
+ * @param {String} file_buffer Buffer of a file to submit for data extraction
379
+ * @param {boolean} delete_after_processing Delete this document from Veryfi after data has been extracted
380
+ * @param {int} max_pages_to_process When sending a long document to Veryfi for processing, this parameter controls how many pages of the document will be read and processed, starting from page 1.
381
+ * @param {Object} kwargs Additional request parameters
382
+ * @return {JSON} Data extracted from the document.
383
+ */
384
+ Client.prototype.process_w2_document_from_buffer = async function (
385
+ file_name,
386
+ file_buffer,
387
+ delete_after_processing = null,
388
+ max_pages_to_process = null,
389
+ {...kwargs} = {}
390
+ ) {
391
+ this._check_w2_version()
392
+ let endpoint_name = "/w2s/"
393
+ let request_arguments = {
394
+ "file_name": file_name,
395
+ "file_data": file_buffer,
396
+ "auto_delete": delete_after_processing,
397
+ "max_pages_to_process": max_pages_to_process,
398
+ }
399
+ request_arguments = Object.assign(request_arguments, kwargs)
400
+ let response = await this._request("POST", endpoint_name, request_arguments)
401
+ return response['data']
402
+ }
403
+
404
+ /**
405
+ * Upload a document from a file path
406
+ * @param {String} file_path Path on disk to a file to submit for data extraction
407
+ * @param {boolean} delete_after_processing Delete this document from Veryfi after data has been extracted
408
+ * @param {int} max_pages_to_process When sending a long document to Veryfi for processing, this parameter controls how many pages of the document will be read and processed, starting from page 1.
409
+ * @param {Object} kwargs Additional request parameters
410
+ * @return {JSON} Data extracted from the document.
411
+ */
412
+ Client.prototype.process_w2_document = async function (
413
+ file_path,
414
+ delete_after_processing = false,
415
+ max_pages_to_process = 1,
416
+ {...kwargs} = {}
417
+ ) {
418
+ const file_name = path.basename(file_path)
419
+ const image_file = fs.readFileSync(file_path, {encoding: 'base64'})
420
+ const base64_encoded_string = Buffer.from(image_file).toString('utf-8')
421
+ return this.process_w2_document_from_buffer(
422
+ file_name,
423
+ base64_encoded_string,
424
+ delete_after_processing,
425
+ max_pages_to_process,
426
+ kwargs
427
+ )
428
+ }
429
+
430
+ /**
431
+ * Process a w2 document from an url.
432
+ * @memberOf Client
433
+ * @param {String} file_name The file name including the extension
434
+ * @memberof Client
435
+ * @param {string} file_url Required if file_urls isn't specified. Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
436
+ * @param {Array} file_urls Required if file_url isn't specified. List of publicly accessible URLs to multiple files, e.g. ["https://cdn.example.com/receipt1.jpg", "https://cdn.example.com/receipt2.jpg"]
437
+ * @param {boolean} delete_after_processing Delete this document from Veryfi after data has been extracted
438
+ * @param {int} max_pages_to_process When sending a long document to Veryfi for processing, this parameter controls how many pages of the document will be read and processed, starting from page 1.
439
+ * @param {Object} kwargs Additional request parameters
440
+ * @return {JSON} Data extracted from the document.
441
+ */
442
+ Client.prototype.process_w2_document_from_url = async function (
443
+ file_name,
444
+ file_url,
445
+ file_urls = null,
446
+ delete_after_processing = false,
447
+ max_pages_to_process = 1,
448
+ {...kwargs} = {}
449
+ ) {
450
+ this._check_w2_version()
451
+ let endpoint_name = "/w2s/"
452
+ let request_arguments = {
453
+ "file_name": file_name,
454
+ "auto_delete": delete_after_processing,
455
+ "file_url": file_url,
456
+ "file_urls": file_urls,
457
+ "max_pages_to_process": max_pages_to_process
458
+ }
459
+ request_arguments = Object.assign(request_arguments, kwargs)
460
+ let response = await this._request("POST", endpoint_name, request_arguments)
461
+ return response['data']
462
+ }
463
+
330
464
  // Exports
331
465
 
332
466
  module.exports = Client;
@@ -40,6 +40,7 @@ export declare type VeryfiDocument = {
40
40
  notes?: null | string;
41
41
  ocr_text?: null | string;
42
42
  order_date?: null | string;
43
+ payment?: null | Payment;
43
44
  payment_display_name?: null | string;
44
45
  payment_terms?: null | string;
45
46
  payment_type?: null | string;
@@ -114,6 +115,13 @@ declare type Vendor = {
114
115
  web?: null | string;
115
116
  };
116
117
 
118
+ declare type Payment = {
119
+ card_number?: null | string;
120
+ display_name?: null | string;
121
+ terms?: null | number;
122
+ type?: null | string;
123
+ };
124
+
117
125
  export declare class Client {
118
126
  /**
119
127
  * Create instance of a Client
package/package.json CHANGED
@@ -1,34 +1,41 @@
1
1
  {
2
2
  "name": "@veryfi/veryfi-sdk",
3
- "version": "1.1.5",
3
+ "version": "1.2.1",
4
4
  "description": "Node.js module for communicating with the Veryfi OCR API",
5
5
  "main": "lib/main.js",
6
6
  "typings": "types/main.d.ts",
7
7
  "scripts": {
8
8
  "test": "jest",
9
9
  "doc": "jsdoc -d docs --configure jsconf.json main.js",
10
- "generate-docs": "jsdoc --configure .jsdoc.json --verbose"
10
+ "generate-docs": "jsdoc --configure jsdoc.json --verbose"
11
11
  },
12
12
  "author": "Veryfi <support@veryfi.com> (https://www.veryfi.com)",
13
13
  "homepage": "https://veryfi.github.io/veryfi-nodejs/",
14
14
  "contributors": [
15
- "Matthew Eng <matthew@veryfi.com>"
15
+ "Matthew Eng <matthew@veryfi.com>",
16
+ "Alejandro Uribe <alejandro@veryfi.com>"
16
17
  ],
17
18
  "license": "MIT",
18
19
  "files": [
19
20
  "lib",
20
- "types"
21
+ "lib/types"
21
22
  ],
22
23
  "directories": {
23
24
  "lib": "lib",
24
25
  "test": "test"
25
26
  },
26
27
  "devDependencies": {
27
- "jest": "^27.0.5",
28
- "jsdoc": "^3.6.7"
28
+ "jest": "^29.0.0",
29
+ "jsdoc": "^3.6.7",
30
+ "minami": "^1.2.3",
31
+ "ts-jest": "^29.0.1",
32
+ "typescript": "^4.8.3"
29
33
  },
30
34
  "dependencies": {
31
- "axios": "^0.21.1"
35
+ "@jest/globals": "^29.0.3",
36
+ "axios": "^0.21.1",
37
+ "docdash": "^1.2.0",
38
+ "jest-config": "^29.0.3"
32
39
  },
33
40
  "repository": {
34
41
  "type": "git",
package/lib/errors.js DELETED
@@ -1,36 +0,0 @@
1
- let VeryfiClientError = function (raw_response, error_info) {
2
- this.raw_response = raw_response['response'];
3
- this.status = this.raw_response['status'];
4
- this.error_info = error_info['error']
5
- }
6
-
7
-
8
- /** Veryfi API returns error messages with a json body
9
- * like:
10
- * {
11
- * 'status': 'fail',
12
- * 'error': 'Human readable error description.'
13
- * }
14
- */
15
- VeryfiClientError.prototype.from_response = function (raw_response){
16
- try{
17
- error_cls = _error_map[this.status]
18
- } catch (KeyError) {
19
- console.error(
20
- "Unknown error Please contact customer support at support@veryfi.com."
21
- )
22
- }
23
-
24
- return {'status':error_cls, 'error':this.error_info}
25
- }
26
-
27
- _error_map = {
28
- 400: 'BadRequest',
29
- 401: 'UnauthorizedAccessToken',
30
- 404: 'NotFound',
31
- 405: 'UnexpectedHTTPMethod',
32
- 409: 'AccessLimitReached',
33
- 500: 'InternalError',
34
- }
35
-
36
- module.exports = VeryfiClientError;