eu_vat_rates_data 2026.3.28 → 2026.3.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b444876a0a0dc2c6aafd9d4e4367514dd72e9a0ef3dab4c8cd42b80e437333d
4
- data.tar.gz: b56a6237e8b942f3b169ca8df3de118f91f40bf64769b5bbb7c8a0495bff8c3a
3
+ metadata.gz: 9aa5cfb0609e948804ee35b2314921d7f07a8561b015a35fde1b24465e6eac39
4
+ data.tar.gz: 909f7e7e7a454a4c83f10030c48e1bdcebdf2dffd96d00dfe47ef8dc017533f4
5
5
  SHA512:
6
- metadata.gz: 8bfe1d99c8aa8457366756781a658c35b44214107619847edff94e6547184d59ac08424c6886e5aa5358574ee39a3869dc5c18ba4d708dfc3f7a708b190c7d4e
7
- data.tar.gz: c41d3ff162e737217675efc767227df1c32f2c0cdbd9989d35c0537346359970ead9fead73ecd773385d20a38eac6a7df242fa86c35b3bed6ab5634e0fa89b9c
6
+ metadata.gz: 47f2770e396b04e9140dd3aacae12c3980eb4a0906d9fd2d6e9a5bde6ca3b75f23a29e349f4d866b5cb4065a907def92c4d4184beb580703b06e206f984cdfe0
7
+ data.tar.gz: cc8cca83cf408f8a816440b86323caeb3e4f451de7c59da4ab647a4453f5f79309ac83b6cceca282b8838e9a417687b17315aec60defbf05750605e4b209b594
data/README.md CHANGED
@@ -4,12 +4,14 @@
4
4
  [![Last updated](https://img.shields.io/github/last-commit/vatnode/eu-vat-rates-data-ruby?path=data%2Feu-vat-rates-data.json&label=last%20updated)](https://github.com/vatnode/eu-vat-rates-data-ruby/commits/main)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
 
7
- VAT rates for **44 European countries** — EU-27 plus Norway, Switzerland, UK, and more. EU rates sourced from the [European Commission TEDB](https://ec.europa.eu/taxation_customs/tedb/) and checked daily. Non-EU rates maintained manually.
7
+ VAT rates for **44 European countries** — EU-27 plus Norway, Switzerland, UK, and more. EU rates sourced from the European Commission TEDB and checked daily. Non-EU rates maintained manually.
8
8
 
9
9
  - Standard, reduced, super-reduced, and parking rates
10
10
  - `eu_member` flag on every country — `true` for EU-27, `false` for non-EU
11
11
  - `vat_name` — official name of the VAT tax in the country's primary official language
12
12
  - `vat_abbr` — short abbreviation used locally (e.g. "ALV", "MwSt", "TVA")
13
+ - **`format` — human-readable VAT number format (e.g. `"ATU + 8 digits"`)** — unique to this package
14
+ - **`pattern` — regex for VAT number validation + built-in `valid_format?()` — free, no API key needed** — unique to this package
13
15
  - No dependencies — pure Ruby 3.0+
14
16
  - Data bundled in the gem — works offline, no network calls
15
17
  - EU rates checked daily via GitHub Actions, new version published only when rates change
@@ -67,6 +69,16 @@ end
67
69
 
68
70
  # When were EU rates last fetched?
69
71
  puts EuVatRatesData.data_version # e.g. "2026-03-27"
72
+
73
+ # VAT number format validation — no API key, no network call
74
+ EuVatRatesData.valid_format?("ATU12345678") # => true
75
+ EuVatRatesData.valid_format?("DE123456789") # => true
76
+ EuVatRatesData.valid_format?("INVALID") # => false
77
+
78
+ # Access format metadata directly
79
+ at = EuVatRatesData.get_rate("AT")
80
+ puts at["format"] # "ATU + 8 digits"
81
+ puts at["pattern"] # "^ATU\\d{8}$"
70
82
  ```
71
83
 
72
84
  ---
@@ -79,6 +91,23 @@ puts EuVatRatesData.data_version # e.g. "2026-03-27"
79
91
 
80
92
  ---
81
93
 
94
+
95
+ ## Keeping rates current
96
+
97
+ Rates are bundled at install time. A new package version is published automatically whenever rates change — but your installed version will not update itself.
98
+
99
+ **Recommended:** add [Renovate](https://renovatebot.com) or [Dependabot](https://docs.github.com/en/code-security/dependabot) to your repo. They detect new versions and open a PR automatically whenever rates change — no manual update commands needed.
100
+
101
+ **Need real-time accuracy?** Fetch the always-current JSON directly:
102
+
103
+ ```
104
+ https://cdn.jsdelivr.net/gh/vatnode/eu-vat-rates-data@main/data/eu-vat-rates-data.json
105
+ ```
106
+
107
+ No package needed — parse it with a single `fetch()` / `http.get()` / `file_get_contents()` call and cache locally.
108
+
109
+ ---
110
+
82
111
  ## Covered countries
83
112
 
84
113
  **EU-27** (daily auto-updates via EC TEDB):
@@ -1,39 +1,45 @@
1
1
  {
2
- "version": "2026-03-28",
2
+ "version": "2026-03-30",
3
3
  "source": "European Commission TEDB",
4
- "url": "https://ec.europa.eu/taxation_customs/tedb/",
5
4
  "rates": {
6
5
  "AD": {
7
6
  "country": "Andorra",
8
7
  "currency": "EUR",
9
8
  "eu_member": false,
10
9
  "vat_name": "Impost General Indirecte",
10
+ "vat_abbr": "IGI",
11
11
  "standard": 4.5,
12
12
  "reduced": [
13
13
  1.0,
14
14
  2.5
15
15
  ],
16
16
  "super_reduced": null,
17
- "parking": null
17
+ "parking": null,
18
+ "format": "AD + alphanumeric",
19
+ "pattern": null
18
20
  },
19
21
  "AL": {
20
22
  "country": "Albania",
21
23
  "currency": "ALL",
22
24
  "eu_member": false,
23
25
  "vat_name": "Tatimi mbi vlerën e shtuar",
26
+ "vat_abbr": "TVSH",
24
27
  "standard": 20.0,
25
28
  "reduced": [
26
29
  6.0,
27
30
  10.0
28
31
  ],
29
32
  "super_reduced": null,
30
- "parking": null
33
+ "parking": null,
34
+ "format": "AL + 1 letter + 8 digits + 1 letter",
35
+ "pattern": "^AL[A-Z]\\d{8}[A-Z]$"
31
36
  },
32
37
  "AT": {
33
38
  "country": "Austria",
34
39
  "currency": "EUR",
35
40
  "eu_member": true,
36
41
  "vat_name": "Umsatzsteuer",
42
+ "vat_abbr": "USt",
37
43
  "standard": 20.0,
38
44
  "reduced": [
39
45
  10.0,
@@ -41,146 +47,182 @@
41
47
  19.0
42
48
  ],
43
49
  "super_reduced": null,
44
- "parking": null
50
+ "parking": null,
51
+ "format": "ATU + 8 digits",
52
+ "pattern": "^ATU\\d{8}$"
45
53
  },
46
54
  "BA": {
47
55
  "country": "Bosnia and Herzegovina",
48
56
  "currency": "BAM",
49
57
  "eu_member": false,
50
58
  "vat_name": "Porez na dodanu vrijednost",
59
+ "vat_abbr": "PDV",
51
60
  "standard": 17.0,
52
61
  "reduced": [],
53
62
  "super_reduced": null,
54
- "parking": null
63
+ "parking": null,
64
+ "format": "BA + alphanumeric",
65
+ "pattern": null
55
66
  },
56
67
  "BE": {
57
68
  "country": "Belgium",
58
69
  "currency": "EUR",
59
70
  "eu_member": true,
60
71
  "vat_name": "Belasting over de toegevoegde waarde",
72
+ "vat_abbr": "BTW",
61
73
  "standard": 21.0,
62
74
  "reduced": [
63
75
  6.0,
64
76
  12.0
65
77
  ],
66
78
  "super_reduced": null,
67
- "parking": 12.0
79
+ "parking": 12.0,
80
+ "format": "BE + 0/1 + 9 digits",
81
+ "pattern": "^BE[01]\\d{9}$"
68
82
  },
69
83
  "BG": {
70
84
  "country": "Bulgaria",
71
85
  "currency": "BGN",
72
86
  "eu_member": true,
73
87
  "vat_name": "Данък върху добавената стойност",
88
+ "vat_abbr": "ДДС",
74
89
  "standard": 20.0,
75
90
  "reduced": [
76
91
  9.0
77
92
  ],
78
93
  "super_reduced": null,
79
- "parking": null
94
+ "parking": null,
95
+ "format": "BG + 9–10 digits",
96
+ "pattern": "^BG\\d{9,10}$"
80
97
  },
81
98
  "CH": {
82
99
  "country": "Switzerland",
83
100
  "currency": "CHF",
84
101
  "eu_member": false,
85
102
  "vat_name": "Mehrwertsteuer",
103
+ "vat_abbr": "MWST",
86
104
  "standard": 8.1,
87
105
  "reduced": [
88
106
  2.6,
89
107
  3.8
90
108
  ],
91
109
  "super_reduced": null,
92
- "parking": null
110
+ "parking": null,
111
+ "format": "CHE + 9 digits (+ MWST/TVA/IVA)",
112
+ "pattern": "^CHE\\d{9}(MWST|TVA|IVA)?$"
93
113
  },
94
114
  "CY": {
95
115
  "country": "Cyprus",
96
116
  "currency": "EUR",
97
117
  "eu_member": true,
98
118
  "vat_name": "Φόρος Προστιθέμενης Αξίας",
119
+ "vat_abbr": "ΦΠΑ",
99
120
  "standard": 19.0,
100
121
  "reduced": [
101
122
  5.0,
102
123
  9.0
103
124
  ],
104
125
  "super_reduced": 3.0,
105
- "parking": null
126
+ "parking": null,
127
+ "format": "CY + 8 digits + 1 letter",
128
+ "pattern": "^CY\\d{8}[A-Z]$"
106
129
  },
107
130
  "CZ": {
108
131
  "country": "Czech Republic",
109
132
  "currency": "CZK",
110
133
  "eu_member": true,
111
134
  "vat_name": "Daň z přidané hodnoty",
135
+ "vat_abbr": "DPH",
112
136
  "standard": 21.0,
113
137
  "reduced": [
114
138
  12.0
115
139
  ],
116
140
  "super_reduced": null,
117
- "parking": null
141
+ "parking": null,
142
+ "format": "CZ + 8–10 digits",
143
+ "pattern": "^CZ\\d{8,10}$"
118
144
  },
119
145
  "DE": {
120
146
  "country": "Germany",
121
147
  "currency": "EUR",
122
148
  "eu_member": true,
123
149
  "vat_name": "Umsatzsteuer",
150
+ "vat_abbr": "MwSt",
124
151
  "standard": 19.0,
125
152
  "reduced": [
126
153
  7.0
127
154
  ],
128
155
  "super_reduced": null,
129
- "parking": null
156
+ "parking": null,
157
+ "format": "DE + 9 digits",
158
+ "pattern": "^DE\\d{9}$"
130
159
  },
131
160
  "DK": {
132
161
  "country": "Denmark",
133
162
  "currency": "DKK",
134
163
  "eu_member": true,
135
164
  "vat_name": "Moms",
165
+ "vat_abbr": "moms",
136
166
  "standard": 25.0,
137
167
  "reduced": [],
138
168
  "super_reduced": null,
139
- "parking": null
169
+ "parking": null,
170
+ "format": "DK + 8 digits",
171
+ "pattern": "^DK\\d{8}$"
140
172
  },
141
173
  "EE": {
142
174
  "country": "Estonia",
143
175
  "currency": "EUR",
144
176
  "eu_member": true,
145
177
  "vat_name": "Käibemaks",
178
+ "vat_abbr": "km",
146
179
  "standard": 24.0,
147
180
  "reduced": [
148
181
  9.0,
149
182
  13.0
150
183
  ],
151
184
  "super_reduced": null,
152
- "parking": null
185
+ "parking": null,
186
+ "format": "EE + 9 digits",
187
+ "pattern": "^EE\\d{9}$"
153
188
  },
154
189
  "ES": {
155
190
  "country": "Spain",
156
191
  "currency": "EUR",
157
192
  "eu_member": true,
158
193
  "vat_name": "Impuesto sobre el Valor Añadido",
194
+ "vat_abbr": "IVA",
159
195
  "standard": 21.0,
160
196
  "reduced": [
161
197
  10.0
162
198
  ],
163
199
  "super_reduced": 4.0,
164
- "parking": null
200
+ "parking": null,
201
+ "format": "ES + letter/digit + 7 digits + letter/digit",
202
+ "pattern": "^ES[A-Z0-9]\\d{7}[A-Z0-9]$"
165
203
  },
166
204
  "FI": {
167
205
  "country": "Finland",
168
206
  "currency": "EUR",
169
207
  "eu_member": true,
170
208
  "vat_name": "Arvonlisävero",
209
+ "vat_abbr": "ALV",
171
210
  "standard": 25.5,
172
211
  "reduced": [
173
212
  10.0,
174
213
  13.5
175
214
  ],
176
215
  "super_reduced": null,
177
- "parking": null
216
+ "parking": null,
217
+ "format": "FI + 8 digits",
218
+ "pattern": "^FI\\d{8}$"
178
219
  },
179
220
  "FR": {
180
221
  "country": "France",
181
222
  "currency": "EUR",
182
223
  "eu_member": true,
183
224
  "vat_name": "Taxe sur la valeur ajoutée",
225
+ "vat_abbr": "TVA",
184
226
  "standard": 20.0,
185
227
  "reduced": [
186
228
  0.9,
@@ -191,35 +233,44 @@
191
233
  13.0
192
234
  ],
193
235
  "super_reduced": 2.1,
194
- "parking": null
236
+ "parking": null,
237
+ "format": "FR + 2 alphanumeric + 9 digits",
238
+ "pattern": "^FR[A-HJ-NP-Z0-9]{2}\\d{9}$"
195
239
  },
196
240
  "GB": {
197
241
  "country": "United Kingdom",
198
242
  "currency": "GBP",
199
243
  "eu_member": false,
200
244
  "vat_name": "Value Added Tax",
245
+ "vat_abbr": "VAT",
201
246
  "standard": 20.0,
202
247
  "reduced": [
203
248
  5.0
204
249
  ],
205
250
  "super_reduced": null,
206
- "parking": null
251
+ "parking": null,
252
+ "format": "GB + 9 or 12 digits (or GD/HA + 3 digits)",
253
+ "pattern": "^GB(\\d{9}|\\d{12}|GD\\d{3}|HA\\d{3})$"
207
254
  },
208
255
  "GE": {
209
256
  "country": "Georgia",
210
257
  "currency": "GEL",
211
258
  "eu_member": false,
212
259
  "vat_name": "დამატებული ღირებულების გადასახადი",
260
+ "vat_abbr": "დღგ",
213
261
  "standard": 18.0,
214
262
  "reduced": [],
215
263
  "super_reduced": null,
216
- "parking": null
264
+ "parking": null,
265
+ "format": "GE + alphanumeric",
266
+ "pattern": null
217
267
  },
218
268
  "GR": {
219
269
  "country": "Greece",
220
270
  "currency": "EUR",
221
271
  "eu_member": true,
222
272
  "vat_name": "Φόρος Προστιθέμενης Αξίας",
273
+ "vat_abbr": "ΦΠΑ",
223
274
  "standard": 24.0,
224
275
  "reduced": [
225
276
  6.0,
@@ -227,231 +278,285 @@
227
278
  17.0
228
279
  ],
229
280
  "super_reduced": 4.0,
230
- "parking": 13.0
281
+ "parking": 13.0,
282
+ "format": "EL + 9 digits",
283
+ "pattern": "^EL\\d{9}$"
231
284
  },
232
285
  "HR": {
233
286
  "country": "Croatia",
234
287
  "currency": "EUR",
235
288
  "eu_member": true,
236
289
  "vat_name": "Porez na dodanu vrijednost",
290
+ "vat_abbr": "PDV",
237
291
  "standard": 25.0,
238
292
  "reduced": [
239
293
  5.0,
240
294
  13.0
241
295
  ],
242
296
  "super_reduced": null,
243
- "parking": null
297
+ "parking": null,
298
+ "format": "HR + 11 digits",
299
+ "pattern": "^HR\\d{11}$"
244
300
  },
245
301
  "HU": {
246
302
  "country": "Hungary",
247
303
  "currency": "HUF",
248
304
  "eu_member": true,
249
305
  "vat_name": "Általános forgalmi adó",
306
+ "vat_abbr": "ÁFA",
250
307
  "standard": 27.0,
251
308
  "reduced": [
252
309
  5.0,
253
310
  18.0
254
311
  ],
255
312
  "super_reduced": null,
256
- "parking": null
313
+ "parking": null,
314
+ "format": "HU + 8 digits",
315
+ "pattern": "^HU\\d{8}$"
257
316
  },
258
317
  "IE": {
259
318
  "country": "Ireland",
260
319
  "currency": "EUR",
261
320
  "eu_member": true,
262
321
  "vat_name": "Value Added Tax",
322
+ "vat_abbr": "VAT",
263
323
  "standard": 23.0,
264
324
  "reduced": [
265
325
  9.0,
266
326
  13.5
267
327
  ],
268
328
  "super_reduced": null,
269
- "parking": null
329
+ "parking": null,
330
+ "format": "IE + 7 digits + 1–2 letters",
331
+ "pattern": "^IE\\d{7}[A-W][A-IW]?$|^IE\\d[A-Z+*]\\d{5}[A-W]$"
270
332
  },
271
333
  "IS": {
272
334
  "country": "Iceland",
273
335
  "currency": "ISK",
274
336
  "eu_member": false,
275
337
  "vat_name": "Virðisaukaskattur",
338
+ "vat_abbr": "VSK",
276
339
  "standard": 24.0,
277
340
  "reduced": [
278
341
  11.0
279
342
  ],
280
343
  "super_reduced": null,
281
- "parking": null
344
+ "parking": null,
345
+ "format": "IS + 5–6 digits",
346
+ "pattern": "^IS\\d{5,6}$"
282
347
  },
283
348
  "IT": {
284
349
  "country": "Italy",
285
350
  "currency": "EUR",
286
351
  "eu_member": true,
287
352
  "vat_name": "Imposta sul valore aggiunto",
353
+ "vat_abbr": "IVA",
288
354
  "standard": 22.0,
289
355
  "reduced": [
290
356
  5.0,
291
357
  10.0
292
358
  ],
293
359
  "super_reduced": 4.0,
294
- "parking": null
360
+ "parking": null,
361
+ "format": "IT + 11 digits",
362
+ "pattern": "^IT\\d{11}$"
295
363
  },
296
364
  "LI": {
297
365
  "country": "Liechtenstein",
298
366
  "currency": "CHF",
299
367
  "eu_member": false,
300
368
  "vat_name": "Mehrwertsteuer",
369
+ "vat_abbr": "MWST",
301
370
  "standard": 8.1,
302
371
  "reduced": [
303
372
  2.6,
304
373
  3.8
305
374
  ],
306
375
  "super_reduced": null,
307
- "parking": null
376
+ "parking": null,
377
+ "format": "LI + alphanumeric",
378
+ "pattern": null
308
379
  },
309
380
  "LT": {
310
381
  "country": "Lithuania",
311
382
  "currency": "EUR",
312
383
  "eu_member": true,
313
384
  "vat_name": "Pridėtinės vertės mokestis",
385
+ "vat_abbr": "PVM",
314
386
  "standard": 21.0,
315
387
  "reduced": [
316
388
  5.0,
317
389
  12.0
318
390
  ],
319
391
  "super_reduced": null,
320
- "parking": null
392
+ "parking": null,
393
+ "format": "LT + 9 or 12 digits",
394
+ "pattern": "^LT(\\d{9}|\\d{12})$"
321
395
  },
322
396
  "LU": {
323
397
  "country": "Luxembourg",
324
398
  "currency": "EUR",
325
399
  "eu_member": true,
326
400
  "vat_name": "Taxe sur la valeur ajoutée",
401
+ "vat_abbr": "TVA",
327
402
  "standard": 17.0,
328
403
  "reduced": [
329
404
  8.0,
330
405
  14.0
331
406
  ],
332
407
  "super_reduced": 3.0,
333
- "parking": 14.0
408
+ "parking": 14.0,
409
+ "format": "LU + 8 digits",
410
+ "pattern": "^LU\\d{8}$"
334
411
  },
335
412
  "LV": {
336
413
  "country": "Latvia",
337
414
  "currency": "EUR",
338
415
  "eu_member": true,
339
416
  "vat_name": "Pievienotās vērtības nodoklis",
417
+ "vat_abbr": "PVN",
340
418
  "standard": 21.0,
341
419
  "reduced": [
342
420
  5.0,
343
421
  12.0
344
422
  ],
345
423
  "super_reduced": null,
346
- "parking": null
424
+ "parking": null,
425
+ "format": "LV + 11 digits",
426
+ "pattern": "^LV\\d{11}$"
347
427
  },
348
428
  "MC": {
349
429
  "country": "Monaco",
350
430
  "currency": "EUR",
351
431
  "eu_member": false,
352
432
  "vat_name": "Taxe sur la valeur ajoutée",
433
+ "vat_abbr": "TVA",
353
434
  "standard": 20.0,
354
435
  "reduced": [
355
436
  5.5,
356
437
  10.0
357
438
  ],
358
439
  "super_reduced": 2.1,
359
- "parking": null
440
+ "parking": null,
441
+ "format": "MC + alphanumeric",
442
+ "pattern": null
360
443
  },
361
444
  "MD": {
362
445
  "country": "Moldova",
363
446
  "currency": "MDL",
364
447
  "eu_member": false,
365
448
  "vat_name": "Taxa pe valoarea adăugată",
449
+ "vat_abbr": "TVA",
366
450
  "standard": 20.0,
367
451
  "reduced": [
368
452
  8.0
369
453
  ],
370
454
  "super_reduced": null,
371
- "parking": null
455
+ "parking": null,
456
+ "format": "MD + alphanumeric",
457
+ "pattern": null
372
458
  },
373
459
  "ME": {
374
460
  "country": "Montenegro",
375
461
  "currency": "EUR",
376
462
  "eu_member": false,
377
463
  "vat_name": "Porez na dodatu vrijednost",
464
+ "vat_abbr": "PDV",
378
465
  "standard": 21.0,
379
466
  "reduced": [
380
467
  7.0,
381
468
  15.0
382
469
  ],
383
470
  "super_reduced": null,
384
- "parking": null
471
+ "parking": null,
472
+ "format": "ME + 8 digits",
473
+ "pattern": "^ME\\d{8}$"
385
474
  },
386
475
  "MK": {
387
476
  "country": "North Macedonia",
388
477
  "currency": "MKD",
389
478
  "eu_member": false,
390
479
  "vat_name": "Данок на додадена вредност",
480
+ "vat_abbr": "ДДВ",
391
481
  "standard": 18.0,
392
482
  "reduced": [
393
483
  5.0,
394
484
  10.0
395
485
  ],
396
486
  "super_reduced": null,
397
- "parking": null
487
+ "parking": null,
488
+ "format": "MK + 13 digits",
489
+ "pattern": "^MK\\d{13}$"
398
490
  },
399
491
  "MT": {
400
492
  "country": "Malta",
401
493
  "currency": "EUR",
402
494
  "eu_member": true,
403
495
  "vat_name": "Taxxa tal-Valur Miżjud",
496
+ "vat_abbr": "VAT",
404
497
  "standard": 18.0,
405
498
  "reduced": [
406
499
  5.0,
407
500
  7.0
408
501
  ],
409
502
  "super_reduced": null,
410
- "parking": 12.0
503
+ "parking": 12.0,
504
+ "format": "MT + 8 digits",
505
+ "pattern": "^MT\\d{8}$"
411
506
  },
412
507
  "NL": {
413
508
  "country": "Netherlands",
414
509
  "currency": "EUR",
415
510
  "eu_member": true,
416
511
  "vat_name": "Belasting over de toegevoegde waarde",
512
+ "vat_abbr": "btw",
417
513
  "standard": 21.0,
418
514
  "reduced": [
419
515
  9.0
420
516
  ],
421
517
  "super_reduced": null,
422
- "parking": null
518
+ "parking": null,
519
+ "format": "NL + 9 digits + B + 2 digits",
520
+ "pattern": "^NL\\d{9}B\\d{2}$"
423
521
  },
424
522
  "NO": {
425
523
  "country": "Norway",
426
524
  "currency": "NOK",
427
525
  "eu_member": false,
428
526
  "vat_name": "Merverdiavgift",
527
+ "vat_abbr": "MVA",
429
528
  "standard": 25.0,
430
529
  "reduced": [
431
530
  12.0,
432
531
  15.0
433
532
  ],
434
533
  "super_reduced": null,
435
- "parking": null
534
+ "parking": null,
535
+ "format": "NO + 9 digits + MVA",
536
+ "pattern": "^NO\\d{9}MVA$"
436
537
  },
437
538
  "PL": {
438
539
  "country": "Poland",
439
540
  "currency": "PLN",
440
541
  "eu_member": true,
441
542
  "vat_name": "Podatek od towarów i usług",
543
+ "vat_abbr": "VAT",
442
544
  "standard": 23.0,
443
545
  "reduced": [
444
546
  5.0,
445
547
  8.0
446
548
  ],
447
549
  "super_reduced": 8.0,
448
- "parking": null
550
+ "parking": null,
551
+ "format": "PL + 10 digits",
552
+ "pattern": "^PL\\d{10}$"
449
553
  },
450
554
  "PT": {
451
555
  "country": "Portugal",
452
556
  "currency": "EUR",
453
557
  "eu_member": true,
454
558
  "vat_name": "Imposto sobre o Valor Acrescentado",
559
+ "vat_abbr": "IVA",
455
560
  "standard": 23.0,
456
561
  "reduced": [
457
562
  6.0,
@@ -460,108 +565,134 @@
460
565
  22.0
461
566
  ],
462
567
  "super_reduced": 6.0,
463
- "parking": 13.0
568
+ "parking": 13.0,
569
+ "format": "PT + 9 digits",
570
+ "pattern": "^PT\\d{9}$"
464
571
  },
465
572
  "RO": {
466
573
  "country": "Romania",
467
574
  "currency": "RON",
468
575
  "eu_member": true,
469
576
  "vat_name": "Taxa pe valoarea adăugată",
577
+ "vat_abbr": "TVA",
470
578
  "standard": 21.0,
471
579
  "reduced": [
472
580
  11.0
473
581
  ],
474
582
  "super_reduced": null,
475
- "parking": null
583
+ "parking": null,
584
+ "format": "RO + 2–10 digits",
585
+ "pattern": "^RO\\d{2,10}$"
476
586
  },
477
587
  "RS": {
478
588
  "country": "Serbia",
479
589
  "currency": "RSD",
480
590
  "eu_member": false,
481
591
  "vat_name": "Porez na dodatu vrednost",
592
+ "vat_abbr": "PDV",
482
593
  "standard": 20.0,
483
594
  "reduced": [
484
595
  10.0
485
596
  ],
486
597
  "super_reduced": null,
487
- "parking": null
598
+ "parking": null,
599
+ "format": "RS + 9 digits",
600
+ "pattern": "^RS\\d{9}$"
488
601
  },
489
602
  "SE": {
490
603
  "country": "Sweden",
491
604
  "currency": "SEK",
492
605
  "eu_member": true,
493
606
  "vat_name": "Mervärdesskatt",
607
+ "vat_abbr": "moms",
494
608
  "standard": 25.0,
495
609
  "reduced": [
496
610
  6.0,
497
611
  12.0
498
612
  ],
499
613
  "super_reduced": null,
500
- "parking": null
614
+ "parking": null,
615
+ "format": "SE + 12 digits",
616
+ "pattern": "^SE\\d{12}$"
501
617
  },
502
618
  "SI": {
503
619
  "country": "Slovenia",
504
620
  "currency": "EUR",
505
621
  "eu_member": true,
506
622
  "vat_name": "Davek na dodano vrednost",
623
+ "vat_abbr": "DDV",
507
624
  "standard": 22.0,
508
625
  "reduced": [
509
626
  5.0,
510
627
  9.5
511
628
  ],
512
629
  "super_reduced": null,
513
- "parking": null
630
+ "parking": null,
631
+ "format": "SI + 8 digits",
632
+ "pattern": "^SI\\d{8}$"
514
633
  },
515
634
  "SK": {
516
635
  "country": "Slovakia",
517
636
  "currency": "EUR",
518
637
  "eu_member": true,
519
638
  "vat_name": "Daň z pridanej hodnoty",
639
+ "vat_abbr": "DPH",
520
640
  "standard": 23.0,
521
641
  "reduced": [
522
642
  5.0,
523
643
  19.0
524
644
  ],
525
645
  "super_reduced": null,
526
- "parking": null
646
+ "parking": null,
647
+ "format": "SK + 10 digits",
648
+ "pattern": "^SK\\d{10}$"
527
649
  },
528
650
  "TR": {
529
651
  "country": "Turkey",
530
652
  "currency": "TRY",
531
653
  "eu_member": false,
532
654
  "vat_name": "Katma Değer Vergisi",
655
+ "vat_abbr": "KDV",
533
656
  "standard": 20.0,
534
657
  "reduced": [
535
658
  1.0,
536
659
  10.0
537
660
  ],
538
661
  "super_reduced": null,
539
- "parking": null
662
+ "parking": null,
663
+ "format": "TR + 10 digits",
664
+ "pattern": "^TR\\d{10}$"
540
665
  },
541
666
  "UA": {
542
667
  "country": "Ukraine",
543
668
  "currency": "UAH",
544
669
  "eu_member": false,
545
670
  "vat_name": "Податок на додану вартість",
671
+ "vat_abbr": "ПДВ",
546
672
  "standard": 20.0,
547
673
  "reduced": [
548
674
  7.0,
549
675
  14.0
550
676
  ],
551
677
  "super_reduced": null,
552
- "parking": null
678
+ "parking": null,
679
+ "format": "UA + 12 digits",
680
+ "pattern": "^UA\\d{12}$"
553
681
  },
554
682
  "XK": {
555
683
  "country": "Kosovo",
556
684
  "currency": "EUR",
557
685
  "eu_member": false,
558
686
  "vat_name": "Tatimi mbi Vlerën e Shtuar",
687
+ "vat_abbr": "TVSH",
559
688
  "standard": 18.0,
560
689
  "reduced": [
561
690
  8.0
562
691
  ],
563
692
  "super_reduced": null,
564
- "parking": null
693
+ "parking": null,
694
+ "format": "XK + alphanumeric",
695
+ "pattern": null
565
696
  }
566
697
  }
567
698
  }
@@ -1,3 +1,3 @@
1
1
  module EuVatRatesData
2
- VERSION = "2026.3.28"
2
+ VERSION = "2026.3.31"
3
3
  end
@@ -68,7 +68,20 @@ module EuVatRatesData
68
68
  rates.key?(country_code.upcase)
69
69
  end
70
70
 
71
- # Return the ISO 8601 date when EU data was last fetched from EC TEDB.
71
+ # Return true if vat_id matches the expected format for its country.
72
+ # Input must include the country code prefix (e.g. "ATU12345678").
73
+ # Returns false when the country has no standardised format or the ID does not match.
74
+ # Note: Greece uses the "EL" prefix, not "GR".
75
+ # @param vat_id [String] VAT number string including country code prefix
76
+ # @return [Boolean]
77
+ def self.valid_format?(vat_id)
78
+ code = vat_id[0, 2].upcase
79
+ rate = get_rate(code)
80
+ return false unless rate && rate["pattern"]
81
+ !!(vat_id.upcase =~ /\A#{rate["pattern"]}\z/)
82
+ end
83
+
84
+ # Return the ISO 8601 date when EU data was last fetched from EC TEDB.
72
85
  # @return [String] e.g. "2026-03-18"
73
86
  def self.data_version
74
87
  dataset["version"]
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eu_vat_rates_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 2026.3.28
4
+ version: 2026.3.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iurii Rogulia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-28 00:00:00.000000000 Z
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: VAT rates (standard, reduced, super-reduced, parking) for 44 European
14
- countries — EU-27 plus Norway, Switzerland, UK, and more. Updated daily from the
15
- official European Commission TEDB. Includes eu_member flag. Useful for billing,
16
- invoicing, e-commerce, fintech, and VAT MOSS compliance.
14
+ countries — EU-27 plus Norway, Switzerland, UK, and more. Includes eu_member flag,
15
+ local VAT name and abbreviation. Useful for billing, invoicing, e-commerce, fintech,
16
+ and VAT compliance.
17
17
  email:
18
18
  - iurii@rogulia.fi
19
19
  executables: []
@@ -51,5 +51,5 @@ rubygems_version: 3.5.22
51
51
  signing_key:
52
52
  specification_version: 4
53
53
  summary: VAT rates for 44 European countries — EU-27 plus Norway, Switzerland, UK,
54
- and more. Daily auto-updates from EC TEDB.
54
+ and more.
55
55
  test_files: []