Module veryfi.client
View Source
import base64
import hashlib
import hmac
import json
import os
import time
from typing import *
import requests
from veryfi.model import AddLineItem, UpdateLineItem
from veryfi.errors import VeryfiClientError
class Client:
API_VERSION = "v8"
API_TIMEOUT = 30
BASE_URL = "https://api.veryfi.com/api/"
CATEGORIES = [
"Advertising & Marketing",
"Automotive",
"Bank Charges & Fees",
"Legal & Professional Services",
"Insurance",
"Meals & Entertainment",
"Office Supplies & Software",
"Taxes & Licenses",
"Travel",
"Rent & Lease",
"Repairs & Maintenance",
"Payroll",
"Utilities",
"Job Supplies",
"Grocery",
]
def __init__(
self,
client_id,
client_secret,
username,
api_key,
base_url=BASE_URL,
api_version=API_VERSION,
timeout=API_TIMEOUT,
):
self.client_id = client_id
self.client_secret = client_secret
self.username = username
self.api_key = api_key
self.base_url = base_url
self.api_version = api_version
self.versioned_url = self.base_url + self.api_version
self.timeout = timeout
self.headers = {}
self._session = requests.Session()
def _get_headers(self) -> Dict:
"""
Prepares the headers needed for a request.
:return: Dictionary with headers
"""
final_headers = {
"User-Agent": "Python Veryfi-Python/3.4.1",
"Accept": "application/json",
"Content-Type": "application/json",
"Client-Id": self.client_id,
}
final_headers.update({"Authorization": f"apikey {self.username}:{self.api_key}"})
return final_headers
def _request(self, http_verb, endpoint_name, request_arguments):
"""
Submit the HTTP request.
:param http_verb: HTTP Method
:param endpoint_name: Endpoint name such as 'documents', 'users', etc.
:param request_arguments: JSON payload to send to Veryfi
:return: A JSON of the response data.
"""
headers = self._get_headers()
api_url = "{0}/partner{1}".format(self.versioned_url, endpoint_name)
if self.client_secret:
timestamp = int(time.time() * 1000)
signature = self._generate_signature(request_arguments, timestamp=timestamp)
headers.update(
{
"X-Veryfi-Request-Timestamp": str(timestamp),
"X-Veryfi-Request-Signature": signature,
}
)
response = self._session.request(
http_verb,
url=api_url,
headers=headers,
data=json.dumps(request_arguments),
timeout=self.timeout,
)
if response.status_code not in [200, 201, 202, 204]:
raise VeryfiClientError.from_response(response)
return response.json()
def _generate_signature(self, payload_params, timestamp):
"""
Generate unique signature for payload params.
:param payload_params: JSON params to be sent to API request
:param timestamp: Unix Long timestamp
:return: Unique signature generated using the client_secret and the payload
"""
payload = "timestamp:{}".format(timestamp)
for key in payload_params.keys():
value = payload_params[key]
payload = "{0},{1}:{2}".format(payload, key, value)
secret_bytes = bytes(self.client_secret, "utf-8")
payload_bytes = bytes(payload, "utf-8")
tmp_signature = hmac.new(secret_bytes, msg=payload_bytes, digestmod=hashlib.sha256).digest()
base64_signature = base64.b64encode(tmp_signature).decode("utf-8").strip()
return base64_signature
def get_documents(
self,
q: Optional[str] = None,
external_id: Optional[str] = None,
tag: Optional[str] = None,
created_gt: Optional[str] = None,
created_gte: Optional[str] = None,
created_lt: Optional[str] = None,
created_lte: Optional[str] = None,
**kwargs: Dict,
):
"""
Get list of documents
:param query: Search term to search for a specific document by its content. These fields will be searched: external_id, category, vendor.name, notes, invoice_number, total and ocr_text.
:param external_id: Search for documents that match your custom identifier
:param tag: Search for documents with the specified tag
:param created__gt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__gte: Search for documents with a created date greater than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__lt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param created__lte: Search for documents with a created date less than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param kwargs: Additional request parameters
:return: List of previously processed documents
"""
endpoint_name = "/documents/"
request_params = {}
if q:
request_params["q"] = q
if external_id:
request_params["external_id"] = external_id
if tag:
request_params["tag"] = tag
if created_gt:
request_params["created__gt"] = created_gt
if created_gte:
request_params["created__gte"] = created_gte
if created_lt:
request_params["created__lt"] = created_lt
if created_lte:
request_params["created__lte"] = created_lte
request_params.update(kwargs)
if request_params:
endpoint_name += "?" + "&".join(f"{k}={v}" for k, v in request_params.items())
documents = self._request("GET", endpoint_name, {})
if "documents" in documents:
return documents["documents"]
return documents
def get_document(self, document_id):
"""
Retrieve document by ID
:param document_id: ID of the document you'd like to retrieve
:return: Data extracted from the Document
"""
endpoint_name = "/documents/{}/".format(document_id)
request_arguments = {"id": document_id}
document = self._request("GET", endpoint_name, request_arguments)
return document
def process_document(
self,
file_path: str,
categories: Optional[List] = None,
delete_after_processing: bool = False,
**kwargs: Dict,
):
"""
Process a document and extract all the fields from it
:param file_path: Path on disk to a file to submit for data extraction
:param categories: List of categories Veryfi can use to categorize the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param kwargs: Additional request parameters
:return: Data extracted from the document
"""
endpoint_name = "/documents/"
if not categories:
categories = self.CATEGORIES
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
"categories": categories,
"auto_delete": delete_after_processing,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
def process_document_url(
self,
file_url: Optional[str] = None,
categories: Optional[List[str]] = None,
delete_after_processing=False,
boost_mode: int = 0,
external_id: Optional[str] = None,
max_pages_to_process: Optional[int] = None,
file_urls: Optional[List[str]] = None,
**kwargs: Dict,
) -> Dict:
"""Process Document from url and extract all the fields from it.
:param file_url: Required if file_urls isn't specified. Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_urls: Required if file_url isn't specifies. List of publicly accessible URLs to multiple files, e.g. ["https://cdn.example.com/receipt1.jpg", "https://cdn.example.com/receipt2.jpg"]
:param categories: List of categories to use when categorizing the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param 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.
:param boost_mode: Flag that tells Veryfi whether boost mode should be enabled. When set to 1, Veryfi will skip data enrichment steps, but will process the document faster. Default value for this flag is 0
:param external_id: Optional custom document identifier. Use this if you would like to assign your own ID to documents
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/documents/"
request_arguments = {
"auto_delete": delete_after_processing,
"boost_mode": boost_mode,
"categories": categories,
"external_id": external_id,
"file_url": file_url,
"file_urls": file_urls,
"max_pages_to_process": max_pages_to_process,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
def process_w9_document_url(
self, file_url: str, file_name: Optional[str] = None, **kwargs: Dict
) -> Dict:
"""
Process W9 Document from url and extract all the fields from it.
:param file_url: Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
if file_name is None:
file_name = os.path.basename(file_url)
endpoint_name = "/w9s/"
request_arguments = {
"file_name": file_name,
"file_url": file_url,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
def process_w9_document(self, file_path: str, file_name: Optional[str] = None, **kwargs):
"""
Process W9 Document from url and extract all the fields from it.
:param file_path: Path on disk to a file to submit for data extraction
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/w9s/"
if file_name is None:
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
def delete_document(self, document_id):
"""
Delete Document from Veryfi
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"id": document_id}
self._request("DELETE", endpoint_name, request_arguments)
def update_document(self, document_id: int, **kwargs) -> Dict:
"""
Update data for a previously processed document, including almost any field like `vendor`, `date`, `notes` and etc.
```veryfi_client.update_document(id, date="2021-01-01", notes="look what I did")```
:param document_id: ID of the document you'd like to update
:param kwargs: fields to update
:return: A document json with updated fields, if fields are writable. Otherwise a document with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/"
return self._request("PUT", endpoint_name, kwargs)
def get_line_items(self, document_id):
"""
Retrieve all line items for a document.
:param document_id: ID of the document you'd like to retrieve
:return: List of line items extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
def get_line_item(self, document_id, line_item_id):
"""
Retrieve a line item for existing document by ID.
:param document_id: ID of the document you'd like to retrieve
:param line_item_id: ID of the line item you'd like to retrieve
:return: Line item extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
def add_line_item(self, document_id: int, payload: Dict) -> Dict:
"""
Add a new line item on an existing document.
:param document_id: ID of the document you'd like to update
:param payload: line item object to add
:return: Added line item data
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = AddLineItem(**payload).dict(exclude_none=True)
return self._request("POST", endpoint_name, request_arguments)
def update_line_item(self, document_id: int, line_item_id: int, payload: Dict) -> Dict:
"""
Update an existing line item on an existing document.
:param document_id: ID of the document you'd like to update
:param line_item_id: ID of the line item you'd like to update
:param payload: line item object to update
:return: Line item data with updated fields, if fields are writable. Otherwise line item data with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = UpdateLineItem(**payload).dict(exclude_none=True)
return self._request("PUT", endpoint_name, request_arguments)
def delete_line_items(self, document_id):
"""
Delete all line items on an existing document.
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
def delete_line_item(self, document_id, line_item_id):
"""
Delete an existing line item on an existing document.
:param document_id: ID of the document you'd like to delete
:param line_item_id: ID of the line item you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
def add_tag(self, document_id, tag_name):
"""
Add a new tag on an existing document.
:param document_id: ID of the document you'd like to update
:param tag_name: name of the new tag
:return: Added tag data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"name": tag_name}
return self._request("PUT", endpoint_name, request_arguments)
def replace_tags(self, document_id, tags):
"""
Replace multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"tags": tags}
return self._request("PUT", endpoint_name, request_arguments)
def add_tags(self, document_id, tags):
"""
Add multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"tags": tags}
return self._request("POST", endpoint_name, request_arguments)
Variables
TYPE_CHECKING
Classes
Client
class Client(
client_id,
client_secret,
username,
api_key,
base_url='https://api.veryfi.com/api/',
api_version='v8',
timeout=30
)
View Source
class Client:
API_VERSION = "v8"
API_TIMEOUT = 30
BASE_URL = "https://api.veryfi.com/api/"
CATEGORIES = [
"Advertising & Marketing",
"Automotive",
"Bank Charges & Fees",
"Legal & Professional Services",
"Insurance",
"Meals & Entertainment",
"Office Supplies & Software",
"Taxes & Licenses",
"Travel",
"Rent & Lease",
"Repairs & Maintenance",
"Payroll",
"Utilities",
"Job Supplies",
"Grocery",
]
def __init__(
self,
client_id,
client_secret,
username,
api_key,
base_url=BASE_URL,
api_version=API_VERSION,
timeout=API_TIMEOUT,
):
self.client_id = client_id
self.client_secret = client_secret
self.username = username
self.api_key = api_key
self.base_url = base_url
self.api_version = api_version
self.versioned_url = self.base_url + self.api_version
self.timeout = timeout
self.headers = {}
self._session = requests.Session()
def _get_headers(self) -> Dict:
"""
Prepares the headers needed for a request.
:return: Dictionary with headers
"""
final_headers = {
"User-Agent": "Python Veryfi-Python/3.4.1",
"Accept": "application/json",
"Content-Type": "application/json",
"Client-Id": self.client_id,
}
final_headers.update({"Authorization": f"apikey {self.username}:{self.api_key}"})
return final_headers
def _request(self, http_verb, endpoint_name, request_arguments):
"""
Submit the HTTP request.
:param http_verb: HTTP Method
:param endpoint_name: Endpoint name such as 'documents', 'users', etc.
:param request_arguments: JSON payload to send to Veryfi
:return: A JSON of the response data.
"""
headers = self._get_headers()
api_url = "{0}/partner{1}".format(self.versioned_url, endpoint_name)
if self.client_secret:
timestamp = int(time.time() * 1000)
signature = self._generate_signature(request_arguments, timestamp=timestamp)
headers.update(
{
"X-Veryfi-Request-Timestamp": str(timestamp),
"X-Veryfi-Request-Signature": signature,
}
)
response = self._session.request(
http_verb,
url=api_url,
headers=headers,
data=json.dumps(request_arguments),
timeout=self.timeout,
)
if response.status_code not in [200, 201, 202, 204]:
raise VeryfiClientError.from_response(response)
return response.json()
def _generate_signature(self, payload_params, timestamp):
"""
Generate unique signature for payload params.
:param payload_params: JSON params to be sent to API request
:param timestamp: Unix Long timestamp
:return: Unique signature generated using the client_secret and the payload
"""
payload = "timestamp:{}".format(timestamp)
for key in payload_params.keys():
value = payload_params[key]
payload = "{0},{1}:{2}".format(payload, key, value)
secret_bytes = bytes(self.client_secret, "utf-8")
payload_bytes = bytes(payload, "utf-8")
tmp_signature = hmac.new(secret_bytes, msg=payload_bytes, digestmod=hashlib.sha256).digest()
base64_signature = base64.b64encode(tmp_signature).decode("utf-8").strip()
return base64_signature
def get_documents(
self,
q: Optional[str] = None,
external_id: Optional[str] = None,
tag: Optional[str] = None,
created_gt: Optional[str] = None,
created_gte: Optional[str] = None,
created_lt: Optional[str] = None,
created_lte: Optional[str] = None,
**kwargs: Dict,
):
"""
Get list of documents
:param query: Search term to search for a specific document by its content. These fields will be searched: external_id, category, vendor.name, notes, invoice_number, total and ocr_text.
:param external_id: Search for documents that match your custom identifier
:param tag: Search for documents with the specified tag
:param created__gt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__gte: Search for documents with a created date greater than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__lt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param created__lte: Search for documents with a created date less than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param kwargs: Additional request parameters
:return: List of previously processed documents
"""
endpoint_name = "/documents/"
request_params = {}
if q:
request_params["q"] = q
if external_id:
request_params["external_id"] = external_id
if tag:
request_params["tag"] = tag
if created_gt:
request_params["created__gt"] = created_gt
if created_gte:
request_params["created__gte"] = created_gte
if created_lt:
request_params["created__lt"] = created_lt
if created_lte:
request_params["created__lte"] = created_lte
request_params.update(kwargs)
if request_params:
endpoint_name += "?" + "&".join(f"{k}={v}" for k, v in request_params.items())
documents = self._request("GET", endpoint_name, {})
if "documents" in documents:
return documents["documents"]
return documents
def get_document(self, document_id):
"""
Retrieve document by ID
:param document_id: ID of the document you'd like to retrieve
:return: Data extracted from the Document
"""
endpoint_name = "/documents/{}/".format(document_id)
request_arguments = {"id": document_id}
document = self._request("GET", endpoint_name, request_arguments)
return document
def process_document(
self,
file_path: str,
categories: Optional[List] = None,
delete_after_processing: bool = False,
**kwargs: Dict,
):
"""
Process a document and extract all the fields from it
:param file_path: Path on disk to a file to submit for data extraction
:param categories: List of categories Veryfi can use to categorize the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param kwargs: Additional request parameters
:return: Data extracted from the document
"""
endpoint_name = "/documents/"
if not categories:
categories = self.CATEGORIES
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
"categories": categories,
"auto_delete": delete_after_processing,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
def process_document_url(
self,
file_url: Optional[str] = None,
categories: Optional[List[str]] = None,
delete_after_processing=False,
boost_mode: int = 0,
external_id: Optional[str] = None,
max_pages_to_process: Optional[int] = None,
file_urls: Optional[List[str]] = None,
**kwargs: Dict,
) -> Dict:
"""Process Document from url and extract all the fields from it.
:param file_url: Required if file_urls isn't specified. Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_urls: Required if file_url isn't specifies. List of publicly accessible URLs to multiple files, e.g. ["https://cdn.example.com/receipt1.jpg", "https://cdn.example.com/receipt2.jpg"]
:param categories: List of categories to use when categorizing the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param 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.
:param boost_mode: Flag that tells Veryfi whether boost mode should be enabled. When set to 1, Veryfi will skip data enrichment steps, but will process the document faster. Default value for this flag is 0
:param external_id: Optional custom document identifier. Use this if you would like to assign your own ID to documents
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/documents/"
request_arguments = {
"auto_delete": delete_after_processing,
"boost_mode": boost_mode,
"categories": categories,
"external_id": external_id,
"file_url": file_url,
"file_urls": file_urls,
"max_pages_to_process": max_pages_to_process,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
def process_w9_document_url(
self, file_url: str, file_name: Optional[str] = None, **kwargs: Dict
) -> Dict:
"""
Process W9 Document from url and extract all the fields from it.
:param file_url: Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
if file_name is None:
file_name = os.path.basename(file_url)
endpoint_name = "/w9s/"
request_arguments = {
"file_name": file_name,
"file_url": file_url,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
def process_w9_document(self, file_path: str, file_name: Optional[str] = None, **kwargs):
"""
Process W9 Document from url and extract all the fields from it.
:param file_path: Path on disk to a file to submit for data extraction
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/w9s/"
if file_name is None:
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
def delete_document(self, document_id):
"""
Delete Document from Veryfi
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"id": document_id}
self._request("DELETE", endpoint_name, request_arguments)
def update_document(self, document_id: int, **kwargs) -> Dict:
"""
Update data for a previously processed document, including almost any field like `vendor`, `date`, `notes` and etc.
```veryfi_client.update_document(id, date="2021-01-01", notes="look what I did")```
:param document_id: ID of the document you'd like to update
:param kwargs: fields to update
:return: A document json with updated fields, if fields are writable. Otherwise a document with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/"
return self._request("PUT", endpoint_name, kwargs)
def get_line_items(self, document_id):
"""
Retrieve all line items for a document.
:param document_id: ID of the document you'd like to retrieve
:return: List of line items extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
def get_line_item(self, document_id, line_item_id):
"""
Retrieve a line item for existing document by ID.
:param document_id: ID of the document you'd like to retrieve
:param line_item_id: ID of the line item you'd like to retrieve
:return: Line item extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
def add_line_item(self, document_id: int, payload: Dict) -> Dict:
"""
Add a new line item on an existing document.
:param document_id: ID of the document you'd like to update
:param payload: line item object to add
:return: Added line item data
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = AddLineItem(**payload).dict(exclude_none=True)
return self._request("POST", endpoint_name, request_arguments)
def update_line_item(self, document_id: int, line_item_id: int, payload: Dict) -> Dict:
"""
Update an existing line item on an existing document.
:param document_id: ID of the document you'd like to update
:param line_item_id: ID of the line item you'd like to update
:param payload: line item object to update
:return: Line item data with updated fields, if fields are writable. Otherwise line item data with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = UpdateLineItem(**payload).dict(exclude_none=True)
return self._request("PUT", endpoint_name, request_arguments)
def delete_line_items(self, document_id):
"""
Delete all line items on an existing document.
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
def delete_line_item(self, document_id, line_item_id):
"""
Delete an existing line item on an existing document.
:param document_id: ID of the document you'd like to delete
:param line_item_id: ID of the line item you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
def add_tag(self, document_id, tag_name):
"""
Add a new tag on an existing document.
:param document_id: ID of the document you'd like to update
:param tag_name: name of the new tag
:return: Added tag data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"name": tag_name}
return self._request("PUT", endpoint_name, request_arguments)
def replace_tags(self, document_id, tags):
"""
Replace multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"tags": tags}
return self._request("PUT", endpoint_name, request_arguments)
def add_tags(self, document_id, tags):
"""
Add multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"tags": tags}
return self._request("POST", endpoint_name, request_arguments)
Class variables
API_TIMEOUT
API_VERSION
BASE_URL
CATEGORIES
Methods
add_line_item
def add_line_item(
self,
document_id: int,
payload: Dict
) -> Dict
Add a new line item on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
payload | None | line item object to add | None |
Returns:
Type | Description |
---|---|
None | Added line item data |
View Source
def add_line_item(self, document_id: int, payload: Dict) -> Dict:
"""
Add a new line item on an existing document.
:param document_id: ID of the document you'd like to update
:param payload: line item object to add
:return: Added line item data
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = AddLineItem(**payload).dict(exclude_none=True)
return self._request("POST", endpoint_name, request_arguments)
add_tag
def add_tag(
self,
document_id,
tag_name
)
Add a new tag on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
tag_name | None | name of the new tag | None |
Returns:
Type | Description |
---|---|
None | Added tag data |
View Source
def add_tag(self, document_id, tag_name):
"""
Add a new tag on an existing document.
:param document_id: ID of the document you'd like to update
:param tag_name: name of the new tag
:return: Added tag data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"name": tag_name}
return self._request("PUT", endpoint_name, request_arguments)
add_tags
def add_tags(
self,
document_id,
tags
)
Add multiple tags on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
tags | None | array of strings | None |
Returns:
Type | Description |
---|---|
None | Added tags data |
View Source
def add_tags(self, document_id, tags):
"""
Add multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/tags/"
request_arguments = {"tags": tags}
return self._request("POST", endpoint_name, request_arguments)
delete_document
def delete_document(
self,
document_id
)
Delete Document from Veryfi
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to delete | None |
View Source
def delete_document(self, document_id):
"""
Delete Document from Veryfi
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"id": document_id}
self._request("DELETE", endpoint_name, request_arguments)
delete_line_item
def delete_line_item(
self,
document_id,
line_item_id
)
Delete an existing line item on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to delete | None |
line_item_id | None | ID of the line item you'd like to delete | None |
View Source
def delete_line_item(self, document_id, line_item_id):
"""
Delete an existing line item on an existing document.
:param document_id: ID of the document you'd like to delete
:param line_item_id: ID of the line item you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
delete_line_items
def delete_line_items(
self,
document_id
)
Delete all line items on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to delete | None |
View Source
def delete_line_items(self, document_id):
"""
Delete all line items on an existing document.
:param document_id: ID of the document you'd like to delete
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
self._request("DELETE", endpoint_name, request_arguments)
get_document
def get_document(
self,
document_id
)
Retrieve document by ID
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to retrieve | None |
Returns:
Type | Description |
---|---|
None | Data extracted from the Document |
View Source
def get_document(self, document_id):
"""
Retrieve document by ID
:param document_id: ID of the document you'd like to retrieve
:return: Data extracted from the Document
"""
endpoint_name = "/documents/{}/".format(document_id)
request_arguments = {"id": document_id}
document = self._request("GET", endpoint_name, request_arguments)
return document
get_documents
def get_documents(
self,
q: Union[str, NoneType] = None,
external_id: Union[str, NoneType] = None,
tag: Union[str, NoneType] = None,
created_gt: Union[str, NoneType] = None,
created_gte: Union[str, NoneType] = None,
created_lt: Union[str, NoneType] = None,
created_lte: Union[str, NoneType] = None,
**kwargs: Dict
)
Get list of documents
Parameters:
Name | Type | Description | Default |
---|---|---|---|
query | None | Search term to search for a specific document by its content. These fields will be searched: external_id, category, vendor.name, notes, invoice_number, total and ocr_text. | None |
external_id | None | Search for documents that match your custom identifier | None |
tag | None | Search for documents with the specified tag | None |
created__gt | None | Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request. | None |
created__gte | None | Search for documents with a created date greater than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request. | None |
created__lt | None | Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request. | None |
created__lte | None | Search for documents with a created date less than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request. | None |
kwargs | None | Additional request parameters | None |
Returns:
Type | Description |
---|---|
None | List of previously processed documents |
View Source
def get_documents(
self,
q: Optional[str] = None,
external_id: Optional[str] = None,
tag: Optional[str] = None,
created_gt: Optional[str] = None,
created_gte: Optional[str] = None,
created_lt: Optional[str] = None,
created_lte: Optional[str] = None,
**kwargs: Dict,
):
"""
Get list of documents
:param query: Search term to search for a specific document by its content. These fields will be searched: external_id, category, vendor.name, notes, invoice_number, total and ocr_text.
:param external_id: Search for documents that match your custom identifier
:param tag: Search for documents with the specified tag
:param created__gt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__gte: Search for documents with a created date greater than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__gt and created__gte in a single request.
:param created__lt: Search for documents with a created date greater than this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param created__lte: Search for documents with a created date less than or equal to this one. Format YYYY-MM-DD+HH:MM:SS. Don't send both created__lt and created__lte in a single request.
:param kwargs: Additional request parameters
:return: List of previously processed documents
"""
endpoint_name = "/documents/"
request_params = {}
if q:
request_params["q"] = q
if external_id:
request_params["external_id"] = external_id
if tag:
request_params["tag"] = tag
if created_gt:
request_params["created__gt"] = created_gt
if created_gte:
request_params["created__gte"] = created_gte
if created_lt:
request_params["created__lt"] = created_lt
if created_lte:
request_params["created__lte"] = created_lte
request_params.update(kwargs)
if request_params:
endpoint_name += "?" + "&".join(f"{k}={v}" for k, v in request_params.items())
documents = self._request("GET", endpoint_name, {})
if "documents" in documents:
return documents["documents"]
return documents
get_line_item
def get_line_item(
self,
document_id,
line_item_id
)
Retrieve a line item for existing document by ID.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to retrieve | None |
line_item_id | None | ID of the line item you'd like to retrieve | None |
Returns:
Type | Description |
---|---|
None | Line item extracted from the document |
View Source
def get_line_item(self, document_id, line_item_id):
"""
Retrieve a line item for existing document by ID.
:param document_id: ID of the document you'd like to retrieve
:param line_item_id: ID of the line item you'd like to retrieve
:return: Line item extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
get_line_items
def get_line_items(
self,
document_id
)
Retrieve all line items for a document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to retrieve | None |
Returns:
Type | Description |
---|---|
None | List of line items extracted from the document |
View Source
def get_line_items(self, document_id):
"""
Retrieve all line items for a document.
:param document_id: ID of the document you'd like to retrieve
:return: List of line items extracted from the document
"""
endpoint_name = f"/documents/{document_id}/line-items/"
request_arguments = {}
line_items = self._request("GET", endpoint_name, request_arguments)
return line_items
process_document
def process_document(
self,
file_path: str,
categories: Union[List, NoneType] = None,
delete_after_processing: bool = False,
**kwargs: Dict
)
Process a document and extract all the fields from it
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_path | None | Path on disk to a file to submit for data extraction | None |
categories | None | List of categories Veryfi can use to categorize the document | None |
delete_after_processing | None | Delete this document from Veryfi after data has been extracted | None |
kwargs | None | Additional request parameters | None |
Returns:
Type | Description |
---|---|
None | Data extracted from the document |
View Source
def process_document(
self,
file_path: str,
categories: Optional[List] = None,
delete_after_processing: bool = False,
**kwargs: Dict,
):
"""
Process a document and extract all the fields from it
:param file_path: Path on disk to a file to submit for data extraction
:param categories: List of categories Veryfi can use to categorize the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param kwargs: Additional request parameters
:return: Data extracted from the document
"""
endpoint_name = "/documents/"
if not categories:
categories = self.CATEGORIES
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
"categories": categories,
"auto_delete": delete_after_processing,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
process_document_url
def process_document_url(
self,
file_url: Union[str, NoneType] = None,
categories: Union[List[str], NoneType] = None,
delete_after_processing=False,
boost_mode: int = 0,
external_id: Union[str, NoneType] = None,
max_pages_to_process: Union[int, NoneType] = None,
file_urls: Union[List[str], NoneType] = None,
**kwargs: Dict
) -> Dict
Process Document from url and extract all the fields from it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_url | None | Required if file_urls isn't specified. Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg". | None |
file_urls | None | Required if file_url isn't specifies. List of publicly accessible URLs to multiple files, e.g. ["https://cdn.example.com/receipt1.jpg", "https://cdn.example.com/receipt2.jpg"] | None |
categories | None | List of categories to use when categorizing the document | None |
delete_after_processing | None | Delete this document from Veryfi after data has been extracted | None |
max_pages_to_process | None | 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. | None |
boost_mode | None | Flag that tells Veryfi whether boost mode should be enabled. When set to 1, Veryfi will skip data enrichment steps, but will process the document faster. Default value for this flag is 0 | None |
external_id | None | Optional custom document identifier. Use this if you would like to assign your own ID to documents | None |
kwargs | None | Additional request parameters | None |
Returns:
Type | Description |
---|---|
None | Data extracted from the document. |
View Source
def process_document_url(
self,
file_url: Optional[str] = None,
categories: Optional[List[str]] = None,
delete_after_processing=False,
boost_mode: int = 0,
external_id: Optional[str] = None,
max_pages_to_process: Optional[int] = None,
file_urls: Optional[List[str]] = None,
**kwargs: Dict,
) -> Dict:
"""Process Document from url and extract all the fields from it.
:param file_url: Required if file_urls isn't specified. Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_urls: Required if file_url isn't specifies. List of publicly accessible URLs to multiple files, e.g. ["https://cdn.example.com/receipt1.jpg", "https://cdn.example.com/receipt2.jpg"]
:param categories: List of categories to use when categorizing the document
:param delete_after_processing: Delete this document from Veryfi after data has been extracted
:param 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.
:param boost_mode: Flag that tells Veryfi whether boost mode should be enabled. When set to 1, Veryfi will skip data enrichment steps, but will process the document faster. Default value for this flag is 0
:param external_id: Optional custom document identifier. Use this if you would like to assign your own ID to documents
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/documents/"
request_arguments = {
"auto_delete": delete_after_processing,
"boost_mode": boost_mode,
"categories": categories,
"external_id": external_id,
"file_url": file_url,
"file_urls": file_urls,
"max_pages_to_process": max_pages_to_process,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
process_w9_document
def process_w9_document(
self,
file_path: str,
file_name: Union[str, NoneType] = None,
**kwargs
)
Process W9 Document from url and extract all the fields from it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_path | None | Path on disk to a file to submit for data extraction | None |
file_name | None | Optional name of file, eg. receipt.jpg | None |
kwargs | None | Additional request parameters | None |
Returns:
Type | Description |
---|---|
None | Data extracted from the document. |
View Source
def process_w9_document(self, file_path: str, file_name: Optional[str] = None, **kwargs):
"""
Process W9 Document from url and extract all the fields from it.
:param file_path: Path on disk to a file to submit for data extraction
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
endpoint_name = "/w9s/"
if file_name is None:
file_name = os.path.basename(file_path)
with open(file_path, "rb") as image_file:
base64_encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
request_arguments = {
"file_name": file_name,
"file_data": base64_encoded_string,
}
request_arguments.update(kwargs)
document = self._request("POST", endpoint_name, request_arguments)
return document
process_w9_document_url
def process_w9_document_url(
self,
file_url: str,
file_name: Union[str, NoneType] = None,
**kwargs: Dict
) -> Dict
Process W9 Document from url and extract all the fields from it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_url | None | Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg". | None |
file_name | None | Optional name of file, eg. receipt.jpg | None |
kwargs | None | Additional request parameters | None |
Returns:
Type | Description |
---|---|
None | Data extracted from the document. |
View Source
def process_w9_document_url(
self, file_url: str, file_name: Optional[str] = None, **kwargs: Dict
) -> Dict:
"""
Process W9 Document from url and extract all the fields from it.
:param file_url: Publicly accessible URL to a file, e.g. "https://cdn.example.com/receipt.jpg".
:param file_name: Optional name of file, eg. receipt.jpg
:param kwargs: Additional request parameters
:return: Data extracted from the document.
"""
if file_name is None:
file_name = os.path.basename(file_url)
endpoint_name = "/w9s/"
request_arguments = {
"file_name": file_name,
"file_url": file_url,
}
request_arguments.update(kwargs)
return self._request("POST", endpoint_name, request_arguments)
replace_tags
def replace_tags(
self,
document_id,
tags
)
Replace multiple tags on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
tags | None | array of strings | None |
Returns:
Type | Description |
---|---|
None | Added tags data |
View Source
def replace_tags(self, document_id, tags):
"""
Replace multiple tags on an existing document.
:param document_id: ID of the document you'd like to update
:param tags: array of strings
:return: Added tags data
"""
endpoint_name = f"/documents/{document_id}/"
request_arguments = {"tags": tags}
return self._request("PUT", endpoint_name, request_arguments)
update_document
def update_document(
self,
document_id: int,
**kwargs
) -> Dict
Update data for a previously processed document, including almost any field like vendor
, date
, notes
and etc.
veryfi_client.update_document(id, date="2021-01-01", notes="look what I did")
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
kwargs | None | fields to update | None |
Returns:
Type | Description |
---|---|
None | A document json with updated fields, if fields are writable. Otherwise a document with unchanged fields. |
View Source
def update_document(self, document_id: int, **kwargs) -> Dict:
"""
Update data for a previously processed document, including almost any field like `vendor`, `date`, `notes` and etc.
```veryfi_client.update_document(id, date="2021-01-01", notes="look what I did")```
:param document_id: ID of the document you'd like to update
:param kwargs: fields to update
:return: A document json with updated fields, if fields are writable. Otherwise a document with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/"
return self._request("PUT", endpoint_name, kwargs)
update_line_item
def update_line_item(
self,
document_id: int,
line_item_id: int,
payload: Dict
) -> Dict
Update an existing line item on an existing document.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
document_id | None | ID of the document you'd like to update | None |
line_item_id | None | ID of the line item you'd like to update | None |
payload | None | line item object to update | None |
Returns:
Type | Description |
---|---|
None | Line item data with updated fields, if fields are writable. Otherwise line item data with unchanged fields. |
View Source
def update_line_item(self, document_id: int, line_item_id: int, payload: Dict) -> Dict:
"""
Update an existing line item on an existing document.
:param document_id: ID of the document you'd like to update
:param line_item_id: ID of the line item you'd like to update
:param payload: line item object to update
:return: Line item data with updated fields, if fields are writable. Otherwise line item data with unchanged fields.
"""
endpoint_name = f"/documents/{document_id}/line-items/{line_item_id}"
request_arguments = UpdateLineItem(**payload).dict(exclude_none=True)
return self._request("PUT", endpoint_name, request_arguments)