Skip to content

isVAT rejects valid Spanish VAT numbers whose control character is a digit #2846

Description

@rodrigobnogueira

Describe the bug

isVAT(value, 'ES') rejects valid Spanish VAT identification numbers whenever the control character is a digit, which is the case for the two most common Spanish company forms.

The matcher is:

ES: /^(ES)?\w\d{7}[A-Z]$/

The final [A-Z] requires the control character to be a letter. Per the Spanish tax agency (AEAT), position 9 is "Alfanumérico. Carácter de control" and is:

  • a digit 0-9 for Spanish legal entities — leading letters A, B, C, D, E, F, G, H, J, U, V, which include A (sociedad anónima) and B (sociedad de responsabilidad limitada), by far the commonest forms;
  • a letter A-J for foreign entities, public bodies, local corporations and religious congregations — leading letters N, W, P, Q, R, S.

So the current regex accepts only the second group and rejects the first.

Examples

const { isVAT } = require('validator');

isVAT('ESA28015865', 'ES'); // false — Telefónica, S.A. (real, valid)
isVAT('ESB84937783', 'ES'); // false — a real sociedad limitada
isVAT('ESA82018474', 'ES'); // false — a real sociedad anónima

isVAT('ESN0032001J', 'ES'); // true  — foreign entity, letter control
isVAT('ESQ2826004J', 'ES'); // true  — public body, letter control

Suggested fix

Allow both control-character forms, and optionally restrict the leading character to the letters actually assigned to a legal form (I, O and T are unassigned; K, L, M, X, Y, Z belong to natural persons):

ES: /^(ES)?[A-HJNP-SUVW]\d{7}[0-9A-J]$/

I'm happy to open a PR with tests if that shape looks right to you.

Additional context

Sources: AEAT, Composición del NIF – personas jurídicas y entidades; Orden EHA/451/2008 (BOE-A-2008-3580), arts. 3–5.

Found while adding a VAT number generator to faker-js (faker-js/faker#3985), where isVAT is used as the test oracle.

Validator.js version: 13.15.35
Node.js version: v24.18.0
OS platform: macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions