EU VAT number validation

Normalises the country code and the number (spaces, punctuation, a repeated prefix, GR → EL), checks the national structure and check digit, then asks VIES (REST first, SOAP fallback). Returns the registered name and address where the member state publishes them, and a consultation number when requester is supplied (prepaid credits or the monthly plan). When VIES or the member state is down, the last answer we hold for that number is returned with source.kind = "cache" and source.stale = true; it is never presented as live. A structurally impossible number answers valid: false without calling VIES and is not counted.

About the upstream

VIES (VAT Information Exchange System) is the European Commission’s relay to the 27 national VAT registers. We call its REST endpoint first and its SOAP service when REST fails; a member state that does not answer gives MS_UNAVAILABLE, which this API turns into a cached answer (marked stale) or a 503. Some states publish no name or address ("---"): the fields are then null. Northern Ireland (XI) is in VIES for goods only; GB is not aliased to XI and answers country_unknown: check UK numbers with HMRC’s free service (gov.uk/check-uk-vat-number), Northern Ireland goods traders send XI. The national check digit is verified for all 28 formats before VIES is asked.

GET/vat/validate

Validate an EU VAT number

Normalises the country code and the number (spaces, punctuation, a repeated prefix, GR → EL), checks the national structure and check digit, then asks VIES (REST first, SOAP fallback). Returns the registered name and address where the member state publishes them, and a consultation number when requester is supplied (prepaid credits or the monthly plan). When VIES or the member state is down, the last answer we hold for that number is returned with source.kind = "cache" and source.stale = true; it is never presented as live. A structurally impossible number answers valid: false without calling VIES and is not counted.

Tiers
anonymousfreecreditsplan
Cost
1 call when VIES or the cache answered; 0 when the structure already fails or when a 5xx is returned

Parameters

NameInTypeDescription
countryquerystringISO 3166-1 alpha-2 of the member state; Greece is EL (GR accepted), Northern Ireland XI. May be omitted when number carries the prefix.Example: DE
number*querystringThe VAT number, with or without the country prefix, spaces or punctuation.Example: 136695976
requesterquerystringYour own EU VAT number (with prefix). VIES then issues a consultation number, the evidence a tax audit accepts. Prepaid credits or the monthly plan.Example: FR40303265045
recordquerybooleantrue keeps this validation as a record on your account for 10 years (or until you delete it), and the answer gains record. A structure-only answer is not kept (record is null), since VIES was not consulted. A record is our dated copy of the answer; only the consultation number is issued by VIES. Prepaid credits or the monthly plan.

Request

curl
curl "https://veriport.io/api/v1/vat/validate?country=DE&number=136695976"

Response 200

The validation result, live or from the dated cache.

FieldTypeDescription
valid*booleanTrue when VIES (or the cached VIES answer) says the number is registered for intra-EU transactions on requestDate.
countryCode*string
vatNumber*stringThe national part, normalised.
full*stringPrefix + number.
structure*object
structure.validboolean
structure.checksum"passed" | "failed" | "not_checked"
structure.expectedstring
namestring | nullRegistered name, when the member state publishes it (some answer "---").
addressstring | null
requestDatestring | null (date)The date VIES stamped the answer with.
recordobject | nullPresent when record=true was sent: the kept record, or null for a structure-only answer.
record.idstring
record.createdAtstring (date-time)
record.digeststring
consultationNumberstring | nullVIES request identifier, issued only when requester is supplied and accepted. Keep it with the invoice.
source*object
source.kind"live" | "cache" | "structure_only"
source.checkedAtstring (date-time)
source.cacheAgeSecondsinteger
source.stalebooleanTrue whenever the answer did not come from VIES during this request.
upstream*object
upstream.service"vies"
upstream.transport"rest" | "soap" | null
upstream.status"ok" | "member_state_unavailable" | "service_unavailable" | "timeout" | "blocked" | "not_called"
upstream.memberStateAvailableboolean | null
tableVersionstring | nullUnused for validation; present for symmetry with the rates endpoints.
200 OK · application/json
{
  "valid": true,
  "countryCode": "DE",
  "vatNumber": "136695976",
  "full": "DE136695976",
  "structure": {
    "valid": true,
    "checksum": "passed",
    "expected": "9 digits"
  },
  "name": null,
  "address": null,
  "requestDate": "2026-10-24",
  "consultationNumber": null,
  "source": {
    "kind": "live",
    "checkedAt": "2026-10-24T09:14:03Z",
    "cacheAgeSeconds": 0,
    "stale": false
  },
  "upstream": {
    "service": "vies",
    "transport": "rest",
    "status": "ok",
    "memberStateAvailable": true
  },
  "tableVersion": null
}

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 400invalid_parameter — A parameter is missing or malformed.
  • 401unauthorized — The API key is missing, unknown or revoked.
  • 402quota_exceeded — Monthly allowance and credits are used up.
  • 403forbidden_for_tier — This option is not included in your tier.
  • 429rate_limited — Too many requests per second.
  • 503vies_unavailable — VIES or the member state is unavailable and no cached answer exists. vies_blocked — VIES refused the request (concurrency or blocking).
POST/vat/validate/bulk

Validate up to 100 EU VAT numbers in one request

Monthly plan only. Each item is processed as GET /vat/validate would, with a bounded concurrency towards VIES; items are answered in order. Each item counts one call. Up to 100 items.

Tiers
plan
Cost
1 call per item

Request body

Media types: application/json.

FieldTypeDescription
items*object[]
requesterstringApplied to every item.
application/json
{
  "items": [
    {
      "country": "DE",
      "number": "136695976"
    },
    {
      "number": "FR40303265045"
    }
  ]
}

Request

curl
curl -X POST -H "Authorization: Bearer vp_live_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"items":[{"country":"DE","number":"136695976"},{"number":"FR40303265045"}]}' \
  "https://veriport.io/api/v1/vat/validate/bulk"

Response 200

One result per item, in order.

FieldTypeDescription
resultsobject[]
countedinteger

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 400invalid_parameter — A parameter is missing or malformed.
  • 401unauthorized — The API key is missing, unknown or revoked.
  • 402quota_exceeded — Monthly allowance and credits are used up.
  • 403forbidden_for_tier — This option is not included in your tier.
  • 429rate_limited — Too many requests per second.
GET/vat/validations

List the validation records kept on your account

The records made with record=true, newest first, on every key of the account (a rotated key keeps them). Open to every key, a lapsed plan included, and not counted. format=csv returns the same page as CSV with the next cursor in X-Next-Cursor.

Tiers
freecreditsplan
Cost
free

Parameters

NameInTypeDescription
numberquerystringOnly this VAT number, with or without its prefix (country supplies a missing prefix).
countryquerystringTwo-letter prefix when number has none.
fromquerystringRecords made at or after this ISO 8601 date or instant.
toquerystringRecords made before this ISO 8601 date or instant.
limitqueryintegerRecords per page.
cursorquerystringThe nextCursor of the previous page.
formatquery"json" | "csv"The answer format.

Request

curl
curl -H "Authorization: Bearer vp_live_YOUR_KEY" "https://veriport.io/api/v1/vat/validations"

Response 200

One page of records.

Media types: application/json, text/csv.

FieldTypeDescription
records*ValidationRecord[]
nextCursor*string | null

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 400invalid_parameter — A parameter is missing or malformed.
  • 401unauthorized — The API key is missing, unknown or revoked.
  • 429rate_limited — Too many requests per second.
GET/vat/validations/{id}

Get one validation record

One record of your account, as it was kept. Open to every key and not counted.

Tiers
freecreditsplan
Cost
free

Parameters

NameInTypeDescription
id*pathstringThe record id (vr_…).

Request

curl
curl -H "Authorization: Bearer vp_live_YOUR_KEY" "https://veriport.io/api/v1/vat/validations/id"

Response 200

The record.

FieldTypeDescription
id*stringThe record id (vr_…).
createdAt*string (date-time)When the record was made.
keyPrefixstringThe prefix of the key that made it.
countryCodestring
vatNumberstring
full*stringThe normalised number with its prefix.
valid*boolean
namestring | null
addressstring | null
requestDatestring | null
consultationNumberstring | nullIssued by VIES when requester was supplied.
requesterstring | null
source*object
source.kind"live" | "cache"
source.checkedAtstring (date-time)
source.staleboolean
upstream*object
upstream.service"vies"
upstream.statusstring
upstream.transport"rest" | "soap" | null
digest*stringSHA-256 (hex) of the JSON array [id, createdAt, full, valid, name, address, requestDate, consultationNumber, requester, source.kind, source.checkedAt, source.stale, upstream.status, upstream.transport]. Store it to compare the record later.

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 401unauthorized — The API key is missing, unknown or revoked.
  • 404not_found — No such resource.
  • 429rate_limited — Too many requests per second.
DELETE/vat/validations/{id}

Delete one validation record

Deletes the record for good. Records cannot be edited, only deleted. Open to every key and not counted.

Tiers
freecreditsplan
Cost
free

Parameters

NameInTypeDescription
id*pathstringThe record id (vr_…).

Request

curl
curl -H "Authorization: Bearer vp_live_YOUR_KEY" "https://veriport.io/api/v1/vat/validations/id"

Response 200

Deleted.

FieldTypeDescription
id*string
deleted*boolean

Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy, X-Quota-Remaining, X-Tier.

Errors

  • 401unauthorized — The API key is missing, unknown or revoked.
  • 404not_found — No such resource.
  • 429rate_limited — Too many requests per second.

Sources