# Extension Tax Flows

This document provides a detailed explanation of the tax calculation flow, including the purpose of the flow, the service involved, and the description of each field in the request and response.

**Example configuration (Dynamic Settings):**

| Key               | Type   | Default   | Description                                            |
| ----------------- | ------ | --------- | ------------------------------------------------------ |
| `TAX_CLIENT_CONF` | Object | See below | Connection settings for the external tax microservice. |

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

## <mark style="color:red;">Purpose of the Flow</mark>

The Tax Calculation Flow is designed to integrate with an external tax microservice to calculate destination-based sales tax for each basket item during checkout. This flow is triggered whenever the customer selects or changes their shipping address or shipping option. This flow is particularly useful for:

* **Destination-Based Tax:** Calculating sales tax based on the shipping address jurisdiction (e.g. US state tax).
* **Per-Item Tax Breakdown:** Providing granular tax amounts and rates per basket item for accurate order pricing and reporting.
* **Non-Blocking Integration:** Tax calculation errors never block checkout — if the microservice is unavailable or returns an unexpected response, checkout proceeds without tax.

This part of the document contains the service that can be integrated in the flow above. 2 configuration parameters will be shared during integration:

| Field    | Description                       |
| -------- | --------------------------------- |
| username | Username for basic authentication |
| password | Password for basic authentication |

## <mark style="color:red;">tax-calculate (POST)</mark>

This service is used to calculate tax amounts for each basket item. It is called during checkout after offer/discount calculation, when the shipping address or basket contents change.

**URL:**

```
^^/tax-calculate
```

**Request Headers**

| Header              | Description                                 | Requirement |
| ------------------- | ------------------------------------------- | ----------- |
| x-akinon-request-id | Unique ID for problem solving & tracing.    | Mandatory   |
| Content-Type        | `application/json`                          | Mandatory   |
| Authorization       | Basic \[BASE64\_encoded(username:password)] | Mandatory   |

**Request Body Structure**

| Field                                     | Type        | Description                                                        |
| ----------------------------------------- | ----------- | ------------------------------------------------------------------ |
| basket                                    | Object      | Container for basket information                                   |
| basket.basketItems                        | Array       | List of items in the basket                                        |
| basket.basketItems\[].id                  | Number      | Unique identifier for the basket item                              |
| basket.basketItems\[].quantity            | Number      | Quantity of the item                                               |
| basket.basketItems\[].unitPrice           | String      | Unit price before discount (decimal value as string)               |
| basket.basketItems\[].unitDiscountedPrice | String      | Unit price after discount (decimal value as string)                |
| basket.basketItems\[].currencyType        | String      | Currency code (ISO 4217)                                           |
| basket.basketItems\[].taxRate             | String      | VAT/KDV rate of the product (0–100 scale, decimal value as string) |
| basket.basketItems\[].product             | Object      | Product information                                                |
| basket.basketItems\[].product.sku         | String      | SKU of the product                                                 |
| basket.basketItems\[].product.name        | String      | Name of the product                                                |
| basket.basketItems\[].product.attributes  | Object      | Additional attributes of the product                               |
| address                                   | Object      | Shipping address used to determine the tax jurisdiction            |
| address.country                           | String      | Country code (ISO 3166-1 alpha-2)                                  |
| address.city                              | String/Null | City name                                                          |
| address.township                          | String/Null | Township name                                                      |
| address.district                          | String/Null | District name                                                      |
| address.postcode                          | String/Null | Postal code                                                        |
| address.line                              | String      | Address line                                                       |
| address.taxOffice                         | String/Null | Tax office (for corporate invoices)                                |
| address.taxNo                             | String/Null | Tax number (for corporate invoices)                                |
| shippingOption                            | Object/Null | Selected shipping option                                           |
| shippingOption.slug                       | String      | Unique slug of the shipping option                                 |
| shippingOption.name                       | String      | Display name of the shipping option                                |

**Request Body Example**

```json
{
  "basket": {
    "basketItems": [
      {
        "id": 1,
        "quantity": 2,
        "unitPrice": "49.99",
        "unitDiscountedPrice": "44.99",
        "currencyType": "USD",
        "taxRate": "0.00",
        "product": {
          "sku": "SKU-001",
          "name": "Classic T-Shirt",
          "attributes": {
            "color": "black",
            "size": "M"
          }
        }
      },
      {
        "id": 2,
        "quantity": 1,
        "unitPrice": "89.99",
        "unitDiscountedPrice": "89.99",
        "currencyType": "USD",
        "taxRate": "0.00",
        "product": {
          "sku": "SKU-002",
          "name": "Denim Jacket",
          "attributes": {
            "color": "blue",
            "size": "L"
          }
        }
      }
    ]
  },
  "address": {
    "country": "US",
    "city": "New York",
    "township": null,
    "district": null,
    "postcode": "10001",
    "line": "123 Main St",
    "taxOffice": null,
    "taxNo": null
  },
  "shippingOption": {
    "slug": "standard-shipping",
    "name": "Standard Shipping"
  }
}
```

**Request Body (typescript interface)**

```ts
interface TaxCalculateRequest {
  basket: TaxBasket;
  address: TaxAddress;
  shippingOption: TaxShippingOption | null;
}

interface TaxBasket {
  basketItems: TaxBasketItem[];
}

interface TaxBasketItem {
  id: number;
  quantity: number;
  unitPrice: string;
  unitDiscountedPrice: string;
  currencyType: string;
  taxRate: string;
  product: TaxProduct;
}

interface TaxProduct {
  sku: string;
  name: string;
  attributes: Record<string, any>;
}

interface TaxAddress {
  country: string;
  city: string | null;
  township: string | null;
  district: string | null;
  postcode: string | null;
  line: string;
  taxOffice: string | null;
  taxNo: string | null;
}

interface TaxShippingOption {
  slug: string;
  name: string;
}
```

**Response Body Structure**

| Field                   | Type   | Description                                                                            |
| ----------------------- | ------ | -------------------------------------------------------------------------------------- |
| \[]                     | Array  | List of tax calculations, one entry per basket item                                    |
| \[].basketItemId        | Number | ID of the basket item this tax applies to                                              |
| \[].total               | String | Total tax amount for this line (quantity already factored in, decimal value as string) |
| \[].breakdown           | Array  | List of individual tax entries (e.g. state tax, county tax)                            |
| \[].breakdown\[].label  | String | Human-readable label for this tax entry (e.g. "CA State Tax")                          |
| \[].breakdown\[].rate   | String | Tax rate for this tax entry (0–1 scale, decimal value as string)                       |
| \[].breakdown\[].amount | String | Tax amount for this tax entry (decimal value as string)                                |

**Response Body Example**

```json
[
  {
    "basketItemId": 1,
    "total": "4.43",
    "breakdown": [
      {"label": "CA State Tax", "rate": "0.0725", "amount": "3.62"},
      {"label": "SF County Tax", "rate": "0.0100", "amount": "0.50"},
      {"label": "District Tax",  "rate": "0.0025", "amount": "0.31"}
    ]
  },
  {
    "basketItemId": 2,
    "total": "7.99",
    "breakdown": [
      {"label": "CA State Tax", "rate": "0.0725", "amount": "6.52"},
      {"label": "SF County Tax", "rate": "0.0100", "amount": "0.90"},
      {"label": "District Tax",  "rate": "0.0025", "amount": "0.57"}
    ]
  }
]
```

**Response Body (typescript interface)**

```ts
type TaxCalculateResponse = TaxCalculateItem[];

interface TaxCalculateItem {
  basketItemId: number;
  total: string;
  breakdown: TaxBreakdownItem[];
}

interface TaxBreakdownItem {
  label: string;
  rate: string;
  amount: string;
}
```

**Response Body For Errors (ALL)**

If any errors are encountered, these errors should be reported in the format below, and the list of error codes should be shared with Akinon. Commerce will log the error and continue checkout without applying tax.

* **Response Body (raw 4xx/5xx json)**

```json
{
  "errors": [
    {
      "code": "",
      "field": "",
      "message": ""
    }
  ]
}
```

* **Response Body (raw 4xx/5xx typescript interface)**

```ts
interface ErrorResponse {
  errors: ErrorItem[];
}

interface ErrorItem {
  code: string;
  field: string;
  message: string;
}
```

## <mark style="color:red;">Changelog</mark>

### Version 1.0.0

#### Added

* Initial implementation of the Tax Calculation Flow
* `tax-calculate` endpoint for per-item sales tax calculation
* HTTP Basic Auth support
* `x-akinon-request-id` header on all requests
* Dirty-check mechanism to avoid redundant microservice calls


---

# 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://apidocs.akinon.com/flows/extension-tax-flows.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.
