Update Tax
The Update Tax endpoint enables you to modify existing tax configurations. This endpoint supports partial updates, allowing you to change specific fields while preserving others. The system maintains strict access control to ensure only authorized applications can modify tax settings.
Endpoint DetailsCopied!
-
URL:
/api/v0/taxes/{id}
-
Method:
PUT
-
Authentication: Required (API Key Authentication)
-
Content-Type:
application/json
AuthenticationCopied!
This endpoint requires API key authentication using:
-
x-client-key
: Your API client key -
x-client-secret
: Your API client secret
Path ParametersCopied!
Required Parameters
Parameter |
Type |
Description |
Validation |
---|---|---|---|
|
|
Unique identifier of the tax to update |
Must be a valid UUID v4 |
Request BodyCopied!
Required Fields
Field |
Type |
Description |
Validation |
---|---|---|---|
|
|
Tax ID (must match path parameter) |
Required, valid UUID v4 |
Optional Fields
Field |
Type |
Description |
Validation |
---|---|---|---|
|
|
Updated tax name |
Optional string |
|
|
Updated tax description |
Optional string |
|
|
Updated tax percentage rate |
Optional number |
|
|
Updated active status |
Optional boolean |
|
|
Updated list of associated application IDs |
Optional array of valid UUIDs |
Request Schema
{
"id": "string",
"name": "string",
"description": "string",
"percentage": "number",
"active": "boolean",
"appIds": ["string"]
}
ResponseCopied!
Success Response (200 OK)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated VAT",
"description": "Updated Value Added Tax for European Union transactions",
"business_id": "456e7890-e89b-12d3-a456-426614174001",
"percentage": 21.0,
"active": true,
"created_at": "2024-01-15T10:30:00.000Z",
"updated_at": "2024-01-25T16:20:00.000Z",
"apps": [
{
"id": "789e0123-e89b-12d3-a456-426614174002",
"business_id": "456e7890-e89b-12d3-a456-426614174001",
"app_name": "eu-store",
"display_name": "European Store",
"environment": "PRODUCTION",
"stage": "PRODUCTION",
"timezone": "Europe/London",
"created_at": "2024-01-10T08:00:00.000Z",
"updated_at": "2024-01-10T08:00:00.000Z"
},
{
"id": "890e1234-e89b-12d3-a456-426614174003",
"business_id": "456e7890-e89b-12d3-a456-426614174001",
"app_name": "new-marketplace",
"display_name": "New Marketplace",
"environment": "PRODUCTION",
"stage": "PRODUCTION",
"timezone": "Europe/Berlin",
"created_at": "2024-01-20T14:00:00.000Z",
"updated_at": "2024-01-20T14:00:00.000Z"
}
]
}
Error Responses
400 Bad Request - Validation Error
{
"statusCode": 400,
"message": [
"id must be a UUID",
"percentage must be a number"
],
"error": "Bad Request"
}
400 Bad Request - ID Mismatch
{
"statusCode": 400,
"message": "Tax ID in path and body must match",
"error": "Bad Request"
}
401 Unauthorized - Missing Authentication
{
"statusCode": 401,
"message": "Application not authenticated",
"error": "Unauthorized"
}
401 Unauthorized - Access Denied
{
"statusCode": 401,
"message": "Access denied to this tax",
"error": "Unauthorized"
}
404 Not Found
{
"statusCode": 404,
"message": "Tax not found",
"error": "Not Found"
}
Business LogicCopied!
Access Control
-
Only applications that are currently associated with the tax can update it
-
The system verifies that your authenticated application has access before allowing modifications
-
Cross-application access is strictly prohibited for security
Automatic App Association
-
Your current application ID is automatically included in the
appIds
array -
Even if you don't include your app ID in the
appIds
field, it will be added -
This ensures the updating application maintains access to the tax
Partial Updates
-
Only provided fields are updated; omitted fields retain their current values
-
The
id
field is required but used for validation (must match path parameter) -
Empty arrays or null values will update the field accordingly
Example RequestsCopied!
Update Tax Rate Only
curl -X PUT https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "x-client-key: your-client-key" \
-H "x-client-secret: your-client-secret" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"percentage": 21.0
}'
Update Name and Description
curl -X PUT https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "x-client-key: your-client-key" \
-H "x-client-secret: your-client-secret" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Updated VAT Rate",
"description": "New VAT rate effective from 2024"
}'
Deactivate Tax
curl -X PUT https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "x-client-key: your-client-key" \
-H "x-client-secret: your-client-secret" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"active": false
}'
Update Associated Applications
curl -X PUT https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "x-client-key: your-client-key" \
-H "x-client-secret: your-client-secret" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"appIds": [
"789e0123-e89b-12d3-a456-426614174002",
"890e1234-e89b-12d3-a456-426614174003",
"901e2345-e89b-12d3-a456-426614174004"
]
}'
Complete Tax Update
curl -X PUT https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "x-client-key: your-client-key" \
-H "x-client-secret: your-client-secret" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "EU VAT Standard Rate",
"description": "Standard VAT rate for European Union member states",
"percentage": 19.0,
"active": true,
"appIds": [
"789e0123-e89b-12d3-a456-426614174002",
"890e1234-e89b-12d3-a456-426614174003"
]
}'
Use CasesCopied!
1. Tax Rate Adjustments
Update tax rates due to regulatory changes:
async function updateTaxRate(taxId, newRate) {
const response = await fetch(`/api/v0/taxes/${taxId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-client-key': 'your-client-key',
'x-client-secret': 'your-client-secret'
},
body: JSON.stringify({
id: taxId,
percentage: newRate
})
});
if (!response.ok) {
throw new Error(`Failed to update tax rate: ${response.statusText}`);
}
return response.json();
}
// Usage
await updateTaxRate('123e4567-e89b-12d3-a456-426614174000', 21.0);
2. Tax Status Management
Activate or deactivate taxes:
async function toggleTaxStatus(taxId, isActive) {
const response = await fetch(`/api/v0/taxes/${taxId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-client-key': 'your-client-key',
'x-client-secret': 'your-client-secret'
},
body: JSON.stringify({
id: taxId,
active: isActive
})
});
const updatedTax = await response.json();
console.log(`Tax "${updatedTax.name}" is now ${isActive ? 'active' : 'inactive'}`);
return updatedTax;
}
3. Application Association Management
Add or remove applications from tax access:
async function updateTaxApplications(taxId, appIds) {
const response = await fetch(`/api/v0/taxes/${taxId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-client-key': 'your-client-key',
'x-client-secret': 'your-client-secret'
},
body: JSON.stringify({
id: taxId,
appIds: appIds
})
});
const updatedTax = await response.json();
console.log(`Tax now associated with ${updatedTax.apps.length} applications`);
return updatedTax;
}
4. Bulk Tax Updates
Update multiple fields at once:
async function updateTaxConfiguration(taxId, updates) {
const updatePayload = {
id: taxId,
...updates
};
const response = await fetch(`/api/v0/taxes/${taxId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-client-key': 'your-client-key',
'x-client-secret': 'your-client-secret'
},
body: JSON.stringify(updatePayload)
});
return response.json();
}
// Usage
await updateTaxConfiguration('123e4567-e89b-12d3-a456-426614174000', {
name: 'Updated Tax Name',
percentage: 22.5,
description: 'New tax configuration for 2024',
active: true
});
Integration ExamplesCopied!
React Component
import React, { useState } from 'react';
function TaxEditor({ taxId, initialData, onUpdate }) {
const [formData, setFormData] = useState({
name: initialData.name || '',
description: initialData.description || '',
percentage: initialData.percentage || 0,
active: initialData.active || true
});
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoading(true);
setError(null);
try {
const response = await fetch(`/api/v0/taxes/${taxId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-client-key': process.env.REACT_APP_CLIENT_KEY,
'x-client-secret': process.env.REACT_APP_CLIENT_SECRET
},
body: JSON.stringify({
id: taxId,
...formData
})
});
if (!response.ok) {
throw new Error(`Update failed: ${response.statusText}`);
}
const updatedTax = await response.json();
onUpdate(updatedTax);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
}
};
const handleChange = (field, value) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Tax Name:</label>
<input
type="text"
value={formData.name}
onChange={(e) => handleChange('name', e.target.value)}
disabled={isLoading}
/>
</div>
<div>
<label>Description:</label>
<textarea
value={formData.description}
onChange={(e) => handleChange('description', e.target.value)}
disabled={isLoading}
/>
</div>
<div>
<label>Percentage:</label>
<input
type="number"
step="0.01"
value={formData.percentage}
onChange={(e) => handleChange('percentage', parseFloat(e.target.value))}
disabled={isLoading}
/>
</div>
<div>
<label>
<input
type="checkbox"
checked={formData.active}
onChange={(e) => handleChange('active', e.target.checked)}
disabled={isLoading}
/>
Active
</label>
</div>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={isLoading}>
{isLoading ? 'Updating...' : 'Update Tax'}
</button>
</form>
);
}
Python Service
import requests
from typing import Dict, Any, Optional
class TaxUpdateService:
def __init__(self, client_key: str, client_secret: str, base_url: str):
self.client_key = client_key
self.client_secret = client_secret
self.base_url = base_url
def _get_headers(self) -> Dict[str, str]:
return {
'Content-Type': 'application/json',
'x-client-key': self.client_key,
'x-client-secret': self.client_secret
}
def update_tax(self, tax_id: str, updates: Dict[str, Any]) -> Dict[str, Any]:
"""Update a tax configuration"""
payload = {
'id': tax_id,
**updates
}
response = requests.put(
f"{self.base_url}/api/v0/taxes/{tax_id}",
json=payload,
headers=self._get_headers()
)
response.raise_for_status()
return response.json()
def update_tax_rate(self, tax_id: str, new_rate: float) -> Dict[str, Any]:
"""Update only the tax rate"""
return self.update_tax(tax_id, {'percentage': new_rate})
def toggle_tax_status(self, tax_id: str, active: bool) -> Dict[str, Any]:
"""Activate or deactivate a tax"""
return self.update_tax(tax_id, {'active': active})
def update_tax_applications(self, tax_id: str, app_ids: list) -> Dict[str, Any]:
"""Update the applications associated with a tax"""
return self.update_tax(tax_id, {'appIds': app_ids})
# Usage
tax_service = TaxUpdateService('your-key', 'your-secret', 'https://api.devdraft.com')
# Update tax rate
updated_tax = tax_service.update_tax_rate(
'123e4567-e89b-12d3-a456-426614174000',
21.0
)
# Update multiple fields
updated_tax = tax_service.update_tax(
'123e4567-e89b-12d3-a456-426614174000',
{
'name': 'New VAT Rate',
'percentage': 19.5,
'description': 'Updated VAT rate for 2024'
}
)
Node.js/Express
const express = require('express');
const axios = require('axios');
class TaxManager {
constructor(clientKey, clientSecret, baseUrl) {
this.clientKey = clientKey;
this.clientSecret = clientSecret;
this.baseUrl = baseUrl;
}
async updateTax(taxId, updates) {
const payload = {
id: taxId,
...updates
};
try {
const response = await axios.put(
`${this.baseUrl}/api/v0/taxes/${taxId}`,
payload,
{
headers: {
'Content-Type': 'application/json',
'x-client-key': this.clientKey,
'x-client-secret': this.clientSecret
}
}
);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(`Update failed: ${error.response.data.message}`);
}
throw error;
}
}
async validateAndUpdateTax(taxId, updates) {
// Validate updates before sending
if (updates.percentage !== undefined && updates.percentage < 0) {
throw new Error('Tax percentage cannot be negative');
}
if (updates.name !== undefined && updates.name.trim() === '') {
throw new Error('Tax name cannot be empty');
}
return this.updateTax(taxId, updates);
}
}
// Express routes
const app = express();
const taxManager = new TaxManager(
process.env.CLIENT_KEY,
process.env.CLIENT_SECRET,
'https://api.devdraft.com'
);
app.put('/taxes/:id', async (req, res) => {
try {
const updatedTax = await taxManager.validateAndUpdateTax(
req.params.id,
req.body
);
res.json(updatedTax);
} catch (error) {
console.error('Tax update error:', error);
res.status(400).json({ error: error.message });
}
});
// Specific update endpoints
app.patch('/taxes/:id/rate', async (req, res) => {
try {
const { percentage } = req.body;
const updatedTax = await taxManager.updateTax(req.params.id, { percentage });
res.json(updatedTax);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.patch('/taxes/:id/status', async (req, res) => {
try {
const { active } = req.body;
const updatedTax = await taxManager.updateTax(req.params.id, { active });
res.json(updatedTax);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
Validation RulesCopied!
ID Validation
-
Path parameter and body
id
must match -
Must be a valid UUID v4 format
-
Tax must exist and be accessible to your application
Field Validation
-
name
: Optional string, no specific length restrictions -
description
: Optional string, can be null -
percentage
: Optional number, can include decimals -
active
: Optional boolean -
appIds
: Optional array of valid UUID v4 strings
Business Rules
-
Cannot update taxes that your application doesn't have access to
-
Your application ID is automatically included in
appIds
-
All specified application IDs must belong to the same business
Rate LimitingCopied!
This endpoint is subject to the standard API rate limits:
-
Production: 1000 requests per hour per API key
-
Development: 100 requests per hour per API key
Best PracticesCopied!
1. Validate Before Update
Always validate data before sending updates:
function validateTaxUpdate(updates) {
const errors = [];
if (updates.percentage !== undefined) {
if (updates.percentage < 0) errors.push('Percentage cannot be negative');
if (updates.percentage > 100) errors.push('Percentage seems unusually high');
}
if (updates.name !== undefined && updates.name.trim() === '') {
errors.push('Name cannot be empty');
}
if (errors.length > 0) {
throw new Error(errors.join(', '));
}
}
2. Partial Updates
Only send fields that actually changed:
function createUpdatePayload(originalTax, formData) {
const updates = { id: originalTax.id };
Object.keys(formData).forEach(key => {
if (formData[key] !== originalTax[key]) {
updates[key] = formData[key];
}
});
return updates;
}
3. Error Recovery
Implement proper error handling and recovery:
async function updateTaxWithRetry(taxId, updates, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await updateTax(taxId, updates);
} catch (error) {
if (attempt === maxRetries || error.status === 404 || error.status === 401) {
throw error;
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
4. Audit Logging
Log important tax changes for compliance:
async function updateTaxWithAudit(taxId, updates, userId) {
const originalTax = await fetchTax(taxId);
const updatedTax = await updateTax(taxId, updates);
// Log the change
await logAuditEvent({
action: 'TAX_UPDATE',
userId: userId,
entityId: taxId,
changes: {
before: originalTax,
after: updatedTax,
fields: Object.keys(updates)
},
timestamp: new Date().toISOString()
});
return updatedTax;
}
Security ConsiderationsCopied!
-
Access Control: Strict application-level access control prevents unauthorized modifications
-
Data Validation: All input is validated to prevent malicious data
-
Business Logic: Automatic inclusion of current app ID prevents loss of access
-
Audit Trail: Consider logging all tax modifications for compliance
-
Rate Limiting: Prevents abuse while allowing legitimate updates