Ir al contenido

Tax classes

Esta página aún no está disponible en tu idioma.

Tax classes define the sales-tax rates your shop charges. Each class is a named bundle of one or more rate components (e.g. a state rate plus a county rate), can be marked tax-inclusive, and can be assigned to a single location for multi-location shops. Exactly one class per tenant is the default, it’s what invoices and estimates pick up when nothing more specific applies.

Rates are stored as exact integer parts-per-million (rate_ppm, so 6.625% = 66250) and echoed as a derived decimal percent (rate_percent). You can supply either form when writing.

{
"object": "tax_class",
"id": 3,
"name": "NJ Sales Tax",
"label": "NJ Sales Tax",
"inclusive": false,
"is_default": true,
"active": true,
"location_id": null,
"components": [
{
"id": 7,
"name": "State",
"jurisdiction": "NJ",
"rate_ppm": 66250,
"rate_percent": 6.625,
"compound": false,
"ordinal": 0
}
],
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-06-10T09:30:00.000Z"
}
FieldTypeDescription
idintegerUnique tax class ID
namestringClass name
labelstring|nullDisplay label (defaults to name)
inclusivebooleantrue when prices already include this tax
is_defaultbooleanExactly one default class exists per tenant
activebooleanfalse = soft-deactivated (kept for historical invoices)
location_idinteger|nullnull = tenant-wide; otherwise assigned to that location
componentsarrayOrdered rate components (see below)
created_atstring|nullISO-8601 creation timestamp
updated_atstring|nullISO-8601 last-updated timestamp
FieldTypeDescription
idintegerComponent ID
namestringComponent name (e.g. "State")
jurisdictionstring|nullJurisdiction label
rate_ppmintegerExact integer rate in parts-per-million (6.625% = 66250)
rate_percentnumberDerived decimal percent (rate_ppm / 10000)
compoundbooleanApplies on top of prior components’ tax
ordinalintegerApplication order

GET /api/v1/tax_classes

Returns the tenant’s complete tax-class catalog (not paginated, a settings-style list). Inactive classes are included by default so historical/deactivated classes stay discoverable; filter with active. The default class sorts first.

Scope required: tax.read

ParameterTypeDescription
activebooleanFilter by active state (true = active only, false = deactivated only)
Terminal window
curl "https://app.benchkey.com/api/v1/tax_classes?active=true" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/tax_classes?active=true",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const { data } = await res.json();
{
"object": "list",
"data": [ { "object": "tax_class", "id": 3, "name": "NJ Sales Tax", "is_default": true } ],
"has_more": false,
"next_cursor": null
}

Additional resource fields are omitted from this example.


GET /api/v1/tax_classes/:id

Returns a single tax class with its components.

Scope required: tax.read

Terminal window
curl "https://app.benchkey.com/api/v1/tax_classes/3" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"

Returns the tax class object. Returns 404 if no tax class with that ID exists.


POST /api/v1/tax_classes

Creates a named tax class with one or more rate components. Each component takes rate_percent (decimal, e.g. 6.625) or rate_ppm (integer parts-per-million, e.g. 66250), not both; omitting both makes a 0% (exempt) component.

The tenant’s first tenant-scoped class is forced to be the default; is_default: true transactionally unseats the previous default. A location_id assigns the class to one location, at most one active class per location; conflicts return 409.

Scope required: tax.write

Send an Idempotency-Key header to make retries safe. See Idempotency.

FieldRequiredTypeDescription
nameyesstringClass name (max 200 characters)
componentsyesarrayOne or more component objects (see below)
labelnostring|nullDisplay label, max 200 characters (defaults to name)
inclusivenobooleanPrices already include this tax (default: false)
is_defaultnobooleanPromote this class to tenant default (default: false)
location_idnointeger|nullAssign the class to one location (immutable after create). null/omitted = tenant-wide
FieldRequiredTypeDescription
nameyesstringComponent name (max 200 characters)
jurisdictionnostring|nullJurisdiction label (max 200 characters)
rate_percentnonumberDecimal percent, 0–100 (e.g. 6.625). Mutually exclusive with rate_ppm
rate_ppmnointegerInteger parts-per-million, 0–1,000,000 (e.g. 66250). Mutually exclusive with rate_percent
compoundnobooleanApplies on top of prior components’ tax (default: false)
ordinalnointegerApplication order (defaults to array position)
Terminal window
curl -X POST https://app.benchkey.com/api/v1/tax_classes \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: taxclass-create-$(uuidgen)" \
-d '{
"name": "NJ Sales Tax",
"components": [
{ "name": "State", "jurisdiction": "NJ", "rate_percent": 6.625 }
]
}'
const res = await fetch("https://app.benchkey.com/api/v1/tax_classes", {
method: "POST",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
name: "NJ Sales Tax",
components: [{ name: "State", jurisdiction: "NJ", rate_percent: 6.625 }],
}),
});
const taxClass = await res.json(); // HTTP 201

Returns the tax class object with HTTP 201.


PATCH /api/v1/tax_classes/:id

Partial update: omitted fields are left untouched. components, when present, replaces the full component list.

is_default: true promotes this class (unseating the previous default). The default flag cannot be dropped directly, and the default class cannot be deactivated (409, promote another class first). location_id is immutable and not accepted here.

Scope required: tax.write

FieldTypeDescription
namestringClass name (max 200 characters)
labelstring|nullDisplay label (max 200 characters)
inclusivebooleanPrices already include this tax
activebooleantrue re-activates a deactivated class
is_defaultbooleantrue promotes this class to tenant default
componentsarrayReplaces the full component list (same fields as create, min 1 item)
Terminal window
curl -X PATCH "https://app.benchkey.com/api/v1/tax_classes/3" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{ "label": "New Jersey Sales Tax", "inclusive": false }'

Returns the updated tax class object.


DELETE /api/v1/tax_classes/:id

Soft-deactivates the class (active: false) and returns the updated object. The row is never hard-deleted, historical invoices and estimates reference it, and it can be re-activated via PATCH with active: true.

Deactivating the default class returns 409 (set another default first). Deactivating an already-inactive class is an idempotent no-op.

Scope required: tax.write

Terminal window
curl -X DELETE "https://app.benchkey.com/api/v1/tax_classes/3" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"

Returns the deactivated tax class object (active: false) with HTTP 200.


HTTP statusCodeMeaning
400invalid_bodyRequest body is not a JSON object
400unknown_fieldBody contains a field this endpoint doesn’t accept (e.g. location_id on PATCH)
400missing_fieldA required field is absent (name, components)
400invalid_fieldA field value is invalid, e.g. both rate_percent and rate_ppm supplied on one component, a rate out of range, or a non-string name
400invalid_queryA list filter parameter was supplied as an array or object instead of a single scalar value
400invalid_paramThe :id is not a valid integer
404not_foundNo tax class with that ID exists for this tenant
409conflictThe location already has an active class, the class is the tenant default and cannot be deactivated, or the default flag would be dropped without a replacement
422create_failedThe tax class could not be created
403insufficient_scopeAPI key lacks tax.read or tax.write

See Errors for the full error envelope format.

Estado del sistema