API Usage Documentation

This document serves to be an example usage of the Attestiv API. When using the Attestiv API, you will generally follow this pattern:

  1. Login (not required with organization access token)
  2. Create record (optional)
  3. Upload metadata/fingerprints
  4. Upload media (optional)
  5. Refresh expired access token (optional)
  6. Logout (not required with organization access token)


A record can be thought of as a container for media and its metadata. The advantage of creating a record is that the media can be accessed and viewed using the Attestiv dashboard. If you upload metadata and fingerprints without creating a record, all the data will be stored and the media can be validated at a later time. If you do not create a record, the assets will have no association with one another and you will not be able to access the images.

Below we show an example of creating a record, uploading metadata and media.

Table of Contents

Login using username and password

First, we login. The REST api uses the SHA256 hash of the user’s password. This can be generated with OpenSSL on a Unix command line (Windows users can use Cygwin, Windows Subsystem for Linux, etc).

				
					$ read -p "Password: " pass; echo -n $pass | openssl sha256
Password: pass123   
(stdin)= 9b8769a4a742959a2d0298c36fb70623f2deacda8436237df08d8dfd5b37374c
				
			
				
					POST https://api.attestiv.net/api/v1/users/login
{
  "username":"user@attestiv.com",
  "password":"9b8769a4a742959a2d0298c36fb70623f2deacda8436237df08d8dfd5b37374c"
}
				
			

A successful login response would be similar to one below (note the accessToken and refreshToken values):

				
					{
  "status": "Success",
  "configVersion": 1,
  "user": {
    "firstName": "John",
    "lastName": "Anderson",
    "email": "john.anderson@acme.com",
    "username": "john.anderson@acme.com",
    "enabled": true
  },
  "organization": {
    "name": "ACME Corp.",
    "identifier": "acme",
    "enabled": true,
    "domains": ["acme.com"]
  },
  "authProvider": "jwt",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbnRpdHkiOiJhdHRlc3RpdiIsInR5cGUiOiJvcmdhbml6YXRpb24iLCJzY29wZXMiOiIqOioiLCJzZWVkIjoiTFRVOG5iV3BFN0c5dkJYZiIsImlhdCI6MTU4MDEzMjMyMywiZXhwIjoxNTgwMTMyMzI2fQ.inhlRmlp4vtiYe4Nt_hoaky-eKPbQesv7p41Zf5gI-A",
  "refreshToken": "mWjDp97w3wpaTdRixYlpSwCGe2wXQnCireSYGwhYyAatWU0ElRjKthbxRG8H4Uu780TH3eeWVCtvNHTwjNHLYIquZt4s8ebVOKvfLP2GZheY3gneTPO8bbyD1OofIE7ooMzIweAmN5qiD3cyTQWWg8n01dwjOIuQWUhXPrDBHyEI3Q27GNAHVmaMqtE8fD4G2XMsWhNHXsqo6e7zcnzo1d014NsiUtKKQF2aN7pCcZkgD1wUMRivnJ5fLn0jPz1Zse9lVL2cGSjq1Jp4PUDtsxqpjYX9Hmo0CQpqJscqSfcZrHVbYAN3dWXVycsdxS996uLHb9eck9oP8GknqnN5ahotdsDkDuUJVaLaLoWtch4FKAjEMdcOwXiLl53xzedY9XnCUKxTGzI2ca3B8uQuXx4H4fsHL2HRb9ijgjPyqZjxLU8FWf2QrNT4tuKhy0VulOZvteR0NhfzkGGxgwmhOg8bd86iEN3HbCNcsaYKwideMeG96gnqSfDynGpyZVu3",
  "expirationDate": "2020-01-27T13:38:46.000Z"
}
				
			

The above example can be done using Javascript by following this example code:

				
					axios.post("/api/v1/users/login",
  {username: "user@attestiv.com", password: "9b8769a4a742959a2d0298c36fb70623f2deacda8436237df08d8dfd5b37374c"} // note that the password must be SHA256 encrypted
).then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Create Record

Next, we create a new record. It takes a name and an optional description. The access token returned from the login response will needed to be set into the request “Authorization” header with prefix of “Bearer“. For example, the header for the create new record request will contain:
				
					Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbnRpdHkiOiJhdHRlc3RpdiIsInR5cGUiOiJvcmdhbml6YXRpb24iLCJzY29wZXMiOiIqOioiLCJzZWVkIjoiTFRVOG5iV3BFN0c5dkJYZiIsImlhdCI6MTU4MDEzMjMyMywiZXhwIjoxNTgwMTMyMzI2fQ.inhlRmlp4vtiYe4Nt_hoaky-eKPbQesv7p41Zf5gI-A

				
			

The following is an example of a create new record request:

				
					POST https://api.attestiv.net/api/v1/records
{
  "name": "A record name",
  "description": "This is a description"
}
				
			

The successful response would be:

				
					{
  "status": "Success",
  "referenceId": "2ee8f783-561d-4def-9868-b8d149da7455"
}
				
			

The above example can be done using Javascript by following this example code:

				
					axios.post("/api/v1/records",
  {name: "A record name", description: "This is a description"}
).then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Calculating Fingerprints

Calculating fingerprints should always be done as close as possible to the origin of the data. If the origin is a camera, then ideally the fingerprinting would be done on the device that the camera is integrated into. If it is a smartphone, this the calculation should be done on the phone. Fingerprint calculations are never done on servers after the data has been transmitted.

The way to calculate a fingerprint is to first integrate the fingerprinting library into the code which creates the data, in this case, a photo. First, the fingerprinting library needs to be loaded. There is both a .wasm file and a .js file that work together. The .js file loads the .wasm file. You can load the library like this:

				
					const fingerprintModule = require("./fingerprint");

// Load the WASM connector module
var attestivFingerprint;
fingerprintModule().then(async instance => {
    console.log("Loaded fingerprint module " + await instance.get_version());
    attestivFingerprint = instance;
});
				
			

What you are loading in the require call is the fingerprint.js file, just like any other javascript module. Once it is loaded, you can fingerprint an image like this:

				
					let fingerprint = await attestivFingerprint.fingerprint_jpg(arrayBuffer);

				
			

In the above code, you must read the file into an array buffer and pass that as the argument to fingerprint_jpg.

The details of calling this API depends on the environment. We currently have libraries available for on several platforms. You may ask why a WASM version? WASM allows us to execute the fingerprinting logic with high efficiency.

If you want to validate the fingerprint you have calculated to see if it is valid, use the Tool in the Dashboard to validate the image. If it validates after you have uploaded the fingerprint data, then you have done it correctly.

Upload Assets with Fingerprint Calculation

In order to create and upload a fingerprint, you will need to use the Attestiv SDK packaged separately to calculate the media fingerprint and then construct the appropriate object to upload. In the first example below we are uploading metadata for a single image.

If the media you fingerprinted was not captured using a camera, but rather was an existing file, then you should include the “import” string in the tags array for the media. If the image is an original and high resolution, then include the “full-scale” string in tags. Finally, if the image is a scaled-down version of the full-scale image, then include the “scaled” flag in tags.

The following is an example of an upload assets request, again with the access token specified in the Authorization header:

				
					POST https://api.attestiv.net/api/v1/assets
{
  "user": "user@attestiv.com",
  "timestamp": 1498279843731, // milliseconds since epoch (Jan 1, 1970)
  "media": [
     {
        "mimeType": "image/jpeg",
        "fingerprint": "ab386530cbe34958bcba8f10b992aef808ace3b445a210a084924125f9069ffa",
        "location": "42.5115648, -71.1565312",
        "size": "3024x4032",
        "tags": ["full-scale","import"],
        "timestamp": 1498279842614 // milliseconds since epoch (Jan 1, 1970)
      }
    ]
  }
}
				
			

The response for the above calls would look like this with the “taskId” being an identifier that represents the work of writing the metadata to the immutable ledger (blockchain):

				
					{
  "taskId": "71399df2-f285-495b-9758-6b8a265a805a"
}
				
			

The body for multiple images would look like this. In this example, the image was scaled down and both were fingerprinted and the metadata uploaded together. Notice the tags and the parentUUID field in the second media element.

				
					POST https://api.attestiv.net/api/v1/assets
{
  "recordId": "8f9c3894-f567-4d1a-ae59-ea1ad9238951", // include record referenceId only if you created a record
  "user": "user@attestiv.com",
  "timestamp": 1498279842614,
  "media": [
    {
      "UUID": "7185a1e3-8ce3-4f9b-8bf3-c3e30318d5e9",
      "mimeType": "image/jpeg",
      "fingerprint": "ab050e6a92a35099452ce3f0ff3f03da464fb55cfb5085c2d3f3e9ad3f930001",
      "location": "42.5115648, -71.1565312",
      "size": "1449x1932",
      "tags": ["full-scale"],
      "timestamp": 1498279847254,
      "parentUUID": ""
    },
    {
      "UUID": "d15ebf62-2d23-434a-a018-f4c880a97bea"
      "mimeType": "image/jpeg",
      "fingerprint": "6ca5160c2f6b203c41ab79eb8c66199a6a1b0a09a994787ad886c3c1ef078002",
      "location": "42.5115648, -71.1565312",
      "size": "300x400",
      "tags": ["scaled"],
      "timestamp": 1498279848321,
      "parentUUID": "7185a1e3-8ce3-4f9b-8bf3-c3e30318d5e9"
    }
  ]
}
				
			

The above example can be done using Javascript by following this example code:

				
					axios.post("/api/v1/assets",
  {
  "user": "user@attestiv.com",
  "timestamp": 1498279843731, // milliseconds since epoch (Jan 1, 1970)
  "media": [
     {
        "mimeType": "image/jpeg",
        "fingerprint": "ab386530cbe34958bcba8f10b992aef808ace3b445a210a084924125f9069ffa",
        "location": "42.5115648, -71.1565312",
        "size": "3024x4032",
        "tags": ["full-scale","import"],
        "timestamp": 1498279842614 // milliseconds since epoch (Jan 1, 1970)
      }]
    }
  }
).then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Upload Media Files

To upload media files such as image files to Attestiv server, you will need to use the files API. Note that while other requests send a JSON body, uploading files is done with Content-Type: multipart/form-data. If you would like to have the Attestiv platform initiate forensic analysis for you, that can also be done from this API call. More on this later in this section.

				
					POST https://api.attestiv.net/api/v1/files
Content-Type: multipart/form-data;boundary=-----------------------------9051914041544843365972754277
Content-Length: 2554
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="uuid" C4304A4E-B93D-4747-89A3-406C10B1E208
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="recordId" 5e1678c2dd587067e560838d
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="media"; filename="myImage.jpg"
Content-Type: image/jpeg <Content of myImage.jpg>
-----------------------------9051914041544843365972754277
				
			

The response from the above would be:

				
					{
  "result": "Success",
  "message": "File uploaded successfully"
}
				
			

The above example can be done using Javascript by following this example code:

				
					let formData = new FormData();
formData.append("recordId", recordId); // The referenceId returned from POST /api/v1/records
formData.append("uuid", mediaUUID); // mediaUUID is the uuid of the cooresponding asset which was returned from the POST /api/v1/assets call
formData.append("media", file); // A Javascript File object, note that this must be appended last

axios.post("/api/v1/files", formData, {
    headers: {
        "Content-Type": "multipart/form-data"
    }
}).then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Initiating Forensic Analysis when Uploading a File

If you would like to have the Attestiv platform execute forensic analysis at the time a file is uploaded, that can be accomplished by adding the runAnalysis url parameter to the /api/v1/files call. The runAnalysis url parameter takes a comma separated list to analysis types to be executed. Currently there are two possible values, triageFull and objectDetection. Expanding on the example above:

				
					POST https://api.attestiv.net/api/v1/files?runAnalysis=triageFull,objectDetection
Content-Type: multipart/form-data;boundary=-----------------------------9051914041544843365972754277
Content-Length: 2554
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="uuid" C4304A4E-B93D-4747-89A3-406C10B1E208
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="recordId" 5e1678c2dd587067e560838d
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="media"; filename="myImage.jpg"
Content-Type: image/jpeg <Content of myImage.jpg>
-----------------------------9051914041544843365972754277
				
			

When the file is uploaded, the Attestiv platform will initiate a full triage of the image file and also run object detection on the photo to detect its contents. Note that if you only desire forensic analysis, then just supply triageFull as the value. The results of the analysis will be stored with the image and will be accessible via the API or in the dashboard.

Validating Fingerprints

Once a fingerprint is calculated, at some time later you may want to validate the source asset is authentic. That is what validation will do. The most common way of validating is to recalculate the fingerprint and use that fingerprint to do a lookup in the immutable ledger. The API for doing this is:

				
					GET https://api.attestiv.net/api/v1/assets?fingerprint=cc197b77ba39578b0542a50e4beece7c0f0939d466bb06e2bd20a5b12b6d734e
{
    "uuid": "de228dc5-7d38-4388-be45-58e3736697dc",
    "recordId": "99cb0ccc-89c7-4acd-98fe-3a0d56d9922a",
    "referenceId": "4c1ede55-ff75-4aa6-b7a5-2927d1cd9b8a",
    "location": "42.200268799999996, -71.22780159999999",
    "timestamp": 1580267251933,
    "media": [
        {
            "UUID": "1f2d559e-b962-4e7b-95c7-4e524b73d5db",
            "mimeType": "image/jpeg",
            "fingerprint": "cc197b77ba39578b0542a50e4beece7c0f0939d466bb06e2bd20a5b12b6d734e",
            "location": "42.200268799999996, -71.22780159999999",
            "size": "605x806",
            "timestamp": 1580267254931,
            "tags": [
                "scaled"
            ],
            "locationAddress": "209 West Central St, Natick, MA 01760, USA"
        }
    ],
    "taskId": "4422f537-ce26-4e56-a4d0-158127a1b05c",
    "address": "615575a1f540222575329daf05bf6ba4eacee3f3ed2f7b4a35ef881b58f80275"
}
				
			

Another way to retrieve a fingerprint is to use this API:

				
					GET https://api.attestiv.net/api/v1/fingerprint/cc197b77ba39578b0542a50e4beece7c0f0939d466bb06e2bd20a5b12b6d734e
				
			

The above yields the same output as the first call. This serves as a simpler more direct way of validating assets.

 

The above example can be done using Javascript by following this example code:

				
					axios.get("/api/v1/fingerprint/cc197b77ba39578b0542a50e4beece7c0f0939d466bb06e2bd20a5b12b6d734e")
.then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Creating Customized Workflow Definitions

Creating customized workflow definitions allows a customer to define workflow definitions that suit their needs. These definitions can then be included in the list of workflows to choose from when creating a request to send to one of their customers. These workflows can also be used to create a link that can be shared on a website, social media, or sent directly to a customer. We use the questionset api to make these calls. (Note: We use workflows and questionsets interchangeably. If you see questionset, we are referring to a workflow definition.)

For details on the structure of a workflow (JSON), please see the document titled “Creating Attestiv Workflow Definitions .”

Once you have created a workflow definition, there are two api operations, validating and uploading. The validation api allows you to validate your workflow before uploading. Note that when you upload, it will be validated before accepting it. The validation api allows you to issue an ad-hoc request to our validator. To validate a workflow you will issue the following request using the questionset api.

				
					POST https://api.attestiv.net/api/v1/questionsets/validate
{
    "name": "Auto Quote (Uploaded by Customer)",
    "recordNameProperties": ["license-2.firstName", "license-2.lastName"],
    "messagingConfig": {
        "emailSubject": "Begin Your Auto Quote",
        "emailBody": "Hello %s %s,<br/><br/>Below is a link for you to use to begin your auto quote. Please click the link below using your mobile device to begin the process.<br/><br/>%s<br/><br/>%s<br/><br/>Thank You<br/>",
        "emailProperties": ["firstName", "lastName", "customMessage", "generatedUrl"],
        "textMessageBody": "Hello %s, below is a link for you to use to begin your auto quote. Please click on it using your mobile device to begin the process.\n\n%s\n\n%s",
        "textMessageProperties": ["firstName", "customMessage", "generatedUrl"]
    },
    "questionSet": {
        "additionalQuestionInsertionIndex": 16,
        "defaultQuestionOrder": [
            "welcome-message",
            "picture-car-1",
            "picture-car-2",
            .
            .
            .
}
				
			

The response for a successful validation will be:

				
					{
    "valid": true,
    "messages": [
        "questionSet is valid"
    ],
    "status": "Success"
}
				
			

A workflow definition with errors may look like this:

				
					{
    "valid": false,
    "messages": [
        "name (string) property is missing or invalid",
        "instance.questionSet requires property \"additionalQuestionInsertionIndex\"",
        "instance requires property \"name\""
    ],
    "status": "Failure"
}
				
			

Once you have validated your workflow and you are ready to submit it, you would POST it to the questionsets api as follows.

				
					POST https://api.attestiv.net/api/v1/questionsets
{
    "name": "Auto Quote (Uploaded by Customer)",
    "recordNameProperties": ["license-2.firstName", "license-2.lastName"],
    "messagingConfig": {
        "emailSubject": "Begin Your Auto Quote",
        "emailBody": "Hello %s %s,<br/><br/>Below is a link for you to use to begin your auto quote. Please click the link below using your mobile device to begin the process.<br/><br/>%s<br/><br/>%s<br/><br/>Thank You<br/>",
        "emailProperties": ["firstName", "lastName", "customMessage", "generatedUrl"],
        "textMessageBody": "Hello %s, below is a link for you to use to begin your auto quote. Please click on it using your mobile device to begin the process.\n\n%s\n\n%s",
        "textMessageProperties": ["firstName", "customMessage", "generatedUrl"]
    },
    "questionSet": {
        "additionalQuestionInsertionIndex": 16,
        "defaultQuestionOrder": [
            "welcome-message",
            "picture-car-1",
            "picture-car-2",
            .
            .
            .
}
				
			

A successful addition will return the following:

				
					{
    "status": "Success",
    "referenceId": "45a20cbb-9f0a-40cd-81bc-4294ec9719c1"
}
				
			

The referenceId which is returned is the way to identify the questionset when making other calls to the Attestiv system. We will see that in the next section.

Sending a Request

To send a request to a user to execute a workflow, we use the clientrequest api. A request will allow you to send either and email, text message, or both to a user. If we wanted to send a request using the API, we would send the following:

				
					POST https://api.attestiv.net/api/v1/clientrequest
{
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "janedoe@example.com",
    "questionset": "45a20cbb-9f0a-40cd-81bc-4294ec9719c1"
}
				
			

The above would send an email with a link to the specified email address. The response would be:

				
					{
    "status": "Success",
    "clientRequest": "40b1dcb3-f6f4-495e-ba84-928863e322bd",
    "url": "https://www.attestiv.com/flow?r=45a20cbb-9f0a-40cd-81bc-4294ec9719c1&rq=40b1dcb3-f6f4-495e-ba84-928863e322bd&c=mcuopl1ljpavmhp"
}
				
			

The url property in the response is the url which is sent to your customer and the clientRequest contains the id of the client request that was created. If we wanted to also send a text message, we would add the following to the request body:

				
					smsNumber: "5555555555"
				
			

In addition to the above, you can include a custom message in the email or text message. To include a custom message, add the customMessage property to the request body. customMessage is a string. In addition, to add internal notes to the request that you can see in the Attestiv dashboard, add a notes property. notes is a string.

If you encounter a situation where you need to send a second workflow request to a user in order to add additional information or retake a photo, would will likely want the information collected to go into the same record as a previous workflow. To indicate this, you can add the addToRecord property to the request body. The value of this property should be the id of a record. The record id is a string (uuid) and looks similar to a questionset id in terms of format.

Register a Web Hook to be Notified When Analysis is Completed

If you would like to be notified when media file analysis is completed, then you must register a webhook into the Attestiv system. This can be done using the notification api. The example below shows a url in your system being registered to receive notifications when analysis of a media file is completed.

				
					POST https://api.attestiv.net/api/v1/notification/register
{
    	"url": "https://api.example.com/notify", // this is a url endpoint in your system
    	"notificationType": "WORKFLOWMEDIA_ANALYSIS_COMPLETED", // the types of notifications you would like to receive
    	"authenticationType": "bearerToken", // currently only supported option
    	"authenticationString": "eyJhbGciOiJIUzI1NiI" // bearerToken goes here
}

				
			

The response will look as follows.

				
					{
    "status": "Success",
    "notificationId": "406d443c-1878-470c-b026-6a365c932739"
}
				
			

Once the web hook is registered, it will remain in the system until it is unregistered. To unregister a webhook, send the following request using the notification id from above.

				
					POST https://api.attestiv.net/api/v1/notification/unregister/406d443c-1878-470c-b026-6a365c932739
				
			

Finally, when calling the detect_async endpoint and when a webhook for the MEDIA_ANALYSIS_COMPLETED type is registered, a notification is sent to the registered url, the https method type is a POST and it is sent with a body similar to the following.

				
					{
  "detect_tampering_result": {
	"assessments": [
  	{
    	"model": "metadata",
    	"compromisedScore": 1,
    	"details": {}
  	},
  	{
    	"model": "provenance",
    	"compromisedScore": 1,
    	"details": {}
  	},
  	{
    	"model": "quality",
    	"compromisedScore": 4,
    	"details": {
      	"message": "This image is very blurry or noisy. "
    	}
  	},
  	{
    	"model": "downloads",
    	"compromisedScore": 1,
    	"details": {}
  	},
  	{
    	"model": "pop",
    	"compromisedScore": 3,
    	"details": {}
  	},
  	{
    	"model": "integrity",
    	"compromisedScore": 1,
    	"details": {}
  	}
	],
	"tamperScore": 60,
	"image": "IMG_0218.jpeg",
	"analysisId": "zPrZaaZTduBXddm6l7D8HyrB0r9NS4WG",
	"_version": "release-72",
	"type": "photo"
  },
  “task_id”: “65911b90-623e-4fe7-b858-0cb75c7dd60e”,
  “notificationType”: “MEDIA_ANALYSIS_COMPLETED”,
  “notificationId”: “518c647f-59bc-44dd-b198-d5d552c13a78"
}

				
			

It is up to you what to do with the result. You should not take long to process this data as we limit the response time. We suggest saving the result, returning a status code of 200, and processing the result outside of this request. You must return a 200 in order for us to know that you received the response successfully, otherwise our retry logic will send the request to you several times.

Updating a Web Hook Authentication Token

If you require that the authentication token, such as a bearer token which is used by Attestiv to call into a webhook in your system, needs to be updated because of security requirements, that can be done by making a POST call to the /api/v1/notification/update endpoint. This endpoint requires three parameters in the JSON body, url, notificationType, and authenticationString. To update the authenticationString for the desired url, the exact url string and notificationType which was used to register the webhook must be supplied. Below is an example of the request body.
				
					POST https://api.attestiv.net/api/v1/notification/update
{
  url: "https://api.example.com/notify", // this is the url that was initially registered
  notificationType: "MEDIA_ANALYSIS_COMPLETED", // the types of notifications you registered to receive at the above url
  authenticationString: "iDbhbGciOiJIUzI1NiI..." // new token goes here
}

				
			

Retrieving a Record and Transactions

Once you receive a notification, you can access the record by using the following api:

				
					GET https://api.attestiv.net/api/v1/records/971ea099-5c2e-47df-bd2e-3d97f0d355e4
{
    "name": "Jane Doe",
    "transactions": [
        "5ecb02eeb9e8cb107cf8e5d7",
        "5ecb02eeb9e8cb107cf8e5d8"
    ],
    "workflowData": [
        "5ecb02eeb9e8cb107cf8e5d5"
    ],
    "referenceId": "971ea099-5c2e-47df-bd2e-3d97f0d355e4",
    "requestId": "719793c0-fea5-41b6-8b42-45d04ad9466f",
    "createdAt": "2019-05-24T23:27:42.090Z"
}
				
			

The above record contains the transactions and workflowData. There is a pair of transactions for each image file. To access the files, first retrieve the transactions as follows.

				
					GET https://api.attestiv.net/api/v1/assets?transaction=5ecb02eeb9e8cb107cf8e5d7,5ecb02eeb9e8cb107cf8e5d8
{
    "total": 2,
    "docs": [
        {
            "fingerprint": "686eff51f6a591ff19d6c7066379fcf2cdf2c322a6180d7330fa5b5d3a559512",
            "transactionId": "aee13222-ff4c-40ac-b84c-7cc89ab9694d",
            "taskId": "e054f46c-e0a3-4b26-aed8-ba20a998b869",
            "filepath": "assets/attestiv/f157a026-67ea-4885-ab39-78be6651d999.jpg",
            "tags": [
                "scaled",
                "id_896d3a1d-bd71-4d78-804b-f1e6394b73d0"
            ],
            "size": "806x605",
            "requestId": "719793c0-fea5-41b6-8b42-45d04ad9466f",
            "createdAt": "2020-05-24T23:27:42.687Z"
        },
        {
            "fingerprint": "30bbc05cd9e0bb97e49ef5c2ae31a737d64aafb83adf6d116215a2df32c15d7d",
            "transactionId": "aee13222-ff4c-40ac-b84c-7cc89ab9694d",
            "taskId": "e054f46c-e0a3-4b26-aed8-ba20a998b869",
            "filepath": "assets/attestiv/896d3a1d-bd71-4d78-804b-f1e6394b73d0.jpg",
            "tags": [
                "full-scale",
                "id_896d3a1d-bd71-4d78-804b-f1e6394b73d0"
            ],
            "size": "3024x4032",
            "requestId": "719793c0-fea5-41b6-8b42-45d04ad9466f",
            "createdAt": "2020-05-24T23:27:42.882Z"
        }
    ]
}

				
			

You will see that the above two transactions refer to the same file. If you look at the tags you will see there is a full resolution image (“full-scale”) and a low resolution image (“scaled”). This is done so that the original image is preserved, but if you need to display images for consumption on the web, there is a lower resolution image for you to use.

Accessing Files

When you need to access a file in a record, you first need to retrieve the transaction. Inside the transaction there is a field called filepath. This will contain the url to access the file. Note that this path, if you are using Attestiv’s standard storage configuration, is an Amazon S3 presigned image URL. These urls are valid for 15 minutes from when the request is made before it expires. Upon expiration, a new url must be requested.

Retrieving Workflow Data

Similar to retrieving transactions, you can retrieve workflow data. This is data that a user may have entered on a form or scanned from a document. To get this data, use the workflowData api.

				
					GET https://api.attestiv.net/api/v1/workflowData/5ecb02eeb9e8cb107cf8e5d5
{
    "questionSetRefId": "39c64261-c549-4eec-9623-d4acd130e8f0",
    "workflowData": [
        {
            "questionID": "property-address",
            "fields": [
                {
                    "fieldID": "streetAddress",
                    "fieldType": "text",
                    "label": "Street Address",
                    "value": "1 Main St",
                    "autocomplete": "address-line1",
                    "required": true
                },
                {
                    "fieldID": "streetAddress2",
                    "fieldType": "text",
                    "label": "Street Address 2",
                    "value": "",
                    "autocomplete": "address-line2",
                    "required": false
                },
                {
                    "fieldID": "city",
                    "fieldType": "text",
                    "label": "City",
                    "value": "Anytown",
                    "autocomplete": "address-level2",
                    "required": true
                },
                {
                    "fieldID": "state",
                    "fieldType": "text",
                    "label": "State",
                    "value": "CA",
                    "autocomplete": "address-level1",
                    "required": true
                },
                {
                    "fieldID": "postalCode",
                    "fieldType": "text",
                    "label": "Postal code",
                    "value": "90210",
                    "required": true,
                    "autocomplete": "postal-code",
                    "validation": "zipcode"
                },
                {
                    "fieldID": "country",
                    "fieldType": "text",
                    "label": "Country",
                    "value": "US",
                    "autocomplete": "country",
                    "required": true
                }
            ]
        },
        {
            "questionID": "contact-info",
            "fields": [
                {
                    "fieldID": "firstName",
                    "fieldType": "text",
                    "label": "First Name",
                    "value": "Jane",
                    "autocomplete": "given-name",
                    "required": true
                },
                {
                    "fieldID": "middleName",
                    "fieldType": "text",
                    "label": "Middle Name",
                    "value": "",
                    "autocomplete": "additional-name",
                    "required": false
                },
                {
                    "fieldID": "lastName",
                    "fieldType": "text",
                    "label": "Last Name",
                    "value": "Doe",
                    "autocomplete": "family-name",
                    "required": true
                },
                {
                    "fieldID": "email",
                    "fieldType": "text",
                    "label": "Email Address",
                    "value": "jane@example.com",
                    "autocomplete": "email",
                    "required": true
                },
                {
                    "fieldID": "phoneNumber",
                    "fieldType": "text",
                    "label": "Phone Number",
                    "value": "555-555-5555",
                    "autocomplete": "tel-national",
                    "required": true
                }
            ]
        }
    ]
}

				
			

In the above, you will see that we store the complete information from the workflow, including the field label, id, and value. The value is the information that was collected when the user executed the workflow.

Scan Text from a Document (Limited Use)

Attestiv provides OCR functionality in order to enhance data gathering during workflows. The document scan API allows you to send a PDF or jpeg photo of a document and receive key-value pairs of the form data in the text. This API is currently limited to very specific use cases; please contact support for more information.

The API accepts an image or pdf content as form data, and you’ll need to specify the type of document to be scanned. This is done by the “workflow” entry in the body. (Note that this workflow has no relation to a workflow a customer executes on their mobile device. This is an OCR extraction workflow.) An example command is below. Note the additional quotes around the workflow entry.

				
					POST https://api.attestiv.net/wapi/v1.0/keyvalue
Content-Type: multipart/form-data;boundary=-----------------------------9051914041544843365972754277
Content-Length: 2554
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="workflow" \"coverage_workflow\"
-----------------------------9051914041544843365972754277
Content-Disposition: form-data; name="image"; filename="myImage.jpg"
Content-Type: image/jpeg <Content of page.pdf or image.jpg>
-----------------------------9051914041544843365972754277
				
			

The response will always have three objects: fields, tables, and confidences. fields will contain any key-value pairs that were found on the document. Each key in fields will have an associated confidence value in confidences. Finally, tables will contain certain tables that were found on the document. Each table is a JSON array of arrays, one per row.

				
					{
  "confidences": {
    "address": 96.05382681523173,
    "coverage_a": 99.66490936279297,
    "coverage_b": 99.66374206542969,
    "coverage_c": 99.5313491821289,
    "coverage_d": 99.56996154785156,
    "coverage_e": 99.7034912109375,
    "coverage_f": 99.82215881347656,
    "deductible": 1.0,
    "description": 98.7684326171875,
    "effective_date": 92.04579162597656,
    "policy": 98.67897033691406,
    "premium": 99.1928482055664
  },
  "fields": {
    "address": "Sample Address PORT HUENEME CA 93041-2624",
    "coverage_a": "$301,000",
    "coverage_b": "$30,100",
    "coverage_c": "$150,500",
    "coverage_d": "$60,200",
    "coverage_e": "$100,000",
    "coverage_f": "$1,000",
    "deductible": "Please see attached photograph",
    "description": "1962 Stucco on frame, Single family home, P rimary residence, 1000ft. or less from hydrant, within 5 miles from fire station",
    "effective_date": "June 28, 2020",
    "policy": "30159961",
    "premium": "$819.00"
  },
  "tables": {
    "coverage": [
      [
        [
          "Coverage"
        ],
        [
          "Limit"
        ],
        [],
        [
          "Premium"
        ]
      ],
      [
        [
          "Section",
          "I",
          "-",
          "Property"
        ],
        [],
        [],
 ...
 ...
 ...
				
			

Refresh Expired Access Token

Each access token is only valid for 8 hours from time of creation, therefore it will be necessary to obtain a new access token by calling the refresh API with the parameter “refreshToken=<valid refresh token>”. To detect if an access token has expired, you will check the response’s status code and message in body. Any API call with an expired access token in Authorization header will have the following in response body:

				
					GET https://api.attestiv.net/api/v1/assets?fingerprint=ab050e6a92a35099452ce3f0ff3f03da464fb55cfb5085c2d3f3e9ad3f930001
{
    "name": "TokenExpiredError",
    "message": "jwt expired",
    "expiredAt": "2020-01-27T15:57:09.000Z"
}
				
			

The following is an example of a refresh API call:

				
					POST https://api.attestiv.net/api/v1/oauth/refresh?refreshToken=mWjDp97w3wpaTdRixYlpSwCGe2wXQnCireSYGwhYyAatWU0ElRjKthbxRG8H4Uu780TH3eeWVCtvNHTwjNHLYIquZt4s8ebVOKvfLP2GZheY3gneTPO8bbyD1OofIE7ooMzIweAmN5qiD3cyTQWWg8n01dwjOIuQWUhXPrDBHyEI3Q27GNAHVmaMqtE8fD4G2XMsWhNHXsqo6e7zcnzo1d014NsiUtKKQF2aN7pCcZkgD1wUMRivnJ5fLn0jPz1Zse9lVL2cGSjq1Jp4PUDtsxqpjYX9Hmo0CQpqJscqSfcZrHVbYAN3dWXVycsdxS996uLHb9eck9oP8GknqnN5ahotdsDkDuUJVaLaLoWtch4FKAjEMdcOwXiLl53xzedY9XnCUKxTGzI2ca3B8uQuXx4H4fsHL2HRb9ijgjPyqZjxLU8FWf2QrNT4tuKhy0VulOZvteR0NhfzkGGxgwmhOg8bd86iEN3HbCNcsaYKwideMeG96gnqSfDynGpyZVu3

				
			

The response from the refresh API call will have the new access token and it expiration date:

				
					{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbnRpdHkiOiJhdHRlc3RpdiIsInR5cGUiOiJvcmdhbml6YXRpb24iLCJzY29wZXMiOiIqOioiLCJzZWVkIjoiTFRVOG5iV3BFN0c5dkJYZiIsImlhdCI6MTU4MDEzMjMyMywiZXhwIjoxNTgwMTMyMzI2fQ.inhlRmlp4vtiYe4Nt_hoaky-eKPbQesv7p41Zf5gI-A",
  "expirationDate": "2020-01-27T13:38:46.000Z"
}
				
			

Logout

Finally, in order to logout, use the following:

				
					POST https://api.attestiv.net/api/v1/users/logout
				
			

and the response would be:

				
					{
  "status": "Success"
}
				
			

The above example can be done using Javascript by following this example code:

				
					axios.post("/api/v1/users/logout")
.then(function(response) {
    // handle response
})
.catch(function(error) {
    // handle error
}
				
			

Resources

Please contact support@attestiv.com with any issues.

Mark Morley

Mark Morley is the Chief Operating Officer of Attestiv.

He received his formative Data Integrity training at Deloitte. Served as the CFO of Iomega (NYSE), the international manufacturer of Zip storage devices, at the time,  the second fastest-growing public company in the U.S.. He served as the CFO of Encore Computer (NASDAQ) as it grew from Revenue of $2 million to over $200 million. During “Desert Storm”, Mark was required to hold the highest U.S. and NATO clearances.

Mark authored a seminal article on Data Integrity online (Wall Street Journal Online). Additionally, he served as EVP, General Counsel and CFO at Digital Guardian, a high-growth cybersecurity company.

Earlier in his career, he worked at an independent insurance agency, Amica as a claims representative, and was the CEO of the captive insurance subsidiary of a NYSE company.

He obtained Bachelor (Economics) and Doctor of Law degrees from Boston College and is a graduate of Harvard Business School.