Fetch Tax

The Fetch Tax endpoint retrieves detailed information about a specific tax configuration by its unique identifier. This endpoint provides complete tax details including associated applications and metadata.

Endpoint DetailsCopied!

  • URL: /api/v0/taxes/{id}

  • Method: GET

  • 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

id

string

Unique identifier of the tax to retrieve

Must be a valid UUID v4

Request ExamplesCopied!

Basic Request

curl -X GET https://api.devdraft.com/api/v0/taxes/123e4567-e89b-12d3-a456-426614174000 \
  -H "x-client-key: your-client-key" \
  -H "x-client-secret: your-client-secret"

JavaScript/Fetch

const taxId = "123e4567-e89b-12d3-a456-426614174000";

const response = await fetch(`/api/v0/taxes/${taxId}`, {
  headers: {
    'x-client-key': 'your-client-key',
    'x-client-secret': 'your-client-secret'
  }
});

const tax = await response.json();

ResponseCopied!

Success Response (200 OK)

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "VAT",
  "description": "Value Added Tax for European Union transactions",
  "business_id": "456e7890-e89b-12d3-a456-426614174001",
  "percentage": 20.0,
  "active": true,
  "created_at": "2024-01-15T10:30:00.000Z",
  "updated_at": "2024-01-20T14:45: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": "uk-marketplace",
      "display_name": "UK Marketplace",
      "environment": "PRODUCTION",
      "stage": "PRODUCTION",
      "timezone": "Europe/London",
      "created_at": "2024-01-05T12:00:00.000Z",
      "updated_at": "2024-01-05T12:00:00.000Z"
    }
  ]
}

Error Responses

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"
}
400 Bad Request - Invalid UUID
{
  "statusCode": 400,
  "message": "Validation failed (uuid v4 is expected)",
  "error": "Bad Request"
}

Response FieldsCopied!

Tax Object Fields

Field

Type

Description

id

string

Unique identifier for the tax (UUID v4)

name

string

Tax name (e.g., "VAT", "Sales Tax", "GST")

description

string | null

Detailed description of the tax

business_id

string

ID of the business this tax belongs to

percentage

number

Tax percentage rate (e.g., 20.0 for 20%)

active

boolean

Whether the tax is currently active and can be used

created_at

string

ISO 8601 timestamp when the tax was created

updated_at

string

ISO 8601 timestamp when the tax was last updated

apps

App[]

Array of applications that have access to this tax

App Object Fields

Field

Type

Description

id

string

Unique identifier for the application

business_id

string

ID of the business this app belongs to

app_name

string

Internal application name (kebab-case)

display_name

string

Human-readable application name

environment

string

Application environment (always "PRODUCTION")

stage

string

Application stage (always "PRODUCTION")

timezone

string

Application timezone (e.g., "UTC", "America/New_York")

created_at

string

ISO 8601 timestamp when the app was created

updated_at

string

ISO 8601 timestamp when the app was last updated

Access ControlCopied!

Application-Scoped Access

  • You can only retrieve taxes that are associated with your authenticated application

  • If a tax is not associated with your app, you'll receive a 401 Unauthorized response

  • This ensures data isolation between different applications

Business-Level Isolation

  • Taxes are scoped to the business level

  • Applications from different businesses cannot access each other's taxes

  • The system automatically enforces this boundary

Use CasesCopied!

1. Tax Configuration Display

Retrieve tax details for configuration screens:

async function displayTaxConfiguration(taxId) {
  try {
    const tax = await fetchTax(taxId);
    
    return {
      name: tax.name,
      rate: `${tax.percentage}%`,
      status: tax.active ? 'Active' : 'Inactive',
      description: tax.description || 'No description provided',
      applications: tax.apps.map(app => app.display_name).join(', '),
      lastUpdated: new Date(tax.updated_at).toLocaleDateString()
    };
  } catch (error) {
    console.error('Failed to load tax configuration:', error);
    throw error;
  }
}

2. Invoice Tax Validation

Verify tax details before applying to invoices:

async function validateTaxForInvoice(taxId) {
  const tax = await fetchTax(taxId);
  
  if (!tax.active) {
    throw new Error(`Tax "${tax.name}" is inactive and cannot be used`);
  }
  
  return {
    id: tax.id,
    name: tax.name,
    percentage: tax.percentage
  };
}

3. Tax Rate Calculation

Get tax rate for price calculations:

async function calculateTaxAmount(taxId, baseAmount) {
  const tax = await fetchTax(taxId);
  
  if (!tax.active) {
    throw new Error('Cannot calculate with inactive tax');
  }
  
  const taxAmount = (baseAmount * tax.percentage) / 100;
  
  return {
    baseAmount,
    taxRate: tax.percentage,
    taxAmount,
    totalAmount: baseAmount + taxAmount,
    taxName: tax.name
  };
}

4. Tax History and Audit

Track tax configuration changes:

async function getTaxAuditInfo(taxId) {
  const tax = await fetchTax(taxId);
  
  return {
    taxId: tax.id,
    currentRate: tax.percentage,
    status: tax.active,
    createdDate: tax.created_at,
    lastModified: tax.updated_at,
    associatedApps: tax.apps.length,
    businessId: tax.business_id
  };
}

Integration ExamplesCopied!

React Component

import React, { useState, useEffect } from 'react';

function TaxDetails({ taxId }) {
  const [tax, setTax] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function loadTax() {
      try {
        setLoading(true);
        const response = await fetch(`/api/v0/taxes/${taxId}`, {
          headers: {
            'x-client-key': process.env.REACT_APP_CLIENT_KEY,
            'x-client-secret': process.env.REACT_APP_CLIENT_SECRET
          }
        });

        if (!response.ok) {
          throw new Error(`Failed to load tax: ${response.statusText}`);
        }

        const taxData = await response.json();
        setTax(taxData);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    if (taxId) {
      loadTax();
    }
  }, [taxId]);

  if (loading) return <div>Loading tax details...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!tax) return <div>Tax not found</div>;

  return (
    <div className="tax-details">
      <h3>{tax.name}</h3>
      <p><strong>Rate:</strong> {tax.percentage}%</p>
      <p><strong>Status:</strong> {tax.active ? 'Active' : 'Inactive'}</p>
      {tax.description && (
        <p><strong>Description:</strong> {tax.description}</p>
      )}
      <p><strong>Applications:</strong> {tax.apps.length}</p>
      <ul>
        {tax.apps.map(app => (
          <li key={app.id}>{app.display_name}</li>
        ))}
      </ul>
    </div>
  );
}

Python

import requests
from typing import Optional, Dict, Any

class TaxService:
    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_tax(self, tax_id: str) -> Optional[Dict[Any, Any]]:
        """Fetch a tax by ID"""
        headers = {
            'x-client-key': self.client_key,
            'x-client-secret': self.client_secret
        }
        
        response = requests.get(
            f"{self.base_url}/api/v0/taxes/{tax_id}",
            headers=headers
        )
        
        if response.status_code == 200:
            return response.json()
        elif response.status_code == 404:
            return None
        else:
            response.raise_for_status()
            
    def calculate_tax(self, tax_id: str, amount: float) -> Dict[str, Any]:
        """Calculate tax amount for a given base amount"""
        tax = self.get_tax(tax_id)
        
        if not tax:
            raise ValueError(f"Tax with ID {tax_id} not found")
            
        if not tax['active']:
            raise ValueError(f"Tax '{tax['name']}' is inactive")
            
        tax_amount = (amount * tax['percentage']) / 100
        
        return {
            'base_amount': amount,
            'tax_rate': tax['percentage'],
            'tax_amount': tax_amount,
            'total_amount': amount + tax_amount,
            'tax_name': tax['name']
        }

# Usage
tax_service = TaxService('your-key', 'your-secret', 'https://api.devdraft.com')
tax = tax_service.get_tax('123e4567-e89b-12d3-a456-426614174000')

if tax:
    print(f"Tax: {tax['name']} ({tax['percentage']}%)")
    calculation = tax_service.calculate_tax(tax['id'], 100.00)
    print(f"Tax on $100: ${calculation['tax_amount']:.2f}")

Node.js/Express

const express = require('express');
const axios = require('axios');

class TaxService {
  constructor(clientKey, clientSecret, baseUrl) {
    this.clientKey = clientKey;
    this.clientSecret = clientSecret;
    this.baseUrl = baseUrl;
  }

  async getTax(taxId) {
    try {
      const response = await axios.get(
        `${this.baseUrl}/api/v0/taxes/${taxId}`,
        {
          headers: {
            'x-client-key': this.clientKey,
            'x-client-secret': this.clientSecret
          }
        }
      );
      
      return response.data;
    } catch (error) {
      if (error.response?.status === 404) {
        return null;
      }
      throw error;
    }
  }

  async validateTaxForUse(taxId) {
    const tax = await this.getTax(taxId);
    
    if (!tax) {
      throw new Error(`Tax with ID ${taxId} not found`);
    }
    
    if (!tax.active) {
      throw new Error(`Tax "${tax.name}" is inactive and cannot be used`);
    }
    
    return tax;
  }
}

// Express route example
const app = express();
const taxService = new TaxService(
  process.env.CLIENT_KEY,
  process.env.CLIENT_SECRET,
  'https://api.devdraft.com'
);

app.get('/taxes/:id', async (req, res) => {
  try {
    const tax = await taxService.getTax(req.params.id);
    
    if (!tax) {
      return res.status(404).json({ error: 'Tax not found' });
    }
    
    res.json(tax);
  } catch (error) {
    console.error('Error fetching tax:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

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. Error Handling

Implement comprehensive error handling:

async function safeFetchTax(taxId) {
  try {
    const tax = await fetchTax(taxId);
    return { success: true, data: tax };
  } catch (error) {
    if (error.status === 404) {
      return { success: false, error: 'Tax not found' };
    } else if (error.status === 401) {
      return { success: false, error: 'Access denied' };
    } else {
      return { success: false, error: 'Network error' };
    }
  }
}

2. Caching

Cache frequently accessed tax data:

const taxCache = new Map();
const CACHE_TTL = 30 * 60 * 1000; // 30 minutes

async function getCachedTax(taxId) {
  const cached = taxCache.get(taxId);
  
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }
  
  const tax = await fetchTax(taxId);
  taxCache.set(taxId, {
    data: tax,
    timestamp: Date.now()
  });
  
  return tax;
}

3. Input Validation

Validate tax ID format before API calls:

function isValidUUID(str) {
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
  return uuidRegex.test(str);
}

async function fetchTaxSafely(taxId) {
  if (!isValidUUID(taxId)) {
    throw new Error('Invalid tax ID format');
  }
  
  return await fetchTax(taxId);
}

4. Status Checking

Always verify tax status before use:

function ensureTaxIsUsable(tax) {
  if (!tax.active) {
    throw new Error(`Tax "${tax.name}" is inactive`);
  }
  
  // Additional business logic checks
  if (tax.percentage < 0) {
    throw new Error('Invalid tax rate');
  }
  
  return true;
}

Security ConsiderationsCopied!

  • Access Control: Only applications associated with the tax can retrieve it

  • Data Isolation: Business-level isolation prevents cross-business access

  • Input Validation: UUID validation prevents injection attacks

  • Rate Limiting: Prevents abuse and ensures fair usage

  • Audit Trail: Consider logging tax access for compliance purposes