Calculating Payroll Taxes
Part 3 of 3
We've found the taxes that we need to set up, but we'll need to make sure we have a few final pieces of information to calculate Astrid's payroll taxes:
- How often does Astrid's employer run payroll? For our example, let's assume her employer runs payroll every two weeks, which means they have 26 pay periods in a year.
- What's the payroll date? As stated in the previous section, Astrid's company is running payroll on January 13, 2023. We don't want to run payroll using a different date from the one we used to retrieve the taxes!
- How much is Astrid earning this payroll? Let's say that Astrid earns $65,000 per year. Given that there's 26 pay periods per year, she'll have gross wages of $2,500 ($65,000 / 26) for each pay period.
- What's Astrid's employee ID? Let's give Astrid the easy-to-remember employee ID of 12345.
With all of this information on hand, we can now make a request ("PayCalcRequest"
) to the the payCalc endpoint:
https://ste-staging.symmetry.com/ste-hosted/v1/payCalc
Sample PayCalcRequest
The following request will compute all of the federal and British Columbia taxes listed in the previous section:
{
"PayCalcRequest": {
"payCalc": [
{
"employeeID": "12345",
"payrollRunParameters": {
"payDate": "2023-01-13",
"payPeriodsPerYear": 26,
"payPeriodNumber": 1
},
"wages": [
{
"locationCode": "80-000-0000",
"wageType": "Regular",
"calcMethodRegularWages": "Annualized",
"calcMethodSupplementalWages": "None",
"hours": 80,
"grossWages": 2500,
"mtdWages": 0,
"qtdWages": 0,
"ytdWages": 0
},
{
"locationCode": "80-000-0000",
"wageType": "CanadaCPP",
"calcMethodRegularWages": "Annualized",
"calcMethodSupplementalWages": "None",
"hours": 80,
"grossWages": 2500,
"mtdWages": 0,
"qtdWages": 0,
"ytdWages": 0
},
{
"locationCode": "80-000-0000",
"wageType": "CanadaEI",
"calcMethodRegularWages": "Annualized",
"calcMethodSupplementalWages": "None",
"hours": 80,
"grossWages": 2500,
"mtdWages": 0,
"qtdWages": 0,
"ytdWages": 0
},
{
"locationCode": "82-000-0000",
"wageType": "Regular",
"calcMethodRegularWages": "Annualized",
"calcMethodSupplementalWages": "None",
"hours": 80,
"grossWages": 2500,
"mtdWages": 0,
"qtdWages": 0,
"ytdWages": 0
},
{
"locationCode": "82-000-0000",
"wageType": "CanadaWorkersCompensation",
"calcMethodRegularWages": "Annualized",
"calcMethodSupplementalWages": "None",
"hours": 80,
"grossWages": 2500,
"mtdWages": 0,
"qtdWages": 0,
"ytdWages": 0
}
],
"taxJurisdictionParms": [
{
"uniqueTaxID": "80-000-0000-CPP-000",
"locationCode": "80-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default"
},
{
"uniqueTaxID": "80-000-0000-EI-000",
"locationCode": "80-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default"
},
{
"uniqueTaxID": "80-000-0000-ER_CPP-000",
"locationCode": "80-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default"
},
{
"uniqueTaxID": "80-000-0000-ER_EI-000",
"locationCode": "80-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default"
},
{
"uniqueTaxID": "80-000-0000-FIT-000",
"locationCode": "80-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default",
"miscParameters": [
{
"parmName": "FEDERAL_TOTAL_CLAIM_AMOUNT",
"parmValue": "15000"
},
{
"parmName": "PRESCRIBED_ZONE_AMOUNT",
"parmValue": "0"
}
]
},
{
"uniqueTaxID": "82-000-0000-ER_WC-000",
"locationCode": "82-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default"
},
{
"uniqueTaxID": "82-000-0000-PIT-000",
"locationCode": "82-000-0000",
"isExempt": false,
"isResident": true,
"mtdWH": 0.0,
"qtdWH": 0.0,
"ytdWH": 0.0,
"roundResult": "Default",
"miscParameters": [
{
"parmName": "PROVINCIAL_TOTAL_CLAIM_AMOUNT",
"parmValue": "11981"
}
]
}
]
}
]
}
}
PayCalcRequest breakdown
Let's go over what we set for the various parts of that request.
"employeeID"
"employeeID"
The calculation results will be returned with the same ID that you entered. If you're running multiple payroll calculations in a single request, then this will allow you to easily track which calculation results belong to which employee.
As stated above, Astrid has an employee ID of "12345"
.
"payrollRunParameters"
"payrollRunParameters"
This object is used to enter information related to the timing of the employer's payroll schedule. It contains the following three properties:
"payDate"
: The actual date of the payroll in YYYY-MM-DD format. We've use the same date as in the previous section —"2023-01-13"
."payPeriodsPerYear"
: The number of payroll periods in the year. Since Astrid's company runs payroll biweekly, we've entered26
."payPeriodNumber"
: Out of those 26 pay periods, which number is the current one? In our example, we've entered1
because this is the first pay period of the year.
"wages"
"wages"
The "wages" array contains one or more objects, each representing gross wages earned by the employee. Generally, you will set up the following wage objects:
- One wage object for "federal" regular wages and one for "provincial" regular wages. Even though these are the same $2,500 amount, we set these up twice because federal and provincial calculations are handled separately in the engine.
- One wage object with the applicable wages for the Canada Pension Plan (CPP) and one for Employment Insurance (EI). In many cases, this will be the same amount as the federal regular wages. But because these are set separately, you have complete control over which wages are subject to CPP/EI. For this payroll, we've just matched the federal regular wages and set the CPP and EI wages to $2,500.
- One wage object with the applicable workers' compensation wages (if calculating workers' compensation tax). These will generally be the same amount as the total provincial regular wages, so we've matched the provincial regular wages and set the workers' compensation wages to $2,500. Like before, these are set separately to give you control over which wages are subject to the workers' compensation tax.
Each object in "wages" has the following properties:
"locationCode"
: The location code representing where wages were earned."wageType"
: The STE supports many different wage types, but for this initial example, we're only concerned with regular wages ("Regular"
). If you're a currently licensed STE client, please see Wage Types in the STE in our Client Support Center for additional details on other types of wages."calcMethodRegularWages"
: Here we're setting this to"Annualized"
for regular annualized payroll. If we we wanted the cumulative calculation method, we would instead use"Cumulative"
."calcMethodSupplementalWages"
: This should always be set to "None" for Canada — other values are only for U.S. payroll calculations. Canadian bonus calculations are handled differently in the STE than U.S. bonus calculations."hours"
: The number of hours worked by the employee for the current pay period. Since Astrid works 40 hours per week and this payroll period covers a two-week timespan, we've set this to80
."grossWages"
: The gross wages earned by the employee for the current pay period. Astrid is earning $2,500 this pay period, so we've entered2500
."mtdWages"
,"qtdWages"
,"ytdWages"
: These represent the month-to-date, quarter-to-date, and year-to-date gross wages earned by the employee. Since this is our first payroll of the year (and because this is Astrid's first paycheck), we've entered0.0
for all three of these.
As a reminder, the STE is stateless and does not store any information! You will need to track and calculate the employee's month-to-date, quarter-to-date, and year-to-date gross wages within your system.
"taxJurisdictionParms"
"taxJurisdictionParms"
The "taxJurisdictionParms"
array contains one or more objects, each representing one tax to be calculated for this pay period for this employee.
"uniqueTaxID"
: The ID for the tax that you want to calculate."locationCode"
: The location code to be used for this tax. Usually this will match the location code where wages are earned."isExempt"
: If you set this to true, the tax will be treated as exempt for this calculation and will return $0 tax withheld. We want all of these taxes to be withheld, so we've set this to false for all taxes in the request."isResident"
: When calculating this tax, should the employee be considered a resident or not? Since Astrid lives and works in British Columbia, we'll set this to true for all of these taxes."mtdWH"
,"qtdWH"
,"ytdWH"
: The month-to-date, quarter-to-date, and year-to-date amounts withheld for this tax for this employee. Since this is our first payroll of the year (and Astrid's first paycheck), we've entered0.0
for all three of these properties for every tax in the request."roundResult"
: Whether to round the tax to the nearest dollar ("Yes"
), not round the tax ("No"
), or to let the STE determine whether the tax should be rounded or not ("Default"
). Recommended to set to"Default"
— the STE internally tracks which taxes should be rounded."miscParameters"
: This array is where we set all of the miscellaneous parameter values that we determined earlier. Each object in this array has the following two properties:"parmName"
: The name of the parameter — this corresponds to the"parameterName"
property returned in our earlier response from the setTaxList endpoint"parmValue"
: The value that of the miscellaneous parameter. Note that all values are passed in as strings (for example,"2.5"
,"true"
, etc.). When calculating, the STE translates the values into other data types to determine if they've been set correctly.
Batch Size
The payCalc endpoint has a batch size limit of 100.
Sample PayCalcResponse
Once we send this request, we'll get a response that looks like this:
{
"PayCalcResponse": {
"payCalc": [
{
"employeeID": "12345",
"taxCalculation": [
{
"locationCode": "80-000-0000",
"uniqueTaxID": "80-000-0000-CPP-000",
"isResident": true,
"wageType": "CanadaCPP",
"description": "Canada Pension Plan Tax",
"taxAmount": 140.74,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "80-000-0000",
"uniqueTaxID": "80-000-0000-EI-000",
"isResident": true,
"wageType": "CanadaEI",
"description": "Canada Employment Insurance Tax",
"taxAmount": 40.75,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "80-000-0000",
"uniqueTaxID": "80-000-0000-ER_CPP-000",
"isResident": true,
"wageType": "CanadaCPP",
"description": "Canada Employer Pension Plan Tax",
"taxAmount": 140.74,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "80-000-0000",
"uniqueTaxID": "80-000-0000-ER_EI-000",
"isResident": true,
"wageType": "CanadaEI",
"description": "Canada Employer Employment Insurance Tax",
"taxAmount": 57.05,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "80-000-0000",
"uniqueTaxID": "80-000-0000-FIT-000",
"isResident": true,
"wageType": "Regular",
"description": "Canada Income Tax",
"taxAmount": 276.99,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "82-000-0000",
"uniqueTaxID": "82-000-0000-ER_WC-000",
"isResident": true,
"wageType": "CanadaWorkersCompensation",
"description": "British Columbia Workers' Compensation",
"taxAmount": 38.75,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
},
{
"locationCode": "82-000-0000",
"uniqueTaxID": "82-000-0000-PIT-000",
"isResident": true,
"wageType": "Regular",
"description": "British Columbia Provincial Tax (PIT)",
"taxAmount": 113.14,
"grossWages": 2500.0,
"subjectWages": 2500.0,
"grossSubjectWages": 2500.0,
"isUnemploymentTax": false,
"rate": 0.0,
"wageBase": 0.0,
"subjectWagesCTD": 0.0,
"excessWagesCTD": 0.0,
"subjectWagesQTD": 0.0,
"excessWagesQTD": 0.0,
"subjectWagesYTD": 0.0,
"excessWagesYTD": 0.0
}
],
"errorStatus": {
"errorCode": 0,
"errorMessage": "No Error"
}
}
],
"transactionStamp": {
"calcDateTime": "2023-04-03T02:19:44Z",
"steVersion": "2023-R4",
"schemaVersion": "v1",
"totalTransactions": 1,
"failedTransactions": 0,
"transactionType": "PayCalc"
},
"errorStatus": {
"errorCode": 0,
"errorMessage": "No error"
}
}
}
PayCalcResponse breakdown
Each object within the "payCalc"
array represents a payroll calculation for each employee. Three properties will be returned for each employee:
"employeeID"
: This will match the"employeeID"
set in the request."taxCalculation"
: The array of taxes calculated for this payroll."errorStatus"
: If there were any errors in the calculation, they will be returned here.
Since we are only running a single payroll request for Astrid, we only have one object returned in the "payCalc"
array.
Within the "taxCalculation"
array, each object represents a separate tax and the withholding amount for that tax. For calculating Astrid's net pay, we'll focus on the following properties for this example:
"uniqueTaxID"
"uniqueTaxID"
The unique ID for the tax.
"locationCode"
"locationCode"
The location code matching the code used when you set up the tax.
"description"
"description"
The "user friendly" name of the tax.
"taxAmount"
"taxAmount"
The tax amount to be withheld.
Calculating employee net pay
Now that you have the tax amounts for each tax, we can compute Astrid's net pay, as well as the amounts that the employer will owe as the result of Astrid's paycheck.
As a reminder, Astrid has $2,500.00 in gross pay. From that, you'll subtract each employee tax in your payroll system:
- 80-000-0000-FIT-000 (Federal Income Tax): $276.99
- 80-000-0000-CPP-000 (Canada Pension Plan) $140.74
- 80-000-0000-EI-000 (Employment Insurance): $40.75
- 82-000-0000-PIT-000 (British Columbia Provincial Tax): $113.14
This will result in net pay of $1,928.38!
In summary, we've run a full payroll request through the STE and found that Astrid will have a total of $571.62 withheld from her paycheck, for a final net pay of $1,928.38.
Updated 6 days ago