Summary

Problem

Every other year, Allianz Global Corporate & Specialty (AGCS) SE gathers feedback by surveying their customers, partners and brokers. AGCS asks a range of questions which focuses on client and broker experience throughout the entire insurance value chain, including pre-purchase, servicing, claims and renewals. AGCS uses the Net Promoter Score (NPS) methodology which is anchored on its True Customer Centricity approach to do business. NPS is a widely used measurement tool which asks survey respondents to indicate the likelihood that they would recommend or ‘promote’ a company, product or service. AGCS collects these insights to better understand what clients think about AGCS at a global and regional level. AGCS’s ultimate goal with this initiative is to solve their clients’ pain points and to provide them with a better service and value proposition.

Regionally, after assessing their recent NPS score and focusing on the response about claims, most of their clients mentioned that (1) Responsiveness of contact, (2) Clear and Transparent Communication and (3) Speed of claim payment are very important to them. As AGCS takes this survey very seriously, the Singapore team started to conceptualize ideas that would further enhance the claims experience.

Solution

To further enhance the claims experience, AGCS SE Singapore Branch wants to introduce a 24/7 claims assistant (ChatBot) that enables users (clients and brokers) to access their claim handler for a particular product, to enquire about their claim status and to notify the company of a new claim, whilst keeping their broker in the loop.

The key benefits and purpose of the Insurance Claims bot is as follows:

  • Provide customers the ability to make a claim easily using mobile devices
  • Provide customers the ability to follow the status of a claim
  • Provide customers the ability to connect with a human agent easily
  • Bot will route the claim to the appropriate claims handler based on location and line of business (LOB) of the claim
  • Provide the ability for the bot to email documentation to agents
  • Provide the ability for the bot to notify the client’s broker of the claim being placed
  • Use mobile authentication to filter out spammers placing claims
  • To provide an improved experience as opposed to filling out a form

After this ideation stage, AGCS SE Singapore Branch is building a prototype using Microsoft Bot Framework that could enhance the claims experience.

Key technologies

  • Microsoft Bot Framework’s Botbuilder SDK for NodeJS
  • Skype web control for the bot interface
  • Azure App Service for hosting the bot server and interface
  • App insights for collecting telemetry for analytics
  • Twilio Authy API for sending SMS for 2FA
  • CosmosDB for storing agent contact information and for bot state
  • Nodemailer for sending emails
  • LUIS for natural language understanding
  • Bing Spell Check API to correct user errors
  • Blob storage to store images and documents sent by users

Customer profile

Allianz Global Corporate & Specialty SE (http://www.agcs.allianz.com) Allianz Global Corporate & Specialty (AGCS) is the Allianz Group’s dedicated carrier for corporate and specialty insurance business. AGCS provides insurance and risk consultancy across the whole spectrum of specialty, alternative risk transfer and corporate business: Marine, Aviation (incl. Space), Energy, Engineering, Entertainment, Financial Lines (incl. D&O), Liability, Mid-Corporate and Property insurance (incl. International Insurance Programs). Worldwide, AGCS operates in 32 countries with own units and in over 210 countries and territories through the Allianz Group network and partners. AGCS SE Singapore Branch is the regional office in Asia.

Location: Singapore

Product or service offerings: Allianz Global Corporate & Specialty offers a comprehensive range of corporate and specialty insurance services, delivered worldwide through a network in over 200 countries and territories:

  • Allianz Multinational
  • Allianz Risk Transfer
  • Aviation & Aerospace
  • Captive Insurance Services
  • Claims Services
  • Energy Insurance
  • Engineering Insurance
  • Entertainment Insurance
  • Liability Insurance
  • Marine Insurance
  • Mid-Corporate Insurance
  • Property Insurance
  • Risk Consulting
  • Space Insurance

Solution overview

Architecture of the bot

Planned architecture: Planned architecture

Implemented architecture: Implemented architecture

The technical requirements for the claims chatbot are as follows:

  • Clients are able to register or authenticate themselves as an existing client with AGCS SG (Twilio Authy API for phone authentication)
  • Upon authentication, clients are able to do 3 key things - place a new claim, check the status of an existing claim, and request to be contacted by their claims handler (Botbuilder is used to facilitate the creation of these dialogs)
  • The bot should collect required information for a claims application. This includes potential photos or documents related to the loss (pictures and documents should be uploaded to blob storage)
  • When all necessary information is gathered, the bot should forward the claims application to the appropriate claims handler via email, and offer the client the option to notify their broker of the claim via email as well (Nodemailer is used to send these emails. The appropriate claims handler is identified through a MongoDB database lookup)
  • Mechanism to prevent members of the public from spamming the chatbot (Twilio Authy API for phone verification helps to verify real clients)

Technical delivery

Implemented overall bot flow:

Verification flow:

verificationflow

Make a claim flow:

makeclaimflow

Prerequisites

Code repository

Full source code for the bot can be found here. In this writeup, we will be mainly focusing on the reusable parts in this writeup - namely the phone verification and email feature which includes sending attachments. Retrieving attachments sent by the user via Skype or MS Teams is slightly tricker because a token is needed to download the full attachment, but we will dive into how to overcome this in the writeup.

Phone verification

Phone verification was used to filter out spammers, as a person using the bot would have to have a unique phone number to verify themselves. In future, there will be a first level of authentication to verify the user is actually a client of AGCS SG.

Twilio’s Authy is a fast and simple way to implement phone verification. You will first need to create a new Authy application on Twilio. You can follow this guide on how to sign up for a Twilio account and create a new Authy application.

We will be using the Authy NodeJS helper client. Instructions on how to install this into the project can be found here.

The dialog for verifying the user using the Authy npm package is as follows:

bot.dialog('verifyUser', [
    (session, args, next) => {
        // Get the person's name if we don't have it yet
        if (!session.userData.registered || session.userData.registered === '') {
            session.beginDialog('GetRegistered');
        } else {
            session.send("Hi there, it's good to see you again.");
            next();
        }
    },
    (session, results) => {
        builder.Prompts.text(session, 'Please provide me with your phone number (without country code) for verification purposes:');
    },
    (session, results) => {
        var phone = results.response;
        console.log(phone);
        if (results.response === 'skip' || results.response === 'Skip') {
            session.beginDialog('menu');
        } else {
            session.privateConversationData.phoneNum = phone;
            // Create a new user
            const user = new User({
                fullName: session.userData.name,
                phone: phone,
                email: session.userData.email, // put placeholder
                countryCode: session.userData.countryCode || '65' // Use singapore as default
            });
            users[session.message.address.conversation.id] = user;
            // If the user is created successfully, send them an account
            // verification token
            user.sendAuthyToken(function(err) {
                if (err) {
                    console.log(err);
                    session.endDialog('Sorry, there was an error sending the verification code.');
                    session.clearDialogStack();
                    session.beginDialog('NoPolicyNumberClaim');
                } else {
                    // Prompt for the token
                    builder.Prompts.text(
                        session,
                        'We have sent you a text at this phone number, please note it may take up to 2 minutes to receive. Enter the verification code received:'
                    );
                }
            });
        }
    },
    (session, results, next) => {
        var user = users[session.message.address.conversation.id];
        // Verify token
        user.verifyAuthyToken(results.response, function(err) {
            if (err) {
                session.endDialog('The token you entered is incorrect. Please try again.');
                session.clearDialogStack();
            } else {
                session.privateConversationData.verified = true;
                session.send('Verification successful.');
                session.beginDialog('menu');
            }
        });
    }
]);

How this works is, the bot will ask the user for their phone number. Once the user enters this phone number, the bot will ask Authy to send the user a code which the user will have to enter back into the bot to verify. The bot then sends this code to Authy to complete the verification.

The User model, which contains the logic for verification and token handling, is as follows:

const mongoose = require('mongoose');
// Use native promises
mongoose.Promise = require('bluebird');

// Create authenticated Authy and Twilio API clients
const authy = require('authy')(process.env.authyKey);
const twilioClient = require('twilio')(process.env.accountSid, process.env.authToken);

// Used to generate password hash
const SALT_WORK_FACTOR = 10;

// Define user model schema
const UserSchema = new mongoose.Schema({
    fullName: {
        type: String,
        required: true
    },
    countryCode: {
        type: String,
        required: true
    },
    phone: {
        type: String,
        required: true
    },
    verified: {
        type: Boolean,
        default: false
    },
    authyId: String,
    email: {
        type: String,
        required: true,
        unique: true
    }
});

// Send a verification token to this user
UserSchema.methods.sendAuthyToken = function(cb) {
    var self = this;

    if (!self.authyId) {
        // Register this user if it's a new user
        authy.register_user(self.email, self.phone, self.countryCode, function(err, response) {
            console.log('register the user');
            if (err || !response.user) return cb.call(self, err);
            self.authyId = response.user.id;
            sendToken();
        });
    } else {
        console.log('existing user');
        // Otherwise send token to a known user
        sendToken();
    }

    // With a valid Authy ID, send the 2FA token for this user
    function sendToken() {
        authy.request_sms(self.authyId, true, function(err, response) {
            cb.call(self, err);
        });
    }
};

// Test a 2FA token
UserSchema.methods.verifyAuthyToken = function(otp, cb) {
    const self = this;
    authy.verify(self.authyId, otp, function(err, response) {
        cb.call(self, err, response);
    });
};

// Send a text message via twilio to this user
UserSchema.methods.sendMessage = function(message, successCallback, errorCallback) {
    const self = this;
    const toNumber = `+${self.countryCode}${self.phone}`;

    twilioClient.messages
        .create({
            to: toNumber,
            from: process.env.twilioNumber,
            body: message
        })
        .then(function() {
            successCallback();
        })
        .catch(function(err) {
            errorCallback(err);
        });
};

// Export user model
module.exports = mongoose.model('User', UserSchema);

Sending emails via the bot

To send emails via the bot, we use the Nodemailer npm package - you can read up more about how it works on the same link. Basically, we have to create an email account that Nodemailer can use to send emails from whenever triggered by our bot. You can create an outlook email account here.

Let’s create a mail.js module that will help us to send emails to other email addresses:

var nodemailer = require('nodemailer');

var transporter = nodemailer.createTransport({
    service: 'hotmail',
    auth: {
        user: '<the email address your bot will use to send emails from>', // use environment variables to populate
        pass: '<the password of above email address>' // use environment variables to populate
    }
});

module.exports = function(params) {
    this.from = '<the email address your bot will use to send emails from>';

    this.send = function() {
        var options = {
            from: this.from,
            to: params.to,
            subject: params.subject,
            text: params.message,
            html: params.html_message,
            attachments: params.attachments
        };
        console.log('mail.send function');
        transporter.sendMail(options, function(err, suc) {
            err ? params.errorCallback(err) : params.successCallback(suc);
        });
    };
};

In the bot code, this is how you can retrieve attachments sent by the user to the bot (via Skype or Teams):

/* Helper methods */

// Request file with Authentication Header
var requestWithToken = function(url) {
    return obtainToken().then(function(token) {
        return request({
            url: url,
            headers: {
                Authorization: 'Bearer ' + token,
                'Content-Type': 'application/octet-stream'
            }
        });
    });
};

// Promise for obtaining JWT Token (requested once)
var obtainToken = Promise.promisify(connector.getAccessToken.bind(connector));

var checkRequiresToken = function(message) {
    return message.source === 'skype' || message.source === 'msteams';
};

To construct the email and prepare for sending (the email will be sent formatted nicely using html):

var options = {
    to: '<emails you wish to send to, comma separated>',
    subject:
        'To be contacted about Policy #' +
        session.privateConversationData.claim.policynum +
        session.privateConversationData.claim.policyCode,
    message:
        'Dear ' +
        subjectName +
        'Thank you for reaching out. ' +
        doc.name +
        ' will be contacting you shortly. You may also note the following contact details for further enquiries:' +
        'Name: ' +
        doc.name +
        ', ' +
        'Email: ' +
        doc.email +
        ', Phone number: ' +
        doc.phone,
    html_message:
        '<b> Dear ' +
        subjectName +
        ', </b> <br/> <br/> ' +
        'We have received a contact notification from ' +
        session.userData.name +
        '. <br/>' +
        'Below are the details of his/her request. <br/><br/>' +
        '<table>' +
        '<tr>' +
        '<td>' +
        'Policy Number#:' +
        '</td>' +
        '<td>' +
        session.privateConversationData.claim.policynum +
        session.privateConversationData.claim.policyCode +
        '</td>' +
        '</tr>' +
        '<tr>' +
        '<td>' +
        'Claim Description:' +
        '</td>' +
        '<td>' +
        session.privateConversationData.claim.description +
        '</td>' +
        '</tr>' +
        '<tr>' +
        '<td>' +
        'Date of Loss:' +
        '</td>' +
        '<td>' +
        session.privateConversationData.claim.date +
        '</td>' +
        '</tr>' +
        '<tr>' +
        '<td>' +
        'Estimated Loss:' +
        '</td>' +
        '<td>' +
        session.privateConversationData.claim.amount +
        '</td>' +
        '</tr>' +
        '</table>' +
        '<br/>' +
        '<br/>' +
        '<br/>' +
        'Claims Auntie'
};

var mailOptions = {
    to: options.to,
    subject: options.subject,
    message: options.message,
    html_message: options.html_message,
    successCallback: function(suc) {
        console.log('Successfully sent email!');
    },
    errorCallback: function(err) {
        console.log('Mail error: ' + err);
    }
};

The full code to download the attachment sent to the bot by the user, then send the email with the attachment, is as follows:

if (attachments) {
    var attachment = attachments[0];
    session.privateConversationData.claim.attachment = attachment;
    var fileDownload = checkRequiresToken(session.message) ? requestWithToken(attachment.contentUrl) : request(attachment.contentUrl);

    fileDownload
        .then(function(response) {
            options.attachments = [
                {
                    filename: attachment.name,
                    content: response,
                    contentType: attachment.contentType
                }
            ];
            mailOptions.attachments = options.attachments;
            var mail = new Mail(mailOptions);

            mail.send();
        })
        .catch(function(err) {
            console.log(err);
            console.log('Error downloading attachment:', { statusCode: err.statusCode, message: err.response.statusMessage });
        });
} else {
    var mail = new Mail(mailOptions);
    mail.send();
}

Conclusion

We started with the client feedback as the main challenge and we decided to test building a prototype that could satisfy their fundamental needs in a digital and automated way. After a couple of envisioning and ideation sessions, we decided to try a chatbot as this solution would tackle overall client’s needs in the best way possible.

Philip Green, Energy Claims Manager

What was interesting to learn from building this prototype was that this technology is a different customer experience that will enable us to learn from customer interactions. It is an evolving technology that could drive customer action and provide personalized service in a timely manner.

Tiago Sanchez, Program Manager Business Innovation Asia

Team

AGCS SG project team:

  • Tiago Sanchez – Program Manager Business Innovation Asia
  • Philip Green – Energy Claims Manager
  • Hussain Kanchwala – IT Developer

Microsoft team:

  • Alyssa Ong, Technical Evangelist
  • Renee Dothard, Program Manager Architect
  • Michael Chi, Software Development Engineer
  • David Mould, Chief Digital Advisor
  • Gurbeena Sahi, Account Executive
  • K S Srikanth, Account Technical Strategist

allianz-logo