NAV
shell java python

Introduction

Welcome to the Itemize Enterprise API documentation. The Itemize Enterprise API allows a client to upload receipt documents and view the raw results in the form of a structured data set.

Sample code is available for reference in Shell, Java, and Python on the right. The Java code requires the Unirest library. The python code requires the Unirest and Json libraries.

To integrate the Itemize Enterprise API with your application, check out the Getting Started section for a step-by-step guide and workflow overview.

Releases

Upcoming

Changelog

Invoices & Hotel Folios - Comprehensive Solution

Released: July 25, 2018

Summary

Invoices and hotel folios can be submitted for human review, which ensures the highest accuracy of an extracted data set. These documents will need to be distinguished from receipts by sending an additional "metadata" parameter on document upload.

Workflow:

Invoice and hotel folio processing follows a pipeline similar to receipt processing. Processing and webhook notifications remain the same.

On upload, send the parameter, "document_type":"invoice" for invoice documents and "document_type":"folio" for hotel folio documents. By default, Itemize considers any unspecified document a "receipt".



API Resources - Updates

"Metadata" Form Fields:
Field Description Allowed Values
document_type
string
Type of document uploaded receipt, invoice, folio

Document:
Field Description Allowed Values
document_type
string
Type of document uploaded receipt, invoice, folio
non_conforming_reason
string
Reason as to why a document may have been marked "is_conforming":false

Comprehensive Solution

Released: July 1, 2018

Summary

Receipt documents have the ability to be submitted for human review, which ensures the highest accuracy of an extracted data set. Clients may opt-in for this exciting new workflow. For existing integrations, processing is unchanged, as the review workflow occurs after core engine processing.

Workflow:

  1. During data extraction, a confidence score is assigned to each data field. If a confidence score falls below a given threshold, the document's field is forwarded for human verification.
  2. A "document.processed" webhook message is sent to notify the client that the document's initial data set is available. The webhook message contains a "sent_for_human_verification" flag that denotes whether the document was forwarded for verification.
  3. Once the document has been reviewed, a "document.updated" webhook message is sent to notify the client that the document's data set has been updated.

For polling (or offline) integrations, two fields in the document's data set denote the "status" of the document. The "sent_for_human_verification" property mimics the webhook message flag (described above). The "is_final" property describes the status of review. Three possible flag combinations are as follows:

sent_for_human_verification is_final Description
false true Document was not sent for human review; the final data set is available.
true false Document was sent for human review; the final data set is not yet available, e.g. current data set may be incomplete.
true true Document was sent for human review; the final data set is available.


API Resources - Updates

Document:
Field Description
is_document
boolean
Denotes whether the file uploaded contains a document
is_conforming
boolean
Denotes whether the document is conforming
sent_for_human_verification
boolean
Flags whether the document was forwarded on for human verification
is_final
boolean
Flags whether the data set is final or awaiting update

Outbound Webhooks:
Field Description
sent_for_human_verification
boolean
Denotes whether a document was sent for human verification

Tip Processing

Released February 28, 2018

Summary

Handwritten tips are now extracted and presented in the document data set by way of human verification. Clients have the ability to opt-in for this supplemental workflow. For existing integrations, processing is unchanged, as the verification workflow occurs after core engine processing.

Tip extraction workflow:

  1. During data extraction, a confidence score is assigned to the likelihood of a tip's presence. If the confidence score falls below a given threshold, the document is forwarded for human verification.
  2. A "document.processed" webhook message is sent to notify the client that the document's initial data set is available. The webhook message contains a "sent_for_human_verification" flag that denotes whether the document was forwarded for verification.
  3. Once the document has been verified by human eyes, the document's tip value is updated in the data set.
  4. A "document.updated" webhook message is sent to notify the client that the document's data set has been updated.

For polling (or offline) integrations, two fields in the document's data set denote the "status" of the document. The "sent_for_human_verification" property mimics the webhook message flag (described above). The "is_final" property states whether the available data set is final or awaiting update. Three possible flag combinations are as follows:

sent_for_human_verification is_final Description
false true Document was not sent for human verification; the final data set is available.
true false Document was sent for human verification; the final data set is not yet available, e.g. current data set may be incomplete.
true true Document was sent for human verification; the final data set is available.


API Resources - Updates

Document:
Field Description
tip
decimal
Value of tip
sent_for_human_verification
boolean
Flags whether the document was forwarded on for human verification
is_final
boolean
Flags whether the data set is final or awaiting update

Outbound Webhooks:
Field Description
sent_for_human_verification
boolean
Denotes whether a document was sent for human verification


See figure below for a tip processing workflow visualization:

Tip Processing Workflow

File Size Limitations

Released February 14, 2018

File size requirements have been added to image uploads. Any image outside of the threshold will be rejected with a HTTP 400 error code and corresponding message. See below table for specifications:

Content Types:

Content-Type File Size Requirements Below Threshold Response Above Threshold Response
Paper
image/jpeg 100KB - 5MB {"error": "Minimum file size is 100KB"} {"error": "Maximum file size is 5MB"}
image/png 100KB - 5MB {"error": "Minimum file size is 100KB"} {"error": "Maximum file size is 5MB"}
application/pdf less than 5MB No minimum. {"error": "Maximum file size is 5MB"}
Digital
text/html less than 5MB No minimum. {"error": "Maximum file size is 5MB"}
text/plain less than 5MB No minimum. {"error": "Maximum file size is 5MB"}

Authentication

To authorize, use this code:

# With Python's Unirest library, just add the auth=(username, password) parameter to each request
import unirest

response = unirest.get("api_endpoint_here", auth=('', 'xxxxxxxxxx'))
print response.raw_body
// With Java's Unirest library, just add the basicAuth(String username, String password) method to each request

GetRequest body = Unirest
          .get("api_endpoint_here")
          .basicAuth("", "xxxxxxxxxx");
# Specify the API token as the password portion for inline authentication

curl -u :xxxxxxxxxx 'api_endpoint_here'

Make sure to replace xxxxxxxxxx with your API token.

In order to use the Enterprise API, clients will need an API token. Requests are authenticated using HTTP Basic Authorization. Use the supplied API token as the Basic Auth password; there is no username.

The Authorization header must be included in all requests in the following format:

Authorization: Basic xxxxxxxxxx

Getting Started

Before integrating the Enterprise API with your application, Itemize recommends understanding the API’s workflow. The Enterprise API serves as an Internet-facing entry/exit point for the Core Processing Engine. Once a document is ingested by the API, it is forwarded to the Core Engine for processing and extraction.

See figures below for an API workflow visualization for each document type:

Paper Receipt Workflow

Digital Receipt Workflow

Basic Request Flow:

  1. Upload a receipt document, e.g. POST /documents
  2. Wait for document.processed outbound webhook, indicating receipt processing is complete and the extracted data set is available
  3. Get the document’s extracted data using the document’s ID returned in the webhook message, e.g. GET /documents/<DOCUMENT-ID>

Step-By-Step Integration

Here, we’ll walk through the steps to create a fully-functioning integration between a client application and the Enterprise API.

Itemize recommends a client first upload documents to the API with the use of a REST client such as POSTMAN, Fiddler, etc. to test the API’s requests and responses.

Next, Itemize recommends working through a coded integration:

  1. A decision should be made on how the client application will get each document’s extracted data set, as this setup will affect the request flow. Since document processing is asynchronous, Itemize has webhooks to notify the client when a document has finished processing and its extracted data set is available.

    Clients can choose one of the following options to handle the asynchronous response:

    • Client polls each document’s endpoint until the extracted data set is available, OR
    • Client registers a webhook callback URL that will recieve messages when a document has finished processing

    To register a callback URL:

    1. Add a new webhook URL, e.g. POST /webhooks
    2. Verify the callback URL has been registered using the "id" field in the response, e.g. GET /webhooks/

    To poll the document endpoint:

    1. Continous GET requests to the document’s endpoint until a 200 OK response status is achieved
  2. Upload a Document, e.g. POST /documents request You’ll want to save the response, as it returns the document’s ID.

If Client registered a callback URL:

  1. Receival of a document.processed webhook message for the uploaded document
  2. Using the url resource field in the webhook message’s data field, get the document’s extracted data set, e.g. GET /documents/ request

If the Client polls the document’s endpoint:

  1. Client polls document’s endpoint until a 200 OK code is achieved and the extracted data set exists in the response body.

Accounts

Clients are provided with an account that serves as the container for all uploaded documents and their data sets.

{
  "id":155,
  "company":"Enterprise Documentation Demo",
  "primary_contact":"FirstName LastName",
  "email_address":"email@gmail.com",
  "markets":["US", "UK"],
  "country":
  {
    "country_code":"US"
  },
  "monthly_processed":1736,
  "total_processed":27807,
  "data_set":"L2",
  "status":"active",
  "created":1460990424
}

Resource Fields:

Field Description Default Allowed Values
id
int
Account ID
company
string
Company name
primary contact
string
Primary contact name
email_address
string
Primary email address
markets
string array
Markets enabled for account US US, UK, AU, NZ, CA, IE, ZA, SG, DE
country
string
Home country
monthly_processed
int
Number of documents processed MTD
total_processed
int
Total number of documents processed
data_set
string
Data level enabled for account, corresponds to receipt extraction level L2 L1, L2, L3, Custom
status
string
Activity status for account active, inactive, suspended
created
long
Date of account creation Unix timestamp in UTC

Get Account Info

Example Request:

import unirest

response = unirest.get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155", auth=('', 'xxxxxxxxxx'))
print response.raw_body
GetRequest response = Unirest
          .get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155")
          .basicAuth("", "xxxxxxxxxx");    
System.out.println(response.asString().getBody().toString());
curl -u :xxxxxxxxxx "https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155"

Make sure to replace xxxxxxxxxx with your API token.

Example Response Body:

{
  "status":"active",
  "country":
  {
    "country_code":"US"
  },
  "total_processed":27807,
  "markets":["US", "UK"],
  "primary_contact":"FirstName LastName",
  "created":1460990424,
  "monthly_processed":1736,
  "email_address":"email@gmail.com",
  "data_set":"L2",
  "id":155,
  "company":"Enterprise Documentation Demo"
}

View the contact info, number of receipts processed, and markets enabled for an an account.

HTTP Request

GET https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>

Response Types

Code Description
200 Successful
401 Unauthorized

Update Account Info

Example Request:

import unirest
import json

response = unirest.put("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155", 
  headers={"Content-Type":"application/json"}, 
  params=json.dumps({"primary_contact":"UpdatedFirstName UpdatedLastName", "email_address":"updatedEmail@gmail.com"}), 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body
HttpResponse<JsonNode> response = Unirest
          .put("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155")
          .basicAuth("", xxxxxxxxxx)
          .header("Content-Type", "application/json")
          .body("{\"primary_contact\":\"UpdatedFirstName UpdatedLastName\", 
                  \"email_address\":\"updatedEmail@gmail.com\"}")
          .asJson();

System.out.println(response.getBody().getObject().toString());
curl -u :xxxxxxxxxx
     -X PUT 
     -H "Content-Type: application/json" 
     -d '{"primary_contact":"UpdatedFirstName UpdatedLastName", "email_address":"updatedEmail@gmail.com"}' 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{
  "status":"active",
  "country":
  {
    "country_code":"US"
  },
  "total_processed":27807,
  "markets":["US", "UK"],
  "primary_contact":"FirstName LastName",
  "created":1460990424,
  "monthly_processed":1736,
  "email_address":"email@gmail.com",
  "data_set":"L2",
  "id":155,
  "company":"Enterprise Documentation Demo"
}

Updates contact info for an account.

HTTP Request

PUT https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>

Content-Type

application/json

Data Params

Field Description
primary_contact
string
Primary contact
email_address
string
Primary email address

Response Types

Code Description
200 Successful
401 Unauthorized

Documents

The Itemize API accepts the following document content types:

{ 
  "id": "64233b41-4f00-4340-9362-caa26da43954",
  "format": "image/jpeg",
  "client_id": "user12345",
  "client_country_id": 1,
  "processed": 1459188044,
  "processed_string": "2016-03-28",
  "market": "US",
  "ocr_text": "this is some sample text.",
  "purchased": 1400457600,
  "purchased_string": "2014-05-19",
  "total": 11.60,
  "currency": "USD",
  "payment_type": "Mastercard",
  "is_document": true,
  "is_conforming": true,
  "sent_for_human_verification": true,
  "document_type": "receipt",
  "non_conforming_reason": null,
  "is_final": true,
  "merchant": {
      "name": "default_Pret A Manger",
      "category": "Food & Dining",
      "icon": "https://s3.amazonaws.com/mcc_icons/food.png",
      "is_tippable": 1,
      "normalized_name": "Pret A Manger",
      "expense_category": "Dining & Entertainment",
      "logo": "http://i.imgur.com/hsh5OCY.jpg",
      "tax_id": null,
      "registered_name": null,
      "branch": {
        "phone": "1234567890" 
      } 
    },
  "subtotal": 9.98,
  "tax": 0.62,
  "tip": 1.00,
  "financial_values": [
    {
      "financial_value_type": tax
      "financial_value": 0.62
    }
  ]
  "attributes": null
  "receipt_items": [
    {
      "item_name": "honey tangerine"
      "item_subtotal": 2.99
      "item_date": null
    }
    {
      "item_name": "avocado pinenut wrap"
      "item_subtotal": 6.99
      "item_date": null
    }
  ]
}

Content Types:

Content-Type File Size Requirements
Paper
image/jpeg 100KB - 5MB
image/png 100KB - 5MB
application/pdf less than 5MB
Digital
text/html less than 5MB
text/plain less than 5MB

Resource Fields:

Field Level Description Allowed Values
id
string
Base Document ID
format
string
Base Document’s Content-Type image/jpeg, image/png, application/pdf,
text/html, text/plain
client_id
string
Base Client-provided UID used to identify and/or link receipts with a unique end user
client_country_id
int
Base Home country of client_id
processed
long
Base Unix timestamp of document’s processing
processed_string
string
1 Formatted string version of "processed" field YYYY-MM-DD
market
string array
Base Document’s origin market; Market of transaction
ocr_text
string
Base OCR text extracted from document image
is_document
boolean
Base Denotes whether the file uploaded contains a document true, false
is_conforming
boolean
Base Denotes whether the document is conforming true, false
is_final
boolean
Base Denotes whether the data set is final or awaiting update true, false
sent_for_human_verification
boolean
Base Denotes whether the document was sent for human verification true, false
document_type
string
Base Type of document uploaded receipt, invoice, folio
non_conforming_reason
string
Base Reason as to why a document may have been marked "is_conforming":false
Level 1
purchased
long
1 Date of transaction Unix timestamp in UTC;
0 indicates inability to extract purchase date
purchased_string
string
1 Formatted string version of "purchased" field YYYY-MM-DD
total
decimal
1 Total amount of transaction including tip
currency
string
1 National Currency of amount tendered ISO codes
payment_type
string
1 Method of Payment for a Purchase Defaults:American Express, Cash, Check, Discover, Mastercard, PaypPal, Visa
merchant
complex object
Level 2
subtotal
decimal
2 Sum of item charges (can excl. or include VAT/tax depending on market)
tax
decimal
2 Captured tax data (US Sales Tax, VAT, GST) rolled up Sum of all taxes on document
tip
decimal
2 Value of tip
financial_values
complex object
2 Array of financial values Flexible representation of financial values on document; expect duplication of types, e.g. state and city tax
attributes
complex object
2 Array of receipt attributes Flexible representation of document fields; includes folio and invoice fields such as start date, end date, due date
Level 3
receipt_items
complex object
3/4 Array of receipt items


merchant Resource Fields:


In the event that Itemize cannot resolve a merchant using the data within a document, a merchant will still exist in the response object. The merchant will have a default name of 'Merchant' and a default normalized_name of 'Merchant'.


Field Level Description Allowed Values
name
string
1 Merchant Name (Not Normalized) Potential for inconsistent names, not recommended for display purposes
category
string
1 Classifies the merchant by the type of goods/services provided
icon
string
1 Generic image representing "category"
is_tippable
int
1 Subjective merchant category field denotes whether a merchant is typically ‘tippable’ 'Tippable’ merchant categories rollup to:
Food & Dining, Entertainment, and Transportation > Taxi & Car Services
Level 2
normalized_name
string
2 Standardized name for chain of stores Recommended for display purposes
expense_category
string
2 IRS Expense Category corresponding to merchant
logo
string
2 Merchant-specific logo associated with normalized merchant
tax_id
string
2 VAT registration number as printed on document
registered_name
int
2 VAT registered merchant name
branch
complex object
2 Location-specific merchant information


branch Resource Fields:

Field Level Description Allowed Values
phone
string
2 Phone unformatted phone number


financial value Resource Fields:

Field Level Description Allowed Values
financial_value_type
string
2 Type of financial values tax, discount, subtotal, balance due, etc.
financial_value
decimal
2 Financial value


attribute Resource Fields:

Field Level Description Allowed Values
attribute_type
string
2 Type of attribute description of attribute label, e.g. start date, end date, due date
attribute_value
string
2 Attribute value If a date, then YYYY-MM-DD format


receipt item Resource Fields:

Field Level Description Allowed Values
item_name
string
3 Name of product or service
item_subtotal
decimal
3 Subtotal of item Typically presented as item_quantity * item_unit_price; less item_discount and plus item_shipping, item_handling, and item_tax
item_date
string
4 Date associated with item, e.g. hotel folio line-item charge date YYYY-MM-DD
item_type
string
4 Type associated with item Currently, only available type is tax

Upload a Document

Submit a receipt document to Itemize for data extraction.

HTTP Request

POST https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/documents

Content-Type

multipart/form-data

Paper

Example Paper Requests:

# JPEG Receipt
import unirest
import json

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents", 
  params={
  "metadata":json.dumps(
    {
    "format":"image/jpeg",
    "document_type":"receipt",
    "latitude": 32.887993, 
    "longitude": -96.766574, 
    "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
    "client_country_id":1,
    "webhook_id": "ADJSwejn23opds92"
    }),
  "document": open("images/receipt.jpeg", 'rb')}, 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body

# PNG Receipt
import unirest
import json

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents", 
  params={
  "metadata":json.dumps(
    {
    "format":"image/png",
    "document_type":"receipt",
    "latitude": 32.887993, 
    "longitude": -96.766574, 
    "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
    "client_country_id":1,
    "webhook_id": "ADJSwejn23opds92"
    }),
  "document": open("images/receipt.png", 'rb')}, 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body

# PDF Receipt
import unirest
import json

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents", 
  params={
  "metadata":json.dumps(
    {
    "format":"application/pdf",
    "document_type":"receipt",
    "latitude": 32.887993, 
    "longitude": -96.766574, 
    "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
    "client_country_id":1,
    "webhook_id": "ADJSwejn23opds92"
    }),
  "document": open("/images/receipt.pdf", 'rb')}, 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body
// JPEG Receipt
MultipartBody body = Unirest
          .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents")
          .basicAuth("", "xxxxxxxxxx")
          .field("metadata", 
              "{\"format\": \"image/jpeg\", 
                \"latitude\": 32.887993, 
                \"longitude\": -96.766574, 
                \"client_id\": \"6g3fgh7h2s-557h-225c-81a3-yyoc8218788\", 
                \"client_country_id\":1,
                \"webhook_id\": \"ADJSwejn23opds92\"}")
          .field("document", 
              new File("images/receipt.jpeg"), 
              "image/jpeg");
System.out.println(body.asString().getBody().toString());

// PNG Receipt
MultipartBody body = Unirest
          .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents")
          .basicAuth("", "xxxxxxxxxx")
          .field("metadata", 
              "{\"format\": \"image/png\", 
                \"latitude\": 32.887993, 
                \"longitude\": -96.766574, 
                \"client_id\": \"6g3fgh7h2s-557h-225c-81a3-yyoc8218788\", 
                \"client_country_id\":1,
                \"webhook_id\": \"ADJSwejn23opds92\"}")
          .field("document", 
              new File("images/receipt.png"), 
              "image/png");
System.out.println(body.asString().getBody().toString());

// PDF Receipt
MultipartBody body = Unirest
          .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents")
          .basicAuth("", "xxxxxxxxxx")
          .field("metadata", 
              "{\"format\": \"application/pdf\", 
                \"latitude\": 32.887993, 
                \"longitude\": -96.766574, 
                \"client_id\": \"6g3fgh7h2s-557h-225c-81a3-yyoc8218788\", 
                \"client_country_id\":1,
                \"webhook_id\": \"ADJSwejn23opds92\"}")
          .field("document", 
              new File("/image/receipt.pdf"), 
              "application/pdf");
System.out.println(body.asString().getBody().toString());
# JPEG Receipt
curl -u :xxxxxxxxxx 
  -F metadata='{"format": "image/jpeg", 
                   "document_type":"receipt",
                   "latitude": 32.887993, 
                   "longitude": -96.766574, 
                   "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
                   "client_country_id":1,
                   "webhook_id": "ADJSwejn23opds92"}'
  -F document=@/image/receipt.jpeg
  'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents'

# PNG Receipt
curl -u :xxxxxxxxxx 
     -F metadata='{"format": "image/png", 
                   "document_type":"receipt",
                   "latitude": 32.887993, 
                   "longitude": -96.766574, 
                   "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
                   "client_country_id":1,
                   "webhook_id": "ADJSwejn23opds92"}'
     -F document=@/image/receipt.png
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents'

# PDF Receipt
curl -u :xxxxxxxxxx 
     -F metadata='{"format": "application/pdf", 
                   "document_type":"receipt",
                   "latitude": 32.887993, 
                   "longitude": -96.766574, 
                   "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
                   "client_country_id":1,
                   "webhook_id": "ADJSwejn23opds92"}'
     -F document=@/image/receipt.pdf
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{
  "id": "64233b41-4f00-4340-9362-caa26da43954", 
  "format": "image/jpeg", 
  "document_type": "receipt", 
  "latitude": 32.887993, 
  "longitude": -96.766574, 
  "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
  "client_country_id":1,
  "webhook_id": "ADJSwejn23opds92"
}

"Metadata" Form Fields

Field Description Allowed Values
format
string
(required)
Document’s content-type image/jpeg,
image/png,
application/pdf
client_id
string
Client-provided UID used to identify and/or link receipts with a unique end user 128 characters or less
client_country_id
int
Home country of end user - to be used along with client_id to aid in accurate data extraction and the mapping of receipts to accounts’ end users
webhook_id
string
Client-provided webhook identifier used to verify the source of the outbound webhook; echoed back in webhook message as "client_token" 6500 characters or less
latitude
decimal
GPS Latitude from document capture
longitude
decimal
GPS Longitude from document capture
document_type
string
Type of document uploaded receipt, invoice, folio

Digital

Example Digital Requests:

# HTML Receipt
import unirest
import json

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents", 
  params={
  "metadata":json.dumps(
    {
    "format":"text/html",
    "document_type":"receipt",
    "latitude": 32.887993, 
    "longitude": -96.766574, 
    "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
    "client_country_id":1,
    "webhook_id": "ADJSwejn23opds92"
    }),
  "document": open("/images/receipt.html", 'rb')}, 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body

# TEXT Receipt
import unirest
import json

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents", 
  params={
  "metadata":json.dumps(
    {
    "format":"text/plain",
    "document_type":"receipt",
    "latitude": 32.887993, 
    "longitude": -96.766574, 
    "client_id": "6g3fgh7h2s-557h-225c-81a3-yyoc8218788", 
    "client_country_id":1,
    "webhook_id": "ADJSwejn23opds92"
    }),
  "document": open("/images/receipt.txt", 'rb')}, 
  auth=('', 'xxxxxxxxxx'))

print response.raw_body
// HTML Receipt
MultipartBody body = Unirest
          .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents")
          .basicAuth("", "xxxxxxxxxx")
          .field("metadata", 
              "{\"format\":\"text/html\", 
                \"from_address\":\"orders@amazon.com\",
                \"subject\":\"Your Recent Amazon Order\",
                \"to_address\":\"testemail@gmail.com\",
                \"received_datetime\":0,
                \"client_id\": \"643ht811g6-23j7-77hg-12ff-bz55n99a768\", 
                \"client_country_id\":1,
                \"webhook_id\": \"ADJSwejn23opds92\"}")
          .field("document", 
              new File("/images/receipt.html"), 
              "text/plain");
System.out.println(body.asString().getBody().toString());

// TEXT Receipt
MultipartBody body = Unirest
          .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents")
          .basicAuth("", "xxxxxxxxxx")
          .field("metadata", 
              "{\"format\":\"text/plain\",
                \"document_type\":\"receipt\",
                \"from_address\":\"orders@amazon.com\",
                \"subject\":\"Your Recent Amazon Order\",
                \"to_address\":\"testemail@gmail.com\",
                \"received_datetime\":0,
                \"client_id\": \"643ht811g6-23j7-77hg-12ff-bz55n99a768\", 
                \"client_country_id\":1,
                \"webhook_id\": \"ADJSwejn23opds92\"}")
          .field("document", 
              new File("/images/receipt.txt"), 
              "text/plain");
System.out.println(body.asString().getBody().toString());
# HTML Receipt
curl -u :xxxxxxxxxx 
     -F metadata='{"format":"text/html", 
                   "document_type":"receipt",
                   "from_address":"orders@amazon.com",
                   "subject":"Your Recent Amazon Order",
                   "to_address":"testemail@gmail.com",
                   "received_datetime":0,
                   "client_id": "643ht811g6-23j7-77hg-12ff-bz55n99a768", 
                   "client_country_id":1,
                   "webhook_id": "ADJSwejn23opds92"}'
     -F document=@/images/receipt.html 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents'

# Text Receipt
curl -u :xxxxxxxxxx 
     -F metadata='{"format":"text/plain", 
                   "document_type":"receipt",
                   "from_address":"orders@amazon.com",
                   "subject":"Your Recent Amazon Order",
                   "to_address":"testemail@gmail.com",
                   "received_datetime":0,
                   "client_id": "643ht811g6-23j7-77hg-12ff-bz55n99a768", 
                   "client_country_id":1,
                   "webhook_id": "ADJSwejn23opds92"}'
     -F document=@/images/receipt.txt
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{
  "id": "64233b41-4f00-4340-9362-caa26da43954", 
  "format": "text/html", 
  "document_type": "receipt", 
  "from_address":"orders@amazon.com",
  "subject":"Your Recent Amazon Order",
  "to_address":"testemail@gmail.com",
  "received_datetime":0,
  "client_id": "643ht811g6-23j7-77hg-12ff-bz55n99a768", 
  "client_country_id":1,
  "webhook_id": "ADJSwejn23opds92"
}

Data Params

Field Description Allowed Values
format
string
(required)
Document’s content-type text/html, text/plain
from_address
string
(required)
Email address that sent the digital receipt email
client_id
string
Client-provided UID used to identify and/or link receipts with a unique end user 128 characters or less
client_country_id
string
Home country of end user; to be used along with client_id to aid in accurate data extraction and the mapping of receipts to clients’ end users
webhook_id
string
Client-provided webhook identifier used to verify the source of the outbound webhook; echoed back in webhook message as "client_token" 6500 characters or less
to_address
string
Receiving email address Defaults to: Enterprise API
subject
string
Subject line of the email Defaults to: Electronic Receipt
received_datetime
long
Date of email receival Unix timestamp in UTC;
Defaults to: 0
document_type
string
Type of document uploaded receipt, invoice, folio

Response Types

Code Description
200 Successful
400 Bad Request - Known Document Upload Error
401 Unauthorized
415 Unsupported Content-Type
500 Generic Server Error

Get Document Data

Example Request:

import unirest

response = unirest.get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents/64233b41-4f00-4340-9362-caa26da43954", auth=('', 'xxxxxxxxxx'))
print response.raw_body
GetRequest body = Unirest
          .get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents/64233b41-4f00-4340-9362-caa26da43954")
          .basicAuth("", xxxxxxxxxx);    
System.out.println(body.asString().getBody().toString());
curl -u :xxxxxxxxxx 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/documents/64233b41-4f00-4340-9362-caa26da43954'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{ 
  "id": "64233b41-4f00-4340-9362-caa26da43954",
  "format": "image/jpeg",
  "client_id": "user12345",
  "client_country_id": 1,
  "processed": 1459188044,
  "processed_string": "2016-03-28",
  "market": "US",
  "ocr_text": "this is some sample text.",
  "purchased": 1400457600,
  "purchased_string": "2014-05-19",
  "total": 11.60,
  "currency": "USD",
  "payment_type": "Mastercard",
  "is_document": true,
  "is_conforming": true,
  "sent_for_human_verification": true,
  "document_type": "receipt",
  "non_conforming_reason": null,
  "is_final": true,
  "merchant": {
      "name": "default_Pret A Manger",
      "category": "Food & Dining",
      "icon": "https://s3.amazonaws.com/mcc_icons/food.png",
      "is_tippable": 1,
      "normalized_name": "Pret A Manger",
      "expense_category": "Dining & Entertainment",
      "logo": "http://i.imgur.com/hsh5OCY.jpg",
      "tax_id": null,
      "registered_name": null,
      "branch": {
        "phone": "1234567890" 
      } 
    },
  "subtotal": 9.98,
  "tax": 0.62,
  "tip": 1.00,
  "financial_values": [
    {
      "financial_value_type": tax
      "financial_value": 0.62
    }
  ]
  "attributes": null
  "receipt_items": [
    {
      "item_name": "honey tangerine"
      "item_subtotal": 2.99
      "item_date": null
    }
    {
      "item_name": "avocado pinenut wrap"
      "item_subtotal": 6.99
      "item_date": null
    }
  ]
}

Retrieves the structured data set for a given document.

HTTP Request

GET https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/documents/<DOCUMENT-ID>

Response Types

Code Description
200 Successful, Document data set is available
401 Unauthorized
404 Resource Not Found - Document has not yet finished processing

Registering Callback URLs

Webhooks serve as the real-time notification system for asynchronous document responses. A webhook notifies a client's application of particular events relating to a document’s workflow.

Accounts can register up to 3 callback URLs for a given API enviroment.

Resource Fields:

{
    "id":105,
    "account_id":155,
    "url":"http://www.example.com",
    "token":"dGVzdA==",
    "created":1459199078
}
Field Description Allowed Values
id
int
Account ID
account_id
int
Account associated with webhook
url
string
Callback URL
token
string
Credential validating outbound webhook’s source Max. 100 characters
created
long
Date of webhook creation Unix timestamp in UTC

Adding Callback URLs

Example Request:

import unirest

response = unirest.post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks",
    headers={"Content-Type":"application/json"},
    params=json.dumps({"url":"http://testwebhookurl.com", "toke":"dGVzdA=="}),
    auth=('', 'xxxxxxxxxx'))
print response.raw_body
HttpResponse<JsonNode> response = Unirest
                    .post("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks")
                    .basicAuth("", "xxxxxxxxxx")
                    .header("Content-Type", "application/json")
                    .body("{\"url\":\"http://testwebhookurl.com\", \"token\":\"dGVzdA==\"}")
                    .asJson();
System.out.println(response.getBody().getObject().toString())
curl -u :xxxxxxxxxx 
     -X POST 
     -H "Content-Type: application/json" 
     -d '{"url":"http://testwebhookurl.com", "token":"dGVzdA=="}' 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

[
    {
        "id":105,
        "url":"http://testwebhookurl.com",
        "account_id":155,
        "token":"dGVzdA=="
    }
]

Registers a callback URL for a client’s account.

HTTP Request

POST https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/webhooks

Data Parameters

Parameter Description Allowed Values
url
string
(required)
Callback URL
token
string
Credential validating outbound webhook’s source Max. 100 characters

Response Types

Code Description
201 Successful, callback URL is registered
401 Unauthorized

Get all Callback URLs

Example Request:

import unirest

response = unirest.get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks", 
    auth=('', 'xxxxxxxxxx'))
print response.raw_body
GetRequest request = Unirest
          .get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks")
          .basicAuth("", "xxxxxxxxxx");    
System.out.println(request.asString().getBody().toString());
curl -u :xxxxxxxxxx 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

[
    {
        "id":49,
        "url":"http://thisisawebhookurl.com",
        "account_id":155
    },
    {
        "id":105,
        "url":"http://testwebhookurl.com",
        "account_id":155
    }
]

Retrieves all registered callback URLs.

HTTP Request

GET https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/webhooks

Response Types

Code Description
200 Successful
401 Unauthorized

Get a Callback URL

Example Request:

import unirest

response = unirest.get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105", 
    auth=('', 'xxxxxxxxxx'))
print response.raw_body
GetRequest request = Unirest
          .get("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105")
          .basicAuth("", "xxxxxxxxxx");    
System.out.println(request.asString().getBody().toString());
curl -u :xxxxxxxxxx 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{
    "id":105,
    "url":"http://testwebhookurl.com",
    "account_id":155
}

Retrieves a specific callback URL.

HTTP Request

GET https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/webhooks/<WEBHOOK-ID>

Response Types

Code Description
200 Successful
401 Unauthorized

Update a Callback URL

Example Request:

response = unirest.put("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105",
    headers={"Content-Type":"application/json"},
    params=json.dumps({"url":"http://www.updatedexample.com", "token":"dGhpc2lzZW5jb2RlZA=="}),
    auth=('', 'xxxxxxxxxx'))
print response.raw_body
HttpResponse<JsonNode> response = Unirest
                    .put("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105")
                    .basicAuth("", "xxxxxxxxxx")
                    .header("Content-Type", "application/json")
                    .body("{\"url\":\"http://www.updatedexample.com\", 
                            \"token\":\"dGhpc2lzZW5jb2RlZA==\"}")
                    .asJson();
System.out.println(response.getBody().getObject().toString());   
curl -u :xxxxxxxxxx 
     -X PUT 
     -H "Content-Type: application/json" 
     -d '{"url":"http://www.updatedexample.com", "token":"dGhpc2lzZW5jb2RlZA=="}' 
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105'

Make sure to replace xxxxxxxxxx with your API token.

Example Response:

{
    "id":105,
    "url":"http://www.updatedexample.com",
    "account_id":155, 
    "token":"dGhpc2lzZW5jb2RlZA=="
}

Updates a specific callback URL.

HTTP Request

PUT https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/<ACCOUNT-ID>/webhooks/<WEBHOOK-ID>

Data Parameters

Parameter Description Allowed Values
url
string
(required)
Callback URL
token
string
Credential validating outbound webhook’s source Max. 100 characters

Response Types

Code Description
200 Successful, URL was updated
401 Unauthorized

Delete a Callback URL

Example Request:

import unirest

response = unirest.delete("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105", auth=('', 'xxxxxxxxxx'))
print response.raw_body
HttpRequestWithBody response = Unirest
                    .delete("https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105")
                    .basicAuth("", "xxxxxxxxxx");      
System.out.print(response.asString().getBody().toString());
curl -u :xxxxxxxxxx 
     -X DELETE
     'https://sandbox.proapi.itemize.com/api/enterprise/v1/accounts/155/webhooks/105'

Example Response:

[]

Deletes a specific callback URL.

HTTP Request

DELETE http://example.com/kittens/<ACCOUNT-ID>/webhooks/<WEBHOOK-ID>

Response Types

Code Description
200 Successful
401 Unauthorized

Outbound Webhooks

Outbound webhooks are used to notify clients of document events. Itemize will deliver a webhook up to 3 times in a tight loop during each delivery attempt.

If the initial delivery is unsuccessful, the webhook will be retried 12 hours later and 36 hours later. If the webhook ultimately fails after the 36-hour retry, it will not be redelivered. It is the client’s responsibility to keep track of a document’s ID in the event of a failed webhook.

Retry Schedule:

Multiple webhook deliveries (apart from retries) can occur for documents; notably those whose extracted data is below a given threshold. Currently, there are 2 types of webhooks, and if multiple deliveries occur, will occur in the following order:

  1. document.processed
  2. document.updated

Client Response

The client’s application must repond to the outbound webhook with a 200 OK status to indicate receival. Any other status code indicates a failure, and the webhook will be retried according to the above retry schedule.

Security

Outbound webhooks allow clients to validate their origin in two ways:

{
    "id":"f7c30fa6-5095-4a65-8a74-1b6e6fe603a0",
    "created":1459188055,
    "type":"document.processed",
    "sent_for_human_verification":true,
    "data":
    {
        "client_token":"ADJSwejn23opds92",
        "url":"/documents/64233b41-4f00-4340-9362-caa26da43954",
        "processed":1459188044,
        "id":"64233b41-4f00-4340-9362-caa26da43954",
        "client_id":"user12345", 
        "client_country_id":1,
	"data_level":"L2"
    }
}

Resource Fields:

Field Description Allowed Values
id
string
Webhook ID
type
string
Document event type document.processed, document.updated
sent_for_human_verification
boolean
Denotes whether the document was sent for verification via a manual source true, false
created
long
Date of webhook message creation Unix timestamp in UTC
data
complex object


data Resource Fields:

Field Description Allowed Values
id
string
Document ID
url
string
Endpoint to get extracted data set
client_id
string
Client-provided UID used to identify unique end users
client_country_id
int
Home country of the client_id
processed
long
Date of receipt document’s processing Unix timestamp in UTC
client_token
string
Client-provided webhook identifier used to validate webhook’s source "webhook_id" provided at document upload
data_level
string
Client-provided UID data set level, or if null, data set level for account L1, L2, L3, Custom

Processed

Example Request Body:

{
    "id":"f7c30fa6-5095-4a65-8a74-1b6e6fe603a0",
    "created":1459188055,
    "type":"document.processed",
    "sent_for_human_verification":true,
    "data":
    {
        "client_token":"ADJSwejn23opds92",
        "url":"/documents/64233b41-4f00-4340-9362-caa26da43954",
        "processed":1459188044,
        "id":"64233b41-4f00-4340-9362-caa26da43954",
        "client_id":"user12345", 
	"client_country_id":1,
        "data_level":"L2"    
    }
}

The document.processed webhook is sent for documents that have finished automated processing in the core engine and have an extracted data set available at the document’s endpoint.

If a client has opted-in for human verification, pending the document meets the verification requirements, an analyst will correct any missing and/or incorrect data. Following human touch, a document.updated webhook will be sent, indicating the document’s corrected data set is available.

Updated

Example Request Body:

{
    "id":"f7c30fa6-5095-4a65-8a74-1b6e6fe603a0",
    "created":1459188055,
    "type":"document.updated",
    "sent_for_human_verification":true,
    "data":
    {
        "client_token":"ADJSwejn23opds92",
        "url":"/documents/64233b41-4f00-4340-9362-caa26da43954",
        "processed":1459188044,
        "id":"64233b41-4f00-4340-9362-caa26da43954",
        "client_id":"user12345", 
	"client_country_id":1,
        "data_level":"L2"
    }
}

The document.updated webhook is sent for documents whose extracted data set has been updated.

If a client has opted-in for human verification, a document is manually reviewed and any missing and/or incorrect data is corrected. The document.updated webhook indicates the document’s corrected data set is available.

Errors

The Enterprise API uses the following error codes:

Error Code Body Meaning What We Really Mean
400 {"error": "Minimum file size is 100KB"}
{"error": "Maximum file size is 5MB"}
{"error": "Incorrect format/mime-type for receipt document."}
{"error": "Incorrect format for multipart/form-data. Please ensure document and metadata parameters are uploaded."}
{"error": "'from_address' is missing in metadata. Please ensure the 'from_address' field is included in the metadata parameter."}
Bad Request One of the following:
  • Document is outside of file size requirements
  • Make sure your document is one of the accepted mime-types
  • Make sure your multipart forms are correct
  • Did you include all of the required data params?
401 {"error": "access denied - invalid token or account"} Unauthorized You probably forgot to include your API Token
404 {"message":"Resource not found"} Not Found The document hasn’t finished pocessing yet
405 {"message":"Method not allowed."} Method Not Allowed You're probably using the wrong HTTP verb
415 {"error": "multipart/form-data is the only content type allowed for document upload"} Unsupported Content-Type Use multipart/form-data instead of application/json for document uploads
500 {"error": "An error has occurred during document upload. Please try again."} Internal Server Error We had a problem parsing your request…try again later…did you include all of your JSON quotations?