Ne işe yarar
GM, Opel ve Chevrolet parça kataloğunu (epc.vin) kendi yazılımınızdan sorgulamak içindir. Asıl iş, müşterinizin aracının VIN'inden o araca uyan parça numaralarını bulup stoğunuzdakilerle karşılaştırmak.
İki yol var, ikisi de aynı hesaplamadan gelir:
POST /parts/check: Elinizdeki numaraları (en çok 500) gönderirsiniz. Her biri için "uyar / uymaz" yanıtı döner; uyuyorsa kataloğun neresinde olduğu da gelir. Az sayıda aday parça için en kolayı budur.GET /vehicles/{vin}/parts: Araca uyan bütün numaraları, alternatifleriyle birlikte alırsınız; karşılaştırmayı kendi sisteminizde yaparsınız. Bütün stoğu taramak için uygundur.
Araç, epc.vin arayüzündeki varsayılan süzgeçlerle değerlendirilir: VIN Süzgeci, UltraVIN ve Yıl Süzgeci açık, parça geçmişi gizli. Arayüzde o aracın sayfalarında görünen her parça API'de de uyar; bu, testlerle doğrulanır. Numaraların alternatifleri, arayüzde numaranın yanındaki G düğmesinin açtığı parça geçmişinin aynısıdır.
Alan adları İngilizce, değerler Türkçedir: açıklamalar, hata ve eşleşme kodları. Yanıtlar UTF-8 JSON'dur; Accept-Encoding: gzip gönderilirse sıkıştırılır.
Hızlı başlangıç
Anahtarınızı bir ortam değişkenine koyun (EPC_API_KEY). Aşağıdaki kurulum, sonraki bütün örneklerde kullanılır. Dili seçtiğinizde sayfadaki bütün örnekler o dile geçer.
export EPC_API_KEY="epc_..." # yönetimden aldığınız anahtar
curl https://api.epc.vin/v1/usage \
-H "Authorization: Bearer $EPC_API_KEY"// .NET 8+. Tek bir HttpClient uygulama boyunca kullanılır.
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
var http = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All })
{
BaseAddress = new Uri("https://api.epc.vin/v1/"),
Timeout = TimeSpan.FromSeconds(60),
};
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("EPC_API_KEY"));
// Alan adları snake_case: part_numbers ↔ PartNumbers
var json = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
};
// Hata yanıtı: { "error": { "code": "...", "message": "..." } }
async Task<T> Read<T>(HttpResponseMessage res)
{
if (res.IsSuccessStatusCode) return (await res.Content.ReadFromJsonAsync<T>(json))!;
var err = await res.Content.ReadFromJsonAsync<ErrorAnswer>(json);
var wait = res.Headers.RetryAfter?.Delta; // 429'da kaç saniye beklenmeli
throw new HttpRequestException($"{(int)res.StatusCode} {err?.Error.Code}: {err?.Error.Message}", null, res.StatusCode);
}
var usage = await Read<JsonElement>(await http.GetAsync("usage"));
Console.WriteLine(usage);
record ErrorAnswer(ErrorBody Error);
record ErrorBody(string Code, string Message);// Node.js 18+ (fetch yerleşik, sıkıştırmayı kendisi açar).
const API = 'https://api.epc.vin/v1';
const KEY = process.env.EPC_API_KEY;
async function epc(path, body) {
const res = await fetch(API + path, {
method: body ? 'POST' : 'GET',
headers: {
Authorization: `Bearer ${KEY}`,
...(body ? { 'Content-Type': 'application/json' } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json();
if (!res.ok) {
// { "error": { "code": "...", "message": "..." } }
const err = new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
err.code = data.error.code;
err.retryAfter = Number(res.headers.get('retry-after')) || undefined; // 429'da saniye
throw err;
}
return data;
}
console.log(await epc('/usage'));# Python 3.9+, requests
import os
import requests
API = "https://api.epc.vin/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['EPC_API_KEY']}"
def epc(path, body=None):
if body is None:
res = session.get(API + path, timeout=60)
else:
res = session.post(API + path, json=body, timeout=60)
if not res.ok:
# { "error": { "code": "...", "message": "..." } }
error = res.json()["error"]
raise RuntimeError(f"{res.status_code} {error['code']}: {error['message']} "
f"(Retry-After: {res.headers.get('Retry-After')})")
return res.json()
print(epc("/usage"))Makine okunur tanım: /v1/openapi.json. Postman, Insomnia ya da NSwag, openapi-generator gibi kod üreticilere doğrudan verilebilir.
Anahtar ve güvenlik
Her istekte Authorization: Bearer <anahtar> başlığı gönderilir. Anahtarlar epc_ ile başlar ve 53 karakterdir; epc.vin yönetimi verir. Anahtar yalnız verildiği anda bir kez gösterilir. Biz yalnız özetini saklarız; anahtar kaybolursa yenisi verilir.
- Anahtarı yalnız sunucunuzda tutun: bir ortam değişkeninde ya da sır deposunda. Tarayıcıda, mobil uygulamada ya da kaynak kodda tutmayın. API tarayıcıdan çağrılamaz, çünkü CORS izni yoktur.
- Her sisteminiz için ayrı anahtar isteyin (ör. "stok sunucusu", "test"). Biri sızarsa yalnız o iptal edilir.
- Anahtarı değiştirirken kesinti olmasın diye önce yenisini alıp sisteminize koyun, sonra eskisini iptal ettirin.
- Yalnız HTTPS kullanılır. Yanıtlar önbelleğe alınmaz (
Cache-Control: no-store). - Her yanıtta bir
X-Request-Idbaşlığı döner. Bir sorunu bildirirken bu kimliği de iletin.
Bir adresten 15 dakikada 30 hatalı anahtar denenirse o adres bir süre bekletilir (cok_fazla_hatali_anahtar).
Sınırlar
| Sınır | Varsayılan | Aşılınca |
|---|---|---|
| Hesap başına dakikada istek | 60 | 429 istek_siniri |
| Günde farklı VIN (İstanbul saatiyle; aynı gün aynı VIN yeniden sayılmaz) | 500 | 429 gunluk_vin_kotasi |
| Bir kontrolde parça numarası | 500 | 400 cok_fazla_numara |
| İstek gövdesi | 64 KB | 413 govde_cok_buyuk |
Sınırlar hesaba özeldir; ihtiyacınız farklıysa yönetimle konuşun. Her yanıtta dakika sınırının durumu, IETF taslağındaki başlıklarla gelir:
RateLimit-Policy: "dakika";q=60;w=60
RateLimit: "dakika";r=57;t=41 # bu dakikadan 57 istek kaldı, 41 sn sonra yenilenir
429 yanıtlarında Retry-After kaç saniye bekleneceğini söyler. O kadar bekleyip yeniden deneyin; art arda denemeyin.
Hatalar
Hatalar her uçta aynı biçimdedir. code programlar için sabittir; message insanlar içindir ve değişebilir.
{
"error": {
"code": "gecersiz_vin",
"message": "VIN 17 karakter olmalı; harf ve rakam, I, O ve Q yok."
}
}
| Durum | Kod | Anlamı |
|---|---|---|
| 400 | gecersiz_vin | VIN 17 karakter değil ya da I, O, Q içeriyor |
| 400 | gecersiz_numara | Parça numarası harf ve rakam dışında karakter içeriyor ya da 32 karakterden uzun |
| 400 | gecersiz_istek | Gövde ya da sorgu okunamadı, tanınmayan bir alan var |
| 400 | numara_yok | part_numbers boş |
| 400 | cok_fazla_numara | 500'den fazla numara |
| 401 | anahtar_yok | Authorization başlığı yok |
| 401 | gecersiz_anahtar | Anahtar tanınmıyor |
| 401 | anahtar_iptal | Anahtar iptal edilmiş |
| 403 | hesap_kapali | API hesabı kapalı ya da süresi doldu |
| 404 | arac_bulunamadi | VIN geçerli ama katalogda aracı yok |
| 404 | donanim_bulunamadi | Verilen equipment_id bu VIN'in araçlarından biri değil |
| 404 | parca_bulunamadi | Parça numarası katalogda yok |
| 404 | bulunamadi | Böyle bir adres yok |
| 405 | yontem_desteklenmiyor | Adres bu yöntemle çağrılmaz (ör. GET yerine POST) |
| 413 | govde_cok_buyuk | Gövde 64 KB'tan büyük |
| 415 | json_bekleniyor | Content-Type: application/json değil |
| 429 | istek_siniri | Dakika sınırı doldu |
| 429 | gunluk_vin_kotasi | Günlük VIN kotası doldu (bugün sorulan VIN'ler yine sorulabilir) |
| 429 | cok_fazla_hatali_anahtar | Bu adresten çok fazla hatalı anahtar denendi |
| 500 | sunucu_hatasi | Bizim tarafta bir hata; X-Request-Id ile bildirin |
VIN'in aracı
VIN'i çözer. Bir VIN bazen birden çok donanıma denk gelir; o durumda diğer uçlara equipment_id verilir, verilmezse ilk araç kullanılır.
İstek
curl https://api.epc.vin/v1/vehicles/KL1SF48W9BB261734 \
-H "Authorization: Bearer $EPC_API_KEY"var answer = await Read<VehicleAnswer>(await http.GetAsync("vehicles/KL1SF48W9BB261734"));
foreach (var v in answer.Vehicles)
Console.WriteLine($"{v.EquipmentId}: {v.Make} {v.Model} ({v.Source})");
record VehicleAnswer(string Vin, List<Vehicle> Vehicles);
record Vehicle(int EquipmentId, string? Make, string? Model, string? CatalogCode, string? CatalogName,
string? EquipmentName, string? ProductionDate, string Source);const { vehicles } = await epc('/vehicles/KL1SF48W9BB261734');
for (const v of vehicles) console.log(`${v.equipment_id}: ${v.make} ${v.model} (${v.source})`);for v in epc("/vehicles/KL1SF48W9BB261734")["vehicles"]:
print(v["equipment_id"], v["make"], v["model"], v["source"])Yanıt 200
{
"vin": "KL1SF48W9BB261734",
"vehicles": [
{
"equipment_id": 2986,
"make": "Chevrolet",
"model": "AVEO (T250 / T255) [EUR] (2006 - 2011)",
"catalog_code": "T06",
"catalog_name": "T06",
"equipment_name": "AVEO (T250/T255) [EUR]",
"production_date": null,
"source": "arac_kaydi"
}
]
}
source, aracın nereden bulunduğunu söyler. arac_kaydi: VIN katalogun araç kayıtlarında var; motor, şanzıman ve seçenekler gibi donanım bilgisi biliniyor. vin_cozumleme: VIN kayıtlarda yok, VIN'in kendisinden çözüldü. Bu araçların donanımı daha az bilindiği için uyan parça listesi daha geniştir; bir parçayı satmadan önce kullanım bilgisine (usage) bakın.
Parça kontrolü
Gönderdiğiniz parça numaralarının araca uyup uymadığını söyler. Her numara gönderildiği sırayla ve gönderildiği yazımla yanıtlanır.
| Alan | Tür | |
|---|---|---|
vin | metin | Zorunlu. Küçük harf de olur. |
part_numbers | metin dizisi | Zorunlu, 1 ile 500 arası. GM parça numarası, Opel KAT numarası ya da tireli numaralar (08361-15063). |
equipment_id | sayı | İsteğe bağlı. VIN birden çok donanıma denk geliyorsa hangisi. |
Karşılaştırmada iki tarafta da boşluk, tire, nokta ve eğik çizgi atılır, harfler büyütülür: 13 300 900, 13-300-900 ve 13300900 aynıdır; 0836115063, katalogdaki 08361-15063'ü bulur.
İstek
curl https://api.epc.vin/v1/parts/check \
-H "Authorization: Bearer $EPC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vin": "KL1SF48W9BB261734",
"part_numbers": ["96829637", "95955933", "13300900", "abc;"]
}'var check = await Read<CheckAnswer>(await http.PostAsJsonAsync("parts/check", new
{
vin = "KL1SF48W9BB261734",
part_numbers = new[] { "96829637", "95955933", "13300900", "abc;" },
}, json));
foreach (var r in check.Results)
{
if (r.Fits)
Console.WriteLine($"{r.PartNumber}: uyar ({r.Match}) → {string.Join(" › ", r.Places![0].Group)}");
else
Console.WriteLine($"{r.PartNumber}: uymaz ({r.Reason})");
}
record CheckAnswer(string Vin, Vehicle Vehicle, CheckSummary Summary, List<CheckResult> Results);
record CheckSummary(int Asked, int Fits);
record CheckResult(string PartNumber, bool Fits, string? Match, List<string>? CatalogPartNumbers,
List<Place>? Places, List<string>? Markets, string? Reason);
record Place(List<string> Group, string? PageCode, string? PageTitle, string? Callout, string? Description,
string? Usage, string? Quantity, List<string> Notes, bool NotServiced, string? CatalogPartNumber);const { results } = await epc('/parts/check', {
vin: 'KL1SF48W9BB261734',
part_numbers: ['96829637', '95955933', '13300900', 'abc;'],
});
for (const r of results) {
if (r.fits) console.log(`${r.part_number}: uyar (${r.match}) → ${r.places[0].group.join(' › ')}`);
else console.log(`${r.part_number}: uymaz (${r.reason})`);
}answer = epc("/parts/check", {
"vin": "KL1SF48W9BB261734",
"part_numbers": ["96829637", "95955933", "13300900", "abc;"],
})
for r in answer["results"]:
if r["fits"]:
print(r["part_number"], "uyar", r["match"], " › ".join(r["places"][0]["group"]))
else:
print(r["part_number"], "uymaz", r["reason"])Yanıt 200
{
"vin": "KL1SF48W9BB261734",
"vehicle": {
"equipment_id": 2986,
"make": "Chevrolet",
"model": "AVEO (T250 / T255) [EUR] (2006 - 2011)",
"catalog_code": "T06",
"catalog_name": "T06",
"equipment_name": "AVEO (T250/T255) [EUR]",
"production_date": null,
"source": "arac_kaydi"
},
"summary": { "asked": 4, "fits": 2 },
"results": [
{
"part_number": "96829637",
"fits": true,
"match": "birebir",
"catalog_part_numbers": ["96829637"],
"places": [
{
"group": ["YAKIT & MOTOR KONTROL", "YAKIT"],
"page_code": "2111",
"page_title": "YAKIT DEPOSU II (2111)",
"callout": "1",
"description": "DEPO A-YAKIT 45L",
"usage": "(BASE,LS,LT,E) (69,08,48) (&LDT/LMU)",
"quantity": "1",
"notes": [],
"not_serviced": false,
"catalog_part_number": "96829637"
}
]
},
{
"part_number": "95955933",
"fits": true,
"match": "yeni_numara",
"catalog_part_numbers": ["96829637"],
"places": [ { "group": ["YAKIT & MOTOR KONTROL", "YAKIT"], "callout": "1", "...": "..." } ],
"markets": ["GM Daewoo", "Tayland", "Meksika"]
},
{ "part_number": "13300900", "fits": false, "reason": "araca_uymuyor" },
{ "part_number": "abc;", "fits": false, "reason": "gecersiz_numara" }
]
}
| Alan | |
|---|---|
match | Uyuyorsa nasıl uyduğu: birebir, yeni_numara, eski_numara (ayrıntı). |
catalog_part_numbers | Katalogda bu araç için listelenen numara(lar). Yeni/eski numarayla uyuyorsa sizin gönderdiğinizden farklıdır. |
places | Kataloğun neresinde olduğu: gruplar (üstten alta), sayfa, çizimdeki numara (callout), açıklama, kullanım, adet. Bir numaranın en çok 20 yeri döner. |
markets | Yalnız yeni/eski numara eşleşmesinde: iki numarayı bağlayan fiyat kitaplarının pazarı. Bizim pazarımız GM Avrupa ve GM Daewoo'dur. |
reason | Uymuyorsa nedeni: araca_uymuyor (numara katalogda var ama bu araca değil), katalogda_yok, gecersiz_numara. |
Araca uyan tüm parçalar
Araca uyan her parça numarası bir kez döner; sıra katalog sırasıdır, grup grup ve sayfa sayfa. Her numara yerleri ve alternatifleriyle gelir. Örnek ölçümler:
| Araç | Numara | Alternatif (ek) | Aranabilecek toplam | Sıkıştırılmış |
|---|---|---|---|---|
Kayıtlı (arac_kaydi), Aveo T250 | 1.776 | 1.846 | 3.622 | ~65 KB |
VIN'den çözülen (vin_cozumleme), Astra-F | 11.827 | 8.260 | 20.087 | ~625 KB (ham 9 MB) |
Bir aracın ilk listesi 2–3 saniye sürebilir; aynı aracın sonraki istekleri 30 dakika boyunca birkaç milisaniyede döner. Accept-Encoding: gzip göndermeyi unutmayın; çoğu HTTP kütüphanesi bunu kendiliğinden yapar.
İstek
curl --compressed https://api.epc.vin/v1/vehicles/KL1SF48W9BB261734/parts \
-H "Authorization: Bearer $EPC_API_KEY"var list = await Read<PartsList>(await http.GetAsync("vehicles/KL1SF48W9BB261734/parts"));
Console.WriteLine($"{list.Vehicle.Model}: {list.Count} parça");
record PartsList(string Vin, Vehicle Vehicle, int Count, List<Part> Parts);
record Part(string PartNumber, string? Description, List<string> ReplacedBy,
List<Alternative> Alternatives, List<Place> Places);
record Alternative(string PartNumber, string Relation, bool Interchangeable, List<string> Markets);const list = await epc('/vehicles/KL1SF48W9BB261734/parts');
console.log(`${list.vehicle.model}: ${list.count} parça`);parts = epc("/vehicles/KL1SF48W9BB261734/parts")
print(parts["vehicle"]["model"], parts["count"], "parça")Yanıt 200
{
"vin": "KL1SF48W9BB261734",
"vehicle": { "equipment_id": 2986, "make": "Chevrolet", "source": "arac_kaydi", "...": "..." },
"count": 1776,
"parts": [
{
"part_number": "96829637",
"description": "DEPO A-YAKIT 45L",
"replaced_by": ["95955933"],
"alternatives": [
{
"part_number": "95955933",
"relation": "yeni_numara",
"interchangeable": true,
"markets": ["GM Daewoo", "Tayland", "Meksika"]
},
{
"part_number": "96537108",
"relation": "eski_numara",
"interchangeable": false,
"markets": ["Tayland"]
}
],
"places": [
{
"group": ["YAKIT & MOTOR KONTROL", "YAKIT"],
"page_code": "2111",
"page_title": "YAKIT DEPOSU II (2111)",
"callout": "1",
"description": "DEPO A-YAKIT 45L",
"usage": "(BASE,LS,LT,E) (69,08,48) (&LDT/LMU)",
"quantity": "1",
"notes": [],
"not_serviced": false
}
]
}
]
}
| Alan | |
|---|---|
replaced_by | Bizim pazarımızın kitaplarında (GM Avrupa, GM Daewoo) numaranın yerine geçen numaralar; zincir sırasıyla gelir, en yenisi sondadır. |
alternatives | Bütün pazarların kitaplarında numarayla bağlı her numara. Bunlar arayüzdeki "G" penceresinin içeriğidir; önce bizim pazarımızınkiler gelir (ayrıntı). |
places | Numaranın kataloğun bu araç için gösterdiği her yeri. |
Parça geçmişi
Numaranın geçmişini verir: bizim pazarımızın kitaplarında yerine geçen ve yerini aldığı numaralar ile bütün pazarlardaki alternatifleri. Stok kartlarınızı güncel numaraya eşlemek için kullanılır. Numara tireli de tiresiz de yazılabilir; yanıt, numarayı katalogun yazdığı biçimde verir.
İstek
curl https://api.epc.vin/v1/parts/96829637 \
-H "Authorization: Bearer $EPC_API_KEY"var history = await Read<PartHistory>(await http.GetAsync("parts/96829637"));
var current = history.ReplacedBy.LastOrDefault() ?? history.PartNumber; // bugünkü numara
record PartHistory(string PartNumber, List<string> ReplacedBy, List<string> Replaces,
List<Alternative> Alternatives);const history = await epc('/parts/96829637');
const current = history.replaced_by.at(-1) ?? history.part_number; // bugünkü numarahistory = epc("/parts/96829637")
current = (history["replaced_by"] or [history["part_number"]])[-1] # bugünkü numaraYanıt 200
{
"part_number": "96829637",
"replaced_by": ["95955933"],
"replaces": [],
"alternatives": [
{
"part_number": "95955933",
"relation": "yeni_numara",
"interchangeable": true,
"markets": ["GM Daewoo", "Tayland", "Meksika"]
},
{
"part_number": "96537108",
"relation": "eski_numara",
"interchangeable": false,
"markets": ["Tayland"]
}
]
}
Kullanım
Hesabın sınırlarını ve bugünkü kullanımını verir (İstanbul saatiyle).
İstek
curl https://api.epc.vin/v1/usage \
-H "Authorization: Bearer $EPC_API_KEY"var usage = await Read<UsageAnswer>(await http.GetAsync("usage"));
Console.WriteLine($"Bugün {usage.Today.Vins}/{usage.Limits.VinsPerDay} VIN");
record UsageAnswer(string Account, Limits Limits, Today Today);
record Limits(int RequestsPerMinute, int VinsPerDay, int PartNumbersPerCheck);
record Today(int Vins, int Requests);const { limits, today } = await epc('/usage');
console.log(`Bugün ${today.vins}/${limits.vins_per_day} VIN`);usage = epc("/usage")
print(f"Bugün {usage['today']['vins']}/{usage['limits']['vins_per_day']} VIN")Yanıt 200
{
"account": "yedekparca",
"limits": {
"requests_per_minute": 60,
"vins_per_day": 500,
"part_numbers_per_check": 500
},
"today": {
"vins": 12,
"requests": 40
}
}
Eşleşme ve alternatifler
Kontrolde bir numara üç yoldan uyar; en iyisi seçilir:
birebir | Numara (ya da KAT numarası), aracın kataloğunda araca uyan bir satırda geçiyor. |
yeni_numara | Katalog eski bir numarayı listeliyor; gönderdiğiniz numara onun yerine geçen yenisi. Genellikle stokta tutulması gereken budur. |
eski_numara | Katalog yeni numarayı listeliyor; gönderdiğiniz numara onun yerini aldığı eskisi. Stoktaki eski parça çoğu zaman kullanılabilir, ama satmadan önce kontrol edin. |
Alternatifler, GM'in pazar pazar tuttuğu fiyat kitaplarındaki parça geçmişidir; arayüzde numaranın yanındaki "G" düğmesi aynı bilgiyi gösterir. Her alternatifte şunlar bulunur:
relation:yeni_numara(bu numaranın yerine geçer) ya daeski_numara(bu numaranın yerini aldığı).interchangeable: kitap ikisini birbirinin yerine kullanılabilir diye işaretliyorsatrue; yalnız biri ötekinin yerine geçiyorsa (tek yön)false.markets: bağı kuran kitapların pazarı: GM Avrupa, GM Daewoo, ABD, Kanada, Meksika, Brezilya, Avustralya, Tayland, Çin, Hindistan… Bizim pazarımızınkiler (GM Avrupa, GM Daewoo) en güvenilir olanlardır; başka pazarların bağı o pazarın parçası içindir, satmadan önce kontrol edin.
Kontrol, alternatiflerin hepsini hesaba katar. Uyan sonuçta bağı kuran pazarlar markets alanında gelir.
Stokla karşılaştırma
Müşteri tezgâhta, VIN elinizde: stokta olan ve araca uyan parçaları göstermek için iki yol.
Az sayıda aday: kontrol
Stoktaki numaraları 500'erli parçalar hâlinde gönderin, uyanları alın.
async Task<List<CheckResult>> Fitting(string vin, IEnumerable<string> stock)
{
var fitting = new List<CheckResult>();
foreach (var chunk in stock.Chunk(500))
{
var answer = await Read<CheckAnswer>(await http.PostAsJsonAsync("parts/check",
new { vin, part_numbers = chunk }, json));
fitting.AddRange(answer.Results.Where(r => r.Fits));
}
return fitting;
}
foreach (var r in await Fitting("KL1SF48W9BB261734", new[] { "96829637", "95955933", "13300900" }))
Console.WriteLine($"{r.PartNumber} {r.Match} {r.Places![0].Description}");async function fitting(vin, stock) {
const out = [];
for (let i = 0; i < stock.length; i += 500) {
const { results } = await epc('/parts/check', { vin, part_numbers: stock.slice(i, i + 500) });
out.push(...results.filter((r) => r.fits));
}
return out;
}
for (const r of await fitting('KL1SF48W9BB261734', ['96829637', '95955933', '13300900'])) {
console.log(r.part_number, r.match, r.places[0].description);
}def fitting(vin, stock):
out = []
for i in range(0, len(stock), 500):
answer = epc("/parts/check", {"vin": vin, "part_numbers": stock[i:i + 500]})
out += [r for r in answer["results"] if r["fits"]]
return out
for r in fitting("KL1SF48W9BB261734", ["96829637", "95955933", "13300900"]):
print(r["part_number"], r["match"], r["places"][0]["description"])Bütün stok: liste
Aracın listesini alın; katalogdaki numarayı ve alternatiflerini stoğunuzda arayın. Numaraları iki tarafta da aynı biçime getirin (boşluk, tire, nokta ve eğik çizgi atılmış, büyük harf).
static string Compact(string n) => new string(n.Where(char.IsLetterOrDigit).ToArray()).ToUpperInvariant();
// stock: numara → adet
async Task<List<(string Number, string? Description, int Count)>> InStock(string vin, Dictionary<string, int> stock)
{
var have = stock.ToDictionary(s => Compact(s.Key), s => s.Value);
var list = await Read<PartsList>(await http.GetAsync($"vehicles/{vin}/parts"));
var found = new List<(string, string?, int)>();
foreach (var p in list.Parts)
{
// Katalogdaki numara, sonra alternatifleri (önce bizim pazarımızınkiler).
var candidates = new[] { p.PartNumber }.Concat(p.Alternatives.Select(a => a.PartNumber));
var hit = candidates.FirstOrDefault(n => have.GetValueOrDefault(Compact(n)) > 0);
if (hit != null) found.Add((hit, p.Description, have[Compact(hit)]));
}
return found;
}const compact = (n) => n.replace(/[^0-9a-z]/gi, '').toUpperCase();
// stock: { "96829637": 3, ... } (numara → adet)
async function inStock(vin, stock) {
const have = new Map(Object.entries(stock).map(([n, count]) => [compact(n), count]));
const { parts } = await epc(`/vehicles/${vin}/parts`);
const found = [];
for (const p of parts) {
// Katalogdaki numara, sonra alternatifleri (önce bizim pazarımızınkiler).
const hit = [p.part_number, ...p.alternatives.map((a) => a.part_number)].find((n) => have.get(compact(n)) > 0);
if (hit) found.push({ number: hit, description: p.description, count: have.get(compact(hit)) });
}
return found;
}def compact(n):
return "".join(ch for ch in n if ch.isalnum()).upper()
def in_stock(vin, stock): # stock: {"96829637": 3, ...} (numara → adet)
have = {compact(n): count for n, count in stock.items()}
for p in epc(f"/vehicles/{vin}/parts")["parts"]:
# Katalogdaki numara, sonra alternatifleri (önce bizim pazarımızınkiler).
for n in [p["part_number"], *(a["part_number"] for a in p["alternatives"])]:
if have.get(compact(n)):
yield n, p["description"], have[compact(n)]
breakAynı müşteri için art arda sorgu atmayın; aracın listesini kendi tarafınızda bir süre saklayabilirsiniz, katalog verisi değişmez.
Notlar ve sürümler
- Sürüm yolu
/v1. Geriye uyumlu eklemeler (yeni alan, yeni uç) bu sürümde yapılır; tanımadığınız alanları görmezden gelin. Uyumu bozan bir değişiklik olursa/v2açılır ve/v1bir süre daha çalışır. - Değerlerin Türkçe olması şimdilik böyledir; kodlar (
birebir,araca_uymuyor…) sabittir. - Bu belge sunucuyla birlikte yayımlanır: gördüğünüz belge her zaman çalışan API'nin belgesidir.
2026-10 · v1.0 ilk sürüm: araç, parça kontrolü, tüm parçalar, parça geçmişi, alternatifler, kullanım.