> For the complete documentation index, see [llms.txt](https://docs.younium.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.younium.com/tax-integrations/avalara.md).

# Avalara

## Overview

The Avalara integration connects Younium to Avalara AvaTax, a cloud-based sales tax calculation and reporting service. It supports automatic tax calculation on draft invoices and tax transaction reporting when invoices are posted in Younium. The integration also supports address validation and exemption type management at account and order level.

***

## Authentication

You connect Avalara with the username and password of your AvaTax account, entered in the integration settings together with a choice of sandbox or production.

Younium checks them against Avalara the moment you save. If Avalara confirms them, the connection is marked active and tax calculation can begin. If it does not, the connection is left inactive and the reason Avalara gave is shown in the settings, so a failed connection tells you what went wrong rather than only that it failed.

The connection lasts until the credentials change in Avalara. Nothing expires on a schedule and there is no periodic reauthorisation.

***

## Sandbox vs. Production

You choose sandbox or production when you connect, and the choice decides which Avalara account Younium calculates and reports against.

Sandbox is a separate Avalara account with its own credentials and its own company records, so moving from testing to live means reconnecting with production credentials, not just changing the choice. Everything the integration does behaves the same in both.

***

## Activation

Activation is the moment Younium first calls Avalara with the credentials you entered. Both a username and a password are required; leaving either blank fails immediately without contacting Avalara.

If Avalara confirms the credentials, they are stored and the connection is marked active. Activation connects and nothing more: the custom fields the integration uses and the exchanges it runs are set up separately when you save the settings.

***

## Deactivation

Deactivation removes the stored Avalara settings and stops both exchanges: draft invoices are no longer sent to Avalara for tax calculation, and posted invoices are no longer reported. Tax amounts already written onto invoices are left as they are.

***

## Save and Setup

When settings are saved, the following setup steps are performed automatically:

* Creates or populates a custom field list on **Account** named `Avalara Exemption Type` with all standard Avalara entity use codes (see Exemption Types below).
* Creates or populates the same custom field list on **Order** named `Avalara Exemption Type` with the same values.
* Creates a custom field on **Charge** named `Avalara Product Tax Code` (type: Text).
* Subscribes or unsubscribes from `InvoiceDraftCreated` based on the **Draft Invoice Calculation** setting.
* Subscribes or unsubscribes from `InvoicePosted` based on the **Post Invoice Calculation** setting.

### Exemption Types

The following exemption type values are populated into the `Avalara Exemption Type` custom field list on both Account and Order. The `Key` is the Avalara `entityUseCode` sent in transactions; the `Value` is the display label in Younium.

| Key       | Value                         |
| --------- | ----------------------------- |
| `A`       | FEDERAL GOV                   |
| `B`       | STATE GOV                     |
| `C`       | TRIBAL GOVERNMENT             |
| `D`       | FOREIGN DIPLOMAT              |
| `E`       | CHARITABLE/EXEMPT ORG         |
| `F`       | RELIGIOUS ORG                 |
| `G`       | RESALE                        |
| `H`       | AGRICULTURE                   |
| `I`       | INDUSTRIAL PROD/MANUFACTURERS |
| `J`       | DIRECT PAY                    |
| `K`       | DIRECT MAIL                   |
| `L`       | OTHER/CUSTOM                  |
| `M`       | EDUCATIONAL ORG               |
| `N`       | LOCAL GOVERNMENT              |
| `P`       | COMMERCIAL AQUACULTURE        |
| `Q`       | COMMERCIAL FISHERY            |
| `R`       | NON-RESIDENT                  |
| `TAXABLE` | NON-EXEMPT TAXABLE CUSTOMER   |

***

## Custom Fields Created by the Integration

The following custom fields are created automatically during setup. They must not be renamed or deleted, as they are referenced by name in the integration logic.

| Entity  | Custom Field Name          | Type | Notes                                      |
| ------- | -------------------------- | ---- | ------------------------------------------ |
| Account | `Avalara Exemption Type`   | List | Populated with Avalara entity use codes    |
| Order   | `Avalara Exemption Type`   | List | Populated with Avalara entity use codes    |
| Charge  | `Avalara Product Tax Code` | Text | Stores the Avalara tax code for the charge |

***

## Tax Line Eligibility

Not all invoice lines are sent to Avalara. For each invoice line, the integration checks the line's `OrderProductCharge.TaxTemplate`. It finds the most specific matching tax template detail for the invoice's destination address and country. A line is only included in the Avalara transaction if that matched tax template detail has `UseExternalTaxEngine = true`.

Lines that do not match this condition are silently skipped.

***

## Transaction Model

Both the draft invoice handler and the posted invoice handler build the same base transaction model via `CreateTransactionModel`. The transaction is always committed (`commit = true`).

### Transaction Field Mapping (Younium → Avalara)

| Younium Field                                  | Avalara `AvaTransaction` Field |
| ---------------------------------------------- | ------------------------------ |
| `Invoice.InvoiceNumber`                        | `code`                         |
| `Invoice.Currency.Code`                        | `currencyCode`                 |
| `Invoice.Account.AccountNumber`                | `customerCode`                 |
| `Invoice.InvoiceDate` (formatted `yyyy-MM-dd`) | `date`                         |
| `AvalaraSettings.CompanyId`                    | `companyId`                    |
| Always `true`                                  | `commit`                       |
| Resolved exemption key (see below)             | `entityUseCode`                |

### Ship From Address (Legal Entity Address)

The ship-from address is always taken from the legal entity's address configured in Younium.

| Younium Field                              | Avalara `shipFrom` Field |
| ------------------------------------------ | ------------------------ |
| `LegalEntity.Address.Street`               | `line1`                  |
| `LegalEntity.Address.Street2`              | `line2`                  |
| `LegalEntity.Address.City`                 | `city`                   |
| `LegalEntity.Address.State`                | `region`                 |
| `LegalEntity.Address.Zip`                  | `postalCode`             |
| `LegalEntity.Address.Country.TwoAlphaCode` | `country`                |

### Ship To Address (Invoice Address)

The ship-to address uses the invoice's **Delivery Address** if present, otherwise the **Invoice Address**. The destination address must have a country set; if it does not, the transaction fails with an error.

| Younium Field                  | Avalara `shipTo` Field |
| ------------------------------ | ---------------------- |
| `Address.Street`               | `line1`                |
| `Address.Street2`              | `line2`                |
| `Address.City`                 | `city`                 |
| `Address.State`                | `region`               |
| `Address.Zip`                  | `postalCode`           |
| `Address.Country.TwoAlphaCode` | `country`              |

### Exemption Code Resolution

The `entityUseCode` on the transaction is resolved as follows, in priority order:

1. If the invoice has an associated **Order** and the order has a value in the `Avalara Exemption Type` custom field, the matching list item's `Key` is used.
2. Otherwise, if the invoice's **Account** has a value in the `Avalara Exemption Type` custom field, the matching list item's `Key` is used.
3. If neither has a value, `entityUseCode` is not set on the transaction.

The lookup uses the custom field list named `Avalara Exemption TypeList` (the list name is the custom field name with `List` appended).

***

## Invoice Line Field Mapping (Younium → Avalara)

For each eligible invoice line (see Tax Line Eligibility above), one `AvaTransaction.Line` is created.

| Younium Field                                                    | Avalara `Line` Field |
| ---------------------------------------------------------------- | -------------------- |
| `InvoiceLine.Subtotal.Amount`                                    | `amount`             |
| `InvoiceLine.ChargeDescription`                                  | `description`        |
| `InvoiceLine.OrderProductCharge.ChargeNumber`                    | `itemCode`           |
| `InvoiceLine.Quantity` (defaults to `1` if null)                 | `quantity`           |
| Sequential line number (string)                                  | `number`             |
| `InvoiceLine.Id` (as string)                                     | `ref1`               |
| Custom field `Avalara Product Tax Code` on `Charge` (if present) | `taxCode`            |

The `taxCode` field is only set if the charge has a non-null value in the `Avalara Product Tax Code` custom field.

***

## Draft Invoice Tax Calculation

Triggered by the `InvoiceDraftCreated` event when **Draft Invoice Calculation** is enabled.

All eligible invoice lines are collected into a single transaction of unspecified type (no `type` field is set explicitly in the draft handler) and posted to:

`{baseUrl}v2/transactions/create`

Line numbers start at `1` and increment sequentially.

After Avalara responds, the tax amounts are written back to Younium:

* Each invoice line is matched to the Avalara response line by `ref1` (which equals `InvoiceLine.Id`).
* For each matched line, each `TaxItem.Amount.Amount` on the invoice line is set to the Avalara response `line.tax` value.
* The base currency amount for each tax item is recalculated.
* `InvoiceLine.Tax` is recalculated as the sum of all `TaxItem.Amount` values.
* `InvoiceLine.Total.Amount` is recalculated as `Subtotal.Amount + Tax.Amount`.
* `InvoiceLine.Total.BaseCurrencyAmount` is recalculated as `Subtotal.BaseCurrencyAmount + Tax.BaseCurrencyAmount`.
* Invoice-level totals are recalculated via `invoiceService.AddInvoiceAmounts`.
* Changes are saved to the database.

The transaction is only posted if there is at least one eligible line. If no eligible lines exist, nothing is sent to Avalara.

***

## Posted Invoice Tax Reporting

Triggered by the `InvoicePosted` event when **Post Invoice Calculation** is enabled.

The integration does **not** write tax amounts back to Younium on post — it only reports the transaction to Avalara for tax filing purposes. Reporting requires a working Avalara connection; without one, the action fails rather than passing silently.

Line numbers start at `0` and increment sequentially.

### Debit Invoices (`Invoice.Subtotal.Amount >= 0`)

A `SalesInvoice` transaction is created. Eligible invoice lines are split into two groups:

* **Debit lines:** lines where `Subtotal.Amount >= 0`
* **Credit lines:** lines where `Subtotal.Amount < 0`

The transaction is only posted if there is at least one debit line. When posted, debit lines are listed first, followed by credit lines.

### Credit Invoices (`Invoice.Subtotal.Amount < 0`)

A `ReturnInvoice` transaction is created. Eligible invoice lines are again split into debit and credit groups.

The transaction is only posted if there is at least one credit line. When posted, credit lines are listed first, followed by debit lines.

Additionally, if there are multiple credited invoice line IDs and no debit lines, the integration looks up the original (debited) invoice to apply a tax date override:

* The transaction `code` is set to the original invoice's `InvoiceNumber`.
* A `taxOverride` is applied with:

| Field     | Value                                                     |
| --------- | --------------------------------------------------------- |
| `type`    | `TaxDate`                                                 |
| `taxDate` | Original invoice's `InvoiceDate` (formatted `yyyy-MM-dd`) |
| `reason`  | `Return`                                                  |

***

## Address Validation

The integration exposes an address validation feature using the Avalara address resolution API:

* **Sandbox:** `https://sandbox-rest.avatax.com/api/v2/addresses/resolve`
* **Production:** `https://rest.avatax.com/api/v2/addresses/resolve`

At least one of `Zip`, `Street`, or `City` must be non-empty; otherwise validation fails immediately with an error.

### Address Validation Request Parameters (Younium → Avalara)

| Younium Field    | Avalara Query Parameter |
| ---------------- | ----------------------- |
| `Address.Zip`    | `postalCode`            |
| `Address.Street` | `line1`                 |
| `Address.City`   | `city`                  |
| `Address.State`  | `region`                |

### Address Validation Response Handling

If validation succeeds, the validated address fields returned by Avalara are written back to the Younium address object (but not saved — the user must explicitly save):

| Avalara `validatedAddress` Field | Younium `Address` Field |
| -------------------------------- | ----------------------- |
| `postalCode`                     | `Address.Zip`           |
| `line1`                          | `Address.Street`        |
| `line2`                          | `Address.Street2`       |
| `region`                         | `Address.State`         |
| `city`                           | `Address.City`          |

If the response contains an `error` object or any message with `severity = "Error"`, the result is returned as an error with the corresponding message. Messages with other severity levels are returned as informational.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.younium.com/tax-integrations/avalara.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
