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

# .NET SDK quickstart

> Embed the STE native library and calculate withholding for one employee with the .NET SDK.

The **.NET SDK** is a managed assembly that wraps the native STE library via P/Invoke. It exposes `STEPayrollCalculator` in the `Symmetry.TaxEngine` namespace, mirroring the Java SDK method-for-method. This quickstart runs a federal + California state calculation for one employee using the modern **STE2-style** configuration.

<Note>
  STE2-style configures every tax through `setJurisdictionData(...)` + `setJurisdictionMiscellaneousParms(...)` using a `uniqueTaxID`. Prefer it over the legacy per-tax setters. (The shipped `HelloPayrollWorld` sample still uses STE1-style calls — use this page as the STE2 template instead.)
</Note>

## Prerequisites

<Steps>
  <Step title="Get the SDK and tax database">
    You need the STE .NET assembly, the native library for your platform (`ste.dll` / `libste.so` / `libste.dylib`), and an **STE home directory** containing the tax database. These come with your STE license.
  </Step>

  <Step title="Put the native library on the load path">
    On Windows, keep `ste.dll` on `PATH` or alongside your executable. See [Linking the native library](/ste/operations/linking-the-native-library) for other platforms.
  </Step>
</Steps>

## Calculate

```csharp theme={null}
using System;
using Symmetry.TaxEngine;

class HelloPayroll
{
    static void Main()
    {
        // 1. Initialize the engine against your STE home directory.
        STEPayrollCalculator ste = new STEPayrollCalculator(@"C:\Program Files\Symmetry Tax Engine\");

        try
        {
            // 2. Start clean for this employee.
            ste.clearPayrollCalculations();
            ste.clearSettings();

            // 3. Describe the pay run: biweekly, 12th period of the year.
            ste.setPayrollRunParameters(new DateTime(2026, 6, 15), 26, 12);

            string federalLoc = "00-000-0000";
            string stateLoc   = "06-000-0000";              // California
            string fitTaxId   = "00-000-0000-FIT-000";      // Federal income tax
            string sitTaxId   = "06-000-0000-SIT-000";      // California SIT
            Money zero = Money.zero();
            Rate  zeroRate = new Rate(0D);

            // 4. Wages: $4,000 gross, 80 hours, at both the federal and state locations.
            ste.setCalculationMethod(federalLoc, CalcMethod.ANNUALIZED, CalcMethod.NONE);
            ste.setCalculationMethod(stateLoc,   CalcMethod.ANNUALIZED, CalcMethod.NONE);
            ste.setWages(federalLoc, WageType.REGULAR, new Hours(80D), new Money(4000D), zero, zero, zero);
            ste.setWages(stateLoc,   WageType.REGULAR, new Hours(80D), new Money(4000D), zero, zero, zero);

            // 5. Federal income tax (STE2): jurisdiction + withholding elections.
            ste.setJurisdictionData(fitTaxId, federalLoc, false, true,
                zero, zero, zero, zero, zero,
                JurisdictionRounding.DEFAULT, false, false,
                zeroRate, zero, zeroRate, zero);
            ste.setJurisdictionMiscellaneousParms(fitTaxId, "FILINGSTATUS", "S");
            ste.setJurisdictionMiscellaneousParms(fitTaxId, "TOTALALLOWANCES", 0);

            // 6. California SIT (STE2).
            ste.setJurisdictionData(sitTaxId, stateLoc, false, true,
                zero, zero, zero, zero, zero,
                JurisdictionRounding.DEFAULT, false, false,
                zeroRate, zero, zeroRate, zero);
            ste.setJurisdictionMiscellaneousParms(sitTaxId, "FILINGSTATUS", "S");
            ste.setJurisdictionMiscellaneousParms(sitTaxId, "TOTALALLOWANCES", "0");

            // 7. Calculate.
            ste.calculateTaxes();

            // 8. Read the withholding per tax.
            Money fit = ste.getJurisdictionCalculation(fitTaxId, WageType.REGULAR).tax;
            Money sit = ste.getJurisdictionCalculation(sitTaxId, WageType.REGULAR).tax;
            Console.WriteLine($"Federal income tax: {fit}");
            Console.WriteLine($"California SIT:     {sit}");
        }
        finally
        {
            // 9. Release native resources.
            ste.Dispose();
        }
    }
}
```

## What each step does

| Step         | Call                                                          | Purpose                                                |
| ------------ | ------------------------------------------------------------- | ------------------------------------------------------ |
| Init         | `new STEPayrollCalculator(steHome)`                           | Opens an engine handle against the tax database.       |
| Reset        | `clearPayrollCalculations()`, `clearSettings()`               | Clears prior state so the handle is reusable.          |
| Pay run      | `setPayrollRunParameters(date, ppy, period)`                  | Pay date, periods per year, and current period.        |
| Wages        | `setCalculationMethod(...)`, `setWages(...)`                  | Method (Annualized/Flat) and gross/hours by location.  |
| Jurisdiction | `setJurisdictionData(uniqueTaxID, …)`                         | Configures one tax; residency, rounding, overrides.    |
| Elections    | `setJurisdictionMiscellaneousParms(uniqueTaxID, name, value)` | Filing status, allowances, and other W-4-style inputs. |
| Calculate    | `calculateTaxes()`                                            | Runs the employee pass.                                |
| Read         | `getJurisdictionCalculation(uniqueTaxID, wageType).tax`       | The amount to withhold for that tax.                   |

<Tip>
  The .NET surface matches Java closely; the main differences are `System.DateTime` instead of `java.util.Date`, `Dispose()` instead of `close()`, and `.tax` (struct field) instead of `.getTax()`.
</Tip>

## Handles, threads, and pooling

A handle is **not thread-safe** — use one per thread. For high volume, reuse handles with `STEObjectPool` (`checkOut()` / `checkIn()`) rather than constructing one per calculation. See [Handles & pooling](/ste/operations/handles-and-pooling).

## Next steps

<Columns cols={2}>
  <Card title="Full calculation walkthrough" href="/ste/calculation-walkthroughs/dotnet-sdk" icon="list-check">
    Install the interface and run a complete, realistic pay calc end to end.
  </Card>

  <Card title="Configuring a calculation" href="/ste/configuration/setting-jurisdictions" icon="sliders">
    Wages, jurisdictions, benefits, and engine options in depth.
  </Card>

  <Card title="Migrating from STE1-style" href="/ste/migration/ste1-to-ste2" icon="arrow-right-arrow-left">
    Map legacy per-tax setters onto STE2-style calls.
  </Card>
</Columns>
