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ç
400dö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).
| Alan | Zorunlu | Açıklama |
|---|---|---|
first_name | firstName | name | Evet | Kişinin adı. Üçünden herhangi biri kabul edilir. |
phone | phoneNumber | Evet | Telefon numarası; en az 10 hane. Dedupe bu alan üzerinden yapılır. |
last_name | lastName | Hayır | Soyad. |
email | Hayır | E-posta. |
company | Hayır | Şirket. |
title | Hayır | Ünvan / pozisyon. |
notes | Hayır | Serbest 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.
| Alan | Tip | Açıklama |
|---|---|---|
id | string | Kontak kimliği (BigInt, string olarak serialize edilir). |
first_name | string | Ad (boşsa ""). |
last_name | string | Soyad (boşsa ""). |
name | string | first_name + last_name birleşimi (trim’lenmiş). |
phone | string | Telefon numarası. |
email | string | null | E-posta. |
company | string | null | Şirket. |
title | string | null | Ünvan. |
status | string | Kontak durumu; yeni kayıtta "new". |
stage | string | Pipeline aşaması; varsayılan "new". |
lead_score | number | Lead skoru; varsayılan 0. |
heat | string | Sıcaklık; varsayılan "cold". |
source | string | null | Kaynak; API ile oluşturulanda "zapier". |
created_at | string | null | ISO 8601 oluşturulma zamanı. |
existing | boolean | Yalnı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.
| Parametre | Açıklama |
|---|---|
phone | Tam eşleşme veya son-10-hane substring eşleşmesi (POST dedupe’siyle aynı mantık). |
search | Büyük/küçük harf duyarsız arama: firstName, lastName, email, company alanlarında ve telefon hanelerinde. |
limit | Döndürülecek maksimum kayıt. Varsayılan 25, üst sınır 100. |
phonevesearchbirlikte verilirsephoneönceliklidir. Sonuçlarcreated_atalanı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
| Belirti | Olası 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 required | Gövdede ad (first_name/firstName/name) veya telefon yok. |
400 Invalid phone — must contain at least 10 digits | Telefon 10 haneden az. E.164 (+90...) biçimi önerilir. |
400 invalid_json | Gövde geçerli JSON değil; Content-Type: application/json gönder. |
400 phone or search parameter is required | GET /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üyor | Beklenen 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. |