> ## Documentation Index
> Fetch the complete documentation index at: https://docs.symmetry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Canadian payroll quickstart

> Run a Canadian payroll calculation in the Symmetry Tax Engine — authenticate, send one request, and read the withholding.

This quickstart runs one Canadian payroll calculation end to end. Canadian location codes are simple enough to write down up front — one code per province, plus `80-000-0000` for federal taxes — so there is no address lookup to do first and you can go straight to a calculation.

Our employee has just started a job in Vancouver, British Columbia and is receiving her first paycheck. She earns \$65,000 a year paid biweekly, so gross wages are **\$2,500** for the period, on a pay date of **January 13, 2026**.

| Jurisdiction     | Location code |
| ---------------- | ------------- |
| Canadian federal | `80-000-0000` |
| British Columbia | `82-000-0000` |

<Note>
  Two Canada-specific rules apply to every calculation on this page. Set `calcMethodSupplementalWages` to `None` — Canada ignores it. And on the on-premise SDK, call the Canadian calculate function rather than the U.S. one. For the complete list, see [Differences between Canadian and U.S. calculations](/ste/taxes/canadian/differences-between-canadian-and-u-s-calculations).
</Note>

## Authenticate

Hosted API requests need an API key. Staging and production use **separate** keys, and each works only in its matching environment.

| Environment | Base URL                                      |
| ----------- | --------------------------------------------- |
| Staging     | `https://ste-staging.symmetry.com/ste-hosted` |
| Production  | `https://ste.symmetry.com/ste-hosted`         |

Pass the key as the **raw value** of the `Authorization` header — no `Bearer` prefix.

```http theme={null}
POST /v1/payCalc HTTP/1.1
Host: ste-staging.symmetry.com
Authorization: your_api_key_here
Content-Type: application/json
Accept: application/json
```

On-premise SDK users have nothing to authenticate — the engine runs locally against your licensed installation. See [Licensing](/ste/overview/licensing).

## Send a `payCalc` request

This calculates four employee taxes and three employer taxes. The two claim amounts come from the employee's tax forms: `16452` from [federal Form TD1](https://www.canada.ca/content/dam/cra-arc/formspubs/pbg/td1/td1-26e.pdf) and `13216` from [Form TD1BC](https://www.canada.ca/content/dam/cra-arc/formspubs/pbg/td1bc/td1bc-26e.pdf).

<Tabs>
  <Tab title="Hosted API">
    ```json theme={null}
    {
      "PayCalcRequest": {
        "payCalc": [
          {
            "employeeID": "12345",
            "payrollRunParameters": { "payDate": "2026-01-13", "payPeriodsPerYear": 26, "payPeriodNumber": 1 },
            "wages": [
              { "locationCode": "80-000-0000", "wageType": "Regular", "hours": 80, "grossWages": 2500, "mtdWages": 0, "qtdWages": 0, "ytdWages": 0, "calcMethodRegularWages": "Annualized", "calcMethodSupplementalWages": "None" },
              { "locationCode": "80-000-0000", "wageType": "CanadaCPP", "hours": 80, "grossWages": 2500, "mtdWages": 0, "qtdWages": 0, "ytdWages": 0, "calcMethodRegularWages": "Annualized", "calcMethodSupplementalWages": "None" },
              { "locationCode": "80-000-0000", "wageType": "CanadaEI", "hours": 80, "grossWages": 2500, "mtdWages": 0, "qtdWages": 0, "ytdWages": 0, "calcMethodRegularWages": "Annualized", "calcMethodSupplementalWages": "None" },
              { "locationCode": "82-000-0000", "wageType": "Regular", "hours": 80, "grossWages": 2500, "mtdWages": 0, "qtdWages": 0, "ytdWages": 0, "calcMethodRegularWages": "Annualized", "calcMethodSupplementalWages": "None" },
              { "locationCode": "82-000-0000", "wageType": "CanadaWorkersCompensation", "hours": 80, "grossWages": 2500, "mtdWages": 0, "qtdWages": 0, "ytdWages": 0, "calcMethodRegularWages": "Annualized", "calcMethodSupplementalWages": "None" }
            ],
            "taxJurisdictionParms": [
              { "uniqueTaxID": "80-000-0000-CPP-000", "locationCode": "80-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default" },
              { "uniqueTaxID": "80-000-0000-EI-000", "locationCode": "80-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default" },
              { "uniqueTaxID": "80-000-0000-ER_CPP-000", "locationCode": "80-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default" },
              { "uniqueTaxID": "80-000-0000-ER_EI-000", "locationCode": "80-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default" },
              {
                "uniqueTaxID": "80-000-0000-FIT-000", "locationCode": "80-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default",
                "miscParameters": [
                  { "parmName": "FEDERAL_TOTAL_CLAIM_AMOUNT", "parmValue": "16452" },
                  { "parmName": "PRESCRIBED_ZONE_AMOUNT", "parmValue": "0" }
                ]
              },
              { "uniqueTaxID": "82-000-0000-ER_WC-000", "locationCode": "82-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default" },
              {
                "uniqueTaxID": "82-000-0000-PIT-000", "locationCode": "82-000-0000", "isExempt": false, "isResident": true, "roundResult": "Default",
                "miscParameters": [
                  { "parmName": "PROVINCIAL_TOTAL_CLAIM_AMOUNT", "parmValue": "13216" }
                ]
              }
            ]
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    ste_handle* ste = ste_init("C:/STE");

    ste_set_payroll_run_parameters(ste, "2026-01-13", 26, 1);
    ste_set_calcmethod(ste, "80-000-0000", ste_CALC_Method_Annualized, ste_CALC_Method_None);
    ste_set_calcmethod(ste, "82-000-0000", ste_CALC_Method_Annualized, ste_CALC_Method_None);

    ste_set_wages(ste, "80-000-0000", ste_WAGE_Regular, 80.0, 2500.0, 0.0, 0.0, 0.0);
    ste_set_wages(ste, "80-000-0000", ste_WAGE_CPP, 80.0, 2500.0, 0.0, 0.0, 0.0);
    ste_set_wages(ste, "80-000-0000", ste_WAGE_EI, 80.0, 2500.0, 0.0, 0.0, 0.0);
    ste_set_wages(ste, "82-000-0000", ste_WAGE_Regular, 80.0, 2500.0, 0.0, 0.0, 0.0);
    ste_set_wages(ste, "82-000-0000", ste_WAGE_WORKERS_COMPENSATION, 80.0, 2500.0, 0.0, 0.0, 0.0);

    ste_set_jurisdiction_data(ste, "80-000-0000-CPP-000", "80-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_data(ste, "80-000-0000-EI-000", "80-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_data(ste, "80-000-0000-ER_CPP-000", "80-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_data(ste, "80-000-0000-ER_EI-000", "80-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_data(ste, "80-000-0000-FIT-000", "80-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_misc_parms(ste, "80-000-0000-FIT-000", "FEDERAL_TOTAL_CLAIM_AMOUNT", "16452");
    ste_set_jurisdiction_data(ste, "82-000-0000-ER_WC-000", "82-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_data(ste, "82-000-0000-PIT-000", "82-000-0000", false, true, 0.0, 0.0, 0.0, 0.0, 0.0, ste_ROUNDING_Default, false, false, 0.0, 0.0, 0.0, 0.0);
    ste_set_jurisdiction_misc_parms(ste, "82-000-0000-PIT-000", "PROVINCIAL_TOTAL_CLAIM_AMOUNT", "13216");

    ste_ca_calculate(ste);   /* not ste_calculate() */
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    STE.setPayrollRunParameters(payDate, 26, 1);
    STE.setCalculationMethod(CAN_FED_LOC_CODE, CalcMethod.ANNUALIZED, CalcMethod.NONE);
    STE.setCalculationMethod(CAN_BC_LOC_CODE, CalcMethod.ANNUALIZED, CalcMethod.NONE);

    STE.setWages(CAN_FED_LOC_CODE, WageType.REGULAR, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_FED_LOC_CODE, WageType.CANADA_CPP, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_FED_LOC_CODE, WageType.CANADA_EI, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_BC_LOC_CODE, WageType.REGULAR, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_BC_LOC_CODE, WageType.CANADA_WORKERS_COMPENSATION, HOURS, WAGES, ZERO, ZERO, ZERO);

    STE.setJurisdictionData("80-000-0000-CPP-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-EI-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-ER_CPP-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-ER_EI-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-FIT-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionMiscellaneousParms("80-000-0000-FIT-000", "FEDERAL_TOTAL_CLAIM_AMOUNT", "16452");
    STE.setJurisdictionData("82-000-0000-ER_WC-000", CAN_BC_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("82-000-0000-PIT-000", CAN_BC_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionMiscellaneousParms("82-000-0000-PIT-000", "PROVINCIAL_TOTAL_CLAIM_AMOUNT", "13216");

    STE.canadaCalculateTaxes();   // not calculateTaxes()
    ```
  </Tab>

  <Tab title=".NET">
    ```csharp theme={null}
    STE.setPayrollRunParameters(new DateTime(2026, 1, 13), 26, 1);
    STE.setCalculationMethod(CAN_FED_LOC_CODE, CalcMethod.ANNUALIZED, CalcMethod.NONE);
    STE.setCalculationMethod(CAN_BC_LOC_CODE, CalcMethod.ANNUALIZED, CalcMethod.NONE);

    STE.setWages(CAN_FED_LOC_CODE, WageType.REGULAR, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_FED_LOC_CODE, WageType.CANADA_CPP, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_FED_LOC_CODE, WageType.CANADA_EI, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_BC_LOC_CODE, WageType.REGULAR, HOURS, WAGES, ZERO, ZERO, ZERO);
    STE.setWages(CAN_BC_LOC_CODE, WageType.CANADA_WORKERS_COMPENSATION, HOURS, WAGES, ZERO, ZERO, ZERO);

    STE.setJurisdictionData("80-000-0000-CPP-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-EI-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-ER_CPP-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-ER_EI-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("80-000-0000-FIT-000", CAN_FED_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionMiscellaneousParms("80-000-0000-FIT-000", "FEDERAL_TOTAL_CLAIM_AMOUNT", "16452");
    STE.setJurisdictionData("82-000-0000-ER_WC-000", CAN_BC_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionData("82-000-0000-PIT-000", CAN_BC_LOC_CODE, false, true, ZERO, ZERO, ZERO, ZERO, ZERO, JurisdictionRounding.DEFAULT, false, false, ZERO_RATE, ZERO, ZERO_RATE, ZERO);
    STE.setJurisdictionMiscellaneousParms("82-000-0000-PIT-000", "PROVINCIAL_TOTAL_CLAIM_AMOUNT", "13216");

    STE.canadaCalculateTaxes();   // not calculateTaxes()
    ```
  </Tab>
</Tabs>

<Warning>
  The STE does not store anything between calls. You must track month-to-date, quarter-to-date, and year-to-date wages and withholding in your own system and pass them in. They are all `0` here because this is the employee's first paycheck of the year.
</Warning>

## Read the response

Each entry in the returned `taxCalculation` array is one tax. The field you withhold on is `taxAmount`.

| `uniqueTaxID`            | Description                              | Paid by  | `taxAmount` |
| ------------------------ | ---------------------------------------- | -------- | ----------- |
| `80-000-0000-FIT-000`    | Canada Income Tax                        | Employee | \$242.58    |
| `80-000-0000-CPP-000`    | Canada Pension Plan - Employee           | Employee | \$140.74    |
| `80-000-0000-EI-000`     | Canada Employment Insurance Tax          | Employee | \$40.75     |
| `82-000-0000-PIT-000`    | British Columbia Provincial Tax          | Employee | \$105.82    |
| `80-000-0000-ER_CPP-000` | Canada Pension Plan - Employer           | Employer | \$140.74    |
| `80-000-0000-ER_EI-000`  | Canada Employer Employment Insurance Tax | Employer | \$57.05     |
| `82-000-0000-ER_WC-000`  | British Columbia Workers' Compensation   | Employer | \$38.75     |

That is **\$529.89** withheld from a \$2,500.00 paycheck, leaving **\$1,970.11** net, plus **\$236.54** owed by the employer.

<Note>
  The response also contains `80-000-0000-CPP2-000` and `80-000-0000-ER_CPP2-000`, the CPP second additional contribution, even though you did not request them. Both are \$0 here because these wages fall below the first earnings ceiling. Expect them and handle them like any other tax.
</Note>

<Warning>
  `subjectWages` comes back alongside each tax amount. For Canadian taxes read it as **pensionable**, **insurable**, or **contributable** wages, whichever applies to that tax.
</Warning>

## Next steps

<Columns cols={2}>
  <Card title="Canadian payroll walkthrough" href="/ste/calculation-walkthroughs/canadian-payroll" icon="list-check">
    The same calculation in depth, with full code for every interface.
  </Card>

  <Card title="Canadian vs. U.S. calculations" href="/ste/taxes/canadian/differences-between-canadian-and-u-s-calculations" icon="right-left">
    Every difference to know before you go live.
  </Card>

  <Card title="Canadian location codes" href="/ste/reference/canadian-location-codes" icon="location-dot">
    The code for each province and territory.
  </Card>

  <Card title="Canadian bonus payments" href="/ste/taxes/canadian/bonus-payments-for-canadian-taxes" icon="gift">
    Off-cycle and bonus runs, which follow different rules.
  </Card>
</Columns>
