Voice Tax Calculator

Tax Returns: Accuracy Matters!

Every year, as taxpayers begin the annual rite of filling out tax forms, governments struggle with ways to streamline the processing and improve the accuracy of tax returns. Tax returns that contain errors are bad for citizens – it can mean the difference between getting a big, or not so big tax refund. It can also dramatically impact how fast refunds are issued. Inaccurate returns are also bad for governments – inaccurate tax returns require more resources to process, particularly if those returns are filed the old fashioned way: on paper.

To be sure, the Internet era has ushered in a host of different options for taxpayers that can help governments better ensure the accuracy of tax return data. Online tax filing, which is growing in popularity, can automatically correct mistakes on tax returns and automatically calculate a tax liability – dramatically reducing the chance for errors. In addition, software tools used by professional tax preparers can generate error free returns quickly and easily.

However, concerns about online filing continue to linger. Governments need to have multi-tiered strategies to enable the submission of accurate tax returns, even for those who still insist on filing paper returns. By using VoiceXML and JavaScript, governments can provide one such mechanism in a way that is simple, cheap and easy to deploy.

A Simple VoiceXML Tax Calculator

Building a simple tax calculator that is available through any standard telephone is one way that governments can help ensure greater accuracy on tax returns. Who hasn’t gotten to the end of their tax return at one time or another and thought – “Gee, did I calculate that right?”

JavaScript Code

To begin, we’ll need to assemble some JavaScript code to do a tax calculation. Most states and the federal government use graduated tax rates to calculate a tax liability. In addition, pretax deductions (which reduce taxable income) and post-tax credits (which provide a dollar for dollar reduction in tax liability) are common features. As such, we’ll use the State of Delaware in this example since all of these features are used for Delaware tax purposes. However, we’ll take care in building the “guts” of our voice tax calculator to make it easy to modify for other governments that have a similar tax structure.

To begin with, lets declare some variables that we’ll use to calculate a tax liability. We’ll do this using the JavaScript keyword “var”:

/* A variable to hold our AGI amount */
var agi_amt;

/* A variable to hold our deduction amount */
var deduct_amt;

/* A variable to hold the number of post-tax credits */
var credit_num;

/* These variables will hold some interim tax calculations.
We'll initialize them now by setting their value equal to zero */

var amt_1=0;
var amt_2=0;
var amt_3=0;
var amt_4=0;
var amt_5=0;
var amt_6=0;
var amt_7=0;

/* Set income tax brackets */
var bracket_1_low = 0;
var bracket_1_high = 2000;
var bracket_2_low = 2001;
var bracket_2_high = 5000;
var bracket_3_low = 5001;
var bracket_3_high = 10000;
var bracket_4_low = 10001;
var bracket_4_high = 20000;
var bracket_5_low = 20001;
var bracket_5_high = 25000;
var bracket_6_low = 25001;
var bracket_6_high = 60000;
var bracket_7 = 60001;
/* Declare income tax rates */
var rate_1 = 0;
var rate_2 = .022;
var rate_3 = .039;
var rate_4 = .048;
var rate_5 = .052;
var rate_6 = .055;
var rate_7 = .0595;
/* Declare personal credit and standard deduction amounts */ var pers_credit = 110;
var standard_deduct = 3250;

OK – we now have all of the pieces that we’ll need to calculate a tax liability. To carry out this calculation, we’ll use a JavaScript function that we can call rom the appropriate part of our VoiceXML document (we haven’t built that part yet, but we’ll get there shortly). We do this using the JavaScript “function” keyword.

/* Tax Calculation Function
a = adjusted gross income; b = deduction amount; c = number of personal credits. */
function liability (a, b, c) {

/* Deduction amount must be at least as much as standard deduction. */
if (b>standard_deduct) { var deduct_amt=b; } else { var deduct_amt=standard_deduct; }

/*At least one personal credit must be taken*/
if (c<1) { var num_cred=1; } else { var num_cred=c; }

var tax_inc = (a-deduct_amt);
if (tax_inc>bracket_1_high) { amt_1=((bracket_1_high-bracket_1_low)*rate_1); } else if (tax_inc>=bracket_1_low) { amt_1=((tax_inc-bracket_1_low)*rate_1); } else { amt_1=0; }

if (tax_inc>bracket_2_high) { amt_2=((bracket_2_high-bracket_2_low)*rate_2); } else if (tax_inc>=bracket_2_low) { amt_2=((tax_inc-bracket_2_low)*rate_2); } else { amt_2=0; }

if (tax_inc>bracket_3_high) { amt_3=((bracket_3_high-bracket_3_low)*rate_3); } else if (tax_inc>=bracket_3_low) { amt_3=((tax_inc-bracket_3_low)*rate_3); } else { amt_3=0; }

if (tax_inc>bracket_4_high) { amt_4=((bracket_4_high-bracket_4_low)*rate_4); } else if (tax_inc>=bracket_4_low) { amt_4=((tax_inc-bracket_4_low)*rate_4); } else { amt_4=0; }

if (tax_inc>bracket_5_high) { amt_5=((bracket_5_high-bracket_5_low)*rate_5); } else if (tax_inc>=bracket_5_low) { amt_5=((tax_inc-bracket_5_low)*rate_5); } else { amt_5=0; }

if (tax_inc>bracket_6_high) { amt_6=((bracket_6_high-bracket_6_low)*rate_6); } else if (tax_inc>=bracket_6_low) { amt_6=((tax_inc-bracket_6_low)*rate_6); } else { amt_6=0; }

if (tax_inc>bracket_7) { amt_7=((tax_inc-bracket_7)*rate_7);} else { amt_7=0; }

var tax_amt = amt_1+amt_2+amt_3+amt_4+amt_5+amt_6+amt_7;
var tax_liab = tax_amt-(num_cred*pers_credit);

/* Tax liability can not be lower than zero */
if (tax_liab > 0) {
return Math.round(tax_liab);
else { return 0;

Although this looks complicated, the tax calculation is really very straightforward. There are probably more efficient ways of writing this function, but doing it this way makes the tax calculation more transparent – for you, and for future developers who might modify or build on your work.

Our function requires three parameters – defined generically as a, b and c. These values are passed to the function as “arguments” that are collected from the user in different parts of the VoiceXML application. These values will be used to calculate the tax liability. We first check to make sure that the deduction amount that is entered by the user is larger than the standard deduction amount. If it isn’t, we’ll assign the value of the standard deduction. This helps make sure that the user is not claiming less than the standard deduction amount – a common mistake on self prepared returns.

Similarly, we’ll make sure that at least one personal credit is taken. Every taxpayer gets at least one credit for themselves, and more if they can claim others as dependents. To avoid a common mistake, we’ll make sure that each user gets at least one credit. Next, we’ll use our deduction amount to calculate taxable income. This is the amount of income that is run through our rate structure.

Graduated tax structures apply a specified rate to a given range of income. The final tax liability is the sum of the amounts generated from applying the different rates to these “tax brackets.” This might help clarify why we declared some variables earlier to hold our interim calculations (i.e., amt_1, amt_2, etc.).

The interim liability for each tax bracket is equal to the the amount of taxable income in that bracket multiplied by the rate for that bracket. Employing an “If / Else” control structure, our JavaScript function uses the taxable income amount that we calculated and first checks to see if it is larger than the high end of the first bracket. If it is, then the tax amount for that bracket is equal to the high end of the bracket minus the low end of the bracket multiplied by that bracket’s rate. It assigns this value to our temporary variable amt_1. We then move on to the next bracket and repeat this exercise.

For example:
Interim amount = (High end of the bracket - low end of the bracket) * bracket rate

In practice, we will reach a point where the amount of taxable income is exceeded by the high end of one of our brackets. When we reach that point, we want to take our taxable income amount and subtract the low end of the bracket. We then apply the final tax rate and sum up all of our temporary variables (i.e., amt_1 through amt_7, one for each of our tax brackets). This is the unadjusted tax liability amount.

Next we reduce our tax liability by the value of our personal credits. We make sure that the amount we calculate is not less than zero and then we round the result. Note – our check to ensure that the final liability is greater than zero is a function of our example state’s tax structure. Some states (and the federal government) use “refundable” credits which can actually result in a negative tax liability, which means that the taxpayer can get a check for the overage amount. A notable example of a refundable credit used by some states and the federal government is the Earned Income Tax Credit.

VoiceXML Code

Blocks of JavaScript can be contained within VoiceXML documents using the <script> element. This isn’t the only place you can use JavaScript in a VoiceXML document (a number of VoiceXML elements can utilize JavaScript expressions through the “expr” attribute – as demonstrated below), but if you are reusing functions or variables in multiple parts of your document, its a good idea to keep your code self contained. Because several of the operators in JavaScript (<, >, &, &&) have special significance in XML, we’ll enclose our script in a CDATA section, like so:

... JavaScript goes here ...

Next we’ll build some VoiceXML dialogs to collect the necessary information from the caller to be used in our JavaScript tax calculator.

In a nutshell, we want to create dialogs to collect three items: the adjusted gross income amount, the deduction amount and the number of personal credits. Each of these values can be mapped to a specific line on a tax return, so it is relatively simple to create these parts of our VoiceXML document. We’ll just ask the user to enter the number on a specific line of the return. We also want to provide a dialog to read back the values that are entered by the user. This will help us avoid confusing taxpayers with inaccurate results from misinterpreted input.

After we have collected and verified the necessary information, we need to pass these values to our JavaScript function so that it can calculate our tax liability. We do this by “calling” our function from within our VoiceXML document and passing it the arguments it needs to return a tax calculation, like so:

<value expr="liability(agi_amt, deduct_amt, credit_num)"/>

We call our function by name – we previously named it “liability”, the word that appears immediately after the function keyword above – and include the arguments in parenthesis separated by commas. You may now better understand why the last statement or two in our function include the word “return” – we have provided our JavaScript function with some values and are asking it to return a calculation.

By inserting the <value> element between the <prompt></prompt> tags, we are telling the VoiceXML interpreter to speak the result of the function call. We use the “expr” attribute to assign the amount returned from the function to the <value> element. If the amount returned is, for example, $400 the result would be the same as if we put the words “four hundred” between the <prompt></prompt> tags, like so:

Four hundred

Finally, we’ll offer a simple dialog for taxpayers that run into trouble. Users can access this section by uttering the word “help” at selected points in the application.

The completed VoiceXML/JavaScript tax checker application can be obtained here. Note – this application is optimized to work on the BeVocal platform, but it could easily be modified to work on other VoiceXML implimentations.


By offering multiple options to taxpayers to better enable them to submit accurate tax returns, governments can cut processing costs, speed refunds and provide better customer service. Adding voice applications to the mix – either through the use of a simple, highly available tax checking application like the one discussed here, or through a full blown telephone tax filing application – can help achieve this goal.

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.