Public APIKontaklar

Public API — Kontaklar

Bir web formu, reklam ya da CRM’den gelen kişiyi tek bir POST çağrısıyla Purvisor AI’ya taşırsın — üstelik aynı numarayı iki kez göndersen bile çift kayıt oluşmaz. /contacts uçları tam olarak Zapier ve Make’in “Create Contact” ve “Find Contact” adımlarını besleyen uçlardır: idempotent oluşturma (aynı telefon → mevcut kaydı döndürür) ve dizi döndüren arama (bulunamazsa 404 değil, boş dizi). Bu yüzden entegrasyon akışların “zaten var mı?” kontrolüyle uğraşmadan güvenle çalışır.

Tüm örnekler production temel URL’ini kullanır: https://app.purvisor.ai/api/v1. Her istek bir API anahtarıyla kimlik doğrular — anahtar oluşturma ve gönderme biçimleri için Kimlik Doğrulama.

POST /contacts — Kontak oluştur (veya mevcut olanı döndür)

Yeni bir kontak yaratır. Ama önce telefona bakar: aynı kişi zaten varsa yeni kayıt açmaz, var olanı döndürür ve yanıta existing: true koyar. Bunu bir “getir-veya-oluştur” musluğu gibi düşün — kaç kez akıtırsan akıt, kişi bir tane kalır.

  • Yeni kontak → HTTP 201, existing: false, source: "zapier", status: "new".
  • Mevcut kontak bulundu → HTTP 200, existing: true (mevcut kaydın alanlarıyla).
  • Kota dolu → HTTP 403, code: "quota_exceeded". Planının kişi adedi kotası dolduğunda kayıt açılmaz.

Kota yalnızca yeni kayıt açılırken denetlenir — dedupe eşleştiği için mevcut kişi dönüyorsa (existing: true) kota tüketilmez. Yani aynı numarayı tekrar tekrar göndermek seni limite yaklaştırmaz.

Dedupe nasıl çalışır?

Telefon numarası tam eşleşme veya son 10 hane substring eşleşmesiyle karşılaştırılır. Yani +90 532 111 22 33 ile 05321112233 aynı kişi sayılır (analiz: son-10-hane import dedupe mantığıyla birebir aynı). Bu, formdan 0532... gelirken CRM’inde +90532... duran numaraların yanlışlıkla ikiye bölünmesini önler.

Telefon en az 10 hane içermelidir; aksi halde uç 400 döner. Son-10-hane eşleşmesi için de en az 7 hane gerekir.

İstek gövdesi

Alanlar hem snake_case hem camelCase kabul edilir (örn. first_name veya firstName).

AlanZorunluAçıklama
first_name | firstName | nameEvetKişinin adı. Üçünden herhangi biri kabul edilir.
phone | phoneNumberEvetTelefon numarası; en az 10 hane. Dedupe bu alan üzerinden yapılır.
last_name | lastNameHayırSoyad.
emailHayırE-posta.
companyHayırŞirket.
titleHayırÜnvan / pozisyon.
notesHayırSerbest not; 2000 karakterde kırpılır.

Yanıt şeması (serializeContact)

Hem POST hem GET, kontağı aynı düz şemayla döndürür; POST ayrıca bir existing bayrağı ekler.

AlanTipAçıklama
idstringKontak kimliği (BigInt, string olarak serialize edilir).
first_namestringAd (boşsa "").
last_namestringSoyad (boşsa "").
namestringfirst_name + last_name birleşimi (trim’lenmiş).
phonestringTelefon numarası.
emailstring | nullE-posta.
companystring | nullŞirket.
titlestring | nullÜnvan.
statusstringKontak durumu; yeni kayıtta "new".
stagestringPipeline aşaması; varsayılan "new".
lead_scorenumberLead skoru; varsayılan 0.
heatstringSıcaklık; varsayılan "cold".
sourcestring | nullKaynak; API ile oluşturulanda "zapier".
created_atstring | nullISO 8601 oluşturulma zamanı.
existingbooleanYalnızca POST yanıtında: kayıt zaten var mıydı?

Örnek — yeni kontak

curl -X POST https://app.purvisor.ai/api/v1/contacts \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Ayşe",
    "last_name": "Yılmaz",
    "phone": "+905321112233",
    "email": "ayse@ornek.com",
    "company": "Örnek A.Ş.",
    "title": "Satın Alma Müdürü"
  }'

HTTP 201 Created:

{
  "id": "48213",
  "first_name": "Ayşe",
  "last_name": "Yılmaz",
  "name": "Ayşe Yılmaz",
  "phone": "+905321112233",
  "email": "ayse@ornek.com",
  "company": "Örnek A.Ş.",
  "title": "Satın Alma Müdürü",
  "status": "new",
  "stage": "new",
  "lead_score": 0,
  "heat": "cold",
  "source": "zapier",
  "created_at": "2026-07-12T09:14:00.000Z",
  "existing": false
}

Örnek — aynı numara ikinci kez gönderilirse

Aynı telefonu (farklı biçimde bile olsa) tekrar gönderirsen yeni kayıt açılmaz; mevcut kayıt HTTP 200 ile existing: true olarak döner:

{
  "id": "48213",
  "first_name": "Ayşe",
  "last_name": "Yılmaz",
  "name": "Ayşe Yılmaz",
  "phone": "+905321112233",
  "status": "new",
  "stage": "new",
  "lead_score": 0,
  "heat": "cold",
  "source": "zapier",
  "created_at": "2026-07-12T09:14:00.000Z",
  "existing": true
}

Yeni bir kontak oluşturulduğunda contact.created webhook olayı tetiklenir (mevcut kayıt döndürüldüğünde tetiklenmez). Abonelik ve imza doğrulama için Webhooklar.

GET /contacts — Kontak bul

Var olan kontakları arar. Zapier/Make “search” adımlarının beklediği gibi her zaman bir dizi döndürür — eşleşme yoksa boş dizi ([]) döner, asla 404 değil. phone veya search parametrelerinden en az biri zorunludur; ikisi de yoksa uç 400 döner.

ParametreAçıklama
phoneTam eşleşme veya son-10-hane substring eşleşmesi (POST dedupe’siyle aynı mantık).
searchBüyük/küçük harf duyarsız arama: firstName, lastName, email, company alanlarında ve telefon hanelerinde.
limitDöndürülecek maksimum kayıt. Varsayılan 25, üst sınır 100.

phone ve search birlikte verilirse phone önceliklidir. Sonuçlar created_at alanına göre en yeniden en eskiye sıralanır.

Örnek — telefonla arama

curl "https://app.purvisor.ai/api/v1/contacts?phone=05321112233" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

HTTP 200 OK — bir kontak dizisi:

[
  {
    "id": "48213",
    "first_name": "Ayşe",
    "last_name": "Yılmaz",
    "name": "Ayşe Yılmaz",
    "phone": "+905321112233",
    "email": "ayse@ornek.com",
    "company": "Örnek A.Ş.",
    "title": "Satın Alma Müdürü",
    "status": "new",
    "stage": "new",
    "lead_score": 0,
    "heat": "cold",
    "source": "zapier",
    "created_at": "2026-07-12T09:14:00.000Z"
  }
]

Örnek — metinle arama

curl "https://app.purvisor.ai/api/v1/contacts?search=Örnek%20A.%C5%9E.&limit=50" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Eşleşme yoksa yanıt boş dizidir:

[]
⚠️

Kontaklar kişisel veridir. API ile aktardığın ad, telefon ve e-posta için KVKK kapsamında açık rıza ve aydınlatma yükümlülüğü sende kalır — özellikle bu kontaklar sonrasında otomatik aranacaksa, rızanın arama kapsamını da içerdiğinden emin ol. Veri saklama ve silme için KVKK ve Veri Yönetimi.

Sorun giderme

BelirtiOlası neden / çözüm
401 {"error":"invalid_api_key"}Anahtar eksik/yanlış ya da pk_live_ ile başlamıyor. Kimlik Doğrulama.
400 first_name and phone are requiredGövdede ad (first_name/firstName/name) veya telefon yok.
400 Invalid phone — must contain at least 10 digitsTelefon 10 haneden az. E.164 (+90...) biçimi önerilir.
400 invalid_jsonGövde geçerli JSON değil; Content-Type: application/json gönder.
400 phone or search parameter is requiredGET /contacts çağrısında phone da search de verilmemiş.
403 {"code":"quota_exceeded"}Planının kişi kotası dolu. Kullanılmayan kişileri sil ya da planını yükselt; yanıttaki quota.current / quota.limit mevcut durumu gösterir. (403 premium_required ile karıştırma — ikisini code alanından ayırt et.)
İkinci kez oluşturunca 201 yerine 200 dönüyorBeklenen davranış — telefon dedupe eşleşti, mevcut kayıt döndü (existing: true).
GET boş dizi ([]) döndüEşleşen kontak yok. Bu bir hata değil; son-10-hane veya arama terimini gözden geçir.

İlgili