Skip to main content

Response Format

Every Vatly response follows the same envelope pattern: either data or error, always accompanied by meta. This means if (response.error) always works as a check.

Success response

{
  "data": {
    "valid": true,
    "vat_number": "NL123456789B01",
    "country_code": "NL",
    "company": {
      "name": "Acme B.V.",
      "address": "Keizersgracht 123, Amsterdam"
    },
    "requested_at": "2026-03-06T12:00:00Z"
  },
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "request_duration_ms": 120,
    "cached": false
  }
}

data fields

FieldTypeDescription
validbooleanWhether the VAT number is active and registered
vat_numberstringThe normalized VAT number
country_codestringTwo-letter country code
companyobject | nullCompany name and address (when valid and available)
company.namestringRegistered company name
company.addressstring | nullRegistered address
consultation_numberstringVIES/HMRC consultation number. Only present when requester_vat_number is provided. Not available for CH, LI, NO, or AU validations
requested_atstringISO 8601 timestamp of the validation

Error response

{
  "error": {
    "code": "invalid_vat_format",
    "message": "The VAT number format is invalid. Expected format: CC123456789",
    "docs_url": "https://docs.vatly.dev/errors/invalid_vat_format"
  },
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000"
  }
}

error fields

FieldTypeDescription
codestringMachine-readable error code
messagestringHuman-readable explanation
docs_urlstringLink to the error documentation page

meta fields

Present on every response, success or error.
FieldTypeDescription
request_idstringUnique request identifier (UUID)
request_duration_msnumberTotal request processing time in milliseconds (success responses only)
cachedbooleanWhether the result came from cache. Omitted when not applicable
cached_atstringISO 8601 timestamp of the cached result. Omitted when not cached
stalebooleantrue when serving an expired cached result due to upstream failure. Omitted when not stale
source_statusstringUpstream data source reliability: "live" (fresh result), "unavailable" (upstream down, stale cache served), or "degraded" (possible silent false negative). Applies to all upstream sources (VIES, HMRC, BFS, Bronnysund, or ABR). Only present on fresh upstream lookups and stale fallbacks
modestring"test" when using a test key. Omitted for live keys

Batch items

Each item in a batch validation response uses the same envelope:
  • Success: { data: VatValidationData, meta }. The data object is the exact same shape as the single validate endpoint
  • Error: { error, meta }. The meta contains the vat_number that failed
Per-item meta contains cache fields (cached, cached_at, stale) and source_status when applicable. Request-level fields like request_id and request_duration_ms live on the top-level meta.

Response headers

HeaderWhen presentDescription
X-Request-IdAlwaysUnique request identifier matching meta.request_id
X-RateLimit-LimitAuthenticated requestsTotal requests allowed this period
X-RateLimit-RemainingAuthenticated requestsRequests remaining this period
X-RateLimit-ResetAuthenticated requestsWhen the quota resets (ISO 8601)
X-Burst-LimitAuthenticated requestsPer-minute burst limit for your tier
X-Burst-RemainingAuthenticated requestsBurst requests remaining this minute
Retry-After429 and 503 responsesSeconds to wait before retrying

Request ID header

Every response includes an X-Request-Id header matching meta.request_id. You can pass your own X-Request-Id header and it will be echoed back - useful for correlating requests in your own logging.
curl -H "Authorization: Bearer vtly_live_your_api_key" \
  -H "X-Request-Id: my-trace-id-123" \
  "https://api.vatly.dev/v1/validate?vat_number=NL123456789B01"