İçindekiler
- Zam günü problemi
- Liste fiyatlarını çekmek
- priceBreakdown alanını okumak
- ÖTV dilimlerini sabit kodlamayın
- Zam takibi ve otomatik bülten
- Kendi kataloğunuzla eşleştirme
- Sektörel kullanım senaryoları
- Kod yazmadan takip
- Sık yapılan hatalar
- Sık sorulan sorular
Özet: Sıfır araç fiyatları yılda onlarca kez değişir; her zamda 58 markanın liste fiyatını elle Excel'e işleyen ekipler hem geç kalır hem hata yapar. Bu rehberde apibir Sıfır Araç Fiyatları API'siyle liste fiyatlarını çekmeyi, priceBreakdown alanından ÖTV ve KDV kırılımını okumayı, ÖTV matrah dilimlerini sabit kodlamadan yönetmeyi ve zam anında otomatik bülten üreten bir fark takip servisi kurmayı anlatıyoruz.
Zam Günü Problemi: Neden Manuel Takip Çöker?
Otomotiv fiyatlaması Türkiye'de tek bir sayıdan ibaret değildir. Bir modelin anahtar teslim fiyatı; vergisiz bedel, motor hacmi ve matraha göre değişen ÖTV oranı, onun üzerine binen KDV ve varsa kampanya indirimlerinin bileşkesidir. Distribütörler bu fiyatları ay başlarında, kur hareketlerinde ve vergi düzenlemelerinde güncellerler — üstelik hepsi aynı gün yapmaz.
Manuel takipte üç şey aynı anda bozulur:
- Gecikme: İlan sitenizde veya galerinizin ekranında iki gün eski fiyat durur; müşteri geldiğinde fiyat farkını siz karşılarsınız.
- Kapsam: Sadece popüler 20 modeli takip edersiniz, geri kalan 4.000+ donanım varyantı güncellenmez.
- İz sürülemezlik: "Bu model geçen ay kaça satılıyordu?" sorusuna yanıt veremezsiniz, çünkü eski fiyat üzerine yazılmıştır.
API tabanlı kurgu üçünü birden çözer: kapsam tam, gecikme dakikalar mertebesinde ve her değişim tarihçesiyle birlikte saklanır.
1. Adım: Liste Fiyatlarını Çekmek
/vehicles/new/prices ucu marka, model, yakıt tipi, kasa tipi ve fiyat sınırına göre filtrelenebilir. Tüm kataloğu tek seferde çekmek yerine marka bazında sayfalayarak ilerlemek hem yanıt boyutunu hem hata yüzeyini küçültür:
curl --request GET \
--url "https://api.apibir.com/v1/vehicles/new/prices?brand=toyota&fuel=hibrit&sort=price_asc" \
--header "authorization: apikey APIBIR-8f2c...9d41" \
--header "accept: application/json"
async function markaFiyatlari(marka) {
const url = new URL("https://api.apibir.com/v1/vehicles/new/prices");
url.searchParams.set("brand", marka);
url.searchParams.set("sort", "price_asc");
const res = await fetch(url, {
headers: { authorization: `apikey ${process.env.APIBIR_KEY}` }
});
if (!res.ok) throw new Error(`apibir ${res.status} — ${marka}`);
const { data, total } = await res.json();
console.log(`${marka}: ${total} donanım`);
return data;
}
const toyota = await markaFiyatlari("toyota");
import os, time, requests
BASE = "https://api.apibir.com/v1"
HEADERS = {"authorization": f"apikey {os.environ['APIBIR_KEY']}"}
def markalar():
r = requests.get(f"{BASE}/vehicles/brands", headers=HEADERS, timeout=10)
r.raise_for_status()
return [m["slug"] for m in r.json()["data"]]
def tum_katalog():
katalog = []
for marka in markalar():
r = requests.get(f"{BASE}/vehicles/new/prices",
params={"brand": marka}, headers=HEADERS, timeout=20)
if r.status_code == 429: # saniyelik limit — biraz bekle
time.sleep(2)
r = requests.get(f"{BASE}/vehicles/new/prices",
params={"brand": marka}, headers=HEADERS, timeout=20)
r.raise_for_status()
katalog.extend(r.json()["data"])
return katalog
print(len(tum_katalog()), "donanım kaydı")
<?php
$url = "https://api.apibir.com/v1/vehicles/new/prices?brand=toyota";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["authorization: apikey " . getenv("APIBIR_KEY")]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($res["data"] as $arac) {
printf("%s %s %s — %s TL\n",
$arac["brand"], $arac["model"], $arac["trim"],
number_format($arac["listPrice"], 0, ",", "."));
}
Yanıtın tek bir kaydı, fiyatın nasıl oluştuğunu da içerir:
{
"success": true,
"creditsUsed": 1,
"currency": "TRY",
"updatedAt": "2026-08-18T08:00:00+03:00",
"total": 3,
"data": [
{
"brand": "Toyota",
"model": "Corolla",
"trim": "1.8 Hybrid Dream e-CVT",
"modelYear": 2026,
"bodyType": "sedan",
"fuel": "hibrit",
"transmission": "e-CVT",
"engineCc": 1798,
"power": 140,
"listPrice": 2189000,
"previousPrice": 2124000,
"changePercent": 3.06,
"priceBreakdown": {
"baseWithoutTax": 1094500,
"otvRate": 45,
"otvAmount": 492525,
"kdvRate": 20,
"kdvAmount": 364855,
"mtvFirstYear": 37095
},
"campaign": "36 ay %0 faizli 500.000 TL kredi",
"availability": "stokta",
"effectiveDate": "2026-08-01"
}
]
}
Buradaki listPrice anahtar teslim fiyattır; yani priceBreakdown içindeki vergisiz bedel, ÖTV ve KDV toplamına karşılık gelir. İlan sitenizde göstereceğiniz sayı budur. previousPrice ve changePercent alanları ise bir önceki liste fiyatını ve değişim oranını taşır — zam bülteni üretmek için ayrıca bir geçmiş sorgusu atmanıza gerek kalmaz.
2. Adım: priceBreakdown Alanını Doğru Okumak
Fiyat kırılımı, müşteriye şeffaf bir fiyat tablosu göstermek isteyen ilan siteleri ve galeriler için en değerli alandır. Alanların anlamı şöyledir:
| Alan | Anlamı | Nerede kullanılır |
|---|---|---|
baseWithoutTax |
Vergisiz araç bedeli (ÖTV matrahı) | ÖTV diliminin belirlenmesinde esas alınan tutar |
otvRate |
Uygulanan ÖTV oranı (%) | Şeffaf fiyat tablosu, kampanya karşılaştırması |
otvAmount |
Hesaplanan ÖTV tutarı (TL) | Vergi payının müşteriye gösterilmesi |
kdvRate / kdvAmount |
KDV oranı ve tutarı | Kurumsal satışta indirilecek KDV hesabı |
mtvFirstYear |
Birinci yıl motorlu taşıtlar vergisi | "Yola çıkma maliyeti" hesabı — liste fiyatına dahil değildir |
campaign |
Aktif kampanya metni (varsa) | İlan kartında rozet veya vurgu satırı |
availability |
stokta · siparise-acik · uretim-durdu |
Stok durumu filtresi ve ilan yayından kaldırma kuralı |
Anahtar teslim fiyatın yeniden üretimi basit bir toplamadır ve bunu bir doğrulama testi olarak kullanmanızı öneririz:
function anahtarTeslimHesapla(kirilim) {
const { baseWithoutTax, otvAmount, kdvAmount } = kirilim;
return baseWithoutTax + otvAmount + kdvAmount;
}
function kirilimTutarliMi(arac, tolerans = 500) {
const hesap = anahtarTeslimHesapla(arac.priceBreakdown);
return Math.abs(hesap - arac.listPrice) <= tolerans;
}
// MTV birinci yıl tutarı fiyata dahil DEĞİLDİR; ayrı gösterin.
const toplamMaliyet = (a) => a.listPrice + a.priceBreakdown.mtvFirstYear;
from decimal import Decimal
def anahtar_teslim(kirilim):
return (Decimal(str(kirilim["baseWithoutTax"]))
+ Decimal(str(kirilim["otvAmount"]))
+ Decimal(str(kirilim["kdvAmount"])))
def kirilim_tutarli_mi(arac, tolerans=500):
fark = abs(anahtar_teslim(arac["priceBreakdown"]) - Decimal(str(arac["listPrice"])))
return fark <= tolerans
# Müşteriye "yola çıkma maliyeti" göstermek isterseniz MTV'yi ayrı satır yapın
def yola_cikma(arac):
return Decimal(str(arac["listPrice"])) + Decimal(str(arac["priceBreakdown"]["mtvFirstYear"]))
Küçük yuvarlama farkları normaldir; distribütör liste fiyatlarını çoğu zaman yuvarlak bir rakama tamamlar. Ancak sapma birkaç yüz TL'yi aşıyorsa kırılımı değil listPrice alanını esas alın — müşteriye gösterilecek olan resmi liste fiyatıdır.
3. Adım: ÖTV Matrah Dilimlerini Sabit Kodlamayın
Türkiye'de binek araçlarda ÖTV oranı, motor hacmi ve vergisiz matrahın hangi dilime düştüğüne göre değişir. Bu dilimlerin sınırları ve oranları idari kararla güncellenir; kodunuza sabit yazdığınız her rakam, bir sonraki düzenlemede sessizce yanlış hesap üretmeye başlar.
Doğru yaklaşım, dilim tablosunu /vehicles/otv-brackets ucundan okuyup önbelleğe almaktır:
curl --request GET \
--url "https://api.apibir.com/v1/vehicles/otv-brackets" \
--header "authorization: apikey APIBIR-8f2c...9d41"
import os, requests
from functools import lru_cache
@lru_cache(maxsize=1) # günde bir kez tazelemek yeterli
def otv_dilimleri():
r = requests.get(
"https://api.apibir.com/v1/vehicles/otv-brackets",
headers={"authorization": f"apikey {os.environ['APIBIR_KEY']}"},
timeout=10,
)
r.raise_for_status()
return r.json()["data"]
def otv_orani(matrah, engine_cc=None, fuel="benzin", power_kw=None):
"""Oranı tabloda ara — asla koda sabit yazma."""
for d in otv_dilimleri():
if d.get("fuel") and d["fuel"] != fuel:
continue
# Elektriklide dilim motor gücüne, diğerlerinde motor hacmine bağlıdır
if fuel == "elektrik":
if power_kw is None or not (d["minKw"] <= power_kw <= d["maxKw"]):
continue
elif engine_cc is None or engine_cc > d["maxEngineCc"]:
continue
if d["minBase"] <= matrah <= d["maxBase"]:
return d["rate"]
raise ValueError("Uygun ÖTV dilimi bulunamadı — tabloyu tazeleyin")
let dilimler = null;
let dilimTarihi = 0;
async function otvDilimleri() {
const GUN = 24 * 60 * 60 * 1000;
if (dilimler && Date.now() - dilimTarihi < GUN) return dilimler;
const res = await fetch("https://api.apibir.com/v1/vehicles/otv-brackets", {
headers: { authorization: `apikey ${process.env.APIBIR_KEY}` }
});
({ data: dilimler } = await res.json());
dilimTarihi = Date.now();
return dilimler;
}
Bu tabloyu günde bir kez tazelemek yeterlidir. Elektrikli araçlarda dilimlendirme motor hacmi yerine motor gücü (kW) üzerinden yapıldığı için, hesaplama fonksiyonunuzu yakıt tipine göre dallandırmayı unutmayın; fuel alanı bu ayrımı zaten veriyor.
Not: Vergi oranları ve matrah dilimleri değişkendir; bu yazıda örnek olarak gösterilen değerler API yanıtından gelen anlık verilerdir, güncel mevzuat metni değildir. Fiyat hesabınızı her zaman API'nin döndüğü güncel dilim tablosu üzerinden kurun. Mevzuat değişikliklerini programatik olarak takip etmek isterseniz Mevzuat Değişiklikleri API'si ve Resmi Gazete özetlerini Slack'e taşıma rehberimiz işinizi görür.
4. Adım: Zam Takibi — Fark Tespiti ve Otomatik Bülten
Otomasyonun asıl değeri burada ortaya çıkar. Günlük olarak tüm kataloğu çekip önceki gün ile karşılaştıran küçük bir servis, zam ve indirimleri siz fark etmeden önce yakalar:
import json, os, pathlib, requests
ANLIK = pathlib.Path("data/arac_fiyat_anlik.json")
def anahtar(a):
return f"{a['brand']}|{a['model']}|{a['trim']}|{a['modelYear']}"
def farklari_bul(yeni_katalog):
onceki = json.loads(ANLIK.read_text()) if ANLIK.exists() else {}
yeni = {anahtar(a): a for a in yeni_katalog}
degisimler = []
for k, arac in yeni.items():
eski = onceki.get(k)
if eski is None:
degisimler.append(("yeni", arac, None))
elif eski["listPrice"] != arac["listPrice"]:
oran = (arac["listPrice"] - eski["listPrice"]) / eski["listPrice"] * 100
degisimler.append(("zam" if oran > 0 else "indirim", arac, round(oran, 2)))
for k in onceki.keys() - yeni.keys():
degisimler.append(("kaldirildi", onceki[k], None))
ANLIK.parent.mkdir(exist_ok=True)
ANLIK.write_text(json.dumps(yeni, ensure_ascii=False))
return degisimler
def bulten_metni(degisimler):
if not degisimler:
return "Bugün sıfır araç liste fiyatlarında değişiklik yok."
satirlar = ["*Sıfır Araç Fiyat Değişiklikleri*", ""]
for tur, arac, oran in sorted(degisimler, key=lambda d: -(d[2] or 0)):
ad = f"{arac['brand']} {arac['model']} {arac['trim']}"
fiyat = f"{arac['listPrice']:,.0f}".replace(",", ".")
if tur in ("zam", "indirim"):
satirlar.append(f"• {ad} → {fiyat} TL ({oran:+.2f}%)")
elif tur == "yeni":
satirlar.append(f"• [YENİ] {ad} → {fiyat} TL")
else:
satirlar.append(f"• [KALDIRILDI] {ad}")
return "\n".join(satirlar)
def gonder(metin):
requests.post(os.environ["SLACK_WEBHOOK"], json={"text": metin}, timeout=10)
# cron: 30 8 * * * → her sabah 08:30
gonder(bulten_metni(farklari_bul(tum_katalog())))
Bu servisi bir cron ile sabah 08:30'da çalıştırıp çıktısını e-posta, Slack veya WhatsApp'a bağladığınızda, satış ekibiniz güne güncel fiyat listesiyle başlar. Aynı kurguyu akaryakıt tarafında nasıl uyguladığımızı 81 il pompa fiyatları rehberinde anlatmıştık; mimari birebir aynıdır, yalnızca uç nokta değişir.
Fiyat tarihçesini kendiniz tutmak istemiyorsanız /vehicles/new/history ucu model bazında fiyat değişim geçmişini döner. "Bu model son 12 ayda kaç kez zamlandı?" sorusuna yanıt veren bir grafik, ilan sitelerinde kullanıcıyı sayfada tutan en etkili içerik bileşenlerinden biridir.
5. Adım: Kendi Kataloğunuzla Eşleştirme Problemi
Entegrasyonun en çok zaman yiyen kısmı genellikle beklenmedik yerdedir: API'den gelen kayıtları kendi veritabanınızdaki ilanlarla eşleştirmek. "Corolla 1.8 Hybrid Dream e-CVT" ile sizin sisteminizdeki "Toyota Corolla Hybrid Dream" aynı aracı işaret eder ama karakter karakter eşleşmez.
Sahada işe yarayan yaklaşım üç aşamalıdır. Önce bileşik anahtar kurun: marka + model + donanım + model yılı. Ardından bu anahtarı normalize edin — küçük harfe çevirin, Türkçe karakterleri sadeleştirin, noktalama ve fazla boşlukları temizleyin. Son olarak eşleşmeyen kayıtlar için otomatik tahmin yapmak yerine bir manuel eşleştirme kuyruğu tutun; yanlış eşleşen bir donanım, hiç eşleşmeyenden çok daha pahalıya mal olur.
import re, unicodedata
TR_HARF = str.maketrans("çğıöşüÇĞİÖŞÜ", "cgiosuCGIOSU")
def normalize(metin: str) -> str:
metin = metin.translate(TR_HARF).lower()
metin = unicodedata.normalize("NFKD", metin)
metin = re.sub(r"[^a-z0-9]+", " ", metin) # noktalama ve sembolleri at
return " ".join(metin.split()) # fazla boşlukları sadeleştir
def bilesik_anahtar(arac):
return "|".join(normalize(str(arac[k]))
for k in ("brand", "model", "trim", "modelYear"))
# "Toyota | Corolla | 1.8 Hybrid Dream e-CVT | 2026"
# -> "toyota|corolla|1 8 hybrid dream e cvt|2026"
def katalogu_esle(api_kayitlari, kendi_ilanlarim, eslesme_tablosu):
"""eslesme_tablosu: {api_anahtari: ilan_id} — kalıcı olarak saklanır."""
guncellenen, kuyruk = [], []
for arac in api_kayitlari:
anahtar = bilesik_anahtar(arac)
ilan_id = eslesme_tablosu.get(anahtar)
if ilan_id is None:
# Otomatik tahmin etme — insan onayına gönder
kuyruk.append({"anahtar": anahtar, "arac": arac})
continue
ilan = kendi_ilanlarim[ilan_id]
if ilan["fiyat"] != arac["listPrice"]:
ilan["fiyat"] = arac["listPrice"]
ilan["fiyat_guncelleme"] = arac["updatedAt"]
guncellenen.append(ilan_id)
return guncellenen, kuyruk
Eşleştirme tablosunu bir kez kurduktan sonra günlük çekimlerde yalnızca yeni gelen donanımlar kuyruğa düşer; pratikte bu ayda birkaç kayıt demektir. modelYear alanını anahtara dahil etmeyi unutmayın: model yılı değiştiğinde donanım adı aynı kalsa bile fiyat ve teknik özellikler farklılaşır.
Sektörel Kullanım Senaryoları
| Kim | Ne yapıyor | Hangi uçlar |
|---|---|---|
| Otomotiv ilan siteleri | Sıfır araç sayfalarını güncel liste fiyatı ve donanım detayıyla otomatik doldurma | /vehicles/new/prices · /vehicles/models |
| Galeri ve yetkili satıcılar | Vitrin ekranı ve teklif formunda güncel fiyat; zam bültenine göre stok kararı | /vehicles/new/prices · /vehicles/new/history |
| Filo kiralama | Araç edinim maliyetini ÖTV kırılımıyla modelleyip kira tarifesi hesaplama | /vehicles/new/prices · /vehicles/otv-brackets |
| Sigorta ve kasko | Yeni ikame bedeli üzerinden teminat limiti güncelleme | /vehicles/new/prices |
| Finansal analiz ve içerik siteleri | "Hangi model bu yıl ne kadar zamlandı?" tipi veri gazeteciliği içerikleri | /vehicles/new/history |
Bu senaryoların üçünde de ortak bir mimari yeterlidir: günde bir kez tam katalog çekimi, fark tespiti, kendi veritabanınızda tarihçe. Gerçek zamanlı sorgu yalnızca kullanıcı tek bir modele tıkladığında gerekir — o da genellikle önbellekten karşılanır. Diğer kullanım örnekleri için kullanım senaryoları sayfasına göz atabilirsiniz.
Kod Yazmadan Takip: Galeri ve Otomotiv Bülteni
Her galerinin yazılım ekibi yoktur. Zam takibini kod yazmadan yapmak isteyen galeri, filo ve sigorta ekipleri için apibir, aynı verinin günlük WhatsApp ve e-posta bülteni halini sunuyor: hangi markada hangi modelin ne kadar zamlandığı, her sabah tek mesajda. Otomotiv ve galeri paketinin güncel koşullarını fiyatlandırma sayfasında, kapsamını ise Hizmetler & Otomasyonlar sayfasında bulabilirsiniz.
Sık Yapılan Entegrasyon Hataları
| Hata | Sonucu | Doğrusu |
|---|---|---|
| ÖTV oran ve dilimlerini koda sabit yazmak | Vergi düzenlemesi değiştiğinde uygulama sessizce yanlış fiyat üretir. | /vehicles/otv-brackets ucundan okuyup günlük önbelleğe alın. |
| Her sayfa görüntülemesinde API çağırmak | Trafiğe orantılı kredi tüketimi; fiyatlar zaten günde bir güncelleniyor. | Günlük toplu çekim yapıp kendi veritabanınızdan servis edin. |
listPrice yerine kırılım toplamını göstermek |
Yuvarlama farkları nedeniyle vitrin fiyatı distribütör fiyatından sapar. | Müşteriye listPrice gösterin; kırılımı yalnızca detay tablosunda kullanın. |
| MTV'yi liste fiyatına eklemek | Rakiplerden yüksek görünen bir fiyat, ilan tıklanma oranını düşürür. | mtvFirstYear ayrı bir satır olarak "yola çıkma maliyeti" başlığında gösterilmeli. |
availability alanını yok saymak |
Üretimi durmuş modeller ilanda kalır; müşteri aradığında satış yapılamaz. | uretim-durdu kayıtlarını arşive taşıyın, arama sonuçlarından çıkarın. |
| Fiyat geçmişini tutmamak | Zam analizi ve "eski fiyat" karşılaştırması yapılamaz. | Her çekimde farkı kaydedin ya da /vehicles/new/history ucunu kullanın. |
Sık Sorulan Sorular
Sıfır araç fiyatları ne sıklıkla güncelleniyor?
Veri günlük olarak tazelenir ve distribütör zam yaptığı anda güncellenir. Yanıttaki updatedAt alanı verinin hangi ana ait olduğunu, effectiveDate ise liste fiyatının hangi tarihten itibaren geçerli olduğunu söyler.
Kaç marka ve model kapsanıyor?
Servis 58 marka, 640'tan fazla model ve 4.100'ü aşkın donanım varyantını kapsar. Marka ve model listelerini /vehicles/brands ve /vehicles/models uçlarından alıp kendi filtre menülerinizi otomatik oluşturabilirsiniz.
ÖTV matrah dilimlerini API'den alabilir miyim?
Evet. /vehicles/otv-brackets ucu güncel dilim sınırlarını ve oranlarını döner. Bu değerler idari kararla değiştiği için uygulamanıza sabit yazmak yerine bu uçtan okumanız, düzenleme sonrası yanlış hesap yapma riskini ortadan kaldırır.
İkinci el araç fiyatları da var mı?
Bu servis sıfır araç liste fiyatlarını kapsar. İkinci el değerleme farklı bir veri problemidir ve kilometre, hasar kaydı gibi araç bazlı parametreler gerektirir; sıfır liste fiyatı bu tür modellerde referans girdi olarak kullanılabilir.
Liste fiyatı ile kırılım toplamı neden tam tutmuyor?
Distribütörler liste fiyatını genellikle yuvarlak bir rakama tamamlar, bu yüzden vergisiz bedel + ÖTV + KDV toplamı ile listPrice arasında birkaç yüz TL fark oluşabilir. Müşteriye gösterilecek resmi fiyat her zaman listPrice alanıdır.
Kod yazmadan zam takibi yapabilir miyim?
Evet. Galeri, filo ve sigorta ekipleri için aynı veri günlük WhatsApp veya e-posta bülteni olarak sunulur; hangi modelin ne kadar zamlandığı her sabah tek mesajda gelir. Kapsam ve koşullar için hizmetler ve fiyatlandırma sayfalarına bakabilirsiniz.
Başlamak için: Ücretsiz plan 100 kredi/ay ile geliştirme ve deneme için yeterlidir. Uç noktaların tamamı ve alan açıklamaları Sıfır Araç Fiyatları API sayfasında, kimlik doğrulama ve hata kodları dokümantasyonda yer alıyor.