# External tax calculators

Commerce Layer supports automatic tax calculation thanks to the out-of-the-box integration with [Avalara](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/avalara_accounts), [Stripe Tax](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/stripe_tax_accounts), [TaxJar](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/taxjar_accounts), and [Vertex](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/vertex_accounts). [Manual tax calculators](https://docs.commercelayer.io/developers/v/api-reference/manual_tax_calculators) can be also configured. On top of that, you also have the complete flexibility to implement any particular custom tax calculation logic building your own [external tax calculator](https://docs.commercelayer.io/developers/v/api-reference/external_tax_calculators).

Whenever the tax calculation is fired, Commerce Layer triggers a `POST` request to the `tax_calculator_url` endpoint, sending the order payload (including its line items and their items) in the request body. To trigger the tax update, the order must be not archived and have the following attributes:

* a valid `shipping_address` or a valid `billing_address`
* an `external_tax_calculator` associated with the market in scope
* a positive `total_amount_cent`
* at least one SKU among its line item (gift cards are not taxed)

### Taxes data granularity

External taxes can be applied either to the whole order or to specific line items, depending on how granular your response is. If you need to pass tax values at the line item level and set tax breakdown attributes, you need to include in the response an array containing the line items you want to be affected by the tax update and specify each line item ID, as the payload passed in the request to your external calculator.

### Values precedence

When designing your external tax calculator response, bear in mind that some values take precedence over other ones, according to the following logic.

#### 1. Line item tax collectable

If the `tax_collectable` attribute is specified for a line item, its value is used to compute the `tax_amount_cents` for the line item, no matter what's the value of the line item `tax_rate` (if any).

{% hint style="info" %}
The `tax_collectable` attribute is a `float` (e.g. `"tax_collectable": 9.0` sets the line item `tax_amount_cents` to 900).
{% endhint %}

#### 2. Line item tax rate

If the `tax_collectable` is missing for a line item, the line item `tax_amount_cents` is computed using the line item `tax_rate`.

#### 3. Global tax rate

If both the line item `tax_collectable` and `tax_rate` are missing, the line item `tax_amount_cents` is computed using the `tax_rate` specified at the `data` level. If the line items array is missing, that tax rate is applied to the whole order.

### Request

The request payload is a [JSON:API](https://jsonapi.org/) compliant object you can query to perform your own computation. Aside from the **target resource** — `orders` in the specific case — some **relationships** are also included to avoid useless API roundtrips:

* `market`
* `customer`
* `line_items`
* `line_items.item`
* `shipping_address`
* `billing_address`

<pre class="language-json"><code class="lang-json">{
  "data": {
    "id": "wBXVhKzrnq",
<strong>    "type": "orders",
</strong>    "links": { ... },
    "attributes": { ... },
    "relationships": { ... },
    "meta": { ... }
  },
  "included": [
    {
      "id": "DvlGRmhdgX",
<strong>      "type": "markets",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "DHvfpESrCx",
<strong>      "type": "customers",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "kdPgtRXOKL",
<strong>      "type": "line_items",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "XGZwpOSrWL",
<strong>      "type": "skus",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "BgnguJvXmb",
<strong>      "type": "addresses",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "AlrkugwyVW",
<strong>      "type": "addresses",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    { ... }
  ]
}
</code></pre>

{% hint style="info" %}
If needed, you can [overwrite the default list](https://docs.commercelayer.io/core/external-resources/..#custom-include-list) of included resources by passing your custom list of order's relationships within the `external_includes` attribute of the external tax calculator at creation or update time (nested relationships are allowed using dot notation).
{% endhint %}

{% hint style="warning" %}
In case the call to your external endpoint goes timeout, responds with an internal server error, or is blocked by the open [circuit breaker](https://docs.commercelayer.io/core/external-resources/..#circuit-breaker), the API keeps responding with a `200 OK` status code. No tax amount is updated on the order and the circuit breaker internal counter (if closed) is incremented.
{% endhint %}

### Response

Your service response (or error) must match the format described in the examples below.

#### Applying the same tax rate to the whole order

{% tabs %}
{% tab title="Response" %}
The successful response must be a JSON object, returning at least the tax rate to be applied to the whole order. If needed, you can optionally enrich the response with some additional information, notification messages, and metadata:

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
<strong>    "tax_rate": 0.25,
</strong>    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response body must be a JSON object containing any other relevant error code and message:

```json
{
  "success": false,
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

#### Applying different tax rates for some line items

{% tabs %}
{% tab title="Response" %}
The successful response must be a JSON object, returning at least the specific tax rate to be applied to the line items. If needed, you can optionally enrich the response with some additional information, notification messages, and metadata:

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
<strong>    "tax_rate": 0.25,
</strong>    "line_items": [
      {
<strong>        "id": "kxnXtEaGxo",
</strong><strong>        "tax_rate": 0.3
</strong>      },
      {
<strong>        "id": "kXBqtrgARW",
</strong><strong>        "tax_rate": 0.4
</strong>      }
    ],
    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response body must be a JSON object containing any other relevant error code and message:

```json
{
  "success": false,
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

#### More complex external tax calculations affecting the tax breakdown

{% tabs %}
{% tab title="Response" %}
The successful response must be a JSON object, returning at least specific tax collectable and tax rate values to be applied to the line items, and some attributes you want to set in the line items tax breakdown. If needed, you can optionally enrich the response with some additional information, notification messages, and metadata:

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
<strong>    "freight_taxable": true,
</strong><strong>    "tax_rate": 0.25,
</strong>    "line_items": [
      {
<strong>        "id": "kxnXtEaGxo",
</strong><strong>        "tax_collectable": 2.25,
</strong><strong>        "country_tax_collectable": 9,
</strong><strong>        "country_tax_rate": 0.2,
</strong><strong>        "country_taxable_amount": 9,
</strong><strong>        "special_tax_rate": 0.05,
</strong><strong>        "taxable_amount": 10,
</strong><strong>        "tax_rate": 0.4
</strong>      },
      {
<strong>        "id": "kXBqtrgARW",
</strong><strong>        "taxable_amount": 12,
</strong><strong>        "tax_rate": 0.3
</strong>      }
    ],
    "messages": [ ... ]
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response body must be a JSON object containing any other relevant error code and message:

```json
{
  "success": false,
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If you specify the `messages` key a [notification](https://docs.commercelayer.io/core/external-resources/..#notifications) with the related information is automatically attached to the associated order.
{% endhint %}

### Security

When you create a new external tax calculator, a **shared secret** is generated. We recommend verifying the callback authenticity by signing the payload with that shared secret and comparing the result with the callback signature header.

{% content-ref url="../callbacks-security" %}
[callbacks-security](https://docs.commercelayer.io/core/callbacks-security)
{% endcontent-ref %}
