Tax rates

Manage named tax lines for every zone and class coordinate, individually or atomically in a batch.

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#

json
// 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

GET read_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

Search tax rates

GET read_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789

Query parameters

Name Type Description
page integer

Page number.

Example: 1
per_page integer

Page size (service-capped).

Example: 20
search string

Free text — matches the zone or class name.

Example: standard
zone_id string

Narrow to one tax zone.

Example: 7c9e4f2b-1a3d-4e5f-8b6c-2d0e1f3a4b5c
class_id string

Narrow to one tax class.

Example: 4e2b8c1a-7f3d-4a5b-9c6d-1e0f2a3b4c5d
compound_mode string

Narrow by compound mode: added_to or compounded.

Example: added_to

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

List coverage gaps

GET read_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789

Query parameters

Name Type Description
page integer

Page number.

Example: 1
per_page integer

Page size (service-capped).

Example: 20
search string

Free text — matches the zone or class name.

Example: standard
zone_id string

Narrow to one tax zone.

Example: 7c9e4f2b-1a3d-4e5f-8b6c-2d0e1f3a4b5c
class_id string

Narrow to one tax class.

Example: 4e2b8c1a-7f3d-4a5b-9c6d-1e0f2a3b4c5d

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

Create a tax rate

POST write_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789

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.

Example: 7c9e4f2b-1a3d-4e5f-8b6c-2d0e1f3a4b5c
tax_class_id required string

The class half of the coordinate.

Example: 4e2b8c1a-7f3d-4a5b-9c6d-1e0f2a3b4c5d
name required string

Line name — unique within its (zone, class) coordinate.

Example: CGST
display_name required string

What the customer sees on orders and invoices.

Example: CGST 9%
rate required string

Percentage as a decimal string, 0–100, with at most four decimal places. Money is never a float on the wire.

Example: 9
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.

Example: added_to

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 400 TAX_RATE_NAME_REQUIRED

    Name is empty after normalization.

  • 400 TAX_RATE_NAME_TOO_LONG

    Name exceeds the limit.

  • 400 TAX_LINE_NAME_REQUIRED

    Display_name is empty.

  • 400 TAX_LINE_NAME_TOO_LONG

    Display_name exceeds the limit.

  • 400 TAX_RATE_REQUIRED

    Rate is empty.

  • 400 TAX_RATE_INVALID

    Rate is not a valid decimal number.

  • 400 TAX_RATE_OUT_OF_RANGE

    Rate is outside 0–100.

  • 400 TAX_RATE_SCALE

    Rate has more than four decimal places.

  • 400 TAX_ZONE_COMPOUND_MODE_INVALID

    Compound_mode is not added_to or compounded.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

  • 404 TAX_ZONE_NOT_FOUND

    Tax zone does not exist in this market.

  • 404 TAX_CLASS_NOT_FOUND

    Tax class does not exist in this market.

  • 409 TAX_RATE_LINE_DUPLICATE

    A line with this name already exists at the (zone, class) coordinate.

  • 400 TAX_RATE_LIMIT_REACHED

    The market has reached its 500-line tax-rate limit.

  • 400 TAX_RATE_COORDINATE_LIMIT_REACHED

    The zone/class coordinate has reached its rate-line limit.

Save tax rate changes

PUT write_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789

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.

Example: [{"client_id":"draft-1","tax_zone_id":"7c9e4f2b-1a3d-4e5f-8b6c-2d0e1f3a4b5c","tax_class_id":"4e2b8c1a-7f3d-4a5b-9c6d-1e0f2a3b4c5d","name":"CGST","display_name":"CGST 9%","rate":"9","compound_mode":"added_to"}]
updates required array

Existing rate lines with id, version, and the complete editable field set.

Example: []
deletes required array

Rate ids and versions to delete.

Example: []

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 400 TAX_RATE_NAME_REQUIRED

    Name is empty after normalization.

  • 400 TAX_RATE_NAME_TOO_LONG

    Name exceeds the limit.

  • 400 TAX_LINE_NAME_REQUIRED

    Display_name is empty.

  • 400 TAX_LINE_NAME_TOO_LONG

    Display_name exceeds the limit.

  • 400 TAX_RATE_REQUIRED

    Rate is empty.

  • 400 TAX_RATE_INVALID

    Rate is not a valid decimal number.

  • 400 TAX_RATE_OUT_OF_RANGE

    Rate is outside 0–100.

  • 400 TAX_RATE_SCALE

    Rate has more than four decimal places.

  • 400 TAX_ZONE_COMPOUND_MODE_INVALID

    Compound_mode is not added_to or compounded.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

  • 404 TAX_ZONE_NOT_FOUND

    Tax zone does not exist in this market.

  • 404 TAX_CLASS_NOT_FOUND

    Tax class does not exist in this market.

  • 409 TAX_RATE_LINE_DUPLICATE

    A line with this name already exists at the (zone, class) coordinate.

  • 400 TAX_RATE_LIMIT_REACHED

    The market has reached its 500-line tax-rate limit.

  • 400 TAX_RATE_COORDINATE_LIMIT_REACHED

    The zone/class coordinate has reached its rate-line limit.

  • 409 TAX_RATE_BATCH_CONFLICT

    At least one update or delete used a stale version; no changes were committed.

  • 404 NOT_FOUND

    A referenced tax rate does not exist in this market.

Get a tax rate

GET read_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789
taxRateId required string

Tax rate id.

Example: 3f8c2d1e-9a4b-4c5d-8e6f-0a1b2c3d4e5f

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

  • 404 NOT_FOUND

    Tax rate does not exist in this market.

Update a tax rate

PUT write_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789
taxRateId required string

Tax rate id.

Example: 3f8c2d1e-9a4b-4c5d-8e6f-0a1b2c3d4e5f

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.

Example: 4e2b8c1a-7f3d-4a5b-9c6d-1e0f2a3b4c5d
name required string

Line name — unique within its (zone, class) coordinate.

Example: CGST
display_name required string

What the customer sees on orders and invoices.

Example: CGST 9%
rate required string

Percentage as a decimal string, 0–100, with at most four decimal places.

Example: 9.975
compound_mode string

added_to or compounded. Defaults to added_to.

Example: added_to

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 400 TAX_RATE_NAME_REQUIRED

    Name is empty after normalization.

  • 400 TAX_RATE_NAME_TOO_LONG

    Name exceeds the limit.

  • 400 TAX_LINE_NAME_REQUIRED

    Display_name is empty.

  • 400 TAX_LINE_NAME_TOO_LONG

    Display_name exceeds the limit.

  • 400 TAX_RATE_REQUIRED

    Rate is empty.

  • 400 TAX_RATE_INVALID

    Rate is not a valid decimal number.

  • 400 TAX_RATE_OUT_OF_RANGE

    Rate is outside 0–100.

  • 400 TAX_RATE_SCALE

    Rate has more than four decimal places.

  • 400 TAX_ZONE_COMPOUND_MODE_INVALID

    Compound_mode is not added_to or compounded.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

  • 404 TAX_ZONE_NOT_FOUND

    Tax zone does not exist in this market.

  • 404 TAX_CLASS_NOT_FOUND

    Tax class does not exist in this market.

  • 409 TAX_RATE_LINE_DUPLICATE

    A line with this name already exists at the (zone, class) coordinate.

  • 400 TAX_RATE_LIMIT_REACHED

    The market has reached its 500-line tax-rate limit.

  • 400 TAX_RATE_COORDINATE_LIMIT_REACHED

    The zone/class coordinate has reached its rate-line limit.

  • 404 NOT_FOUND

    Tax rate does not exist in this market.

Delete a tax rate

DELETE write_markets

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.

Example: 9a1f2c3d-4e5f-6789-abcd-ef0123456789
taxRateId required string

Tax rate id.

Example: 3f8c2d1e-9a4b-4c5d-8e6f-0a1b2c3d4e5f

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    marketId must be a valid UUID.

  • 404 MARKET_NOT_FOUND

    Market does not exist in this store.

  • 404 NOT_FOUND

    Tax 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

EVENT tax_rates/create App scope: read_markets Staff permission: markets:write

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

EVENT tax_rates/update App scope: read_markets Staff permission: markets:write

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

EVENT tax_rates/delete App scope: read_markets Staff permission: markets:write

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.