Özel Entegrasyon — PHP Lead Formları
Connect your website contact form to TCRM with a secure server-to-server HTTPS request. This guide is for PHP developers, agencies, and landing-page teams.
Bu sayfada
- Genel Bakış
- Mimari
- Başlamadan Önce
- Uç Nokta
- İstek Alanları
- Kimlik Doğrulama
- external_id ve nonce
- Temel HTML Formu
- PHP Entegrasyonu
- Entegrasyon Anahtarınızı Koruma
- UTM Takibi
- Yeniden Deneme ve Tekrarlı Gönderim Koruması
- API Yanıtları
- Test
- WordPress ile Kullanım
- Sorun Giderme
- Güvenlik Kontrol Listesi
- Yapılmaması Gerekenler
1. Genel Bakış
TCRM can receive leads from your public website through a dedicated inbound integration. After a visitor submits a contact form, your website server signs the payload and posts it to TCRM. The lead then appears in the customer's CRM pipeline.
Bu bir sunucudan sunucuya entegrasyondur. Tarayıcı JavaScript'i entegrasyon anahtarını tutmamalı ve kimlik doğrulamalı uç noktayı doğrudan çağırmamalıdır.
2. Mimari
Browser
↓
Customer website form
↓
Website SERVER-SIDE PHP
↓
HTTPS + HMAC authenticated request
↓
TCRM inbound endpoint
↓
Lead created in TCRM
3. Başlamadan Önce
TCRM yöneticisinden / müşteri başarı ekibinden şunları isteyin:
- Entegrasyon uç nokta URL'niz
- Entegrasyon anahtarınız
- Müşteriye özel zorunlu alanlar veya adlandırma kuralları
- Entegrasyonun ilgili müşteri için etkinleştirildiğinin onayı
Anahtarı bir ortam değişkeninde veya genel web kökünün dışındaki bir PHP yapılandırma dosyasında saklayın.
4. Uç Nokta
Müşteriniz için sağlanan uç noktayı kullanın. Genel yol kalıbı şöyledir:
POST https://YOUR-TCRM-DOMAIN/api/v1/integrations/YOUR-INTEGRATION/leads
Replace YOUR-TCRM-DOMAIN and YOUR-INTEGRATION with the values issued for your project.
Always use HTTPS.
| Öğe | Değer |
|---|---|
| Yöntem | POST |
| Content-Type | application/json |
| Gövde | JSON nesnesi (UTF-8) |
| Auth | HMAC-SHA256 istek imzası |
5. İstek Alanları
{
"external_id": "11111111-1111-4111-8111-111111111111",
"name": "Jane Doe",
"phone": "+905321234567",
"email": "jane@example.com",
"message": "I would like more information",
"source": "Website",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "summer_campaign",
"utm_adgroup": "villa_ads",
"utm_keyword": "villa istanbul",
"referrer_url": "https://example.com/?utm_source=google",
"submitted_at": "2026-08-09T10:00:00+03:00"
}
Zorunlu
external_id— UUID v4 that uniquely identifies this form submissionname— visitor full namephone— visitor phone number
İsteğe bağlı
email,message,sourceutm_source,utm_medium,utm_campaign,utm_adgroup,utm_keywordreferrer_url,submitted_at
Do not send privileged CRM fields such as owner, team, stage, or account identifiers. Assignment is controlled by TCRM for your customer.
6. Kimlik Doğrulama
Her istek şu başlıkları içermelidir:
| Başlık | Açıklama |
|---|---|
X-TCRM-Timestamp | Saniye cinsinden Unix zaman damgası (metin) |
X-TCRM-Nonce | Bu HTTP denemesi için benzersiz değer (UUID önerilir) |
X-TCRM-Signature | Küçük harf onaltılık HMAC-SHA256 imzası |
Kurallı (canonical) dizeyi tam olarak şöyle oluşturun:
timestamp + "." + nonce + "." + raw_request_body
Ardından hesaplayın:
signature = HMAC-SHA256(secret, canonical_string) → lowercase hex
- POST gövdesinde göndereceğiniz tam JSON baytlarını kullanın.
- İmzaladıktan sonra JSON'u yeniden kodlamayın.
- İzin verilen pencerenin dışındaki zaman damgaları reddedilir.
- Yeniden kullanılan nonce reddedilir.
7. external_id ve nonce
external_id
Tek bir form gönderimini tanımlar. Zaman aşımından sonra aynı lead için yeniden denerken aynı kalmalıdır.
X-TCRM-Nonce
Tek bir HTTP istek denemesini tanımlar. Yeniden denemeler dahil her deneme için yeni bir nonce üretin.
First attempt:
external_id = abc-123
nonce = nonce-1
Retry after timeout:
external_id = abc-123 (SAME)
nonce = nonce-2 (NEW)
8. Temel HTML Formu
API anahtarı HTML, JavaScript veya tarayıcı deposunda bulunmamalıdır.
9. PHP Entegrasyonu
Example private config outside the public web root (config/tcrm.php):
getenv('TCRM_LEAD_ENDPOINT'),
'secret' => getenv('TCRM_INTEGRATION_SECRET'),
];
Example submit-lead.php (conceptual):
true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'X-TCRM-Timestamp: ' . $timestamp,
'X-TCRM-Nonce: ' . $nonce,
'X-TCRM-Signature: ' . $signature,
],
CURLOPT_POSTFIELDS => $json, // EXACT signed body — do not re-encode
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
]);
$body = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
return ['code' => $code, 'body' => $body, 'error' => $err];
}
$name = trim((string)($_POST['name'] ?? ''));
$phone = trim((string)($_POST['phone'] ?? ''));
$email = trim((string)($_POST['email'] ?? ''));
$message = trim((string)($_POST['message'] ?? ''));
if ($name === '' || $phone === '') {
http_response_code(400);
exit('Name and phone are required.');
}
// Create external_id ONCE for this form submission.
$payload = [
'external_id' => uuid_v4(),
'name' => $name,
'phone' => $phone,
'email' => $email,
'message' => $message,
'source' => 'Website',
'utm_source' => trim((string)($_POST['utm_source'] ?? '')),
'utm_medium' => trim((string)($_POST['utm_medium'] ?? '')),
'utm_campaign' => trim((string)($_POST['utm_campaign'] ?? '')),
'utm_adgroup' => trim((string)($_POST['utm_adgroup'] ?? '')),
'utm_keyword' => trim((string)($_POST['utm_keyword'] ?? '')),
'referrer_url' => substr((string)($_SERVER['HTTP_REFERER'] ?? ''), 0, 2000),
'submitted_at' => date('c'),
];
// Encode JSON EXACTLY ONCE. Sign and send these same bytes on every attempt.
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$maxAttempts = 3;
$result = ['code' => 0, 'error' => 'not_attempted'];
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
$result = post_tcrm_lead($endpoint, $secret, $json);
$code = $result['code'];
// Never log secrets, signatures, or full PII — status only.
error_log('TCRM lead post attempt=' . $attempt . ' status=' . $code);
if ($code === 201 || $code === 200) {
header('Location: /thank-you.php');
exit;
}
// Do not retry client/auth/validation errors.
if (in_array($code, [400, 401, 403, 422], true)) {
break;
}
// Retry temporary failures: transport error, 429, selected 5xx.
$temporary = ($result['error'] !== '') || $code === 429 || ($code >= 500 && $code <= 599);
if (!$temporary || $attempt === $maxAttempts) {
break;
}
usleep(250000 * $attempt); // brief backoff
}
http_response_code(502);
exit('We could not submit your request right now. Please try again.');
10. Entegrasyon Anahtarınızı Koruma
İyi
- Ortam değişkenleri
- Sunucu gizli anahtar yöneticisi
- Genel web kökünün dışında PHP yapılandırması
- Kısıtlayıcı dosya izinleri
Kötü
- JavaScript / tarayıcı fetch
- HTML kaynağı
- Git deposu
- Ön yüz ortam dosyaları
- Google Tag Manager
- Sorgu parametreleri, çerezler, localStorage
11. UTM Takibi
Pass marketing parameters from the landing URL into hidden form fields, then include them in the JSON payload. This helps sales and marketing teams understand which campaigns generate CRM leads.
Supported optional fields: utm_source, utm_medium, utm_campaign,
utm_adgroup, utm_keyword, referrer_url.
12. Yeniden Deneme ve Tekrarlı Gönderim Koruması
Yalnızca bağlantı hataları, zaman aşımları, HTTP 429 veya seçili 5xx yanıtları gibi geçici durumları yeniden deneyin.
HTTP 400, 401, 403 veya 422 yanıtlarını körü körüne yeniden denemeyin.
Her yeniden denemede: yeni bir nonce üretin, aynı external_id'yi koruyun ve isteği yeniden imzalayın.
13. API Yanıtları
Yeni lead — HTTP 201
{"success": true, "duplicate": false, "lead_id": 123}
Tekrarlı (idempotent) deneme — HTTP 200
{"success": true, "duplicate": true, "lead_id": 123}
Kimlik doğrulama hatası — HTTP 401
{"success": false, "error": "unauthorized"}
Doğrulama — HTTP 422
{"success": false, "error": "validation_failed"}
Hız sınırı — HTTP 429
{"success": false, "error": "rate_limited"}
Entegrasyon kapalı — HTTP 503
{"success": false, "error": "integration_disabled"}
14. Test
- Entegrasyon TCRM'de sağlandı
- Anahtar sunucu tarafında saklandı
- Uç nokta yapılandırıldı
- Tanınabilir bir test lead'i gönderin
- HTTP 201 alın
- Lead'in TCRM'de göründüğünü doğrulayın
- Resend the same
external_idwith a new nonce - Receive HTTP 200 with
duplicate: true - Yalnızca bir lead olduğunu doğrulayın
- Geçersiz imza ile test edin ve HTTP 401 doğrulayın
- Canlı formun hâlâ teşekkür sayfasını gösterdiğini doğrulayın
15. WordPress ile Kullanım
Özel WordPress formları, Elementor form kancaları, Contact Form 7 veya WPForms kancalarını bağlayabilirsiniz. Form eklentisi ne olursa olsun, kimlik doğrulamalı TCRM isteği yine sunucu tarafı PHP'de çalışmalıdır.
Entegrasyon anahtarını Elementor özel JS, tema ön yüz betikleri veya tarayıcı konsol parçacıklarına koymayın.
16. Sorun Giderme
| Belirti | Olası nedenler |
|---|---|
401 unauthorized |
Yanlış anahtar, hatalı kurallı dize, imzadan sonra değişen gövde, süresi dolmuş zaman damgası, yeniden kullanılan nonce |
422 validation_failed |
Eksik ad/telefon, geçersiz alan biçimi, beklenmeyen alanlar |
429 rate_limited |
Sunucu IP'nizden çok fazla istek |
503 integration_disabled |
Entegrasyon müşteri için henüz etkinleştirilmedi |
| cURL bağlantı hatası | DNS, giden güvenlik duvarı, TLS sorunu, zaman aşımı |
| Beklenmeyen yinelenen lead | A new external_id was generated during a retry |
| Türkçe karakterlerde imza başarısız | JSON'u bir kez UTF-8 olarak kodlayın, tam o baytları imzalayın, aynı dizeyi gönderin |
17. Güvenlik Kontrol Listesi
- Yalnızca HTTPS
- Yalnızca sunucudan sunucuya
- Anahtarlar tarayıcının dışında
- HMAC kimlik doğrulama
- Her deneme için benzersiz nonce
- Güncel zaman damgası
- UUID
external_idper submission - Tam gövde imzalama
- Kısa bağlantı/HTTP zaman aşımları
- Güvenli yeniden deneme stratejisi
- Uygulama günlüklerinde PII veya anahtar yok
- TLS doğrulamayı kapatmayın
- İmzaları günlüğe yazmayın
- Ham API hatalarını site ziyaretçilerine göstermeyin
18. Yapılmaması Gerekenler
Bunu yapmayın:
// BAD — never call TCRM with the secret from the browser
fetch("https://YOUR-TCRM-DOMAIN/api/v1/integrations/YOUR-INTEGRATION/leads", {
method: "POST",
headers: {
"X-TCRM-Signature": "SECRET_IN_THE_BROWSER"
}
});