Sunday, February 3, 2019

InContact Custom Report API


Summary

This post will walk through the steps necessary to generate a custom report job on InContact's platform via API.  I'll show examples in Node.js (asynchronous) and Python (synchronous).

Overview of Steps


Get Token

Node.js

 getToken() {
  console.log('getToken()');
  const url = 'https://api.incontact.com/InContactAuthorizationServer/Token';
  const body = {
    'grant_type' : 'password',
    'username' : this.username,
    'password' : this.password
  };
  return fetch(url, {
   method: 'POST',
   body: JSON.stringify(body),
   headers: {
    'Content-Type' : 'application/json', 
    'Authorization' : 'basic ' + this.authCode
   },
   cache: 'no-store',
      mode: 'cors'
  })
  .then(response => {
   if (response.ok) {
    return response.json();
   }
   else {
    const msg = 'response status: ' + response.status;
    throw new Error(msg);
   } 
  })
  .then(json => {
   if (json && json.access_token && json.resource_server_base_uri) {
    return json;
   }
   else {
    const msg = 'missing token and/or uri';
    throw new Error(msg);
   }
  })
  .catch(err => {
   console.error('getToken() - ' + err.message);
   throw err;
  });
 }

Python

    def getToken(self):
        print('getToken()')
        url = 'https://api.incontact.com/InContactAuthorizationServer/Token'
        header = {'Authorization' : b'basic ' + self.authCode, 'Content-Type': 'application/json'}
        body =  {'grant_type' : 'password', 'username' : self.username, 'password' : self.password}
        resp = requests.post(url, headers=header, json=body)
        resp.raise_for_status()
        return resp.json()

Start Report Job

Node.js

 startReportJob(reportId, reportURL, token) {
  const url = reportURL + reportId;
  console.log('startReportJob() - url: ' + url);
  const body = {
    'fileType': 'CSV',
    'includeHeaders': 'true',
    'appendDate': 'true',
    'deleteAfter': '7',
    'overwrite': 'true'
  };
  
  return fetch(url, {
   method: 'POST',
   body: JSON.stringify(body),
   headers: {
    'Content-Type' : 'application/json', 
    'Authorization' : 'bearer ' + token
   },
   cache: 'no-store',
   mode: 'cors'
  })
  .then(response => {
   if (response.ok) {
    return response.json();
   }
   else {
    const msg = 'response status: ' + response.status;
    throw new Error(msg);
   }
  })
  .then(json => {
    return json.jobId;
  })
  .catch(err => {
   console.error('startReportJob() - ' + err.message);
   throw err;
  });
 }

Python

    def startReportJob(self, reportId, reportURL, token):
        url = reportURL + reportId
        print('startReportJob() - url: ' + url);
        body = {
                'fileType': 'CSV',
                'includeHeaders': 'true',
                'appendDate': 'true',
                'deleteAfter': '7',
                'overwrite': 'true'
        }
        header = { 'Content-Type' : 'application/json', 'Authorization' : 'bearer ' + token}
        resp = requests.post(url, headers=header, json=body)
        resp.raise_for_status()
        return resp.json()['jobId']

Get File URL

Node.js

 getFileURL(jobId, reportURL, token, numTries=10) {
  console.log('getFileURL() - jobId: ' + jobId + ' numTries: ' + numTries);
  const that = this;
  const url = reportURL + jobId;
  
  return fetch(url, {
   method: 'GET',
   headers: {
    'Content-Type' : 'application/x-www-form-urlencoded', 
    'Authorization' : 'bearer ' + token
   },
   cache: 'no-store',
   mode: 'cors'
  })
  .then(response => {
   if (response.ok) {
    return response.json();
   }
   else {
    const msg = 'response status: ' + response.status;
    throw new Error(msg);
   }
  })
  .then(json => {
   if (json.jobResult.resultFileURL) {
    return json.jobResult.resultFileURL;
   }
   else {
    if (numTries > 0) {  //loop (recursive) up to the numTries parameter
     return new Promise((resolve, reject) => {
      setTimeout(() => { 
       resolve(that.getFileURL(jobId, reportURL, token, numTries-1));
      }, 60000);  //retry once per minute
     });
    }
    else {
     throw new Error('Maximum retries reached');
    } 
   }
  })
  .catch(err => {
   console.error('getFileURL() - ' + err.message);
   throw err;
  });
 }

Python

    def getFileURL(self, jobId, reportURL, token):
        url = reportURL + jobId
        header = { 'Content-Type' : 'application/x-www-form-urlencoded', 'Authorization' : 'bearer ' + token }
        resp = requests.get(url, headers=header)
        fileURL = resp.json()['jobResult']['resultFileURL']
        numTries = 10
        
        while (not fileURL and numTries > 0):
            print('getFileURL() - jobId: ' + jobId + ' numTries: ' + str(numTries))
            time.sleep(60)
            resp = requests.get(url, headers=header)
            fileURL = resp.json()['jobResult']['resultFileURL']
            numTries -= 1
        
        return fileURL

Download Report

Node.js

 
 downloadReport(url, token) {
  console.log('downLoadReport() - url: ' + url);
  
  return fetch(url, {
   method: 'GET',
   headers: {'Authorization' : 'bearer ' + token},
   cache: 'no-store',
   mode: 'cors'
  })
  .then(response => {
   if (response.ok) {
    return response.json();
   }
   else {
    const msg = 'response status: ' + response.status;
    throw new Error(msg);
   }
  })
  .then(json => {
    return json.files.file;
  })
  .catch(err => {
   console.error('downloadReport() - ' + err.message);
   throw err;
  })

Python

    def downloadReport(self, url, token):
        print('downLoadReport() - url: ' + url)
        header = { 'Content-Type' : 'application/x-www-form-urlencoded', 'Authorization' : 'bearer ' + token }
        resp = requests.get(url, headers=header)
        return resp.json()['files']['file']   

Output

Node.js

getReport() - reportId: 4477
getToken()
startReportJob() - url: https://api-c7.incontact.com/inContactAPI/services/v13.0/report-jobs/4477
getFileURL() - jobId: 825795 numTries: 10
getFileURL() - jobId: 825795 numTries: 9
getFileURL() - jobId: 825795 numTries: 8
getFileURL() - jobId: 825795 numTries: 7
downLoadReport() - url: https://api-C7.incontact.com/inContactAPI/services/V15.0/files?fileName=CustomReports%5cApiReports%5cService+Levels_20190203T054855.csv
Job Complete

Python

getReport() - reportId: 4477
getToken()
startReportJob() - url: https://api-c7.incontact.com/inContactAPI/services/v13.0/report-jobs/4477
getFileURL() - jobId: 825797 numTries: 10
getFileURL() - jobId: 825797 numTries: 9
getFileURL() - jobId: 825797 numTries: 8
downLoadReport() - url: https://api-C7.incontact.com/inContactAPI/services/V15.0/files?fileName=CustomReports%5cApiReports%5cService+Levels_20190203T055156.csv
Job Complete

Source

Full source w/comments - https://github.com/joeywhelan/reportdemo

Copyright ©1993-2024 Joey E Whelan, All rights reserved.