Getting Started

The Immuto API enables developers to provide immutability guarantees in their own applications.

We offer two main abstractions of our immutable record-keeping. Data Management is simple and flexible enough to support a wide variety of applications. Digital Agreements add extended functionality that may be required by more sophisticated use. A more detailed overview of each category is provided below.

The API is RESTful, and we currently provide a JavaScript framework for easy integration with web applications and NodeJS. Our open-source libraries can be found here.

Please contact us to request development-scale API access.


Authentication

Authentication is a two step process. Begin the login process with the following request:

URI: /submit-login
Method: POST
Params:

email: user's email (case insensitive)
pass: user's password (hashed once with keccak256)

Returns: (JSON)

.encryptedKey: keystore v3 JSON
.salt: salt used for encryption / decryption
.authToken: credential for future requests

Example (JavaScript)
let sendstring = "email=" + email 
sendstring += "&password=" + web3.utils.sha3(pass)

var http = new XMLHttpRequest()
http.open("POST", "https://www.immuto.io/submit-login", true)
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
http.onreadystatechange = function() {
        if (http.readyState == 4 && http.status == 200) {
            let response = JSON.parse(http.responseText) 
        } // else handle errors
}
http.send(sendstring)

After completing the above request, decrypt your private key and use it to sign the credential. Then, perform the following request:

URI: /prove-address
Method: POST
Params:

address: user's public account address
signature: cryptographically signed credential
authToken: credential from login process

Returns:

204 (No Content): Login successful

Example (JavaScript)
//authToken, encryptedKey, and salt from prior request (/submit-login)
let account = web3.eth.accounts.decrypt( // uses web3.js
    encryptedKey, 
    YOUR_PASSWORD + salt 
);
let signature = account.sign(authToken)

let sendstring = "address=" + account.address 
sendstring += "&signature=" + JSON.stringify(signature)
sendstring += "&authToken=" + authToken

var http = new XMLHttpRequest()
http.open("POST", "https://www.immuto.io/prove-address", true)
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
http.onreadystatechange = function() {
    if (http.readyState == 4 && http.status == 204) {
        // login successful, can use authToken to authenticate future API requests for 24 hours
    } // else handle errors
}
http.send(sendstring)

Authenticate a user and enable record verification:

Function: authenticate
Params:

string: user's email (case insensitive)
string: user's password

Returns: (Promise)

Success: credential for future requests
Failure: error message

Example
let im = Immuto.init(true, "https://dev.immuto.io") // remove init params for production use
let email = "example@immuto.io"
let password = "example-password"

im.authenticate(email, password).then((authToken) => {
    // user successfully logged-in
}).catch((err) => {
    console.error(err)
})

Data Management

The Data Management abstraction allows for the creation of single-use and updatable records of any data. Each version of a record is signed, timestamped, and allows for data verification. The entire history of an updatable record is tracked over time, creating a robust audit trail. Immuto does not see nor store the original data, so privacy is completely preserved.

You can create a new Data Management record as follows:

URI: /submit-new-data-upload
Method: POST
Params:

signature: user's signature on data hash (account.sign format)
filename: name of record
filedesc: (optional) description of record
type: type of contract ('basic' or 'editable')
authToken: credential from login process

Returns: (Plaintext)

Record Identifier: unique string for data verification

Example (JavaScript)
let signableContent = "YOUR_DATA_HERE"
let name = "UNIQUE_NAME"
let desc = "" // optional
let type = "basic" // 'editable' if content will be updated

// Good practice to keep account encrypted unless in use (signing transaction)
let account = undefined;
try { 
    account = web3.eth.accounts.decrypt(
        encryptedKey, 
        password + salt
    );
} catch(err) {
    return err;
}

let signature = account.sign(signableContent)
signature.message = "" // Maintain data privacy

var xhr = new XMLHttpRequest();
var fd = new FormData();

xhr.open("POST", "https://www.immuto.io/submit-new-data-upload", true);
xhr.setRequestHeader('Accept', 'application/json, text/javascript');
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        let recordID = xhr.responseText // store for later use
    } // else handle errors
};

fd.append('filename', name)
fd.append('filedesc', desc)
fd.append('signature', JSON.stringify(signature))
fd.append('type', type)
fd.append('authToken', authToken)
xhr.send(fd);

Editable Data Management records can be updated with the following request:

URI: /update-data-storage
Method: POST
Params:

signature: user's signature on data hash (account.sign format)
contractAddr: Data Management record identifier
authToken: credential from login process

Returns:

204 (No Content): Update successful

Example (JavaScript)
let signableContent = "YOUR_DATA_HERE"

// Good practice to keep account encrypted unless in use (signing transaction)
let account = undefined;
try {
    account = web3.eth.accounts.decrypt(
        encryptedKey, 
        password + salt
    );
} catch(err) {
    return err;
}

let priorHash = "" // Good practice to include 'verification hash' of prior version of record
let signature = account.sign(signableContent + priorHash)
signature.message = "" // Waste of space to send full message

var xhr = new XMLHttpRequest();
var fd = new FormData();

xhr.open("POST", "https://www.immuto.io/update-data-storage", true);
xhr.setRequestHeader('Accept', 'application/json, text/javascript');
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 204) {
        // update successful, recordID unchanged
    }
};
fd.append('contractAddr', recordID) // from submit-new-data-upload
fd.append('signature', JSON.stringify(signature))
fd.append('authToken', authToken)
xhr.send(fd);

For Data Management verification examples, please select a specific language by clicking the appropriate tab above. We currently support in-browser and NodeJS-based verification with our open-source libraries.

Create a Data Management record:

Function: create_data_management
Params:

string: content of record - the data to be verified
string: name of record
string: record type ('basic' or 'editable')
string: user's password
string: description of record (optional)

Returns: (Promise)

Success: identifier of new Data Management record
Failure: error message

Example
let im = Immuto.init(true, "https://dev.immuto.io") // remove init params for production use
let content = "EXAMPLE CONTENT"
let recordName = "A Record"
let type = "basic" // alternatively, could be 'editable'
let password = "USER_PASSWORD" 
let desc = "Record Description" // optional

im.create_data_management(content, recordName, type, password, desc).then((recordID) => {
    // store recordID for future use
}).catch((err) => {
    console.error(err)
})

Update an editable Data Management record:

Function: update_data_management
Params:

string: record identifier (as returned by create_data_management)
string: updated content
string: user's password

Returns: (Promise)

Success:
Failure: error message

Example
let im = Immuto.init(true, "https://dev.immuto.io") // remove init params for production use
let recordID = "0x06012c8cf97bead5deae237070f9587f8e7a266d" // must correspond to existing record
let newContent = "NEW CONTENT"
let password = "USER_PASSWORD" 

im.update_data_management(recordID, newContent, password).then(() => {
    // update successful
}).catch((err) => {
    console.error(err)
})

Verify a Data Management record:

Function: verify_data_management
Params:

string: record identifier (as returned by create_data_management)
string: record type ('basic' or 'editable')
string: content to be verified

Returns: (Promise)

Successful Verification:

{ 
    timestamp: human readable timestamp (string)
    hash: hash of verified record (string)
    signer: identifier of signer (string) 
    email: signer's email (string) 
}
Invalid Verification: false
Failure: error message

Example
let im = Immuto.init(true, "https://dev.immuto.io") // remove init params for production use
let recordID = "0x06012c8cf97bead5deae237070f9587f8e7a266d" // must correspond to existing record
let type = 'basic' // alternatively, could be 'editable' 
let verificationContent = "CONTENT TO VERIFY"

im.verify_data_management(recordID, type, verificationContent).then((verification) => {
    if (verification === false) {
        // invalid content
    } else {
        console.log(verification) 
    }
}).catch((err) => {
    console.error(err)
})

Get the history of a Data Management record:

Function: get_data_management_history
Params:

string: record identifier (as returned by create_data_management)
string: record type ('basic' or 'editable')

Returns: (Promise)

Success: (list of objects)

[{ 
    timestamp: human readable timestamp (string)
    hash: hash of verified record (string)
    signer: identifier of signer (string) 
}]

Note: a 'basic' record will always return a list of length 1.

Failure: error message

Example
let im = Immuto.init(true, "https://dev.immuto.io") // remove init params for production use
let recordID = "0x06012c8cf97bead5deae237070f9587f8e7a266d" // must correspond to existing record
let type = 'basic' // alternatively, could be 'editable' 

im.get_data_management_history(recordID, type).then((history) => {
    console.log(history)
}).catch((err) => {
    console.error(err)
})

The Digital Agreements abstraction offers the same core functionality as Data Management. In addition, any number of signatures can be applied to the current version of a record. In use cases where a record requires approval from various parties, this abstraction offers better flexibility.