How to configure your taxes
View as MarkdownCreate and manage tax rates through the Tax GraphQL subgraph — the store-scoped endpoint for all tax configuration operations.
Overview
Tax rates define what percentage is applied to purchases in your store. All Tax operations (reads, creates, status changes, and deletes) are GraphQL queries and mutations sent to POST /v2/commerce/stores/{storeId}/tax-subgraph. Send x-store-id on every request — that header is what the Tax subgraph authorizes against. If the header is missing, GraphQL returns AUTHENTICATION_ERROR (Failed to authorize) with HTTP 200. If the path {storeId} and header disagree, the header wins.
The Tax subgraph also supports Classifications, Jurisdictions, and Overrides for more advanced tax configurations. This article covers the core rate operations. Go to the Tax GraphQL reference for the full schema.
Prerequisites
The following prerequisites are required before you can configure taxes:
- a GoDaddy account with an active commerce store
- a Personal Access Token (PAT) with the scopes for the operations you need (
commerce.tax:readfor queries;commerce.tax:create,:write, or:deletefor the corresponding mutations) - your
storeIdFind your store ID
Go to Your stores to find your store ID.
List tax rates
rates(first, after, ...) returns a paginated collection of rates. Results use edge-based cursor pagination. Go to Paginate results for cursor-based pagination guidance. Optional orderBy takes exactly one of id, name, createdAt, or updatedAt with ASC or DESC — not "desc", and not two keys in one object.
The following procedure retrieves the first page of tax rates.
- Query the first 10 tax rates:
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d '{"query": "query GetRates($first: Int) { rates(first: $first) { edges { node { id name label status value { __typename ... on RatePercentage { percentage } ... on RateAmount { amount { value currencyCode } } } } } pageInfo { hasNextPage endCursor } } }", "variables": {"first": 10}}'- Review the paginated response:
{
"data": {
"rates": {
"edges": [
{
"node": {
"id": "<TAX_RATE_ID>",
"name": "<TAX_RATE_NAME>",
"label": "<TAX_RATE_DISPLAY_LABEL>",
"status": "<TAX_RATE_STATUS>",
"value": {
"__typename": "RatePercentage",
"percentage": "<RATE_PERCENTAGE>"
}
}
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "<PAGINATION_CURSOR>"
}
}
}
}Get a tax rate
rate(id: ID!) retrieves a single tax rate by its ID.
The following procedure reads a single tax rate by ID.
- Retrieve a tax rate by its
id:
RATE_ID="<TAX_RATE_ID>"
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d "{\"query\": \"query GetRate(\$id: ID!) { rate(id: \$id) { id name label status value { __typename ... on RatePercentage { percentage } ... on RateAmount { amount { value currencyCode } } } createdAt } }\", \"variables\": {\"id\": \"${RATE_ID}\"}}"Create a tax rate
createRate(input: MutationCreateRateInput!) creates a new rate. label and value are required. name is generated from the label when omitted. status defaults to ACTIVE. value is a RateValueInput: set percentage (string, out of 100) or amount ({ value, currencyCode }), not both. For amount.value, send integer minor units (850, not 8.5).
Optional input fields from the schema: calculationMethod (ADDITIVE or INCLUSIVE; defaults to ADDITIVE), description, jurisdictionId, metafields, and references. You can omit metafields and references entirely. If you send metafields, the array must be nonempty — [] is rejected. Don't send createdAt or updatedAt — those fields exist only for Tax v1 to v2 migration. For metafields, prefer type: "string" (lowercase).
When you read a rate, value is a union. Select it with inline fragments (... on RatePercentage / ... on RateAmount) — there is no value { rate } field.
The following procedure creates a new tax rate.
- Create a tax rate with a label and value:
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation CreateRate($input: MutationCreateRateInput!) { createRate(input: $input) { id name label status createdAt } }",
"variables": {
"input": {
"label": "<TAX_RATE_DISPLAY_LABEL>",
"name": "<TAX_RATE_UNIQUE_NAME>",
"value": { "percentage": "8.5" }
}
}
}'- Save the
idfrom the response (you'll need it to activate or modify the rate):
{
"data": {
"createRate": {
"id": "<TAX_RATE_ID>",
"name": "<TAX_RATE_UNIQUE_NAME>",
"label": "<TAX_RATE_DISPLAY_LABEL>",
"status": "ACTIVE",
"createdAt": "<ISO8601_CREATED_TIMESTAMP>"
}
}
}Activate a tax rate
activateRate(id: ID!) sets a rate's status to ACTIVE. Requires commerce.tax:write.
The following procedure activates an existing tax rate.
- Activate a rate by its
id:
RATE_ID="<TAX_RATE_ID>"
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d "{\"query\": \"mutation ActivateRate(\$id: ID!) { activateRate(id: \$id) { id label status activatedAt } }\", \"variables\": {\"id\": \"${RATE_ID}\"}}"- Confirm the rate status updated to
ACTIVE:
{
"data": {
"activateRate": {
"id": "<TAX_RATE_ID>",
"label": "<TAX_RATE_DISPLAY_LABEL>",
"status": "ACTIVE",
"activatedAt": "<ISO8601_ACTIVATED_TIMESTAMP>"
}
}
}Deactivate a tax rate
deactivateRate(id: ID!) sets a rate's status to INACTIVE. Requires commerce.tax:write. Deactivated rates no longer apply to purchases.
The following procedure deactivates an active tax rate.
- Deactivate a rate by its
id:
RATE_ID="<TAX_RATE_ID>"
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d "{\"query\": \"mutation DeactivateRate(\$id: ID!) { deactivateRate(id: \$id) { id label status } }\", \"variables\": {\"id\": \"${RATE_ID}\"}}"- Confirm the rate status updated to
INACTIVE:
{
"data": {
"deactivateRate": {
"id": "<TAX_RATE_ID>",
"label": "<TAX_RATE_DISPLAY_LABEL>",
"status": "INACTIVE"
}
}
}Delete a tax rate
deleteRate(id: ID!) permanently removes a tax rate. Requires commerce.tax:delete. This action can't be undone. Use deactivateRate instead if you might need the rate again.
The following procedure deletes a tax rate.
- Delete a rate by its
id:
RATE_ID="<TAX_RATE_ID>"
curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/tax-subgraph" \
-H "Authorization: Bearer $GODADDY_PAT" \
-H "x-store-id: ${STORE_ID}" \
-H "Content-Type: application/json" \
-d "{\"query\": \"mutation DeleteRate(\$id: ID!) { deleteRate(id: \$id) { id label } }\", \"variables\": {\"id\": \"${RATE_ID}\"}}"deleteRatereturns the deletedRateobject. Selecting no subfields is a GraphQL validation error (Field "deleteRate" of type "Rate" must have a selection of subfields).
{
"data": {
"deleteRate": {
"id": "<TAX_RATE_ID>",
"label": "<TAX_RATE_DISPLAY_LABEL>"
}
}
}Common errors
| Status | Most likely cause | Note |
|---|---|---|
200 with errors[].extensions.code: AUTHENTICATION_ERROR | x-store-id is missing or is not a store this token can access. | Authorization uses the header, not the path {storeId}. |
400 | GraphQL selection or variables are invalid. | deleteRate must select fields on Rate. Rate.value is a union — use ... on RatePercentage / ... on RateAmount. |
401 | PAT is missing or expired. Go to Authentication to generate a new token. | |
403 | Token doesn't include the required scope for the operation. | |
404 | Tax rate ID doesn't exist or isn't accessible with the provided token. | |
429 | Rate limit exceeded. | Honor the Retry-After header before retrying. |
Agent & Automation Notes
commerce.tax:read, commerce.tax:create, commerce.tax:write, commerce.tax:deleteRelated
Last updated on
How is this guide?