Skip to main content
Products let you maintain a catalog of what you sell, with tax codes attached. Once a product is saved, you reference it as a preset in calculations and transactions instead of repeating tax attributes on every line item. Two supporting endpoints feed into this workflow:

Simple lifecycle

Use this when your products map cleanly to a single tax code and you don’t need attribute-level refinement.

1. Create the product

Send a POST /products with the minimum required fields — source_id and name — and optionally a tax_codes array. Omit tax_codes to inherit your organization’s default tax code.
The response includes Taxwire’s stable id for the product. Save it — you’ll use it as a preset.
Response (201)
resolved_tax_codes is what Taxwire actually uses during a calculation. When tax_codes is empty, resolved_tax_codes reflects your organization’s default. When you assign codes explicitly, both fields match.

2. Reference the product as a preset in a calculation

Pass the product’s id in product.preset on a line item. Taxwire loads the tax codes from the saved product automatically.
Line item using a product preset

3. Update the product when it changes

PATCH /products/{product_id} is a partial update — omit any field you don’t want to touch.
To clear the tax code override and fall back to the organization default, send "tax_codes": [].

Complex lifecycle

Use this when a product’s taxability depends on how it is delivered or used — downloaded vs. shipped, rented vs. sold, B2B vs. B2C. Product attributes express those distinctions.

1. Find the right base tax code

Call GET /product-tax-codes to browse available codes.
Response (excerpt)
See also the product tax code hierarchy for the full tree.

2. Find applicable attributes

Call GET /product-attributes to see all available modifiers. Pass ?ptc= to filter to only the attributes that apply to your chosen code.
Response (excerpt)
Attributes within the same group can be mutually exclusive — check the group.exclusive flag. An attribute appends to the code as a trailing .-separated component: DIGITAL_PROPERTY.DIGITAL_SOFTWARE._DOWNLOADED.An empty ptcs array means the attribute applies to every product, regardless of tax code.

3. Compose the full tax code

Append the chosen attribute to the base code:
Attributes always trail the category path. Multiple attributes chain further: DIGITAL_PROPERTY.DIGITAL_SOFTWARE._DOWNLOADED._B2B. See Tax attributes for full composition rules.

4. Create the product with the composed code

5. Reference the product as a preset

Same as the simple lifecycle — use product.preset on any line item.
Line item

6. Update the tax code when delivery method changes

If the same software starts shipping on USB drives instead, update the attribute:
source_updated_at must move forward — sending a timestamp older than the current value is rejected with a 422. Omit it if you don’t track source-system change timestamps.

Key concepts


Putting it all together

Complete sync of 5 products. The script:
  1. Fetches the full PTC catalog (paginated) and matches PTCs to your product types by keyword.
  2. Fetches attributes for the 3 matched PTCs in parallel.
  3. Resolves specific attributes by code — fails loudly if not found.
  4. Builds and creates all 5 products in parallel.