No description, website, or topics provided.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Sending expense to Concur with AT&T's Speech API

This code demonstrates how to submit business expense with voice using AT&T's Speech Recognition API and the Concur SDK. You can check out the demo video here

The diagram above describes the flow of the demo, and the file/code where each logic is located. The Code section below will explain how this all works. This code uses the HTML5 Audio API (use Chrome) to record voice, and node.js to drive the backend (primarily to accept client calls and call out web APIs). The AudioRecorder code is credited to Chris Wilson (check out his other demos here).


You would need to sign up for three developer accounts:

  • Firebase - Used to store/transfer the audio between the client and server
  • AT&T Developer - Speech API to translate audio into text
  • Concur Developer - QuickExpense API to submit expense amount to Concur

Once you've signed up for all the three accounts above, you need to manually generate the access token for AT&T and Concur in the config.js file described below. Follow these links on how to do that:

For Firebase, you simply need to add your Firebase URL that ends with

config.att.accessToken = "<insert AT&T access token here>";
config.concur.accessToken = "<insert Concur access token here>";
config.firebase.url = "<insert Firebase URL here>";


Please refer to the diagram at the top of this README to follow the code explanation below:

  1. Tap the microphone icon on the app to start recording voice. Tap it again to end recording.

  2. Capture voice into blob. The function below will already hold the audio blob, ready to be sent Firebase

     function doneEncoding( blob ) {
       // sendVoiceToNode called in concuratt.js
       Recorder.setupDownload( blob, "myRecording" + ((recIndex<10)?"0":"") + recIndex + ".wav" );
  3. Trigger server to wait; Send B64'd blob to Firebase

     // set up POST call as trigger to wait for Firebase to receive the B64 voice/binary file
     var xhr = new XMLHttpRequest();"POST", '/receiveVoice', true);
     xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
     // send the call to trigger server into wait mode
     // ... and send B64'd blob to Firebase
     sendToFirebase(blob, id);
  4. Receive Base-64'd blob from Firebase

     // receive B64'd blob from Firebase
     myVoiceRootRef.on('child_added', function(snapshot) {
          if (!newVoiceItems) return; // Keep from loading entire list
          var fbaseObj = snapshot.val();
          var b64string = fbaseObj.voiceBlobBase64;
          var buf = new Buffer(b64string, 'base64');
  5. Call AT&T Speech API on voice blob

     // set up call to AT&T Speech Recognition on blob turned to buffer
     var headers = {
        'Content-Type': 'audio/wav',
        'Authorization': 'Bearer ' + config.att.accessToken,
        'Accept' : 'application/json'
     var options = {
        host: '',
        path: '/speech/v3/speechToText',
        method: 'POST',
        headers: headers
     // Setup the request.
     var req = https.request(options, function (res) {
        var responseString = '';
        res.on('data', function (data) {
     	   responseString += data;
        res.on('end', function () {
     	   console.log("Response: " + responseString);
     req.on('error', function (e) {
        // TODO: handle error.
     // make the request to AT&T Speech Recognition API
  6. Send expense to Concur through QuickExpense API using the Concur SDK

     // Upon confirmation from user, send amount to Concur'/receiveExpense', function(req, res) {
       var amount = req.body.amount;
       var now = new Date();
       var year = now.getFullYear();
       var month = now.getMonth();
       var date = now.getDate();
       var fullDate = year + '-' + (month +1) + '-' + date;
       var concurBody = {
         "CurrencyCode": "USD",
         "TransactionAmount": amount,
         "TransactionDate": fullDate
       var options = {
         oauthToken: config.concur.accessToken,
           //Contains the ID and URI to the resource
           console.log("QuickExpense created! " + amount);
           res.send("QuickExpense created! " + amount);
        .fail(function (error) {
           //Error contains the error returned


If you have questions about this code, please email me at