Validate a Turkish tax number (VKN) in C#
The Turkish tax number (Vergi Kimlik Numarası, VKN) has 10 digits. The last digit is a check digit calculated from the first nine. Companies use a VKN. Sole proprietors use the owner's identity number (TCKN) as tax number. This page explains the algorithm and shows a check that accepts both.
Short answer
using HeroKit.Globalization;
using HeroKit.Globalization.Turkey;
"4840847211".IsValidVkn(); // true
"4840847212".IsValidVkn(); // false
"10000000146".IsValidTaxId(Countries.Turkey); // true: sole proprietor, TCKN
"4840847211".IsValidTaxId(Countries.Turkey); // true: company, VKN
dotnet add package HeroKit
Rules
- The number has exactly 10 digits.
- For each of the first 9 digits, with
pthe position (1–9):a = (digit + 10 − p) mod 10b = (a × 2^(10 − p)) mod 9- if
ais not zero andbis zero,b = 9.
- Add up all
bvalues. The 10th digit is(10 − sum mod 10) mod 10.
Example: 4840847211
| Position | Digit | a | 2^(10 − p) | b |
|---|---|---|---|---|
| 1 | 4 | 3 | 512 | 6 |
| 2 | 8 | 6 | 256 | 6 |
| 3 | 4 | 1 | 128 | 2 |
| 4 | 0 | 6 | 64 | 6 |
| 5 | 8 | 3 | 32 | 6 |
| 6 | 4 | 8 | 16 | 2 |
| 7 | 7 | 0 | 8 | 0 |
| 8 | 2 | 4 | 4 | 7 |
| 9 | 1 | 2 | 2 | 4 |
The sum is 39. The check digit is (10 − 9) mod 10 = 1, which is the last digit, so the number is valid.
Plain C# without a library
static bool IsValidVkn(string? value)
{
if (value is null || value.Length != 10 || !value.All(char.IsAsciiDigit))
return false;
int sum = 0;
for (int i = 0; i < 9; i++) // i = position − 1
{
int a = (value[i] - '0' + 9 - i) % 10;
int b = a * (1 << (9 - i)) % 9; // 1 << n = 2^n
if (a != 0 && b == 0)
b = 9;
sum += b;
}
return (10 - sum % 10) % 10 == value[9] - '0';
}
This code gives the same result as HeroKit's IsValidVkn for 300,000 random numbers.
Common mistakes
- Missing the 9 rule. When
ais not zero andbis zero,bmust be 9. Without this rule, some valid numbers are rejected. - Rejecting sole proprietors. If an invoice or customer form accepts only a VKN, sole proprietors cannot enter their TCKN. Use
IsValidTaxId(Countries.Turkey)or[TaxId("TR")]for that field. - Storing it as a number. A VKN can start with 0. Stored as
long, the leading zero is lost. Usestring. - Taking a well-formed number for a registered taxpayer. The algorithm says the number is well formed. It does not say that a taxpayer with this number is registered. Use the services of the Revenue Administration (GİB) for that.
ASP.NET Core form validation
using HeroKit.Validation;
public sealed class InvoiceForm
{
[Required, TaxId("TR")] // VKN or TCKN
public string? TaxNumber { get; set; }
[Vkn] // VKN only
public string? CompanyTaxNumber { get; set; }
}
With FluentValidation (dotnet add package HeroKit.FluentValidation):
RuleFor(x => x.TaxNumber).NotEmpty().TaxId(Countries.Turkey);
RuleFor(x => x.CompanyTaxNumber).Vkn();
MERSİS number
The 16-digit MERSİS number is "0", the company's VKN and a 5-digit serial:
"0879001756600379".IsValidMersis(); // true
Related
- TCKN validation
- IBAN validation
- Form validation: every validation attribute