# Update tax code

`PUT /api/configuration/tax-codes/{taxcodeId}`

- **Products:** Operator (`FOH`)
- **Features:** Front of House Generic Access (`FOHGENERIC`)

HTML version: [Update tax code](https://support.gladstonesoftware.cloud/reference/configuration/update-tax-code)

## Overview

Updates a tax code — the named rate applied to a product's price when tax is calculated.

**This is a full replacement, not a partial update.** `description`, `rate` and `reference` are written from your body on every call, so a field you leave out is overwritten with its default rather than left alone. In particular **omitting `rate` sets the tax code to 0%**, which will quietly under-charge tax on everything using that code. `translations` behaves the same way: the existing translations are deleted and re-created from the array you send, so omitting it removes them all.

Read the current values with [Retrieve a tax code's details](retrieve-a-tax-codes-details.md), apply your change, and send the whole object back. A successful update returns `204 No Content`.

Changing a rate here changes it for every product that references this tax code, from the moment the update is applied. Historic transactions are not recalculated. If you need the old rate to remain available, create a new tax code with [Create tax code](create-tax-code.md) instead of editing this one.

One oddity to expect in error responses: two of the validation messages mention "price level" rather than "tax code". They are the correct messages for this endpoint despite the wording.

## Endpoint

`PUT {base_url}/api/configuration/tax-codes/{taxcodeId}`

`{base_url}` is the environment URL issued to your integration. See [Authenticating with Gladstone APIs](../../guides/authenticating-with-gladstone-apis.md).

## Path parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `taxCodeId` | string | Yes | The tax code's identifier, as returned in `id` by [List all tax codes](list-all-tax-codes.md). Up to 15 characters. The value is converted to upper case before the lookup, so case in the URL does not matter. An id that matches no tax code fails with `404`. |

## Request body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `description` | string | No | The tax code's display name, for example `Standard VAT`. Maximum 25 characters — a longer value fails with `The price level description cannot be more than 25 characters` (the message says "price level"; it is describing this field) — and an empty string fails with `A blank description is not allowed`. Written unconditionally, so **omitting it or sending null clears the stored description**. |
| `rate` | number (double) | No | The tax percentage, as a percentage rather than a fraction — send `20` for 20%, not `0.2`. Must be between 0 and 100 inclusive, and may carry at most two decimal places; a third decimal fails with `The tax rate can only be specified to two decimal places` rather than being rounded. **Omitting it or sending null sets it to `0`**, making the code zero-rated. |
| `reference` | string | No | A free-text reference for reconciling this tax code with your finance system or ledger; not used by the platform's own tax calculation. Maximum 25 characters — a longer value fails with `The price level reference cannot be more than 25 characters` (again, the message names the wrong entity). Written unconditionally, so **omitting it or sending null clears the stored reference**. |
| `translations` | array of object | No | Translated text for the tax code, one entry per property per culture. Replaced wholesale: every existing translation for this tax code is deleted before yours are added, so **omitting the array or sending `[]` removes them all**. Resend the current set from [Retrieve a tax code's details](retrieve-a-tax-codes-details.md) if you are not changing them. |
| `translations[].type` | string | No | Which property of the tax code this entry translates; use the property's name — `Description` for the tax code's display name. No length or value validation is applied here, so a mistyped property name is accepted and simply never matches when translations are read back. |
| `translations[].culture` | string | No | The culture code the text is written in. It must be one of the platform's known culture codes — the shipped set includes `cy-gb`, `en-gb`, `en-ie`, `en-us`, `de`, `es`, `fr`, `gd` and `pt`. This field is not validated up front, so an unrecognised code surfaces as `500` rather than `400`. |
| `translations[].text` | string | No | The translated text for the named property in that culture. No length validation is applied on this endpoint. |

## Sample request

```bash title="cURL"
curl -X PUT '{base_url}/api/configuration/tax-codes/{taxcodeId}' \
  -H 'Authorization: Bearer {accessToken}' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "description": "string",
  "rate": 10.5,
  "reference": "string",
  "translations": [
    {
      "type": "string",
      "culture": "string",
      "text": "string"
    }
  ]
}'
```

## Errors

| Status | Meaning | When |
|--------|---------|------|
| `400` | Bad request | `description` is blank or over 25 characters, `reference` is over 25 characters, or `rate` is outside 0–100. The body is a validation error object keyed by field name, carrying messages such as `Rate has to be between 0 and 100 inclusive`. |
| `400` | Bad request | `rate` has more than two decimal places — `The tax rate can only be specified to two decimal places`. The value is not rounded for you. |
| `404` | Not found | No tax code has that `taxCodeId` — `Record cannot be found`. |
| `500` | Internal server error | A `translations[].culture` that is not a recognised culture code, or any other unexpected server-side failure. The tax code's own fields are saved before translations are written, so a translation failure can leave the change to `description`, `rate` and `reference` applied. |
