# How to Configure Tax Calculation

This document provides a step-by-step guide on how to configure and integrate the **Tax Calculation Flow** in Commerce. The Tax Calculation Flow connects Commerce to an external tax microservice that calculates destination-based sales tax for each basket item during checkout.

This integration is particularly useful for markets where tax rates vary by jurisdiction — for example, US state and county taxes — and where each basket item may carry a different tax rate based on the shipping address.

## <mark style="color:red;">1. Overview</mark> <a href="#id-1-overview" id="id-1-overview"></a>

When a customer selects or changes their shipping address or shipping option during checkout, Commerce sends a request to the configured tax microservice. The service returns a tax breakdown per basket item, which Commerce applies to the basket.

Key characteristics of this flow:

* **Destination-based tax:** Tax is calculated based on the shipping address jurisdiction.
* **Per-item breakdown:** Each basket item receives its own tax total and a breakdown of individual tax entries (e.g. state tax, county tax).
* **Non-blocking:** If the tax microservice is unavailable or returns an error, checkout continues without applying tax.
* **Exclusive tax at basket phase:** Tax is displayed separately from the product price during checkout.
* **Inclusive tax at order phase:** When the order is placed, tax is incorporated into the order item price.

## <mark style="color:red;">2. Setup</mark> <a href="#id-2-setup" id="id-2-setup"></a>

The Tax Calculation Flow is configured via the `TAX_CLIENT_CONF` dynamic setting in Omnitron.

### <mark style="color:red;">2.1. Configuring TAX\_CLIENT\_CONF</mark>

1. Log in to **Omnitron** using your own credentials.

   <figure><img src="/files/i8QWGPZddVK4HOYZ6sAp" alt=""><figcaption></figcaption></figure>
2. Navigate to **Sales Channels → Sales Channel Settings → Dynamic Settings**.

   <figure><img src="/files/SAObd0WUbnLJRQp0Qe0n" alt=""><figcaption></figcaption></figure>
3. Search for **TAX\_CLIENT\_CONF** in the search box and click on it in the list.

   <figure><img src="/files/IlDUTEszdTLQdZsOPLXG" alt=""><figcaption></figcaption></figure>
4. Update the configuration on the edit screen with the following fields.

   <figure><img src="/files/PjKCdUyBSaRC0qtdq0p8" alt=""><figcaption></figcaption></figure>

| Field           | Description                                                                     |
| --------------- | ------------------------------------------------------------------------------- |
| `enabled`       | Set to `true` to activate the tax flow. When `false`, no tax requests are made. |
| `base_url`      | The base URL of your tax microservice.                                          |
| `auth.username` | Username for HTTP Basic Authentication.                                         |
| `auth.password` | Password for HTTP Basic Authentication.                                         |

**Example configuration:**

```json
{
  "enabled": true,
  "base_url": "https://tax-service.example.com/",
  "auth": {
    "username": "your-username",
    "password": "your-password"
  }
}
```

When `enabled` is `false`, Commerce skips the tax calculation step entirely.

## <mark style="color:red;">3. How the Flow Works</mark> <a href="#id-3-how-the-flow-works" id="id-3-how-the-flow-works"></a>

### <mark style="color:red;">3.1. Trigger</mark>

The tax calculation is triggered during checkout whenever:

* The customer selects a shipping address, or
* The customer changes their shipping option.

Commerce checks whether the basket state has changed since the last tax calculation (dirty-check). If nothing relevant has changed, the microservice is not called again — avoiding redundant requests.

### <mark style="color:red;">3.2. Checkout Phase</mark>

Once Commerce receives the tax response, it stores the tax data in each `BasketItem.attributes` under the `tax` key:

```json
{
  "tax": {
    "mode": "exclusive",
    "total": "8.25",
    "breakdown": [
      {"label": "CA State Tax", "rate": "0.0725", "amount": "7.25"},
      {"label": "SF County Tax", "rate": "0.0100", "amount": "1.00"}
    ]
  }
}
```

`mode: "exclusive"` means the tax is displayed on top of the product price — the basket item price does not include tax.

The pre-order summary (`PreOrderSerializer`) exposes a `tax` field that aggregates all item taxes:

```json
{
  "tax": {
    "mode": "exclusive",
    "total": "16.24",
    "breakdown": [
      {"label": "CA State Tax", "amount": "13.77"},
      {"label": "SF County Tax", "amount": "1.90"}
    ]
  }
}
```

### <mark style="color:red;">3.3. Order Phase</mark>

When the order is placed, each `BasketItem` is converted to one `OrderItem` per unit. Commerce adjusts the tax data accordingly:

* The tax total and each breakdown amount are **divided by the basket item quantity** to produce per-unit values.
* The mode is changed from `"exclusive"` to `"inclusive"` — tax is now baked into the order item price.

This means the `OrderItem.price` reflects the full unit price including tax, and `OrderItem.attributes["tax"]` records the per-unit tax breakdown for reporting purposes.

### <mark style="color:red;">3.4. Clearing Tax</mark>

If the customer removes their shipping address or the basket state changes in a way that invalidates the previous tax calculation, Commerce clears the `tax` attribute from all basket items and recalculates on the next trigger.

## <mark style="color:red;">4. Implementing the Extension Service</mark> <a href="#id-4-implementing-the-extension-service" id="id-4-implementing-the-extension-service"></a>

To integrate a tax microservice, you need to implement an HTTP endpoint that Commerce will call during checkout. Once the extension service is deployed, set its URL as the `base_url` in `TAX_CLIENT_CONF` to connect it to Commerce. For the full API specification — including request/response structure, field descriptions, and error handling — refer to the [Extension Tax Flows](https://github.com/akinon/docs/blob/main/apireference/flows/extension-tax-flows.md) documentation.


---

# Agent Instructions: 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:

```
GET https://docs.akinon.com/tutorials/commerce/how-to-configure-tax-calculation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
