> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.solvimon.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server.

# Tax calculation and integrations

Solvimon calculates VAT and sales tax on every invoice, either with its own tax category rules or by delegating the calculation (and filing) to a connected tax engine: Avalara AvaTax, Anrok, or Sphere.

---

## Why this matters

Charging the wrong VAT or sales tax rate is a compliance problem, not a cosmetic one. Whether you rely on Solvimon's built-in tax categories or connect a dedicated tax engine depends on how many jurisdictions you operate in and how much of the rate lookup and filing you want to outsource.

| Provider       | Status              | Notes                                                                                 |
| -------------- | ------------------- | ------------------------------------------------------------------------------------- |
| Avalara AvaTax | Generally available | Configurable via API and Desk. Supports forwarding finalised invoices for tax filing. |
| Anrok          | Private beta        | Contact your Solvimon representative to enable it for your platform.                  |
| Sphere         | Private beta        | Contact your Solvimon representative to enable it for your platform.                  |

> **Note**
>
> Anrok and Sphere are in private beta: reach out to your Solvimon contact to get access before configuring either.

## How Solvimon and a tax provider divide the work

Once a tax calculation integration is connected, Solvimon is the system of record for the invoice; the provider is the source of truth for tax law, rates, and filing. Solvimon doesn't determine what you owe on a connected billing entity: it sends invoice data to the provider for every calculation and reflects the result back on the invoice.

**Solvimon is responsible for:**

| Area                          | Details                                                                                                                                                                              |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Providing calculation inputs  | Invoice line items, amounts, and currency; the customer's address, tax ID, and exemption status; and the tax category configured on each product, product item, or product category. |
| Presenting tax on the invoice | Applying the tax amounts returned by the provider to the correct lines and totals, and displaying the tax breakdown and the billing entity's tax ID on the invoice.                  |
| Forwarding for filing         | Sending finalised invoices to the provider for filing, when `enable_tax_filing` is on for that integration.                                                                          |

**Your tax provider is responsible for:**

| Area                          | Details                                                                                                                                  |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Tax calculation               | Determining nexus and jurisdiction obligations, and applying the correct rate per line based on the tax category or code Solvimon sends. |
| Exemptions and reverse charge | Applying exemption or reverse-charge treatment based on the customer's tax ID and exemption status.                                      |
| Filing and remittance         | Recording and reporting transactions for per-jurisdiction filing, and maintaining the audit trail tax authorities require.               |

**You are responsible for:**

| Area                  | Details                                                                                                                                                                    |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Configuration         | Mapping Solvimon's tax categories to your provider's tax codes, and using `custom_tax_codes` for line types (commitments, fallback products) that don't map automatically. |
| Customer data hygiene | Keeping customer addresses, tax IDs, and exemption status current, since Solvimon sends whatever is currently on the customer at calculation time.                         |

If no tax calculation integration is connected for a billing entity, Solvimon calculates tax itself with its native rate tables (for example, standard and reduced EU VAT rates per country) against the tax category and both parties' countries.

## What Solvimon sends and receives

Every tax provider expects a different payload shape, but the data Solvimon sends follows the same general pattern:

* **Customer identity and address** – the customer's `registered_address` (organization) or `residential_address` (individual), used to determine jurisdiction.
* **Line items** – one entry per invoice line, with its amount and the tax category (`STANDARD`, `NO_TAX`, or `EXEMPT`) configured on the product, product item, or product category.
* **Currency** – the invoice's billing currency, used for rate lookups.
* **Tax ID and exemption context** – the customer's tax ID(s) and `tax_exempt` status, so the provider can apply reverse charge or exemption logic.
* **Billing entity context** – the `company_code` linking the billing entity to your account on the provider's side.

What comes back is applied straight onto the invoice: a tax amount per line, an invoice-level total, and (where the provider returns it) rate and jurisdiction detail. Solvimon surfaces this as a **tax category summary** per invoice: base amount, tax amount, percentage, the applicable rates, and any notes (for example, a reverse-charge note). See the [invoice header report](/platform-guides/analytics-and-reporting/report-downloads/invoice-header-report#tax-summaries) for the exact fields.

## Configuring customers for tax calculation

**Address.** A customer needs a `registered_address` (organization) or `residential_address` (individual) with a country code for Solvimon, or a connected provider, to determine the applicable jurisdiction. Set it via [PATCH /v1/customers/\{id}](https://docs.solvimon.com/api-docs/configuration-api/customers/patch-customers-by-resource-id-or-reference) or from the customer details page in Desk.

**Tax-exempt customers.** Mark a customer `tax_exempt` (with an optional note explaining why) directly on the customer resource; see [tax exemption](/platform-guides/invoicing/tax#tax-exemption) for how this is configured. When a tax calculation integration is connected, the exemption status is sent along with the calculation so the provider can apply the correct treatment; if you use a provider-side exemption certificate, use the same customer identifier in both systems so it matches up.

**Customer tax IDs.** A customer's tax ID(s) are sent to the provider at calculation time, so it can determine reverse-charge eligibility for VAT-registered customers. See [validating a customer's VAT number](#validating-a-customers-vat-number) below for checking a tax ID before you save it.

## Merchant tax identifiers

A [billing entity](/platform-guides/platform-configuration/billing-entities) carries its own `tax_id`/`tax_ids`, `registration_number`, and `registered_address`, and can hold additional `tax_registrations` for jurisdictions where you're registered separately from your main entity address. These are what appear in the invoice's "sold from" details and on the PDF, and are the seller context passed to a connected provider.

## Tax on credit notes and voids

* **Credit notes** follow the normal [invoice lifecycle](/platform-guides/invoicing/invoices/invoice-lifecycle) and reach `Final`, so tax on a credit note is calculated the same way as on the invoice it credits: natively, or via whichever provider is connected to that billing entity.
* **Voids** are different: voiding is only possible on `Open` or `Draft` invoices, never `Final` ones. A voided invoice never reaches finalisation, so it never gets forwarded to a connected provider for filing.

See [credit notes](/platform-guides/invoicing/invoice-corrections/credit-invoices) for how crediting works.

## Implementation

### Via API

Connect an AvaTax integration to a billing entity:

### Request

POST [https://test.api.solvimon.com/v\{version}/integrations](https://test.api.solvimon.com/v\{version}/integrations)

**`Integrations_postIntegrations_example`**

```curl Integrations_postIntegrations_example
curl -X POST https://test.api.solvimon.com/v1/integrations \
     -H "X-API-KEY: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "reference": "stripe_us",
  "type": "PAYMENT_GATEWAY",
  "name": "Stripe (US)",
  "description": "Card and ACH payments collected by Lumen AI, Inc.",
  "status": "ACTIVE",
  "authentication": {
    "api_key": {
      "value": "sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk"
    }
  },
  "payment_gateway": {
    "variant": "STRIPE",
    "stripe": {
      "public_key": "pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa",
      "signing_secret": "whsec_9fK2mQ7xL4pR8tV1zN6bY3cH"
    }
  }
}'
```

**`Integrations_postIntegrations_example`**

```python Integrations_postIntegrations_example
import requests

url = "https://test.api.solvimon.com/v1/integrations"

payload = {
    "reference": "stripe_us",
    "type": "PAYMENT_GATEWAY",
    "name": "Stripe (US)",
    "description": "Card and ACH payments collected by Lumen AI, Inc.",
    "status": "ACTIVE",
    "authentication": { "api_key": { "value": "sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk" } },
    "payment_gateway": {
        "variant": "STRIPE",
        "stripe": {
            "public_key": "pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa",
            "signing_secret": "whsec_9fK2mQ7xL4pR8tV1zN6bY3cH"
        }
    }
}
headers = {
    "X-API-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Integrations_postIntegrations_example`**

```javascript Integrations_postIntegrations_example
const url = 'https://test.api.solvimon.com/v1/integrations';
const options = {
  method: 'POST',
  headers: {'X-API-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"reference":"stripe_us","type":"PAYMENT_GATEWAY","name":"Stripe (US)","description":"Card and ACH payments collected by Lumen AI, Inc.","status":"ACTIVE","authentication":{"api_key":{"value":"sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk"}},"payment_gateway":{"variant":"STRIPE","stripe":{"public_key":"pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa","signing_secret":"whsec_9fK2mQ7xL4pR8tV1zN6bY3cH"}}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Integrations_postIntegrations_example`**

```go Integrations_postIntegrations_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://test.api.solvimon.com/v1/integrations"

	payload := strings.NewReader("{\n  \"reference\": \"stripe_us\",\n  \"type\": \"PAYMENT_GATEWAY\",\n  \"name\": \"Stripe (US)\",\n  \"description\": \"Card and ACH payments collected by Lumen AI, Inc.\",\n  \"status\": \"ACTIVE\",\n  \"authentication\": {\n    \"api_key\": {\n      \"value\": \"sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk\"\n    }\n  },\n  \"payment_gateway\": {\n    \"variant\": \"STRIPE\",\n    \"stripe\": {\n      \"public_key\": \"pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa\",\n      \"signing_secret\": \"whsec_9fK2mQ7xL4pR8tV1zN6bY3cH\"\n    }\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-API-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Integrations_postIntegrations_example`**

```ruby Integrations_postIntegrations_example
require 'uri'
require 'net/http'

url = URI("https://test.api.solvimon.com/v1/integrations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"reference\": \"stripe_us\",\n  \"type\": \"PAYMENT_GATEWAY\",\n  \"name\": \"Stripe (US)\",\n  \"description\": \"Card and ACH payments collected by Lumen AI, Inc.\",\n  \"status\": \"ACTIVE\",\n  \"authentication\": {\n    \"api_key\": {\n      \"value\": \"sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk\"\n    }\n  },\n  \"payment_gateway\": {\n    \"variant\": \"STRIPE\",\n    \"stripe\": {\n      \"public_key\": \"pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa\",\n      \"signing_secret\": \"whsec_9fK2mQ7xL4pR8tV1zN6bY3cH\"\n    }\n  }\n}"

response = http.request(request)
puts response.read_body
```

**`Integrations_postIntegrations_example`**

```java Integrations_postIntegrations_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://test.api.solvimon.com/v1/integrations")
  .header("X-API-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"reference\": \"stripe_us\",\n  \"type\": \"PAYMENT_GATEWAY\",\n  \"name\": \"Stripe (US)\",\n  \"description\": \"Card and ACH payments collected by Lumen AI, Inc.\",\n  \"status\": \"ACTIVE\",\n  \"authentication\": {\n    \"api_key\": {\n      \"value\": \"sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk\"\n    }\n  },\n  \"payment_gateway\": {\n    \"variant\": \"STRIPE\",\n    \"stripe\": {\n      \"public_key\": \"pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa\",\n      \"signing_secret\": \"whsec_9fK2mQ7xL4pR8tV1zN6bY3cH\"\n    }\n  }\n}")
  .asString();
```

**`Integrations_postIntegrations_example`**

```php Integrations_postIntegrations_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://test.api.solvimon.com/v1/integrations', [
  'body' => '{
  "reference": "stripe_us",
  "type": "PAYMENT_GATEWAY",
  "name": "Stripe (US)",
  "description": "Card and ACH payments collected by Lumen AI, Inc.",
  "status": "ACTIVE",
  "authentication": {
    "api_key": {
      "value": "sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk"
    }
  },
  "payment_gateway": {
    "variant": "STRIPE",
    "stripe": {
      "public_key": "pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa",
      "signing_secret": "whsec_9fK2mQ7xL4pR8tV1zN6bY3cH"
    }
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-API-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Integrations_postIntegrations_example`**

```csharp Integrations_postIntegrations_example
using RestSharp;

var client = new RestClient("https://test.api.solvimon.com/v1/integrations");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"reference\": \"stripe_us\",\n  \"type\": \"PAYMENT_GATEWAY\",\n  \"name\": \"Stripe (US)\",\n  \"description\": \"Card and ACH payments collected by Lumen AI, Inc.\",\n  \"status\": \"ACTIVE\",\n  \"authentication\": {\n    \"api_key\": {\n      \"value\": \"sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk\"\n    }\n  },\n  \"payment_gateway\": {\n    \"variant\": \"STRIPE\",\n    \"stripe\": {\n      \"public_key\": \"pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa\",\n      \"signing_secret\": \"whsec_9fK2mQ7xL4pR8tV1zN6bY3cH\"\n    }\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Integrations_postIntegrations_example`**

```swift Integrations_postIntegrations_example
import Foundation

let headers = [
  "X-API-KEY": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "reference": "stripe_us",
  "type": "PAYMENT_GATEWAY",
  "name": "Stripe (US)",
  "description": "Card and ACH payments collected by Lumen AI, Inc.",
  "status": "ACTIVE",
  "authentication": ["api_key": ["value": "sk_test_51Q0LumenAIexampleKey4f8ZqYc2Rk"]],
  "payment_gateway": [
    "variant": "STRIPE",
    "stripe": [
      "public_key": "pk_test_51Q0LumenAIexampleKey7Hn3Lw9Xa",
      "signing_secret": "whsec_9fK2mQ7xL4pR8tV1zN6bY3cH"
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://test.api.solvimon.com/v1/integrations")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response (201)

```json
{
  "object_type": "string",
  "id": "string",
  "reference": "string",
  "name": "string",
  "description": "string",
  "status": "DRAFT",
  "message": "string",
  "type": "PAYMENT_GATEWAY",
  "variant": "DEFAULT",
  "paragon_settings": {
    "paragon_external_id": "string"
  },
  "authentication": {
    "api_key": {
      "header": "string",
      "value": "string"
    },
    "client_credentials": {
      "client_id": "string",
      "client_secret": "string"
    },
    "username_password": {
      "username": "string",
      "password": "string"
    }
  },
  "payment_gateway": {
    "variant": "ADYEN",
    "adyen": {
      "company_account": "string",
      "environment": "LIVE",
      "live_prefix": "string",
      "merchant_accounts": [
        "string"
      ],
      "public_key": "string",
      "signing_secret": "string",
      "ownership": "PLATFORM",
      "system_ownership_details": {
        "account_holder_id": "string",
        "balance_account_id": "string",
        "legal_entity_id": "string",
        "store_id": "string"
      },
      "balance_platform_details": {
        "account": "string",
        "authentication": {
          "api_key": {
            "header": "string",
            "value": "string"
          },
          "client_credentials": {
            "client_id": "string",
            "client_secret": "string"
          },
          "username_password": {
            "username": "string",
            "password": "string"
          }
        }
      },
      "legal_entity_manager_details": {
        "authentication": {
          "api_key": {
            "header": "string",
            "value": "string"
          },
          "client_credentials": {
            "client_id": "string",
            "client_secret": "string"
          },
          "username_password": {
            "username": "string",
            "password": "string"
          }
        }
      },
      "enabled_payment_methods": [
        "string"
      ]
    },
    "stripe": {
      "public_key": "string",
      "signing_secret": "string"
    }
  },
  "e_invoicing": {
    "mandates": [
      {
        "name": "string",
        "country": "string",
        "mappings": [
          {
            "target": "string",
            "source": "string",
            "description": "string"
          }
        ],
        "condition_groups": [
          {
            "conditions": [
              {
                "field": "string",
                "comparator_type": "EQUALS",
                "value": "string"
              }
            ]
          }
        ],
        "include_pdf_in_einvoice": true,
        "supported_file_formats": [
          {
            "type": "string",
            "description": "string"
          }
        ]
      }
    ],
    "processor": "AVALARA"
  },
  "data_export": {
    "variant": "S3",
    "s3": {
      "bucket_name": "string",
      "bucket_path": "string",
      "bucket_region": "string",
      "authentication_type": "ACCESS_KEY_AND_SECRET",
      "role_arn": "string",
      "external_id": "string"
    },
    "bigquery": {
      "project_id": "string",
      "dataset_id": "string",
      "dataset_location": "string",
      "gcs_bucket_name": "string",
      "gcs_hmac_key_access_id": "string",
      "gcs_hmac_key_secret": "string"
    },
    "gcs": {
      "bucket_region": "string",
      "bucket_name": "string",
      "bucket_path": "string",
      "flattening": true
    },
    "snowflake": {
      "host": "string",
      "role": "string",
      "warehouse": "string",
      "database": "string",
      "schema": "string"
    },
    "transport_type": "string"
  },
  "tax_calculation": {
    "billing_entity_id": "string",
    "variant": "AVATAX",
    "ava_tax": {
      "company_code": "string"
    },
    "custom_tax_codes": [
      {
        "field": "INVOICE_COMMITMENT",
        "value": "string"
      }
    ],
    "enable_tax_filing": true
  },
  "linked_resources_configurations": [
    {
      "resource_type": "string",
      "link_details": [
        {
          "base_url": "string",
          "custom_field_reference": "string"
        }
      ]
    }
  ],
  "email_provider": {
    "variant": "SYSTEM",
    "mailgun": {
      "domain": "string",
      "region": "US",
      "plan": "string"
    },
    "delivery_window": {
      "type": "DAY",
      "value": 1
    }
  },
  "erp": {
    "variant": "XERO"
  }
}
```

| Field                                  | Description                                                                                                                                                      |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                                 | Set to `TAX_CALCULATION`.                                                                                                                                        |
| `tax_calculation.variant`              | `AVATAX` is the only variant currently exposed via the API; Anrok and Sphere are enabled by Solvimon during private beta onboarding.                             |
| `tax_calculation.ava_tax.company_code` | Links the billing entity to the corresponding company in your AvaTax account.                                                                                    |
| `tax_calculation.enable_tax_filing`    | When `true`, finalised invoices are also sent to AvaTax for tax filing, not just rate calculation.                                                               |
| `tax_calculation.custom_tax_codes`     | Optional overrides that map specific line types (`INVOICE_COMMITMENT`, `PRODUCT_FALLBACK`) to a tax code, for cases the automatic product mapping doesn't cover. |

Once the integration is `ACTIVE`, invoices for that billing entity are calculated through AvaTax automatically; no per-invoice configuration is needed.

### Validating a customer's VAT number

Validate a tax ID before saving it on a customer, so invalid EU VAT numbers don't slip through:

**`Validate an EU VAT number`**

```bash Validate an EU VAT number
curl -X POST https://test.api.solvimon.com/v1/customers/validate-tax-id \
  -H "X-API-KEY: <apiKey>" \
  -H "Content-Type: application/json" \
  -d '{
    "object_type": "CUSTOMER",
    "type": "ORGANIZATION",
    "organization": {
      "legal_name": "SuperStore GmbH",
      "tax_ids": [
        { "id": "NL123456789B01", "type": "ORGANIZATION" }
      ],
      "registered_address": { "country": "NL" }
    }
  }'
```

**`Response`**

```json Response
{
  "data": [
    {
      "id": "NL123456789B01",
      "valid": "VALID",
      "source": "VIES",
      "validation_date": "2026-07-24T10:00:00Z"
    }
  ]
}
```

For EU tax IDs, Solvimon checks validity against [VIES](https://ec.europa.eu/taxation_customs/vies/), the EU's VAT Information Exchange System. `valid` is `VALID`, `NOT_VALID`, or `UNKNOWN` – `UNKNOWN` is returned when VIES is unreachable or the tax ID's country doesn't support automated lookup, so treat it as "couldn't confirm" rather than "invalid".

To check which tax ID types are accepted for a given country before submitting one, use [GET /v1/tax-id-types](https://docs.solvimon.com/api-docs/configuration-api/tax-id-types/get-tax-id-types):

**`Get allowed tax id types for Canada. Omit the country parameter to get all countries.`**

```bash Get allowed tax id types for Canada. Omit the country parameter to get all countries.
curl -G https://test.api.solvimon.com/v1/tax-id-types \
  -H "X-API-KEY: <apiKey>" \
  --data-urlencode "country=CA"
```

### Via Desk

Configure a tax calculation integration from **Settings → Integrations → Add integration**, selecting the tax provider and entering its credentials. Tax categories, customer exemptions, and US sales tax percentages are configured as described in the [Tax overview](/platform-guides/invoicing/tax).

## Edge cases

* Connecting an external tax engine to a billing entity doesn't remove the need to set tax categories: providers like AvaTax still expect a product tax code, so map your product categories to the provider's codes (or use `custom_tax_codes` for line types with no direct product mapping).
* Reverse-charge and exemption treatment is applied by the provider, based on the tax ID and exemption status Solvimon sends; Solvimon itself doesn't decide reverse-charge eligibility once a provider is connected.
* If a tax ID fails VIES validation, the invoice still generates. Validation is a check you run before saving a tax ID; it doesn't block invoicing on its own.
* Voided invoices never reach `Final`, so they're never forwarded to a connected provider for filing; credited invoices do reach `Final` again and are filed the same way as any other finalised invoice.

---