Sales tax
GET /v1/entities/{entity}/customers/{party}/sales-tax
Get a customer's tax area and exemption
The customer's state, tax area and exemption certificate, and whether it is valid today.
| Required scope | read (admin implies every scope) |
| Operation id | get_customer_v1_entities__entity__customers__party__sales_tax_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | party |
string | yes | Customer code, e.g. C-DE, or its id. A vendor is not a customer: its statement is GET .../vendors/{party}/statement. |
Example request
curl "$ERP_URL/v1/entities/CH01/customers/C-DE/sales-tax" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxCustomerOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"party": "string",
"state": "string",
"area": "string",
"area_name": "string",
"exemption_number": "string",
"exemption_reason": "government",
"exempt_from": "2026-09-21",
"exempt_until": "2026-09-21",
"exempt_states": [
"string"
],
"exempt_today": true
}
PUT /v1/entities/{entity}/customers/{party}/sales-tax
Set a customer's tax area and exemption
Replaces the customer's tax area (one of its state) and exemption certificate: with a
certificate valid on a document's day, the customer is charged no sales tax. Needs the policy
action change_party_details, which agents are always denied (403).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | put_customer_v1_entities__entity__customers__party__sales_tax_put |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | party |
string | yes | Customer code, e.g. C-DE, or its id. A vendor is not a customer: its statement is GET .../vendors/{party}/statement. |
Request body
application/json (required): SalesTaxCustomerInput
| Field | Type | Required | Description |
|---|---|---|---|
area |
string or null | The tax area of the customer's location (its code), or null. | |
exemption_number |
string or null | The exemption certificate's number, or null. (max length 60) | |
exemption_reason |
"government" | "manufacturing" | "nonprofit" | "other" | "resale" or null |
Why it is exempt: resale, nonprofit, government, manufacturing or other; required with a number. |
|
exempt_from |
string (date) or null | The first day the certificate is valid; with a number, the day it is recorded when omitted. | |
exempt_until |
string (date) or null | The certificate's expiry; null when it does not expire. | |
exempt_states |
array of string or null | The states the certificate is valid in (e.g. a multistate certificate); with a number, the customer's own state when omitted. |
Example request
curl -X PUT "$ERP_URL/v1/entities/CH01/customers/C-DE/sales-tax" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"area": "LOS-ANGELES",
"exempt_from": "2026-01-01",
"exempt_states": [
"US-CA"
],
"exempt_until": "2027-12-31",
"exemption_number": "SR-FH-123456",
"exemption_reason": "resale"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxCustomerOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"party": "string",
"state": "string",
"area": "string",
"area_name": "string",
"exemption_number": "string",
"exemption_reason": "government",
"exempt_from": "2026-09-21",
"exempt_until": "2026-09-21",
"exempt_states": [
"string"
],
"exempt_today": true
}
GET /v1/entities/{entity}/sales-tax
Get the sales tax setup
A US company's states it is registered in (with each state's liability account and what
it owes now), its jurisdictions and their rates (the one in force on on), its tax areas
with their combined rates, and the product taxability it recorded per state. applies is
false for a company outside the US, which charges VAT.
| Required scope | read (admin implies every scope) |
| Operation id | get_setup_v1_entities__entity__sales_tax_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| query | on |
string (date) or null | The day the rates in force are shown for; default today. |
Example request
curl "$ERP_URL/v1/entities/CH01/sales-tax" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxSetupOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"applies": true,
"on": "2026-09-21",
"categories": [
"clothing"
],
"registrations": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"state_name": "string",
"permit_number": "string",
"registered_from": "2026-09-21",
"registered_until": "2026-09-21",
"filing_frequency": "month",
"account": "string",
"account_name": "string",
"use_tax_area": "string",
"balance": "string"
}
],
"jurisdictions": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"level": "city",
"rate": "string",
"rates": [
null
]
}
],
"areas": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"jurisdictions": [
"string"
],
"combined_rate": "string"
}
],
"rules": [
{
"state": "string",
"category": "clothing",
"taxable_percent": "string",
"note": "string"
}
]
}
POST /v1/entities/{entity}/sales-tax/areas
Add a tax area
A place's local jurisdictions (county, city, districts) on top of its state; a customer located there gets the area. Answers 422 for a jurisdiction of another state.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | add_area_v1_entities__entity__sales_tax_areas_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
Request body
application/json (required): SalesTaxAreaInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
code |
string or null | A code of its own, e.g. LOS-ANGELES. Omitted: made from the name (capitals, digits and hyphens, with -2 when taken). (pattern ^[A-Z0-9][A-Z0-9-]{0,39}$) |
|
name |
string | yes | Its name. (min length 1; max length 120) |
jurisdictions |
array of string | yes | The codes of its local jurisdictions (county, city, district) in the same state; the state's own rate always applies on top. (max items 20) |
Example request
curl -X POST "$ERP_URL/v1/entities/CH01/sales-tax/areas" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "LOS-ANGELES",
"jurisdictions": [
"CA-LA-DIST"
],
"name": "City of Los Angeles",
"state": "US-CA"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | SalesTaxAreaOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"jurisdictions": [
"string"
],
"combined_rate": "string"
}
PATCH /v1/entities/{entity}/sales-tax/areas/{area}
Change a tax area
Renames the area or replaces its local jurisdictions; documents dated from now on use it.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | update_area_v1_entities__entity__sales_tax_areas__area__patch |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | area |
string | yes | A tax area's code, e.g. LOS-ANGELES. |
Request body
application/json (required): SalesTaxAreaUpdate
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | New name. (min length 1; max length 120) | |
jurisdictions |
array of string or null | The codes of its local jurisdictions. (max items 20) |
Example request
curl -X PATCH "$ERP_URL/v1/entities/CH01/sales-tax/areas/{area}" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"jurisdictions": [
"CA-LA-DIST"
]
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxAreaOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"jurisdictions": [
"string"
],
"combined_rate": "string"
}
PUT /v1/entities/{entity}/sales-tax/category-rules
Set how much of a product category a state taxes
taxable_percent of the price of products of category is taxed in state: 0
exempt, 100 (also when nothing is recorded) fully taxed.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | set_rule_v1_entities__entity__sales_tax_category_rules_put |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
Request body
application/json (required): SalesTaxCategoryRuleInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state. (pattern ^US-[A-Z]{2}$) |
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product category. |
taxable_percent |
decimal string | yes | How much of the price the state taxes: 0 exempt, 100 fully taxed, 80 for Texas data processing. (min 0; max 100) |
note |
string or null | Why, e.g. the statute. (max length 300) |
Example request
curl -X PUT "$ERP_URL/v1/entities/CH01/sales-tax/category-rules" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"category": "saas",
"state": "US-TX",
"taxable_percent": "80"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxCategoryRuleOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"state": "string",
"category": "clothing",
"taxable_percent": "string",
"note": "string"
}
POST /v1/entities/{entity}/sales-tax/jurisdictions
Add a county, city or district
A local jurisdiction of a state with its first rate; a tax area names it to charge it. Answers 409 when the code is taken.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | add_jurisdiction_v1_entities__entity__sales_tax_jurisdictions_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
Request body
application/json (required): SalesTaxJurisdictionInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state it lies in, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
code |
string or null | A code of its own, e.g. CA-LA-DIST. Omitted: made from the name (capitals, digits and hyphens, with -2 when taken). (pattern ^[A-Z0-9][A-Z0-9-]{0,39}$) |
|
name |
string | yes | Its name. (min length 1; max length 120) |
level |
"city" | "county" | "district" |
yes | county, city or district. |
rate |
decimal string | yes | Its rate in percent. (min 0) |
valid_from |
string (date) | yes | The first day of the rate. |
Example request
curl -X POST "$ERP_URL/v1/entities/CH01/sales-tax/jurisdictions" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "CA-LA-DIST",
"level": "district",
"name": "Los Angeles County district taxes",
"rate": "2.5",
"state": "US-CA",
"valid_from": "2025-04-01"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | SalesTaxJurisdictionOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"level": "city",
"rate": "string",
"rates": [
{
"valid_from": "2026-09-21",
"rate": "string",
"source": "string"
}
]
}
POST /v1/entities/{entity}/sales-tax/jurisdictions/{jurisdiction}/rates
Set a jurisdiction's rate from a day
A new rate from valid_from for documents dated on or after it (a rate of the same day
is replaced); posted documents keep the rates they were charged at.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | set_rate_v1_entities__entity__sales_tax_jurisdictions__jurisdiction__rates_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | jurisdiction |
string | yes | A jurisdiction's code, e.g. CA-LA-DIST. |
Request body
application/json (required): SalesTaxRateInput
| Field | Type | Required | Description |
|---|---|---|---|
valid_from |
string (date) | yes | The first day of the rate; a rate of the same day is replaced. |
rate |
decimal string | yes | The rate in percent. (min 0) |
source |
string or null | Where it comes from, e.g. the state's notice. (max length 500) |
Example request
curl -X POST "$ERP_URL/v1/entities/CH01/sales-tax/jurisdictions/{jurisdiction}/rates" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"rate": "7.5",
"valid_from": "2027-01-01"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxJurisdictionOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"code": "string",
"name": "string",
"level": "city",
"rate": "string",
"rates": [
{
"valid_from": "2026-09-21",
"rate": "string",
"source": "string"
}
]
}
GET /v1/entities/{entity}/sales-tax/periods
List the sales tax return periods of a year
Each registration's periods of the year that have started, with the tax from the ledger
and their state (open, to_file, due_soon, overdue, awaiting_approval, filed,
paid) with the day each return is due, and the year's sales into states the
company is not registered in.
| Required scope | read (admin implies every scope) |
| Operation id | list_periods_v1_entities__entity__sales_tax_periods_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| query | year |
integer | yes | The calendar year. (min 2000; max 2100) |
Example request
curl "$ERP_URL/v1/entities/CH01/sales-tax/periods?year=value" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxPeriodsOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"year": 1,
"currency": "string",
"periods": [
{
"state": "string",
"state_name": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"tax": "string",
"tax_due": "string",
"filed_on": "2026-09-21",
"return_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"unregistered": [
{
"state": "string",
"state_name": "string",
"sales": "string",
"documents": 1
}
]
}
POST /v1/entities/{entity}/sales-tax/registrations
Register the company in a state
Records that the company is registered for sales tax in a state from a day (nexus): from
then on its sales to customers in that state are taxed. Creates the state's liability account
(2200-CA, under the company's sales tax payable) and the state's jurisdiction at the state
rate (state_rate, else the base rate data-vNext has). Answers 409 when already registered,
422 for a company outside the US (sales_tax_not_us) or a state data-vNext has no rate for
and none was given (sales_tax_state_rate_unknown). Needs the policy action
manage_accounts.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | register_v1_entities__entity__sales_tax_registrations_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
Request body
application/json (required): SalesTaxRegistrationInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, ISO 3166-2, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
permit_number |
string or null | The state's seller's permit or account number. (max length 60) | |
registered_from |
string (date) | yes | The first day tax is charged in the state. |
registered_until |
string (date) or null | The last day, when the registration ended; null while in force. | |
filing_frequency |
"month" | "quarter" | "year" |
yes | How often the state's return is filed: month, quarter or year. |
state_rate |
decimal string or null | The state rate in percent, from registered_from. Omit to take the state base rate data-vNext has (422 sales_tax_state_rate_unknown when it has none). Ignored when the state already has its jurisdiction. (min 0) |
|
use_tax_area |
string or null | In the company's own state: the tax area (its code) where it uses what it buys, whose local rates its use tax is self-assessed at; null for the state rate only. |
Example request
curl -X POST "$ERP_URL/v1/entities/CH01/sales-tax/registrations" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"filing_frequency": "quarter",
"permit_number": "102-345678",
"registered_from": "2026-01-01",
"state": "US-CA"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | SalesTaxRegistrationOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"state_name": "string",
"permit_number": "string",
"registered_from": "2026-09-21",
"registered_until": "2026-09-21",
"filing_frequency": "month",
"account": "string",
"account_name": "string",
"use_tax_area": "string",
"balance": "string"
}
PATCH /v1/entities/{entity}/sales-tax/registrations/{state}
Change a state registration
Changes the permit number, the last day (registered_until: no tax is charged in the
state after it) or the filing frequency. Only the fields sent change.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | update_registration_v1_entities__entity__sales_tax_registrations__state__patch |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | state |
string | yes | The state, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
Request body
application/json (required): SalesTaxRegistrationUpdate
| Field | Type | Required | Description |
|---|---|---|---|
permit_number |
string or null | The state's permit number. (max length 60) | |
registered_until |
string (date) or null | The last day of the registration; null while in force. | |
filing_frequency |
"month" | "quarter" | "year" or null |
How often it files; not changed once a return is recorded as filed (409 sales_tax_frequency_filed). |
|
use_tax_area |
string or null | The use tax area's code; null for the state rate only. |
Example request
curl -X PATCH "$ERP_URL/v1/entities/CH01/sales-tax/registrations/{state}" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"registered_until": "2026-12-31"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxRegistrationOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"state": "string",
"state_name": "string",
"permit_number": "string",
"registered_from": "2026-09-21",
"registered_until": "2026-09-21",
"filing_frequency": "month",
"account": "string",
"account_name": "string",
"use_tax_area": "string",
"balance": "string"
}
POST /v1/entities/{entity}/sales-tax/returns
Record a sales tax return as filed
Records that the state's return for the period was filed with the state on filed_on,
with the state's confirmation number, and keeps the figures as they are now; a second person
approves the record (POST /v1/sales-tax-returns/{id}/approve). Nothing is sent:
the application files no return, and in a test copy (test_copy) the record is local only.
Answers 409 when already recorded (withdraw it first), 422 for a day in the future or in the
period. A person's act: needs the policy action finalize_vat_return, which agents are
always denied (403).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | file_return_v1_entities__entity__sales_tax_returns_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
Request body
application/json (required): SalesTaxFileInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, e.g. US-TX. (pattern ^US-[A-Z]{2}$) |
period |
string | yes | The period by the registration's frequency: 2026-08, 2026-Q3, 2026. (pattern `^\d{4}(-(0[1-9] |
filed_on |
string (date) | yes | The day it was filed with the state: after the period, not in the future. |
confirmation |
string or null | The state's confirmation number. Optional. (max length 200) |
Example request
curl -X POST "$ERP_URL/v1/entities/CH01/sales-tax/returns" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"confirmation": "TX-0918-55821",
"filed_on": "2026-09-18",
"period": "2026-08",
"state": "US-TX"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
GET /v1/entities/{entity}/sales-tax/returns/{state}/{period}
Get a state's sales tax return
The state's return for the period from the posted journal lines: gross, exempt and taxable sales, the tax by jurisdiction, the check against the state's account, and the filing with its payments when recorded. Answers 422 for a period not of the state's filing frequency.
| Required scope | read (admin implies every scope) |
| Operation id | get_return_v1_entities__entity__sales_tax_returns__state___period__get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | entity |
string | yes | Entity code, e.g. CH01 (GET /v1/entities). |
| path | state |
string | yes | The state, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
| path | period |
string | yes | 2026-08, 2026-Q3 or 2026, by the state's filing frequency. (pattern `^\d{4}(-(0[1-9] |
Example request
curl "$ERP_URL/v1/entities/CH01/sales-tax/returns/{state}/{period}" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
GET /v1/products/{product_id}/sales-tax
Get a product's sales tax category
The product's category; general when none was set.
| Required scope | read (admin implies every scope) |
| Operation id | get_product_v1_products__product_id__sales_tax_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | product_id |
string (uuid) | yes | Id of the product (GET /v1/products). |
Example request
curl "$ERP_URL/v1/products/{product_id}/sales-tax" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxProductOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"product": "string",
"category": "clothing"
}
PUT /v1/products/{product_id}/sales-tax
Set a product's sales tax category
The product's category, which decides with the state's rules how much of its price is
taxed. Needs the admin scope and the policy action manage_accounts.
| Required scope | admin (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | put_product_v1_products__product_id__sales_tax_put |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | product_id |
string (uuid) | yes | Id of the product (GET /v1/products). |
Request body
application/json (required): SalesTaxProductInput
| Field | Type | Required | Description |
|---|---|---|---|
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product's sales tax category. |
Example request
curl -X PUT "$ERP_URL/v1/products/{product_id}/sales-tax" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"category": "saas"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxProductOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"product": "string",
"category": "clothing"
}
POST /v1/sales-tax-returns/{sales_tax_return_id}/approve
Approve a sales tax filing
A second person approves the filing recorded by someone else (403 for whoever recorded
it, under the separation-of-duties rule finalize_own_vat_return); only an approved filing
is paid. Answers 409 when already approved or withdrawn. A person's act
(finalize_vat_return).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | approve_v1_sales_tax_returns__sales_tax_return_id__approve_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | sales_tax_return_id |
string (uuid) | yes | Id of a filed sales tax return. |
Example request
curl -X POST "$ERP_URL/v1/sales-tax-returns/{sales_tax_return_id}/approve" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
GET /v1/sales-tax-returns/{sales_tax_return_id}/payment-candidates
List the entries that may have paid a sales tax return
Posted entries of the company dated after the period, with a debit on the state's account that is no sales tax posting, not linked to a return yet: typically the bank entry made by matching the state's debit on the bank worksheet.
| Required scope | read (admin implies every scope) |
| Operation id | payment_candidates_v1_sales_tax_returns__sales_tax_return_id__payment_candidates_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | sales_tax_return_id |
string (uuid) | yes | Id of a filed sales tax return. |
Example request
curl "$ERP_URL/v1/sales-tax-returns/{sales_tax_return_id}/payment-candidates" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | array of SalesTaxPaymentCandidate |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
[
{
"journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"entry_number": "string",
"entry_date": "2026-09-21",
"description": "string",
"source": "string",
"amount": "string"
}
]
POST /v1/sales-tax-returns/{sales_tax_return_id}/payments
Link the entry that paid a sales tax return
Links a posted entry as paying the filed return: its amount is its debit on the state's
account. The return is paid once the links cover tax_due. Answers 409 for a withdrawn
filing or an entry already linked, 422 for an entry of another company, not posted, dated in
the period or without a debit on the account. A person's act (finalize_vat_return).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | link_payment_v1_sales_tax_returns__sales_tax_return_id__payments_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | sales_tax_return_id |
string (uuid) | yes | Id of a filed sales tax return. |
Request body
application/json (required): SalesTaxPaymentInput
| Field | Type | Required | Description |
|---|---|---|---|
journal_entry_id |
string (uuid) | yes | The posted entry that paid the state: of the return's company, dated after the period, with a debit on the state's account (GET .../payment-candidates). |
Example request
curl -X POST "$ERP_URL/v1/sales-tax-returns/{sales_tax_return_id}/payments" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
POST /v1/sales-tax-returns/{sales_tax_return_id}/payments/{sales_tax_payment_id}/unlink
Unlink a payment from a sales tax return
Undoes a payment link made by mistake, with the reason; the entry stays posted. A
person's act (finalize_vat_return).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | unlink_payment_v1_sales_tax_returns__sales_tax_return_id__payments__sales_tax_payment_id__unlink_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | sales_tax_return_id |
string (uuid) | yes | Id of a filed sales tax return. |
| path | sales_tax_payment_id |
string (uuid) | yes | Id of the payment link (payments[].id). |
Request body
application/json (required): SalesTaxReasonInput
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Why, in a few words; kept in the history. (min length 1; max length 500) |
Example request
curl -X POST "$ERP_URL/v1/sales-tax-returns/{sales_tax_return_id}/payments/{sales_tax_payment_id}/unlink" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "Filed twice"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
POST /v1/sales-tax-returns/{sales_tax_return_id}/withdraw
Withdraw a sales tax filing
Withdraws a filing recorded by mistake, with the reason (kept; the record is not
deleted). Answers 409 while payments are linked. A person's act (finalize_vat_return).
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | withdraw_v1_sales_tax_returns__sales_tax_return_id__withdraw_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | sales_tax_return_id |
string (uuid) | yes | Id of a filed sales tax return. |
Request body
application/json (required): SalesTaxReasonInput
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Why, in a few words; kept in the history. (min length 1; max length 500) |
Example request
curl -X POST "$ERP_URL/v1/sales-tax-returns/{sales_tax_return_id}/withdraw" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "Filed twice"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | SalesTaxReturnOut |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"entity": "string",
"currency": "string",
"state": "string",
"state_name": "string",
"permit_number": "string",
"period": "string",
"start": "2026-09-21",
"end": "2026-09-21",
"due_on": "2026-09-21",
"status": "awaiting_approval",
"figures": {
"gross_sales": "string",
"exempt_customer_sales": "string",
"exempt_product_sales": "string",
"taxable_sales": "string",
"tax": "string",
"use_tax_purchases": "string",
"use_tax": "string",
"tax_due": "string",
"jurisdictions": [
{
"code": null,
"name": null,
"level": null,
"rate": null,
"taxable": null,
"tax": null,
"purchases": null,
"use_tax": null
}
]
},
"account": "string",
"ledger_tax": "string",
"unexplained_difference": "string",
"changed_since_filing": "string",
"filing": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"filed_on": "2026-09-21",
"confirmation": "string",
"filed_by": {},
"filed_at": "2026-09-21T09:30:00Z",
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"figures": {
"gross_sales": null,
"exempt_customer_sales": null,
"exempt_product_sales": null,
"taxable_sales": null,
"tax": null,
"use_tax_purchases": null,
"use_tax": null,
"tax_due": null,
"jurisdictions": null
},
"tax_due": "string",
"paid_amount": "string",
"payment_difference": "string",
"payments": [
null
],
"test_copy": true
}
}
Schemas
SalesTaxAreaInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
code |
string or null | A code of its own, e.g. LOS-ANGELES. Omitted: made from the name (capitals, digits and hyphens, with -2 when taken). (pattern ^[A-Z0-9][A-Z0-9-]{0,39}$) |
|
name |
string | yes | Its name. (min length 1; max length 120) |
jurisdictions |
array of string | yes | The codes of its local jurisdictions (county, city, district) in the same state; the state's own rate always applies on top. (max items 20) |
SalesTaxAreaOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the area. |
state |
string | yes | The state. |
code |
string | yes | Its code. |
name |
string | yes | Its name. |
jurisdictions |
array of string | yes | The codes of its local jurisdictions. |
combined_rate |
string or null | yes | State plus local rates in force on on; null when one has no rate yet. |
SalesTaxAreaUpdate
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | New name. (min length 1; max length 120) | |
jurisdictions |
array of string or null | The codes of its local jurisdictions. (max items 20) |
SalesTaxCategoryRuleInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state. (pattern ^US-[A-Z]{2}$) |
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product category. |
taxable_percent |
decimal string | yes | How much of the price the state taxes: 0 exempt, 100 fully taxed, 80 for Texas data processing. (min 0; max 100) |
note |
string or null | Why, e.g. the statute. (max length 300) |
SalesTaxCategoryRuleOut
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state. |
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product category. |
taxable_percent |
string | yes | How much of the price is taxed, in percent. |
note |
string or null | yes | Why, or null. |
SalesTaxCustomerInput
| Field | Type | Required | Description |
|---|---|---|---|
area |
string or null | The tax area of the customer's location (its code), or null. | |
exemption_number |
string or null | The exemption certificate's number, or null. (max length 60) | |
exemption_reason |
"government" | "manufacturing" | "nonprofit" | "other" | "resale" or null |
Why it is exempt: resale, nonprofit, government, manufacturing or other; required with a number. |
|
exempt_from |
string (date) or null | The first day the certificate is valid; with a number, the day it is recorded when omitted. | |
exempt_until |
string (date) or null | The certificate's expiry; null when it does not expire. | |
exempt_states |
array of string or null | The states the certificate is valid in (e.g. a multistate certificate); with a number, the customer's own state when omitted. |
SalesTaxCustomerOut
| Field | Type | Required | Description |
|---|---|---|---|
party |
string | yes | The customer's code. |
state |
string or null | yes | The customer's state, e.g. US-CA, or null. |
area |
string or null | yes | Its tax area's code, or null. |
area_name |
string or null | yes | Its tax area's name, or null. |
exemption_number |
string or null | yes | Its exemption certificate's number. |
exemption_reason |
"government" | "manufacturing" | "nonprofit" | "other" | "resale" or null |
yes | Why it is exempt. |
exempt_from |
string (date) or null | yes | The first day the certificate is valid. |
exempt_until |
string (date) or null | yes | When the certificate expires. |
exempt_states |
array of string | yes | The states the certificate is valid in. |
exempt_today |
boolean | yes | True when the certificate is valid today in the customer's state. |
SalesTaxFigures
What a state's return asks for, from the posted journal lines of the period.
| Field | Type | Required | Description |
|---|---|---|---|
gross_sales |
string | yes | All sales to customers in the state, net of credit notes and discounts. |
exempt_customer_sales |
string | yes | Sales to customers with a valid exemption certificate. |
exempt_product_sales |
string | yes | Sales of products, or parts of their price, the state does not tax. |
taxable_sales |
string | yes | Gross sales less the exempt ones. |
tax |
string | yes | The sales tax collected. |
use_tax_purchases |
string | yes | Purchases the vendor charged no sales tax on, used in the state: the use tax base. |
use_tax |
string | yes | The use tax self-assessed on them. |
tax_due |
string | yes | tax plus use_tax: what is due to the state. |
jurisdictions |
array of SalesTaxJurisdictionLine |
yes | The tax collected by jurisdiction and rate, state first. |
SalesTaxFileInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, e.g. US-TX. (pattern ^US-[A-Z]{2}$) |
period |
string | yes | The period by the registration's frequency: 2026-08, 2026-Q3, 2026. (pattern `^\d{4}(-(0[1-9] |
filed_on |
string (date) | yes | The day it was filed with the state: after the period, not in the future. |
confirmation |
string or null | The state's confirmation number. Optional. (max length 200) |
SalesTaxFilingOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the filed return. |
filed_on |
string (date) | yes | The day it was filed with the state. |
confirmation |
string or null | yes | The state's confirmation number, or null. |
filed_by |
object | yes | Who recorded the filing (type and id). |
filed_at |
string (date-time) | yes | When it was recorded (UTC). |
approved_by |
object or null | yes | Who approved the filing (a second person), or null while awaiting approval. |
approved_at |
string (date-time) or null | yes | When it was approved (UTC), or null. |
figures |
SalesTaxFigures |
yes | The figures as filed. |
tax_due |
string | yes | The tax filed: what the payments must cover. |
paid_amount |
string | yes | What the linked payments cover. |
payment_difference |
string | yes | tax_due minus paid_amount: what is still to pay; negative when more. |
payments |
array of SalesTaxPaymentOut |
yes | The linked payments, oldest first. |
test_copy |
boolean | yes | True in a test copy: a record only, nothing is filed. |
SalesTaxJurisdictionInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state it lies in, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
code |
string or null | A code of its own, e.g. CA-LA-DIST. Omitted: made from the name (capitals, digits and hyphens, with -2 when taken). (pattern ^[A-Z0-9][A-Z0-9-]{0,39}$) |
|
name |
string | yes | Its name. (min length 1; max length 120) |
level |
"city" | "county" | "district" |
yes | county, city or district. |
rate |
decimal string | yes | Its rate in percent. (min 0) |
valid_from |
string (date) | yes | The first day of the rate. |
SalesTaxJurisdictionLine
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | The jurisdiction's code. |
name |
string | yes | Its name. |
level |
string | yes | state, county, city or district. |
rate |
string | yes | The rate charged, in percent. |
taxable |
string | yes | The taxable sales it was charged on. |
tax |
string | yes | The tax collected for it. |
purchases |
string | yes | The purchases use tax was self-assessed on for it. |
use_tax |
string | yes | The use tax self-assessed for it. |
SalesTaxJurisdictionOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the jurisdiction. |
state |
string | yes | The state it lies in. |
code |
string | yes | Its code. |
name |
string | yes | Its name. |
level |
"city" | "county" | "district" | "state" |
yes | state, county, city or district. |
rate |
string or null | yes | The rate in force on on, or null if none yet. |
rates |
array of SalesTaxRateOut |
yes | Every rate, oldest first. |
SalesTaxPaymentCandidate
| Field | Type | Required | Description |
|---|---|---|---|
journal_entry_id |
string (uuid) | yes | Id of the posted entry. |
entry_number |
string or null | yes | Its number. |
entry_date |
string (date) | yes | Its date. |
description |
string | yes | Its description. |
source |
string | yes | Its source, such as bank or manual. |
amount |
string | yes | What it debits to the state's account. |
SalesTaxPaymentInput
| Field | Type | Required | Description |
|---|---|---|---|
journal_entry_id |
string (uuid) | yes | The posted entry that paid the state: of the return's company, dated after the period, with a debit on the state's account (GET .../payment-candidates). |
SalesTaxPaymentOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the link (the {payment_id} to unlink it). |
journal_entry_id |
string (uuid) | yes | Id of the posted entry that paid. |
entry_number |
string or null | yes | Number of that entry. |
paid_on |
string (date) | yes | The entry's date (ISO 8601 date). |
amount |
string | yes | What it debited to the state's account. |
linked_by |
object | yes | Who linked it (type and id). |
linked_at |
string (date-time) | yes | When it was linked (ISO 8601 timestamp, UTC). |
SalesTaxPeriodRow
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state. |
state_name |
string | yes | Its name. |
period |
string | yes | 2026-08, 2026-Q3 or 2026. |
start |
string (date) | yes | First day. |
end |
string (date) | yes | Last day. |
due_on |
string (date) | yes | The day the return is due with the state. |
status |
"awaiting_approval" | "due_soon" | "filed" | "open" | "overdue" | "paid" | "to_file" |
yes | open (the period has not ended), to_file, due_soon (due within 10 days), overdue (not recorded as filed by its due day), awaiting_approval (recorded as filed, not approved by a second person yet), filed or paid. |
tax |
string | yes | The tax due for the period (sales and use tax), from the ledger now. |
tax_due |
string or null | yes | The tax filed, or null when not filed. |
filed_on |
string (date) or null | yes | The day it was filed, or null. |
return_id |
string (uuid) or null | yes | Id of the filed return, or null. |
SalesTaxPeriodsOut
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | The company's code. |
year |
integer | yes | The calendar year. |
currency |
string | yes | The currency of the amounts. |
periods |
array of SalesTaxPeriodRow |
yes | By state, then period. |
unregistered |
array of UnregisteredStateRow |
yes | Sales of the year into states the company is not registered in: what economic nexus is measured on. |
SalesTaxProductInput
| Field | Type | Required | Description |
|---|---|---|---|
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product's sales tax category. |
SalesTaxProductOut
| Field | Type | Required | Description |
|---|---|---|---|
product |
string | yes | The product's code. |
category |
"clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | Its sales tax category (general when not set). |
SalesTaxRateInput
| Field | Type | Required | Description |
|---|---|---|---|
valid_from |
string (date) | yes | The first day of the rate; a rate of the same day is replaced. |
rate |
decimal string | yes | The rate in percent. (min 0) |
source |
string or null | Where it comes from, e.g. the state's notice. (max length 500) |
SalesTaxRateOut
| Field | Type | Required | Description |
|---|---|---|---|
valid_from |
string (date) | yes | The first day of the rate (ISO 8601 date). |
rate |
string | yes | Percent, e.g. 7.25. |
source |
string or null | yes | Where the rate came from, e.g. data-vNext's series. |
SalesTaxReasonInput
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Why, in a few words; kept in the history. (min length 1; max length 500) |
SalesTaxRegistrationInput
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | The state, ISO 3166-2, e.g. US-CA. (pattern ^US-[A-Z]{2}$) |
permit_number |
string or null | The state's seller's permit or account number. (max length 60) | |
registered_from |
string (date) | yes | The first day tax is charged in the state. |
registered_until |
string (date) or null | The last day, when the registration ended; null while in force. | |
filing_frequency |
"month" | "quarter" | "year" |
yes | How often the state's return is filed: month, quarter or year. |
state_rate |
decimal string or null | The state rate in percent, from registered_from. Omit to take the state base rate data-vNext has (422 sales_tax_state_rate_unknown when it has none). Ignored when the state already has its jurisdiction. (min 0) |
|
use_tax_area |
string or null | In the company's own state: the tax area (its code) where it uses what it buys, whose local rates its use tax is self-assessed at; null for the state rate only. |
SalesTaxRegistrationOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the registration. |
state |
string | yes | The state, e.g. US-CA. |
state_name |
string | yes | The state's name, e.g. California. |
permit_number |
string or null | yes | The state's permit number, or null. |
registered_from |
string (date) | yes | First day tax is charged (ISO 8601 date). |
registered_until |
string (date) or null | yes | Last day, or null while in force. |
filing_frequency |
"month" | "quarter" | "year" |
yes | month, quarter or year. |
account |
string | yes | The liability account the state's tax is booked to. |
account_name |
string | yes | That account's name. |
use_tax_area |
string or null | yes | The tax area use tax is self-assessed at. |
balance |
string | yes | That account's balance today, credit positive: the tax owed to the state. |
SalesTaxRegistrationUpdate
Only the fields sent change; send registered_until: null to reopen a registration.
| Field | Type | Required | Description |
|---|---|---|---|
permit_number |
string or null | The state's permit number. (max length 60) | |
registered_until |
string (date) or null | The last day of the registration; null while in force. | |
filing_frequency |
"month" | "quarter" | "year" or null |
How often it files; not changed once a return is recorded as filed (409 sales_tax_frequency_filed). |
|
use_tax_area |
string or null | The use tax area's code; null for the state rate only. |
SalesTaxReturnOut
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | The company's code. |
currency |
string | yes | The currency of the amounts (the company's). |
state |
string | yes | The state, e.g. US-CA. |
state_name |
string | yes | The state's name. |
permit_number |
string or null | yes | The company's permit number in the state. |
period |
string | yes | 2026-08, 2026-Q3 or 2026. |
start |
string (date) | yes | First day of the period. |
end |
string (date) | yes | Last day of the period. |
due_on |
string (date) | yes | The day the return is due with the state. |
status |
"awaiting_approval" | "due_soon" | "filed" | "open" | "overdue" | "paid" | "to_file" |
yes | open (the period has not ended), to_file, due_soon (due within 10 days), overdue (not recorded as filed by its due day), awaiting_approval (recorded as filed, not approved by a second person yet), filed or paid. |
figures |
SalesTaxFigures |
yes | The figures from the ledger as it is now. |
account |
string | yes | The state's liability account. |
ledger_tax |
string | yes | The movement on that account in the period, credit positive, without the entries linked as paying a return. |
unexplained_difference |
string | yes | ledger_tax minus figures.tax_due: entries on the account that are not sales tax postings (a manual journal, a payment not linked yet); zero when it ties. |
changed_since_filing |
string or null | yes | The tax due now less the tax filed: postings dated in the period after it was filed (file an amended return with the state); null when not filed. |
filing |
SalesTaxFilingOut or null |
yes | The filing in force, or null. |
SalesTaxSetupOut
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | The company's code. |
applies |
boolean | yes | True for a company in the US: its sales use sales tax. |
on |
string (date) | yes | The day the rates in force are shown for. |
categories |
array of "clothing" | "digital_goods" | "general" | "groceries" | "medical" | "professional_services" | "saas" |
yes | The product categories, in order. |
registrations |
array of SalesTaxRegistrationOut |
yes | By state. |
jurisdictions |
array of SalesTaxJurisdictionOut |
yes | By state, then code. |
areas |
array of SalesTaxAreaOut |
yes | By state, then code. |
rules |
array of SalesTaxCategoryRuleOut |
yes | Product taxability by state; a category without a rule is taxed in full. |
UnregisteredStateRow
| Field | Type | Required | Description |
|---|---|---|---|
state |
string | yes | A state the company sold into without a registration. |
state_name |
string | yes | Its name. |
sales |
string | yes | Its sales there in the period, net of credit notes. |
documents |
integer | yes | How many invoices and credit notes. |