VKN (vergi no) ne değildir, ne değildir?

Vergi Kimlik Numarası (VKN) — halk arasında kısaca "vergi no" veya "vergi numarası" — Gelir İdaresi Başkanlığı (GİB) tarafından vergi mükellefi tüzel kişilere (şirketler, kooperatifler, dernekler, vakıflar) atanan 10 haneli benzersiz bir numaradır. 2006 yılında yapılan düzenlemeyle gerçek kişilerin VKN'si TCKN ile birleştirildi; dolayısıyla bugün "VKN" dediğimizde neredeyse her zaman bir tüzel kişilikten bahsediyoruz.

VKN, ticari bir kimliktir ve KVKK'nın "kişisel veri" kategorisine girmez — tıpkı bir işyerinin ünvanı veya adresi gibi kamuya açık sayılır. GİB'in internet vergi dairesi üzerinden vergi no sorgulaması yapılabilir. Bu durum, TCKN ile arasındaki en temel farklardan biridir ve log'da saklama politikalarınızı doğrudan etkiler; detayı için KVKK rehberimize bakın.

Bu yazı, yazılım ekiplerinin VKN üzerinde format doğrulaması yapmak için bilmesi gereken her şeyi kapsıyor: on haneli yapının matematiksel tanımı, kontrol hanesi algoritmasının adım adım uygulanışı ve dikkat edilmesi gereken edge case'ler. Kendi vergi no üret rutininizi yazarken aynı kurallar geçerli olacak. Kendi sistemleriniz için kod yazmadan hızlıca vkn üret aracı ile sentetik data oluşturabilirsiniz.

VKN'nin 10 haneli yapısı

VKN 10 rakamdan oluşur: v[0] v[1] ... v[9]. İlk dokuz hane kimlik bilgisini temsil eder, onuncu hane (v[9]) bir kontrol hanesidir ve bir checksum algoritmasına göre hesaplanır.

İlk haneler hakkında yaygın bir yanılgı vardır: "vergi numarasının ilk üç hanesi il kodudur" gibi. Bu doğru değildir. GİB'in bugünkü numaralandırma şemasında ilk haneler özel bir coğrafi kodlamayı temsil etmez. Numaralar, tarihsel blok atamaları ve sıralı tahsisat mantığı ile verilmiştir. Bu yüzden bir VKN'nin ilk hanelerine bakarak hangi ilden olduğunu çıkarmaya çalışmak güvenilir değildir.

v[0] = 0 teorik olarak mümkündür ama pratikte GİB çıkışlı listelerde nadirdir. Yine de leading zero içeren bir VKN ile karşılaşırsanız string olarak işleyin, asla integer'a cast etmeyin. Aynı sorunun TCKN tarafındaki örneklerini TCKN algoritması yazımızda göstermiştik.

VKN (Vergi No) kontrol hanesi algoritması

VKN'nin 10. hanesi, ilk 9 hane üzerinden şu adımlarla hesaplanır:

  1. Her i için (i = 0..8), geçici bir dizi tmp oluştur:

tmp[i] = (v[i] + (9 - i)) mod 10

  1. Her tmp[i] için, p[i] = (tmp[i] * 2^(9 - i)) mod 9 hesapla. Eğer tmp[i] != 0 ve sonuç 0 ise, p[i] = 9 olarak düzelt.
  2. Tüm p[i] değerlerini topla: S = p[0] + p[1] + ... + p[8].
  3. Son rakam: v[9] = (10 - (S mod 10)) mod 10.

Bu algoritma, TCKN'den daha karmaşıktır çünkü hem toplama hem de mod 9 (ISO 7064 ailesinden türetilmiş) işlemlerini birleştirir. mod 9 kısmı "9-excess" aritmetiğiyle ilgili klasik bir tasarım seçimidir ve rakamların pozisyon bazlı ağırlıklandırılmasını etkinleştirir.

Sayısal bir örnek

VKN 1234567890 için:

  • i=0: tmp = (1 + 9) mod 10 = 0p = 0 (tmp=0 durumu)
  • i=1: tmp = (2 + 8) mod 10 = 0p = 0
  • i=2: tmp = (3 + 7) mod 10 = 0p = 0
  • ... ilk 7 hane böyle devam eder ...
  • i=8: tmp = (9 + 1) mod 10 = 0p = 0

S = 0, v[9] = (10 - 0) mod 10 = 0. Yani 1234567890 format olarak geçerli.

Gerçek hayatta VKN'ler daha rastgele olduğu için tmp değerleri sıfırdan farklı olur ve mod 9 kısmı işler.

Referans implementasyon

export function isValidVkn(input) {
  if (typeof input !== 'string') return false;
  const vkn = input.trim();
  if (!/^[0-9]{10}$/.test(vkn)) return false;

  const v = [...vkn].map(Number);
  let sum = 0;
  for (let i = 0; i < 9; i++) {
    const tmp = (v[i] + (9 - i)) % 10;
    if (tmp === 0) continue;
    let product = (tmp * Math.pow(2, 9 - i)) % 9;
    if (product === 0) product = 9;
    sum += product;
  }
  const check = (10 - (sum % 10)) % 10;
  return v[9] === check;
}

Python versiyonu:

import re

_VKN_RE = re.compile(r"^[0-9]{10}$")

def is_valid_vkn(value: str) -> bool:
    if not isinstance(value, str) or not _VKN_RE.match(value.strip()):
        return False
    v = [int(ch) for ch in value.strip()]
    total = 0
    for i in range(9):
        tmp = (v[i] + (9 - i)) % 10
        if tmp == 0:
            continue
        product = (tmp * (2 ** (9 - i))) % 9
        if product == 0:
            product = 9
        total += product
    check = (10 - (total % 10)) % 10
    return v[9] == check

Diğer diller için TCKN/VKN API entegrasyonu makalesinde Go, Java ve C# varyantlarını da paylaştık.

GİB kayıtlarıyla ilişki

Format doğrulaması ile mükellef doğrulaması iki ayrı şeydir. Format doğrulaması (yukarıdaki algoritma), VKN'nin matematiksel olarak tutarlı olup olmadığını söyler — "bir insanın rasgele yazıp vermediğini" anlamaya yarar. Ancak "bu VKN gerçekten bir şirkete ait mi, hangi şirkete ait?" sorusuna cevap vermez.

Bu ikinci soru için GİB'in sunduğu kanallar vardır:

  • İnternet Vergi Dairesi "Sicil Sorgusu": https://sorgu.gib.gov.tr/ üzerinden web arayüzlü sorgu. Manuel kullanım içindir; otomasyona uygun değildir.
  • e-Fatura / e-Arşiv mükellef sorgulama: GİB'in entegratör dokümanlarında yer alan servisler aracılığıyla bir VKN'nin e-Fatura mükellefi olup olmadığı kontrol edilebilir. Bu genelde bir UBL-TR entegratörü (Logo, Mikro, Uyumsoft vb.) aracılığıyla yapılır.
  • Özel entegratör API'leri: Ticari sağlayıcılar VKN → ünvan eşleştirmesi sunar, ancak bunlar GİB'in birebir resmi kayıtları yerine sözleşmeli veri havuzlarıdır.

Kendi projenizde "bu VKN gerçek mi?" sorusuna cevap arıyorsanız, iş gereksinimi neyse ona göre seçim yapın. Çoğu form için format doğrulaması yeterlidir. Fatura/tahsilat süreçleri için e-Fatura mükellef sorgusu yapmanız gerekir.

Yaygın format sorunları

  • Boşluk ve tire karakterleri: "1234-5678-90" veya "1 2 3 4 5 6 7 8 9 0" gibi yapıştırılmış metinler yaygın. Normalize edin: input.replace(/[\s\-]/g, '').
  • Integer overflow: JavaScript Number tipi 10 haneli VKN'yi doğru temsil eder (2^53'ün çok altında), ama yine de string olarak tutun. Leading zero'yu kaybetmemek için kritik.
  • Unicode rakamlar: TCKN yazımızdaki not aynen VKN için de geçerli — [0-9] yerine \d kullanmayın.
  • 10 yerine 11 hane: TCKN ile VKN'yi aynı input alanında kabul eden formlarda (örnek: "vergi kimlik numarası veya TC kimlik numarası") uzunluk bazlı branch yapılmalı: 11 → TCKN algoritması, 10 → VKN algoritması.

Daha geniş bir hata kataloğu için TCKN/VKN doğrulamada sık yapılan hatalar makalesine bakın.

Tek alanda TCKN ve VKN kabul etmek

Birçok Türk iş formunda "TC Kimlik No / Vergi No" tek bir alandır. Uygulama basit bir branch ile bunu yönetebilir:

function isValidIdentifier(input) {
  const trimmed = String(input ?? '').trim();
  if (trimmed.length === 11) return isValidTckn(trimmed);
  if (trimmed.length === 10) return isValidVkn(trimmed);
  return false;
}

Bu yaklaşım hem gerçek kişiler (TCKN) hem tüzel kişiler (VKN) için tek giriş noktası sunar. Fatura kesilen B2B/B2C karışık senaryolarda çok işe yarar.

Performans ve ölçeklendirme

VKN doğrulaması TCKN'den biraz daha pahalı (üstel hesap ve fazladan mod) ancak yine de O(1) ve bir CPU döngüsünde birkaç yüz nanosaniye civarı. Milyonlarca kayıtlı veri tabanı migration'ı senaryoları için bile darboğaz yaratmaz; darboğaz her zaman I/O tarafındadır.

Toplu senaryolarda doğru stratejiyi kurmak için toplu TCKN/VKN doğrulama rehberine mutlaka göz atın.

Sonuç ve araçlar

VKN'nin 10 haneli yapısı ve kontrol hanesi algoritması, GİB tarafından tanımlanmış bir ISO 7064 türevidir. Doğru implementasyon ile kullanıcılarınızın yanlışlıkla yanlış VKN girmesinin önüne %100'e yakın geçebilirsiniz. Ancak "bu VKN hangi şirkete ait?" sorusu için GİB tarafındaki ek servislere ihtiyacınız olur.

Aracı deneyin: VKN Doğrulayıcı ve VKN (Vergi No) Üretici. Toplu işler için Toplu TCKN/VKN Doğrulama sayfasını kullanın.