HubSpot'tan Salesforce'a veri taşırken External ID, upsert ve ilişki sırası: Geliştirici notları
CRM göçü dendiğinde çoğu ekip önce lisans fiyatlarını, sonra arayüzü konuşur. Oysa projeyi gerçekten zorlayan kısım, yıllardır biriken kayıtların ve aralarındaki ilişkilerin bir sistemden ötekine bozulmadan taşınmasıdır. Ben, Koray Yalçın olarak lead yönetimi, CRM mimarisi ve pazarlama otomasyonu ü

CRM göçü dendiğinde çoğu ekip önce lisans fiyatlarını, sonra arayüzü konuşur. Oysa projeyi gerçekten zorlayan kısım, yıllardır biriken kayıtların ve aralarındaki ilişkilerin bir sistemden ötekine bozulmadan taşınmasıdır. Ben, Koray Yalçın olarak lead yönetimi, CRM mimarisi ve pazarlama otomasyonu üzerine çalışırken bu işin büyük ölçüde bir veri mühendisliği problemi olduğunu defalarca gördüm. Bu yazıda HubSpot'tan Salesforce'a geçişi iş tarafından değil, kodu yazacak geliştiricinin gözünden ele alıyorum: kimlik eşleştirme, upsert mantığı, yükleme sırası, delta aktarımı ve doğrulama.
Yazı belirli bir aracı satmıyor. Data Loader, Bulk API, bir ETL aracı ya da kendi yazdığınız Python betiği; hangisini seçerseniz seçin, aşağıdaki ilkeler değişmiyor.
HubSpot ile Salesforce aynı kavramları farklı modellerle tutar. HubSpot'ta tek bir Contact nesnesi vardır; Salesforce ise ham adayı (Lead) ve nitelikli kişiyi (Contact) ayırır. HubSpot'taki Company, Salesforce'ta Account olur ve Account hiyerarşisi (ana şirket ile alt şirketler) çok daha katı işler. Deal, Opportunity'ye; Ticket, Case'e; özel property'ler ise __c sonekli özel alanlara dönüşür.
Bu farklar yüzünden tablo kopyalamak yetmez. Asıl taşınması gereken şey kayıtlar arasındaki bağlardır: bir fırsatın hangi şirkete ait olduğu, hangi kişiyle konuşulduğu, iki yıllık e-posta ve not geçmişinin kime bağlı olduğu. İlişkiler koparsa veri "taşınmış" görünür ama satış ekibi için işe yaramaz hale gelir.
Göçün omurgası, kaynak sistemdeki benzersiz kimliğin hedef sisteme taşınmasıdır. HubSpot'ta her nesnenin bir hs_object_id değeri vardır. Salesforce tarafında her hedef nesneye, örneğin HubSpot_ID__c adında, External ID ve Unique olarak işaretlenmiş bir metin alanı açarsınız.
Pratik bir uyarı: External ID alanını metin tipinde tutun. Kimlikler sayısal görünse bile, sayısal alan baştaki sıfırları ve büyük değerleri sorunlu işleyebilir.
İlişkili nesneler bağımlılık sırasıyla yüklenmelidir. Tipik sıra şöyledir:
Account hiyerarşisini tek geçişte yüklemeye çalışmak sık yapılan bir hatadır. Alt şirket, henüz oluşmamış bir ana şirkete bağlanamaz. Güvenli yol iki geçiştir: önce tüm Account'ları ParentId boş olarak upsert edin, ardından ikinci bir geçişte yalnızca ebeveyn ilişkisini External ID üzerinden güncelleyin.
Sahiplik (OwnerId) de ayrı bir eşleme tablosu ister. HubSpot'taki owner kimliklerini Salesforce kullanıcılarına bağlayan küçük bir sözlük tutun ve işten ayrılmış kişilerin kayıtlarını kime devredeceğinize göçten önce karar verin.
Aşağıdaki örnek, simple-salesforce kütüphanesiyle bir Opportunity'yi kendi External ID'si üzerinden upsert ediyor ve Account ilişkisini Account'un External ID'siyle kuruyor. Kimlik bilgileri ortam değişkenlerinden okunuyor; anahtarları koda yazmayın.
import os from simple_salesforce import Salesforce sf = Salesforce ( username = os. environ [ " SF_USER " ], password = os. environ [ " SF_PASS " ], security_token = os. environ [ " SF_TOKEN " ], domain = " test ", # önce sandbox ) def upsert_opportunity ( deal: dict ) -> None: payload = { " Name ": deal [ " dealname " ], " StageName ": STAGE_MAP [ deal [ " dealstage " ]], " CloseDate ": deal [ " closedate " ][: 10 ], " Amount ": deal. get ( " amount " ), # İlişkiyi Salesforce Id yerine Account'un External ID'si ile kur " Account ": { " HubSpot_ID__c ": deal [ " company_id " ]}, } sf. Opportunity. upsert ( f " HubSpot_ID__c/ { deal [ ' hs_object_id ' ] } ", payload ) Enter fullscreen mode Exit fullscreen mode Burada iki şey önemli. Birincisi STAGE_MAP: HubSpot pipeline aşamaları ile Salesforce StageName picklist değerleri birebir eşleştirilmeli ve eşleşmeyen her değer yükleme başlamadan raporlanmalı. İkincisi tarih ve para birimi: çok para birimli bir yapıdaysanız CurrencyIsoCode alanını ve kur tablosunu göçten önce kurun.
Büyük hacimlerde kayıt kayıt çağrı yapmak yerine Bulk API 2.0 kullanın. Mantık aynıdır; CSV içinde ilişki sütununu Account.HubSpot_ID__c gibi bir başlıkla verirsiniz ve Salesforce eşleştirmeyi kendisi yapar.
Kirli veriyi yeni sisteme taşımak, sorunu pahalı bir sisteme kopyalamaktır. Göç öncesi temizlik adımında en azından şunları yapın:
Salesforce tarafında duplicate ve matching kurallarını göç sırasında geçici olarak gevşetmeniz gerekebilir; ama bunu bilinçli yapın ve göç bitince yeniden açın.
Üretime dokunmadan önce tam bir prova yapın. Kaynak sistem rehberinde de önerilen yaklaşım, kayıtların rastgele bir örneklemini sandbox'a aktarıp doğrulamaktır. Geliştirici açısından bu provanın çıktısı bir rapor olmalı:
Bu raporu her provada yeniden üretebiliyorsanız, göçünüz tekrarlanabilir demektir. Upsert ve External ID sayesinde aynı betiği ikinci, üçüncü kez çalıştırmak yeni kopya üretmez; sadece farkları günceller.
Bir de otomasyonlara dikkat: Salesforce'ta tetikleyiciler, Flow'lar ve doğrulama kuralları yükleme sırasında devreye girerek binlerce gereksiz e-posta ya da görev üretebilir. Göç kullanıcısı için bunları atlayan bir mekanizma (örneğin özel bir izin ya da ayar ile kontrol edilen bir bayrak) kurmak işinizi çok kolaylaştırır.
Tam veri aktarımı saatler sürebilir; bu sırada satış ekibi HubSpot'ta çalışmaya devam eder. Bu yüzden geçiş iki parçalı planlanır:
Delta için ana yüklemenin başladığı zaman damgasını kaydedin ve küçük bir güvenlik payı bırakın. Upsert kullandığınız için çakışan kayıtlar sorun çıkarmaz; aynı kayıt iki kez gelirse sadece güncellenir.
Geçişten sonra web formları, reklam platformlarının sunucu taraflı dönüşüm entegrasyonları ve diğer uç noktalar Salesforce'a yönlendirilir. Bu adım çoğu zaman unutulur ve ilk gün gelen leadler eski sisteme düşer. Geçiş kontrol listesine her entegrasyonu tek tek yazın.
Göçten sonra şu kontrolleri otomatikleştirin:
Bu kontroller bir kez değil, ilk haftalarda düzenli çalışmalı. Satış ekibinin "bu müşterinin geçmişi kaybolmuş" şikâyeti geldiğinde External ID sayesinde sorunu dakikalar içinde izleyebilirsiniz.
Teknik olarak kusursuz bir göç bile satış temsilcileri yeni sistemi kullanmazsa başarısız sayılır. Geliştirici olarak katkınız burada da büyük: sayfa düzenlerini sadeleştirip temsilcinin günlük işinde gerçekten kullandığı az sayıda alanı öne çıkarmak, e-posta ve takvim kayıtlarının otomatik işlenmesini sağlamak ve rol bazlı (SDR, AE, yönetici) farklı görünümler hazırlamak benimsemeyi doğrudan etkiler.
External ID kullanmadan göç yapılabilir mi? Yapılabilir ama önerilmez. External ID olmadan her ilişki için Salesforce'un ürettiği kimlikleri bulup eşlemeniz gerekir ve göçü güvenle tekrar çalıştıramazsınız. Her tekrar yeni kopyalar üretir.
Lead mi Contact mı? HubSpot kişilerini nereye taşımalıyım? Genel yaklaşım, henüz nitelendirilmemiş adayları Lead, bir şirketle ilişkilendirilmiş ve satış sürecine girmiş kişileri Contact olarak taşımaktır. Kuralı yaşam döngüsü aşaması gibi açık bir alana bağlayın ki karar kişiden kişiye değişmesin.
Aktivite geçmişini taşımak şart mı? Satış ekibi için çoğu zaman en değerli veri budur. Hacim büyükse son belirli bir dönemi tam taşıyıp daha eskisini arşivde erişilebilir tutmak makul bir orta yoldur.
Göç ne kadar sürer? Bu tamamen veri hacmine, özel nesne sayısına ve entegrasyonlara bağlıdır. Süreyi belirleyen şey genellikle yükleme değil, temizlik ve eşleme kararlarıdır.
Bulk API mi, kayıt kayıt REST çağrısı mı? Binlerce kaydın üzerindeki her şey için Bulk API daha uygundur. REST çağrıları küçük düzeltmeler ve delta aktarımı için pratiktir.
Göç sırasında satış ekibi çalışmaya devam edebilir mi? Evet, ana yükleme sırasında edebilir. Yalnızca kesin geçiş penceresinde kaynak sistem salt okunur yapılır; bu yüzden pencereyi hafta sonu gibi düşük yoğunluklu bir zamana planlamak yaygındır.
Koray Yalçın; lead yönetimi, CRM mimarisi, dijital pazarlama ve yapay zekâ entegrasyonları üzerine çalışıyor. Gayrimenkul ve B2B satış ekipleri için reklamdan CRM'e uzanan veri akışları kuruyor.