Error Handling

vatnode uses standard HTTP status codes and returns detailed error information in JSON format.

Error Response Format

All errors follow this structure:

Error Response
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "requestId": "req_abc123",
    "details": {}
  }
}
FieldTypeDescription
codestringMachine-readable error code
messagestringHuman-readable description
requestIdstringUnique request ID for debugging
detailsobjectAdditional context (optional)

HTTP Status Codes

StatusMeaning
200Success
400Bad Request - Invalid input
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not Found - Resource doesn't exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error
502Bad Gateway - Upstream error (VIES)
503Service Unavailable
504Gateway Timeout - VIES timeout

Error Codes

INVALID_INPUT

The request contains invalid parameters.

400 Bad Request
{
  "error": {
    "code": "INVALID_INPUT",
    "message": "Invalid VAT ID format",
    "requestId": "req_abc123"
  }
}

INVALID_FORMAT

The VAT number format is invalid.

400 Bad Request
{
  "error": {
    "code": "INVALID_FORMAT",
    "message": "Invalid VAT ID format. Expected format: country code (2 letters) followed by VAT number",
    "requestId": "req_abc123"
  }
}

RATE_LIMITED

You've exceeded your rate limit.

429 Too Many Requests
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Please try again later.",
    "retryAfter": 30,
    "requestId": "req_abc123"
  }
}

How to handle:

  • Check the Retry-After header for when to retry
  • Implement exponential backoff
  • Consider upgrading your plan for higher limits

VIES_UNAVAILABLE

The VIES service is temporarily unavailable.

503 Service Unavailable
{
  "error": {
    "code": "VIES_UNAVAILABLE",
    "message": "VIES service is temporarily unavailable",
    "viesCode": "SERVICE_UNAVAILABLE",
    "requestId": "req_abc123"
  }
}

VIES_ERROR

An error occurred while communicating with VIES.

502 Bad Gateway
{
  "error": {
    "code": "VIES_ERROR",
    "message": "An error occurred while validating VAT",
    "viesCode": "MS_UNAVAILABLE",
    "requestId": "req_abc123"
  }
}

VIES-specific codes returned in the viesCode field:

viesCodeDescription
MS_UNAVAILABLEMember state's national service is down or not responding
MS_MAX_CONCURRENT_REQMember state's service is busy; max concurrent requests exceeded
MS_MAX_CONCURRENT_REQ_TIMEMember state's service is busy; concurrent request timed out
GLOBAL_MAX_CONCURRENT_REQVIES global concurrent request limit exceeded
GLOBAL_MAX_CONCURRENT_REQ_TIMEVIES global concurrent request timeout
SERVICE_UNAVAILABLECentral VIES service is unavailable
TIMEOUTVIES request timed out
INVALID_INPUTVIES rejected the input (invalid country code or empty VAT number)
VAT_BLOCKEDThe requested VAT number is blocked in VIES
IP_BLOCKEDThe requesting IP address is blocked by VIES

PLAN_LIMIT

Your monthly request quota has been reached.

403 Forbidden
{
  "error": {
    "code": "PLAN_LIMIT",
    "message": "Monthly request quota exceeded. Upgrade your plan to continue.",
    "requestId": "req_abc123"
  }
}

ALREADY_EXISTS

The resource you are trying to create already exists (e.g., duplicate API key label or webhook URL).

409 Conflict
{
  "error": {
    "code": "ALREADY_EXISTS",
    "message": "A resource with this identifier already exists.",
    "requestId": "req_abc123"
  }
}

CREATION_FAILED

An internal error occurred while creating a resource. Retrying the request is safe.

500 Internal Server Error
{
  "error": {
    "code": "CREATION_FAILED",
    "message": "Failed to create resource. Please try again.",
    "requestId": "req_abc123"
  }
}

Best Practices

1. Always Check HTTP Status

JavaScript
const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();

  switch (response.status) {
    case 400:
      console.error('Invalid request:', error.error.message);
      break;
    case 429:
      const retryAfter = response.headers.get('Retry-After');
      console.error('Rate limited, retry after:', retryAfter);
      break;
    case 503:
      console.error('Service unavailable, retrying...');
      break;
    default:
      console.error('Error:', error.error.message);
  }
}

2. Implement Retry Logic

JavaScript
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.ok) return response.json();

      if (response.status === 429 || response.status >= 500) {
        const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }

      // Client error, don't retry
      const error = await response.json();
      throw new Error(error.error.message);
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}

3. Log Request IDs

Always log the requestId from error responses. This helps us investigate issues:

JavaScript
try {
  const result = await validateVat('IE6388047V');
} catch (error) {
  console.error('Validation failed:', {
    message: error.message,
    requestId: error.requestId, // Include this in support tickets
  });
}

4. Handle VIES Downtime Gracefully

VIES has scheduled maintenance and occasional outages. Consider showing a user-friendly message:

JavaScript
async function validateVatWithFallback(vatId) {
  try {
    return await validateVat(vatId);
  } catch (error) {
    if (error.code === 'VIES_UNAVAILABLE') {
      return {
        valid: null, // Unknown
        vatId,
        message: 'VAT validation temporarily unavailable. Will verify later.',
        pendingVerification: true,
      };
    }
    throw error;
  }
}

Support

If you encounter persistent errors:

  1. Check the vatnode status page for known issues
  2. Review your API key and rate limits in the Dashboard
  3. Contact support with your requestId for investigation