VKN (vergi no) nedir, 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.

Tüzel kişi VKN'si ticari bir kimliktir; tek başına belirli bir gerçek kişiyi işaret etmediği için KVKK'nın "kişisel veri" tanımına girmez — tıpkı bir işyerinin ünvanı veya adresi gibi. Ancak bu genelleme her mükellef için geçerli değildir: şahıs şirketlerinde mükellef bir gerçek kişidir; o kayda bağlı ünvan ve adres çoğu zaman kişinin kendi adı ve ev adresidir ve bunlar kişisel veridir. Kayıt tipini ayırt etmeden "VKN kişisel veri değildir" varsayımıyla log/saklama politikası kurmayın; 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 Üretici ile sentetik veri 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 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 1000036109 için (ilk dokuz hane: 1 0 0 0 0 3 6 1 0):

ip = 9−itmp = (v[i]+p) mod 10res = (tmp × 2^p) mod 9düzeltmekatkı
09(1+9) mod 10 = 00tmp = 0, düzeltme yok0
18(0+8) mod 10 = 8(8×256) mod 9 = 5—5
27(0+7) mod 10 = 7(7×128) mod 9 = 5—5
36(0+6) mod 10 = 6(6×64) mod 9 = 6—6
45(0+5) mod 10 = 5(5×32) mod 9 = 7—7
54(3+4) mod 10 = 7(7×16) mod 9 = 4—4
63(6+3) mod 10 = 9(9×8) mod 9 = 0tmp ≠ 0 → 99
72(1+2) mod 10 = 3(3×4) mod 9 = 3—3
81(0+1) mod 10 = 1(1×2) mod 9 = 2—2

S = 0+5+5+6+7+4+9+3+2 = 41 → v[9] = (10 − (41 mod 10)) mod 10 = **9**. Numaranın 10. hanesi de 9 olduğuna göre 1000036109 geçerlidir.

Bu örneği bilinçli olarak seçtik: i=6 satırı tmp ≠ 0 ve res = 0 → res = 9 düzeltmesini çalıştırır, i=0 satırı ise tmp = 0 dalını gösterir. Algoritmanın her iki özel durumu da tek örnekte görünür. (1234567890 gibi ardışık numaralarda dokuz adımın dokuzunda da tmp = 0 çıkar; sonuç doğrudur ama öğretici değildir.)

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;
}

Tek bir uç durum: 4444444444 yukarıdaki checksum'dan geçer. Tüm haneleri aynı olan on haneli numaralar içinde checksum'ı sağlayan tek numara odur. Gerçek bir mükellefe karşılık gelmesi beklenmediği için bizim araçlarımız onu ayrıca reddeder; siz de aynısını yapacaksanız new Set(v).size === 1 kontrolünü ekleyin. Bu, algoritmanın parçası değil, üstüne konan bir kabul kuralıdır — API sözleşmenizde bunu açıkça belirtin, yoksa iki uygulama aynı numara için farklı cevap verir.

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 sorgulama ekranları: GİB'in İnteraktif Vergi Dairesi ü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. Bunu çağıran taraf normalize etmelidir: input.replace(/[\s\-]/g, ''). Kütüphane katmanının sessizce temizlemesi tavsiye edilmez; bizim yayımladığımız doğrulama spec'i de girdiyi olduğu gibi değerlendirip tireli/boşluklu girdiye invalid_characters döndürmeyi hedefler. Nedeni basit: temizleyen bir doğrulayıcı, "kullanıcı ne yazdı" sorusunun cevabını kaybeder ve hata mesajını yanlış yere bağlar.
  • 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ı, ağırlıklı bir kontrol hanesi şemasıdır. Doğru implementasyon, kullanıcının yazım hatalarının çoğunu forma girildiği anda yakalar — ama sınırını bilin: checksum tek hane hatalarını güvenilir şekilde yakalar, bazı yer değiştirmeleri kaçırır ve doğru formatlı ama başka bir kuruma ait bir numarayı hiç yakalamaz. "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.