Tax rates belong to a market and use read_markets / write_markets. A line connects one zone to one class and carries an internal name, a customer-facing display name, a percentage, and a compound mode. Search and coverage endpoints are paginated. The atomic save endpoint is the preferred path for an editor because it validates creates, updates, and deletes as one proposed state and commits all of them or none.
Connect zones and classes#
Every rate line belongs to one tax zone and one tax class. That pair is a coordinate. A coordinate can contain several named lines, such as a 9% state line and a 9% central line. added_to lines are each calculated from the taxable amount and then summed. compounded lines use the taxable amount plus the complete added_to total. Tringify applies that order consistently; clients choose the mode, not a line sequence.
Save several changes atomically#
// PUT /api/2025-01/markets/{marketId}/tax-rates
{
"creates": [{
"client_id": "draft-1",
"tax_zone_id": "9b2d7c41-3e8a-4f60-a1d2-5c7e9f013b48",
"tax_class_id": "7c9e4f2b-1a3d-4e5f-8b6c-2d0e1f3a4b5c",
"name": "State tax",
"display_name": "State tax 9%",
"rate": "9.00",
"compound_mode": "added_to"
}],
"updates": [],
"deletes": []
}
The batch endpoint validates the complete proposed result before writing. A duplicate name, stale update, invalid coordinate, or exceeded limit rejects the whole request. A successful response reports created, updated, and deleted counts. The saved changes and their webhook events become visible together only after the complete batch succeeds.
Endpoints#
Get tax rate limits
Fetch tax-rate validation limits.
Returns every live tax-rate limit: 500 lines per market, 10 lines per zone-and-class coordinate, the name length cap (counted in characters), and list pagination bounds. Read this endpoint instead of hardcoding numbers.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
Search tax rates
List a market's tax rates, filtered and paginated.
Returns paginated rate lines — one row per line, a (zone, class) coordinate may hold several. Free-text search matches the zone or class name; zone_id, class_id, and compound_mode each narrow further. The response also carries the market's coverage figures: total_combinations (zones × classes) and configured_combinations (coordinates holding at least one rate) — server-computed so every client agrees.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Query parameters
| Name | Type | Description |
|---|---|---|
page
|
integer |
Page number. |
per_page
|
integer |
Page size (service-capped). |
search
|
string |
Free text — matches the zone or class name. |
zone_id
|
string |
Narrow to one tax zone. |
class_id
|
string |
Narrow to one tax class. |
compound_mode
|
string |
Narrow by compound mode: added_to or compounded. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
List coverage gaps
List the (zone, class) combinations that hold no rate.
Returns the paginated (zone, class) coordinates carrying zero rate lines — the cells still to fill. Same filter semantics as search, and the same coverage figures ride along. An unfilled coordinate means items of that class sold into that zone carry no tax from zone rates.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Query parameters
| Name | Type | Description |
|---|---|---|
page
|
integer |
Page number. |
per_page
|
integer |
Page size (service-capped). |
search
|
string |
Free text — matches the zone or class name. |
zone_id
|
string |
Narrow to one tax zone. |
class_id
|
string |
Narrow to one tax class. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
Create a tax rate
Create a rate line at a (zone, class) coordinate.
Creates a rate line. name, display_name (what the customer sees on orders and invoices), rate (a decimal string, 0–100), tax_zone_id, and tax_class_id are required; compound_mode defaults to added_to. A coordinate may hold multiple lines (CGST + SGST), but each line name must be unique within its coordinate — a duplicate is rejected, never silently stacked. Fires tax_rates/create.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
tax_zone_id
required
|
string |
The zone half of the coordinate. |
tax_class_id
required
|
string |
The class half of the coordinate. |
name
required
|
string |
Line name — unique within its (zone, class) coordinate. |
display_name
required
|
string |
What the customer sees on orders and invoices. |
rate
required
|
string |
Percentage as a decimal string, 0–100, with at most four decimal places. Money is never a float on the wire. |
compound_mode
|
string |
added_to (calculated on the price itself, lines sum) or compounded (calculated on price plus the tax other lines already added). Defaults to added_to. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400TAX_RATE_NAME_REQUIREDName is empty after normalization.
-
400TAX_RATE_NAME_TOO_LONGName exceeds the limit.
-
400TAX_LINE_NAME_REQUIREDDisplay_name is empty.
-
400TAX_LINE_NAME_TOO_LONGDisplay_name exceeds the limit.
-
400TAX_RATE_REQUIREDRate is empty.
-
400TAX_RATE_INVALIDRate is not a valid decimal number.
-
400TAX_RATE_OUT_OF_RANGERate is outside 0–100.
-
400TAX_RATE_SCALERate has more than four decimal places.
-
400TAX_ZONE_COMPOUND_MODE_INVALIDCompound_mode is not added_to or compounded.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404TAX_ZONE_NOT_FOUNDTax zone does not exist in this market.
-
404TAX_CLASS_NOT_FOUNDTax class does not exist in this market.
-
409TAX_RATE_LINE_DUPLICATEA line with this name already exists at the (zone, class) coordinate.
-
400TAX_RATE_LIMIT_REACHEDThe market has reached its 500-line tax-rate limit.
-
400TAX_RATE_COORDINATE_LIMIT_REACHEDThe zone/class coordinate has reached its rate-line limit.
Save tax rate changes
Create, update, and delete tax rates in one transaction.
Applies the complete change set atomically: either every create, update, and delete succeeds or none of them do. Updates and deletes must include the opaque version returned by the read APIs; a stale version rejects the whole change set. The service validates the final market state, so valid line-name swaps work and no intermediate write can violate a limit. Each written rate still emits its canonical create, update, or delete webhook.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
creates
required
|
array |
New rate lines. Each item uses the create fields and may include a client_id for reconciliation. |
updates
required
|
array |
Existing rate lines with id, version, and the complete editable field set. |
deletes
required
|
array |
Rate ids and versions to delete. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400TAX_RATE_NAME_REQUIREDName is empty after normalization.
-
400TAX_RATE_NAME_TOO_LONGName exceeds the limit.
-
400TAX_LINE_NAME_REQUIREDDisplay_name is empty.
-
400TAX_LINE_NAME_TOO_LONGDisplay_name exceeds the limit.
-
400TAX_RATE_REQUIREDRate is empty.
-
400TAX_RATE_INVALIDRate is not a valid decimal number.
-
400TAX_RATE_OUT_OF_RANGERate is outside 0–100.
-
400TAX_RATE_SCALERate has more than four decimal places.
-
400TAX_ZONE_COMPOUND_MODE_INVALIDCompound_mode is not added_to or compounded.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404TAX_ZONE_NOT_FOUNDTax zone does not exist in this market.
-
404TAX_CLASS_NOT_FOUNDTax class does not exist in this market.
-
409TAX_RATE_LINE_DUPLICATEA line with this name already exists at the (zone, class) coordinate.
-
400TAX_RATE_LIMIT_REACHEDThe market has reached its 500-line tax-rate limit.
-
400TAX_RATE_COORDINATE_LIMIT_REACHEDThe zone/class coordinate has reached its rate-line limit.
-
409TAX_RATE_BATCH_CONFLICTAt least one update or delete used a stale version; no changes were committed.
-
404NOT_FOUNDA referenced tax rate does not exist in this market.
Get a tax rate
Fetch one rate line.
Returns the rate line, with its zone and class names joined.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
taxRateId
required
|
string |
Tax rate id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404NOT_FOUNDTax rate does not exist in this market.
Update a tax rate
Update a rate line.
Updates the line's name, display name, rate, compound mode, and optionally moves it to another class (tax_class_id). Renaming must not collide with a sibling line at the same coordinate. Fires tax_rates/update.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
taxRateId
required
|
string |
Tax rate id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
tax_class_id
|
string |
Move the line to another class in the same zone. Omit to keep it. |
name
required
|
string |
Line name — unique within its (zone, class) coordinate. |
display_name
required
|
string |
What the customer sees on orders and invoices. |
rate
required
|
string |
Percentage as a decimal string, 0–100, with at most four decimal places. |
compound_mode
|
string |
added_to or compounded. Defaults to added_to. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400TAX_RATE_NAME_REQUIREDName is empty after normalization.
-
400TAX_RATE_NAME_TOO_LONGName exceeds the limit.
-
400TAX_LINE_NAME_REQUIREDDisplay_name is empty.
-
400TAX_LINE_NAME_TOO_LONGDisplay_name exceeds the limit.
-
400TAX_RATE_REQUIREDRate is empty.
-
400TAX_RATE_INVALIDRate is not a valid decimal number.
-
400TAX_RATE_OUT_OF_RANGERate is outside 0–100.
-
400TAX_RATE_SCALERate has more than four decimal places.
-
400TAX_ZONE_COMPOUND_MODE_INVALIDCompound_mode is not added_to or compounded.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404TAX_ZONE_NOT_FOUNDTax zone does not exist in this market.
-
404TAX_CLASS_NOT_FOUNDTax class does not exist in this market.
-
409TAX_RATE_LINE_DUPLICATEA line with this name already exists at the (zone, class) coordinate.
-
400TAX_RATE_LIMIT_REACHEDThe market has reached its 500-line tax-rate limit.
-
400TAX_RATE_COORDINATE_LIMIT_REACHEDThe zone/class coordinate has reached its rate-line limit.
-
404NOT_FOUNDTax rate does not exist in this market.
Delete a tax rate
Delete a rate line.
Deletes the rate line. If it was the coordinate's only line, that (zone, class) combination becomes unconfigured and items of that class in that zone carry no tax from zone rates. Fires tax_rates/delete.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
taxRateId
required
|
string |
Tax rate id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404NOT_FOUNDTax rate does not exist in this market.
Webhook events#
Atomic saves publish the corresponding create, update, and delete event for every changed line only after the complete batch succeeds. No change or event is published when any part of the batch is rejected.
Tax rate created
Subscribe to receive a tax rate line after it is created at a market's zone-and-class coordinate.
Payload fields
| Field | Type | Description |
|---|---|---|
tax_rate.id |
string |
Always present
The stable tax rate line id. |
tax_rate.market_id |
string |
Selectable in the Payload builder
The market where the rate line is evaluated. |
tax_rate.tax_zone_id |
string |
Selectable in the Payload builder
The tax zone half of this rate coordinate. |
tax_rate.tax_class_id |
string |
Selectable in the Payload builder
The tax class half of this rate coordinate. |
tax_rate.name |
string |
Selectable in the Payload builder
The internal rate-line name, unique within its zone-and-class coordinate. |
tax_rate.display_name |
string |
Selectable in the Payload builder
The rate-line name shown to customers on orders and invoices. |
tax_rate.rate |
string |
Selectable in the Payload builder
The percentage rate as a decimal string. |
tax_rate.compound_mode |
string |
Selectable in the Payload builder
Whether the line uses the taxable amount or the taxable amount plus the added-tax total. |
tax_rate.tax_zone_name |
string |
Selectable in the Payload builder
The current name of the related tax zone. |
tax_rate.tax_class_name |
string |
Selectable in the Payload builder
The current name of the related tax class. |
tax_rate.created_at |
string |
Selectable in the Payload builder
When the rate line was created. |
tax_rate.updated_at |
string |
Selectable in the Payload builder
When the rate line last changed. |
Tax rate updated
Subscribe to receive the current tax rate line after its name, display name, rate, compound mode, or tax class changes.
Payload fields
| Field | Type | Description |
|---|---|---|
tax_rate.id |
string |
Always present
The stable tax rate line id. |
tax_rate.market_id |
string |
Selectable in the Payload builder
The market where the rate line is evaluated. |
tax_rate.tax_zone_id |
string |
Selectable in the Payload builder
The tax zone half of this rate coordinate. |
tax_rate.tax_class_id |
string |
Selectable in the Payload builder
The tax class half of this rate coordinate. |
tax_rate.name |
string |
Selectable in the Payload builder
The internal rate-line name, unique within its zone-and-class coordinate. |
tax_rate.display_name |
string |
Selectable in the Payload builder
The rate-line name shown to customers on orders and invoices. |
tax_rate.rate |
string |
Selectable in the Payload builder
The percentage rate as a decimal string. |
tax_rate.compound_mode |
string |
Selectable in the Payload builder
Whether the line uses the taxable amount or the taxable amount plus the added-tax total. |
tax_rate.tax_zone_name |
string |
Selectable in the Payload builder
The current name of the related tax zone. |
tax_rate.tax_class_name |
string |
Selectable in the Payload builder
The current name of the related tax class. |
tax_rate.created_at |
string |
Selectable in the Payload builder
When the rate line was created. |
tax_rate.updated_at |
string |
Selectable in the Payload builder
When the rate line last changed. |
Tax rate deleted
Subscribe to remove a deleted tax rate line from your integration. The payload keeps the ids and last known name needed to identify it.
Payload fields
| Field | Type | Description |
|---|---|---|
tax_rate.id |
string |
Always present
The stable tax rate line id. |
tax_rate.market_id |
string |
Selectable in the Payload builder
The market where the rate line is evaluated. |
tax_rate.tax_zone_id |
string |
Selectable in the Payload builder
The tax zone half of this rate coordinate. |
tax_rate.tax_class_id |
string |
Selectable in the Payload builder
The tax class half of this rate coordinate. |
tax_rate.name |
string |
Selectable in the Payload builder
The internal rate-line name, unique within its zone-and-class coordinate. |