Verifly API Dokümantasyonu
Modern, güvenli ve kolay 2FA doğrulama sistemi
Giriş
Verifly, kullanıcılarınızın telefon numaralarını veya e-postalarını doğrulamanızı sağlayan modern bir 2FA platformudur. Geleneksel OTP sistemlerinden farklı olarak, inbound verification yaklaşımı kullanır - yani kullanıcılar size kod gönderir, siz onlara göndermezsiniz.
Neden Verifly?
Maliyet Etkin
Outbound SMS göndermek yerine, kullanıcı size mesaj atar
Çoklu Kanal
SMS, WhatsApp, Sesli Arama, E-posta desteği
Spam Yok
SMS spam klasörü problemi ortadan kalkar
Gerçek Zamanlı
Socket.io ve Webhook desteği
Nasıl Çalışır?
- 1. Backend'inizde bir verification session oluşturursunuz
- 2. Kullanıcıya bir QR kod gösterilir
- 3. Kullanıcı QR kodu okutup doğrulama kodunu seçtiği yöntemle gönderir
- 4. Verifly doğrulama kodunu kontrol eder ve sonucu webhook ile size bildirir
Hızlı Başlangıç
ℹ️ Önkoşullar: Node.js 14+ veya PHP 7.4+ yüklü olmalı
Adım 1: Hesap Oluşturma
İlk olarak kayıt sayfasından bir hesap oluşturun. E-posta doğrulaması yaptıktan sonra dashboard'a erişebilirsiniz.
Adım 2: Uygulama Oluşturma
Dashboard'dan "Yeni Uygulama" butonuna tıklayın ve aşağıdaki bilgileri girin:
| Uygulama Adı: | Örn: "Benim Web Sitem" |
| Uygulama URL'i: | Örn: https://example.com |
| Bildirim API: | Doğrulama sonuçları bu API'ye bildirilecektir. |
| Servisler: | SMS, WhatsApp, Arama, E-posta (istediğinizi seçin) |
Adım 3: API Anahtarlarını Alma
Uygulama oluşturduktan sonra size iki anahtar verilir:
API Key (Public)
vf_abc123def456ghi789...
Frontend'de kullanılabilir, görünmesi sorun değil
Secret Key (Private)
96fd73b0c28fff2d9cfd9dc35...
⚠️ SADECE backend'de kullanın! Asla frontend'e eklemeyin.
Adım 4: İlk Verification Session Oluşturma
Backend'inizde bir verification session oluşturun. İşte Node.js örneği:
const crypto = require('crypto');
const axios = require('axios');
const API_KEY = 'vf_abc123...'; // Dashboard'dan aldığınız
const SECRET_KEY = '96fd73b0c28fff2d9cfd9dc35...'; // Dashboard'dan aldığınız
// 1. Signature oluştur (güvenlik için)
function createSignature(payload, secretKey) {
const timestamp = Date.now().toString();
const data = timestamp + JSON.stringify(payload);
const signature = crypto
.createHmac('sha256', secretKey)
.update(data)
.digest('hex');
return { signature, timestamp };
}
// 2. Session oluştur
async function createVerificationSession(phone) {
const payload = {
phone: phone, // Örn: '05461234567'
methods: ['sms', 'whatsapp'], // İzin verilen metodlar
lang: 'tr', // Dil
timeout: 5, // Dakika cinsinden timeout (1-15)
data: 'user_123_or_jwt_token' // Webhook'ta geri gönderilecek özel veri
};
const { signature, timestamp } = createSignature(payload, SECRET_KEY);
const response = await axios.post(
'https://www.verifly.net/api/verify/create',
payload,
{
headers: {
'X-API-Key': API_KEY,
'X-Signature': signature,
'X-Timestamp': timestamp,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
// Kullanım
createVerificationSession('05461234567')
.then(result => {
console.log('Session ID:', result.data.sessionId);
console.log('Iframe URL:', result.data.iframeUrl);
})
.catch(error => {
console.error('Hata:', error.response.data);
});
Adım 5: Iframe'i Frontend'e Ekleyin
Backend'den aldığınız iframeUrl'i kullanarak doğrulama arayüzünü gösterin:
<!-- HTML -->
<iframe
id="verifly-iframe"
src="https://www.verifly.net/verify/iframe/SESSION_ID"
width="100%"
height="600"
frameborder="0">
</iframe>
<script>
// Doğrulama sonucunu dinle
window.addEventListener('message', function(event) {
// Güvenlik: Sadece Verifly'dan gelen mesajları kabul et
if (event.origin !== 'https://www.verifly.net') return;
const { type, sessionId, reason } = event.data;
switch(type) {
case 'VERIFICATION_SUCCESS':
console.log('✅ Doğrulama başarılı!', sessionId);
// Kullanıcıyı yönlendir
window.location.href = '/dashboard';
break;
case 'VERIFICATION_FAILED':
console.log('❌ Doğrulama başarısız!', reason);
alert('Doğrulama başarısız: ' + reason);
break;
case 'VERIFICATION_EXPIRED':
console.log('⏰ Doğrulama süresi doldu', sessionId);
alert('Doğrulama süresi doldu. Lütfen tekrar deneyin.');
break;
case 'VERIFICATION_ABORTED':
console.log('❌ Doğrulama kullanıcı tarafından iptal edildi', sessionId);
alert('Doğrulama kullanıcı tarafından iptal edildi.');
break;
}
});
</script>
Iframe Event Tipleri
Iframe içinden parent window'a gönderilen postMessage event'leri:
VERIFICATION_SUCCESS
Doğrulama başarıyla tamamlandı.
Payload:
{ type: 'VERIFICATION_SUCCESS', sessionId: 'abc-123' }
Kullanım Senaryoları:
- Kullanıcıyı dashboard'a yönlendir
- Doğrulanmış kullanıcı badge'i göster
- Backend'e ajax ile bildirim gönder
- Kullanıcı profilini güncelle
VERIFICATION_FAILED
Doğrulama başarısız oldu (maksimum deneme sayısı aşıldı).
Payload:
{ type: 'VERIFICATION_FAILED', sessionId: 'abc-123', reason: 'Maximum attempts exceeded' }
Kullanım Senaryoları:
- Hata mesajı göster
- "Tekrar Dene" butonu göster
- Yeni session oluştur
- Alternatif doğrulama yöntemi öner
- Destek ekibiyle iletişim seçeneği sun
VERIFICATION_EXPIRED
Session süresi doldu (varsayılan: 2 dakika).
Payload:
{ type: 'VERIFICATION_EXPIRED', sessionId: 'abc-123' }
Kullanım Senaryoları:
- "Oturum süresi doldu" mesajı göster
- "Yeni Doğrulama Başlat" butonu göster
- Yeni session oluştur
- Kullanıcıyı başlangıç sayfasına yönlendir
VERIFICATION_ABORTED
Doğrulama kullanıcı tarafından iptal edildi.
Payload:
{ type: 'VERIFICATION_ABORTED', sessionId: 'abc-123' }
Kullanım Senaryoları:
- "Doğrulama iptal edildi" mesajı göster
- "Yeni Doğrulama Başlat" butonu göster
- Yeni session oluştur
- Kullanıcıyı başlangıç sayfasına yönlendir
💡 İleri Seviye Event Yönetimi
1. Event Logger: Tüm event'leri analytics'e gönderin
2. State Management: Redux/Vuex store'da session durumunu güncelleyin
3. UI Feedback: Toast/snackbar bildirimleri gösterin
4. Retry Logic: Failed/Expired durumlarında otomatik yeni session oluşturun
5. A/B Testing: Farklı event senaryolarını test edin
Gelişmiş Örnek: React Entegrasyonu
import { useState, useEffect } from 'react';
function VerificationModal({ sessionId, iframeUrl }) {
const [status, setStatus] = useState('pending');
useEffect(() => {
const handleMessage = (event) => {
if (event.origin !== 'https://www.verifly.net') return;
const { type, sessionId: sid } = event.data;
if (sid !== sessionId) return; // Session kontrolü
switch(type) {
case 'VERIFICATION_SUCCESS':
setStatus('success');
// Analytics event
gtag('event', 'verification_success', { session_id: sid });
// Backend'e bildir
fetch('/api/user/verify-complete', {
method: 'POST',
body: JSON.stringify({ sessionId: sid })
});
// 2 saniye sonra kapat
setTimeout(() => window.location.href = '/dashboard', 2000);
break;
case 'VERIFICATION_FAILED':
setStatus('failed');
// Analytics event
gtag('event', 'verification_failed', { session_id: sid });
// Hata mesajı göster
toast.error('Doğrulama başarısız. Lütfen tekrar deneyin.');
break;
case 'VERIFICATION_EXPIRED':
setStatus('expired');
// Yeni session oluştur
createNewSession();
break;
}
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, [sessionId]);
return (
<div className="modal">
{status === 'success' && (
<div className="success-message">✅ Doğrulama Başarılı!</div>
)}
<iframe src={iframeUrl} width="100%" height="600" />
</div>
);
}
✅ Tebrikler! İlk doğrulama sisteminizi kurdunuz. Şimdi API detaylarına geçebilirsiniz.
Custom UI / Headless API Kullanımı
Iframe kullanmak istemiyorsanız veya mobil uygulama geliştiriyorsanız, Verifly API'lerini doğrudan kullanarak kendi doğrulama UI'ınızı oluşturabilirsiniz.
📱 Kullanım Senaryoları
- iOS/Android Mobil Uygulamaları - React Native, Flutter, Swift, Kotlin
- Custom Web UI - Kendi tasarımınıza uygun doğrulama sayfası
- Desktop Uygulamaları - Electron, Tauri, .NET
- API-First Sistemler - Headless commerce, microservices
Genel Bakış
Verifly API'si tamamen headless çalışacak şekilde tasarlanmıştır. Tüm doğrulama işlemlerini API endpoint'leri üzerinden yönetebilirsiniz.
🔌 Kullanılacak API Endpoint'leri
/api/verify/create
Session oluştur
/api/verify/:sessionId
Session durumunu kontrol et
/api/verify/:sessionId/select-method
Doğrulama yöntemi seç ve başlat
/api/verify/:sessionId/cancel
Mevcut yöntemi iptal et
/api/verify/:sessionId/abort
Session'ı tamamen iptal et
Akış Diyagramı
Mobil Uygulama Örneği (React Native)
import React, { useState, useEffect } from 'react';
import { View, Text, Button, Image, StyleSheet, Linking } from 'react-native';
function VerificationScreen({ phone }) {
const [sessionId, setSessionId] = useState(null);
const [verificationData, setVerificationData] = useState(null);
const [status, setStatus] = useState('idle'); // idle, loading, waiting, success, failed
// 1. Session oluştur
const createSession = async () => {
setStatus('loading');
const response = await fetch('https://www.verifly.net/api/verify/create', {
method: 'POST',
headers: {
'X-API-Key': 'your_api_key',
'X-Signature': generateSignature(...), // HMAC-SHA256
'X-Timestamp': Date.now(),
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: phone,
methods: ['sms', 'whatsapp']
})
});
const data = await response.json();
setSessionId(data.data.sessionId);
};
// 2. Method seç
const selectMethod = async (method) => {
setStatus('loading');
const response = await fetch(
`https://www.verifly.net/api/verify/${sessionId}/select-method`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ method })
}
);
const data = await response.json();
setVerificationData(data.data);
setStatus('waiting');
// Polling başlat
startPolling();
};
// 3. Status polling (Socket.IO yerine)
const startPolling = () => {
const interval = setInterval(async () => {
const response = await fetch(
`https://www.verifly.net/api/verify/${sessionId}`
);
const data = await response.json();
if (data.data.status === 'verified') {
clearInterval(interval);
setStatus('success');
} else if (data.data.status === 'failed' || data.data.status === 'expired') {
clearInterval(interval);
setStatus('failed');
}
}, 2000); // Her 2 saniyede kontrol
};
// 4. SMS uygulamasını aç
const openSMSApp = () => {
const url = `sms:${verificationData.selectedServiceContact}?body=${verificationData.verificationCode}`;
Linking.openURL(url);
};
// 5. WhatsApp'ı aç
const openWhatsApp = () => {
const url = `whatsapp://send?phone=${verificationData.selectedServiceContact}&text=${verificationData.verificationCode}`;
Linking.openURL(url);
};
return (
<View style={styles.container}>
{status === 'idle' && (
<Button title="Doğrulama Başlat" onPress={createSession} />
)}
{sessionId && status === 'loading' && (
<View>
<Text>Method Seçin:</Text>
<Button title="📱 SMS" onPress={() => selectMethod('sms')} />
<Button title="💬 WhatsApp" onPress={() => selectMethod('whatsapp')} />
</View>
)}
{status === 'waiting' && verificationData && (
<View style={styles.waitingContainer}>
<Text style={styles.title}>Doğrulama Kodu Gönder</Text>
<Image
source={{ uri: verificationData.qrCodeData }}
style={styles.qrCode}
/>
<Text style={styles.label}>Bu numaraya mesaj gönderin:</Text>
<Text style={styles.contact}>{verificationData.selectedServiceContact}</Text>
<Text style={styles.label}>Mesaj içeriği:</Text>
<Text style={styles.code}>{verificationData.verificationCode}</Text>
{verificationData.method === 'sms' && (
<Button title="SMS Uygulamasını Aç" onPress={openSMSApp} />
)}
{verificationData.method === 'whatsapp' && (
<Button title="WhatsApp'ı Aç" onPress={openWhatsApp} />
)}
<Text style={styles.waiting}>Doğrulama bekleniyor...</Text>
</View>
)}
{status === 'success' && (
<View style={styles.successContainer}>
<Text style={styles.successText}>✅ Doğrulama Başarılı!</Text>
</View>
)}
{status === 'failed' && (
<View style={styles.failedContainer}>
<Text style={styles.failedText}>❌ Doğrulama Başarısız</Text>
<Button title="Tekrar Dene" onPress={createSession} />
</View>
)}
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 20, justifyContent: 'center' },
qrCode: { width: 200, height: 200, alignSelf: 'center', marginVertical: 20 },
title: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', marginBottom: 20 },
label: { fontSize: 14, color: '#666', marginTop: 15 },
contact: { fontSize: 20, fontWeight: 'bold', marginVertical: 5 },
code: { fontSize: 32, fontWeight: 'bold', color: '#007AFF', marginVertical: 10 },
waiting: { marginTop: 20, textAlign: 'center', color: '#666' },
successText: { fontSize: 24, color: 'green', fontWeight: 'bold', textAlign: 'center' },
failedText: { fontSize: 24, color: 'red', fontWeight: 'bold', textAlign: 'center' }
});
export default VerificationScreen;
Web Örneği (React + Socket.IO)
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
function CustomVerificationUI({ apiKey, phone }) {
const [sessionId, setSessionId] = useState(null);
const [verificationData, setVerificationData] = useState(null);
const [status, setStatus] = useState('idle');
const [socket, setSocket] = useState(null);
// Socket.IO bağlantısı
useEffect(() => {
const newSocket = io('https://www.verifly.net');
setSocket(newSocket);
return () => newSocket.close();
}, []);
// Socket event listener
useEffect(() => {
if (!socket || !sessionId) return;
socket.emit('join-verification', sessionId);
socket.on('verification-update', (data) => {
if (data.status === 'verified') {
setStatus('success');
// Başarılı! Kullanıcıyı yönlendir
setTimeout(() => {
window.location.href = '/dashboard';
}, 2000);
} else if (data.status === 'failed') {
setStatus('failed');
}
});
return () => {
socket.emit('leave-verification', sessionId);
socket.off('verification-update');
};
}, [socket, sessionId]);
const createSession = async () => {
const response = await fetch('/api/verify/create', {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'X-Signature': generateSignature(...),
'X-Timestamp': Date.now(),
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone,
methods: ['sms', 'whatsapp', 'call']
})
});
const data = await response.json();
setSessionId(data.data.sessionId);
};
const selectMethod = async (method) => {
const response = await fetch(`/api/verify/${sessionId}/select-method`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ method })
});
const data = await response.json();
setVerificationData(data.data);
setStatus('waiting');
};
return (
<div className="custom-verification">
{!sessionId ? (
<button onClick={createSession}>Doğrulama Başlat</button>
) : !verificationData ? (
<div className="method-selection">
<h3>Doğrulama Yöntemi Seçin</h3>
<button onClick={() => selectMethod('sms')}>📱 SMS</button>
<button onClick={() => selectMethod('whatsapp')}>💬 WhatsApp</button>
<button onClick={() => selectMethod('call')}>📞 Sesli Arama</button>
</div>
) : status === 'waiting' ? (
<div className="verification-waiting">
<h3>Doğrulama Kodu Gönder</h3>
<img src={verificationData.qrCodeData} alt="QR Code" />
<p><strong>{verificationData.selectedServiceContact}</strong> numarasına</p>
<p className="code">{verificationData.verificationCode}</p>
<p>kodunu gönderin</p>
{verificationData.method === 'sms' && (
<a href={`sms:${verificationData.selectedServiceContact}?body=${verificationData.verificationCode}`}>
SMS Gönder
</a>
)}
<div className="spinner">Doğrulama bekleniyor...</div>
</div>
) : status === 'success' ? (
<div className="success">
<h2>✅ Doğrulama Başarılı!</h2>
<p>Yönlendiriliyorsunuz...</p>
</div>
) : (
<div className="failed">
<h2>❌ Doğrulama Başarısız</h2>
<button onClick={createSession}>Tekrar Dene</button>
</div>
)}
</div>
);
}
Polling Yöntemi (Socket.IO Olmadan)
Socket.IO kullanamıyorsanız, GET /api/verify/:sessionId endpoint'ini düzenli aralıklarla çağırarak status kontrol edebilirsiniz.
// Polling fonksiyonu
const startStatusPolling = (sessionId, callback) => {
const pollInterval = setInterval(async () => {
try {
const response = await fetch(`https://www.verifly.net/api/verify/${sessionId}`);
const data = await response.json();
if (data.success) {
const status = data.data.status;
// Callback'i çağır
callback(status, data.data);
// Terminal durumlar - polling'i durdur
if (['verified', 'failed', 'expired'].includes(status)) {
clearInterval(pollInterval);
}
}
} catch (error) {
console.error('Polling error:', error);
}
}, 2000); // Her 2 saniyede bir kontrol
// Cleanup fonksiyonu döndür
return () => clearInterval(pollInterval);
};
// Kullanım
const stopPolling = startStatusPolling(sessionId, (status, data) => {
console.log('Status:', status);
if (status === 'verified') {
alert('✅ Doğrulama başarılı!');
window.location.href = '/dashboard';
} else if (status === 'failed') {
alert('❌ Doğrulama başarısız!');
} else if (status === 'expired') {
alert('⏰ Oturum süresi doldu!');
}
});
// Component unmount olduğunda durdur
// stopPolling();
⚠️ Polling Best Practices
- Interval: 2-3 saniye ideal (çok sık istek yapmayın)
- Timeout: Session süresi boyunca polling yapın (max 15 dakika)
- Cleanup: Component unmount olduğunda interval'i temizleyin
- Error Handling: Network hatalarında exponential backoff uygulayın
- Battery: Mobil cihazlarda pil tüketimini göz önünde bulundurun
✅ Custom UI Hazır! Artık iframe'e ihtiyaç duymadan kendi doğrulama UI'ınızı oluşturabilirsiniz. Webhook'lar ile backend entegrasyonunu tamamlayabilirsiniz.
API Authentication
Verifly API'si, her isteği HMAC-SHA256 imzalama ile güvenli hale getirir. Bu yöntem, isteklerin değiştirilmesini engeller ve sadece sizin oluşturabileceğiniz imzaları doğrular.
🔐 Güvenlik Katmanları
- ✓ Man-in-the-middle saldırılarını engeller
- ✓ Request tampering'i tespit eder
- ✓ Replay attack'ları önler (timestamp kontrolü)
- ✓ Her istek için benzersiz imza gerektirir
Gerekli Header'lar
Her API isteğinde aşağıdaki header'lar gönderilmelidir:
| Header | Açıklama | Zorunlu |
|---|---|---|
X-API-Key |
Uygulamanızın public API key'i | ✓ Evet |
X-Signature |
HMAC-SHA256 imzası (hex formatında) | ✓ Evet |
X-Timestamp |
Unix timestamp (milisaniye cinsinden) | ✓ Evet |
Content-Type |
application/json | ✓ Evet |
İmza (Signature) Nasıl Oluşturulur?
📋 İmza Oluşturma Adımları
- 1. Şu anki zamanı milisaniye cinsinden alın:
Date.now() - 2. Request body'yi JSON string'e çevirin:
JSON.stringify(payload) - 3. Timestamp ve JSON'u birleştirin:
timestamp + jsonString - 4. Secret Key ile HMAC-SHA256 hash'i oluşturun
- 5. Hash'i hexadecimal formatına çevirin
Node.js Örnek Kod
const crypto = require('crypto');
function createSignature(payload, secretKey) {
// 1. Timestamp al
const timestamp = Date.now().toString();
// 2. Payload'ı JSON string yap
const jsonPayload = JSON.stringify(payload);
// 3. Data string oluştur
const data = timestamp + jsonPayload;
// 4. HMAC-SHA256 hash oluştur
const signature = crypto
.createHmac('sha256', secretKey)
.update(data)
.digest('hex');
return { signature, timestamp };
}
// Kullanım örneği
const payload = {
phone: '05461234567',
methods: ['sms', 'whatsapp'],
lang: 'tr'
};
const { signature, timestamp } = createSignature(payload, 'sk_your_secret_key');
console.log('Timestamp:', timestamp);
console.log('Signature:', signature);
PHP Örnek Kod
<?php
function createSignature($payload, $secretKey) {
// 1. Timestamp al (milisaniye)
$timestamp = (string)(time() * 1000);
// 2. Payload'ı JSON yap
$jsonPayload = json_encode($payload);
// 3. Data string oluştur
$data = $timestamp . $jsonPayload;
// 4. HMAC-SHA256 hash oluştur
$signature = hash_hmac('sha256', $data, $secretKey);
return [
'signature' => $signature,
'timestamp' => $timestamp
];
}
// Kullanım örneği
$payload = [
'phone' => '05461234567',
'methods' => ['sms', 'whatsapp'],
'lang' => 'tr'
];
$result = createSignature($payload, 'your_secret_key');
echo 'Timestamp: ' . $result['timestamp'] . "\n";
echo 'Signature: ' . $result['signature'] . "\n";
?>
Python Örnek Kod
import hmac
import hashlib
import json
import time
def create_signature(payload, secret_key):
# 1. Timestamp al (milisaniye)
timestamp = str(int(time.time() * 1000))
# 2. Payload'ı JSON yap
json_payload = json.dumps(payload)
# 3. Data string oluştur
data = timestamp + json_payload
# 4. HMAC-SHA256 hash oluştur
signature = hmac.new(
secret_key.encode('utf-8'),
data.encode('utf-8'),
hashlib.sha256
).hexdigest()
return {
'signature': signature,
'timestamp': timestamp
}
# Kullanım örneği
payload = {
'phone': '05461234567',
'methods': ['sms', 'whatsapp'],
'lang': 'tr'
}
result = create_signature(payload, 'your_secret_key')
print(f'Timestamp: {result["timestamp"]}')
print(f'Signature: {result["signature"]}')
⚠️ Önemli Güvenlik Notları
- • Secret Key'i ASLA frontend kodunda kullanmayın
- • Secret Key'i environment variable olarak saklayın
- • Git repository'e commit etmeyin (.env dosyasını .gitignore'a ekleyin)
- • Timestamp 5 dakikadan eski istekler reddedilir (replay attack önlemi)
- • Her istek için yeni signature oluşturulmalıdır
Test Etme
İmza oluşturma fonksiyonunuzu test etmek için basit bir örnek:
Input
Secret Key:
test_secret_123
Payload:
{"phone":"05551234567"}
Timestamp:
1704067200000
Expected Output
Data String:
1704067200000{"phone":"05551234567"}
Signature (HMAC):
a1b2c3d4e5f6...
API Endpoints
Verifly API'si RESTful tasarım prensiplerini takip eder. Tüm istekler https://www.verifly.net/api base URL'i ile başlar.
📌 Genel Bilgiler
- Base URL:
https://www.verifly.net/api - Format: JSON (application/json)
- Encoding: UTF-8
- Rate Limit: 100 req/dakika (session oluşturma), 1000 req/dakika (diğer)
/verify/create
Yeni bir doğrulama session'ı oluşturur
Request Body
| Parametre | Tip | Açıklama | Zorunlu |
|---|---|---|---|
phone |
string | Telefon numarası (ör: "05461234567"). Verilmezse kullanıcı iframe'de girer. | Hayır |
email |
string | E-posta adresi. Verilmezse kullanıcı iframe'de girer. | Hayır |
methods |
array | İzin verilen yöntemler: ["sms", "whatsapp", "call", "email"] | Hayır |
lang |
string | Dil kodu: "tr" veya "en" (varsayılan: "tr") | Hayır |
timeout |
number | Session süresi (dakika): 1-15 arası (varsayılan: 2) | Hayır |
webhookUrl |
string | Doğrulama sonucu gönderilecek webhook URL | Hayır |
redirectUrl |
string | Başarılı doğrulama sonrası yönlendirilecek URL | Hayır |
data |
string | Özel veri (JSON, JWT token veya herhangi bir string) - başarılı doğrulama sırasında webhook'ta geri gönderilir | Hayır |
💡 Not: phone veya email parametreleri opsiyoneldir. Eğer verilmezse, kullanıcı seçtiği yönteme göre iframe içinde bu bilgileri kendisi girer.
💡 Not: webhookUrl parametresi opsiyoneldir. Eğer girilmezse uygulama ayarlarındaki webhookURL'e post edilir.
Örnek Request
curl -X POST https://www.verifly.net/api/verify/create \
-H "X-API-Key: vf_your_api_key" \
-H "X-Signature: generated_signature" \
-H "X-Timestamp: 1704067200000" \
-H "Content-Type: application/json" \
-d '{
"phone": "05461234567",
"methods": ["sms", "whatsapp"],
"lang": "tr",
"timeout": 5,
"webhookUrl": "https://yoursite.com/webhook",
"data": "user_123_or_jwt_token"
}'
Response (200 OK)
{
"success": true,
"data": {
"sessionId": "abc-123-def-456",
"iframeUrl": "https://www.verifly.net/verify/iframe/abc-123",
"expiresAt": "2024-01-01T12:30:00.000Z",
"allowedMethods": ["sms", "whatsapp"],
"method": null,
"userInputRequired": false
}
}
Response Field Açıklamaları
sessionId
Benzersiz session ID'si. Tüm işlemlerde kullanılır.
iframeUrl
Iframe içine gömülecek doğrulama sayfası URL'i.
allowedMethods
Kullanılabilir doğrulama yöntemleri.
userInputRequired
Kullanıcının telefon/email girmesi gerekip gerekmediği.
/verify/:sessionId
Session durumunu ve detaylarını sorgular
URL Parameters
sessionId - Session oluştururken aldığınız benzersiz ID
Örnek Request
curl -X GET https://www.verifly.net/api/verify/abc-123-def-456 \
-H "X-API-Key: vf_your_api_key" \
-H "X-Signature: generated_signature" \
-H "X-Timestamp: 1704067200000"
Response (200 OK)
{
"success": true,
"data": {
"sessionId": "abc-123-def-456",
"status": "success",
"method": "sms",
"recipientContact": "05461234567",
"selectedServiceContact": "08502411444",
"verifiedAt": "2024-01-01T12:25:30.000Z",
"expiresAt": "2024-01-01T12:30:00.000Z",
"createdAt": "2024-01-01T12:20:00.000Z"
}
}
Status Değerleri
| Status | Açıklama |
|---|---|
pending |
Kullanıcı henüz yöntem seçmedi |
waiting |
Yöntem seçildi, doğrulama kodu bekleniyor |
success |
Doğrulama başarıyla tamamlandı |
expired |
Session süresi doldu |
cancelled |
Kullanıcı iptal etti |
/verify/:sessionId/select-method
Doğrulama yöntemi seçer ve doğrulama sürecini başlatır (Custom UI için)
URL Parameters
sessionId - Session ID
Request Body
| Parametre | Tip | Açıklama | Zorunlu |
|---|---|---|---|
method |
string | Seçilen yöntem: "sms", "whatsapp", "call", "email" | ✓ Evet |
recipientContact |
string | Telefon/email (create'de verilmemişse gerekli) | Hayır* |
Örnek Request
curl -X POST https://www.verifly.net/api/verify/abc-123/select-method \
-H "Content-Type: application/json" \
-d '{
"method": "sms"
}'
Response (200 OK)
{
"success": true,
"data": {
"sessionId": "abc-123-def-456",
"status": "waiting",
"method": "sms",
"recipientContact": "05461234567",
"selectedServiceContact": "08502411444",
"verificationCode": "123456",
"qrCodeData": "data:image/png;base64,iVBORw0KGgo...",
"expiresAt": "2024-01-01T12:30:00.000Z"
}
}
💡 Önemli: Bu endpoint Custom UI kullanırken kritiktir. Response'da verificationCode ve selectedServiceContact döner, bunları kullanıcıya göstererek doğrulama kodunu göndermesini istersiniz.
Response Field Açıklamaları
verificationCode
Kullanıcının göndermesi gereken 6 haneli kod
selectedServiceContact
Kodun gönderileceği telefon/email adresi
qrCodeData
QR kod PNG verisi (base64), tarayarak hızlı gönderim için
status
"waiting" - Doğrulama kodu bekleniyor
/verify/:sessionId/cancel
Mevcut doğrulama yöntemini iptal eder, kullanıcı başka yöntem seçebilir
URL Parameters
sessionId - Session ID
💡 Kullanım: Session açık kalır, sadece seçili yöntem sıfırlanır. Kullanıcı başka bir yöntem deneyebilir. Tamamen iptal için /abort kullanın.
Örnek Request
curl -X POST https://www.verifly.net/api/verify/abc-123/cancel \
-H "Content-Type: application/json"
Response (200 OK)
{
"success": true,
"message": "Verification reset - select another method",
"data": {
"sessionId": "abc-123-def-456",
"status": "pending"
}
}
/verify/:sessionId/abort
Session'ı tamamen iptal eder ve kapatır (geri dönüş yok)
URL Parameters
sessionId - Session ID
⚠️ Dikkat: Bu işlem geri alınamaz! Session status'ü "failed" olarak işaretlenir ve webhook gönderilir. Yeni doğrulama için yeni session oluşturmalısınız.
Örnek Request
curl -X POST https://www.verifly.net/api/verify/abc-123/abort \
-H "Content-Type: application/json"
Response (200 OK)
{
"success": true,
"message": "Verification aborted successfully",
"data": {
"sessionId": "abc-123-def-456",
"status": "aborted",
"abortedAt": "2024-01-01T12:25:00.000Z"
}
}
/verify/balance
Hesap bakiyenizi sorgular
Örnek Request
curl -X GET https://www.verifly.net/api/verify/balance \
-H "X-API-Key: vf_your_api_key" \
-H "X-Signature: generated_signature" \
-H "X-Timestamp: 1704067200000"
Response (200 OK)
{
"success": true,
"data": {
"balance": 150.50,
"currency": "TRY",
"userId": "507f1f77bcf86cd799439011"
}
}
⚠️ Hata Kodları
400 Bad Request
Geçersiz parametre veya eksik alan
401 Unauthorized
Geçersiz API Key veya Signature
404 Not Found
Session bulunamadı
429 Too Many Requests
Rate limit aşıldı
402 Payment Required
Yetersiz bakiye
Webhooks
Webhook'lar, doğrulama işlemi tamamlandığında otomatik olarak sunucunuza POST isteği gönderir. Bu sayede gerçek zamanlı bildirim alabilir ve kullanıcı işlemlerini otomatikleştirebilirsiniz.
✨ Webhook Avantajları
Webhook URL Ayarlama
Webhook URL'ini iki şekilde ayarlayabilirsiniz:
1️⃣ Uygulama Seviyesinde
Dashboard'dan her uygulama için varsayılan webhook URL ayarlayın.
Settings → Webhook URL
2️⃣ Session Bazında
Session oluştururken webhookUrl parametresi ile özel URL belirleyin.
POST /verify/create
Webhook Payload
Doğrulama tamamlandığında webhook URL'inize aşağıdaki formatta POST isteği gönderilir:
Webhook Headers
Content-Type: application/jsonX-Verifly-Signature: hmac_sha256_hashX-Verifly-Timestamp: unix_timestamp_msX-Verifly-Attempt: attempt_numberUser-Agent: Verifly-Webhook/1.0
Webhook Body
{
"event": "verification.success",
"sessionId": "abc-123-def-456",
"status": "success",
"data": "custom_data_or_jwt_token_or_json_string",
"method": "sms",
"recipientContact": "05461234567",
"verifiedAt": "2024-01-01T12:25:30.000Z",
"createdAt": "2024-01-01T12:20:00.000Z",
"attemptCount": 1
}
Event Tipleri
| Event | Açıklama |
|---|---|
verification.success |
Doğrulama başarıyla tamamlandı. |
verification.failed |
Doğrulama başarısız. |
verification.expired |
Doğrulama için izin verilen süre doldu. |
verification.cancelled |
Yeni doğrulama başlatıldı ve mevcut doğrulama iptal edildi. |
verification.aborted |
Kullanıcı doğrulamayı iptal etti. |
Webhook Güvenliği (HMAC Doğrulama)
Her webhook isteği X-Verifly-Signature header'ı ile imzalanır. Bu imzayı doğrulayarak isteğin gerçekten Verifly'dan geldiğinden emin olabilirsiniz.
🔒 İmza Doğrulama Adımları
- 1. Header'lardan
X-Verifly-SignatureveX-Verifly-Timestamp'i alın - 2. Timestamp'in 5 dakikadan eski olmadığını kontrol edin (replay attack önlemi)
- 3. Webhook payload'ını JSON string'e çevirin
- 4. Data string oluşturun:
timestamp + jsonPayload - 5. Secret Key ile HMAC-SHA256 hash'i oluşturun
- 6. Oluşturduğunuz hash ile gelen
X-Verifly-Signature'ıtimingSafeEqualile karşılaştırın - 7. Eşleşmiyorsa isteği reddedin (401 döndürün)
Node.js Webhook Handler
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const SECRET_KEY = process.env.VERIFLY_SECRET_KEY;
// Webhook endpoint
app.post('/webhook/verifly', (req, res) => {
// 1. Header'lardan bilgileri al
const signature = req.headers['x-verifly-signature'];
const timestamp = req.headers['x-verifly-timestamp'];
if (!signature || !timestamp) {
return res.status(401).json({ error: 'Missing signature or timestamp' });
}
// 2. Timestamp kontrolü (5 dakika)
const now = Date.now();
if (Math.abs(now - parseInt(timestamp)) > 5 * 60 * 1000) {
return res.status(401).json({ error: 'Timestamp too old' });
}
// 3. Payload'ı JSON string yap
const payload = JSON.stringify(req.body);
const data = timestamp + payload;
// 4. Kendi signature'ımızı oluştur
const expectedSignature = crypto
.createHmac('sha256', SECRET_KEY)
.update(data)
.digest('hex');
// 5. Signature'ları güvenli karşılaştır
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
console.log('⚠️ Invalid webhook signature!');
return res.status(401).json({ error: 'Invalid signature' });
}
// 6. Event tipine göre işlem yap
const { event, sessionId, status, data } = req.body;
if (event === 'verification.success') {
console.log('✅ Verification successful:', sessionId);
console.log('Method:', data.method);
console.log('Contact:', data.recipientContact);
// Veritabanını güncelle, kullanıcıyı aktif et, vs.
// updateUserVerification(sessionId, data);
} else if (event === 'verification.failed') {
console.log('❌ Verification failed:', sessionId);
} else if (event === 'verification.expired') {
console.log('⏰ Verification expired:', sessionId);
} else if (event === 'verification.cancelled') {
console.log('🚫 Verification cancelled:', sessionId);
}
// 7. 200 OK döndür
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
PHP Webhook Handler
<?php
// webhook.php
$secretKey = getenv('VERIFLY_SECRET_KEY');
// 1. Header'lardan bilgileri al
$signature = $_SERVER['HTTP_X_VERIFLY_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_VERIFLY_TIMESTAMP'] ?? '';
if (empty($signature) || empty($timestamp)) {
http_response_code(401);
echo json_encode(['error' => 'Missing signature or timestamp']);
exit;
}
// 2. Timestamp kontrolü (5 dakika)
$now = time() * 1000; // milisaniye
if (abs($now - intval($timestamp)) > 5 * 60 * 1000) {
http_response_code(401);
echo json_encode(['error' => 'Timestamp too old']);
exit;
}
// 3. Payload'ı al
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// 4. Signature data oluştur (timestamp + payload)
$signatureData = $timestamp . $payload;
// 5. Kendi signature'ımızı oluştur
$expectedSignature = hash_hmac('sha256', $signatureData, $secretKey);
// 6. Signature'ları güvenli karşılaştır
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
// 7. Event tipine göre işlem yap
$event = $data['event'];
$sessionId = $data['sessionId'];
$status = $data['status'];
switch ($event) {
case 'verification.success':
error_log("✅ Verification successful: $sessionId");
// Veritabanını güncelle
// updateUserVerification($sessionId, $data['data']);
break;
case 'verification.failed':
error_log("❌ Verification failed: $sessionId");
break;
case 'verification.expired':
error_log("⏰ Verification expired: $sessionId");
break;
case 'verification.cancelled':
error_log("🚫 Verification cancelled: $sessionId");
break;
}
// 8. 200 OK döndür
http_response_code(200);
echo json_encode(['received' => true]);
?>
Retry Mekanizması
Webhook isteği başarısız olursa (timeout, 5xx hata, vs.) Verifly otomatik olarak tekrar dener:
1. Deneme
Hemen
2. Deneme
30 saniye sonra
3. Deneme
5 dakika sonra
💡 Best Practices
- • Webhook endpoint'iniz 200 OK dönmeli (5 saniye içinde)
- • Ağır işlemleri queue'ya atın, webhook'u hızlı cevaplayın
- • Her webhook için idempotent işlem yapın (aynı istek 2 kez gelirse sorun çıkmasın)
- • HTTPS kullanın (HTTP webhook URL'leri reddedilir)
- • Signature doğrulamayı atlamayın (güvenlik açığı yaratır)
Test Etme
Webhook'larınızı test etmek için geliştirme ortamında şu araçları kullanabilirsiniz:
🌐 ngrok
Local sunucunuzu public URL'e çevirir
ngrok http 3000
🪝 webhook.site
Gelen webhook'ları görselleştirir
webhook.site
Şifresiz Giriş (Passwordless Login)
Verifly OAuth ile kullanıcılarınızın şifre girmeden uygulamalarınıza giriş yapmalarını sağlayabilirsiniz.
✨ Avantajları
Genel Bakış
Verifly OAuth, kullanıcılarınızın e-posta veya telefon numarası ile şifre kullanmadan giriş yapmalarını sağlayan bir sistemdir. Tek bir JavaScript SDK ile entegre edebilirsiniz.
Giriş Akışı
OAuth akışı 4 adımdan oluşur:
Kullanıcı Butona Tıklar
SDK ile oluşturulmuş 'Sign in with Verifly' butonuna tıklar
Initiate Endpoint'e Yönlendirilir
Backend'inizdeki /oauth/verifly/initiate endpoint'ine yönlendirilir, signature oluşturulur
Verifly OAuth Sayfasına Redirect
www.verifly.net/oauth sayfasına redirect edilir, kullanıcı e-posta/telefon girer ve doğrulama yapar
Callback ve Session Oluşturma
Doğrulama başarılı olursa callback URL'e yönlendirilir, backend session'ı doğrular ve kullanıcı giriş yapar
1. SDK Kurulumu
Verifly OAuth SDK'sını sayfanıza ekleyerek başlayın.
SDK'yı Ekleyin
<!-- HEAD bölümüne ekleyin -->
<script src="https://www.verifly.net/js/verifly-oauth.js"></script>
SDK'yı Kullanın
<!-- Buton için container oluşturun -->
<div id="verifly-signin-btn"></div>
<script>
VeriflyOAuth.init({
initiateUrl: '/oauth/verifly',
siteName: 'Your Site Name',
buttonId: 'verifly-signin-btn',
buttonText: 'Sign in with Verifly',
buttonStyle: 'default', // default, light, dark
});
</script>
SDK Ayarları
| Parametre | Tip | Açıklama |
|---|---|---|
initiateUrl |
required | Backend'inizdeki initiate endpoint URL'i |
siteName |
required | OAuth sayfasında gösterilecek site adı |
buttonId |
required | Butonun oluşturulacağı div'in ID'si |
buttonText |
optional | Buton üzerindeki metin. Varsayılan: 'Sign in with Verifly' |
buttonStyle |
optional | Buton stili: 'default', 'light', 'dark'. Varsayılan: 'default' |
2. Initiate Endpoint
Kullanıcı butona tıkladığında SDK bu endpoint'i çağırır. Burada signature oluşturup Verifly OAuth sayfasına redirect yapmalısınız.
// Örnek Initiate Endpoint
router.get('/oauth/verifly', async (req, res) => {
try {
const crypto = require('crypto');
// Environment'tan credentials al
const API_KEY = process.env.VERIFLY_API_KEY;
const SECRET_KEY = process.env.VERIFLY_SECRET_KEY;
if (!API_KEY || !SECRET_KEY) {
return res.status(500).send('Credentials not configured');
}
// Signature oluştur
const timestamp = Date.now();
const signature = crypto
.createHmac('sha256', SECRET_KEY)
.update(`${timestamp}`)
.digest('hex');
// Callback URL belirle
const baseUrl = req.protocol + '://' + req.get('host');
const callbackUrl = `${baseUrl}/oauth/verifly/callback`;
// Query parametrelerini al
const theme = req.query.theme || 'default';
const site = req.query.site || 'Verifly';
const methods = req.query.methods || '';
// OAuth URL'ini oluştur
let oauthUrl = `https://www.verifly.net/oauth?client_key=${encodeURIComponent(API_KEY)}×tamp=${timestamp}&signature=${encodeURIComponent(signature)}&callback_url=${encodeURIComponent(callbackUrl)}&site=${encodeURIComponent(site)}&theme=${theme}`;
if (methods) {
oauthUrl += `&methods=${encodeURIComponent(methods)}`;
}
// Verifly OAuth'a redirect yap
res.redirect(oauthUrl);
} catch (error) {
console.error('OAuth initiate error:', error);
res.status(500).send('Initiate error: ' + error.message);
}
});
OAuth URL Parametreleri
| Parametre | Açıklama |
|---|---|
client_key |
API Key |
timestamp |
Timestamp (milisaniye) |
signature |
HMAC-SHA256 signature (timestamp ile hesaplanır) |
callback_url |
Doğrulama başarılı olduğunda yönlendirilecek URL |
site |
OAuth sayfasında gösterilecek site adı |
theme |
Tema: 'default', 'light', 'dark' |
methods |
İzin verilen doğrulama metodları (virgülle ayrılmış): 'email,sms,whatsapp,call' |
3. Callback Endpoint
Kullanıcı doğrulamayı tamamladıktan sonra Verifly bu endpoint'e yönlendirir. Burada session'ı doğrulayıp kullanıcı girişini tamamlamalısınız.
// Örnek Callback Endpoint
router.get('/oauth/verifly/callback', async (req, res) => {
try {
const { session_id } = req.query;
// session_id parametresini kontrol et
if (!session_id) {
return res.status(400).send('Missing session_id');
}
const crypto = require('crypto');
const axios = require('axios');
const API_KEY = process.env.VERIFLY_API_KEY;
const SECRET_KEY = process.env.VERIFLY_SECRET_KEY;
// Verify için signature oluştur
const timestamp = Date.now();
const signatureData = `${timestamp}${session_id}`;
const signature = crypto
.createHmac('sha256', SECRET_KEY)
.update(signatureData)
.digest('hex');
// Verifly API'sine verify isteği gönder
const verifyResponse = await axios.post(`https://www.verifly.net/api/oauth/${session_id}/verify`,
{},
{
headers: {
'X-API-Key': API_KEY,
'X-Signature': signature,
'X-Timestamp': timestamp.toString(),
'Content-Type': 'application/json',
},
}
);
const sessionData = verifyResponse.data.data;
// Dönen veri
// sessionData = {
// status: 'verified',
// method: 'email',
// email: '[email protected]',
// phone: null,
// recipientContact: '[email protected]',
// sessionId: 'abc-123',
// verifiedAt: '2024-01-01T12:00:00.000Z'
// }
// Kullanıcıyı veritabanında ara
let user = await User.findOne({
$or: [
{ email: sessionData.email },
{ phone: sessionData.phone }
]
});
if (!user) {
// Yoksa yeni kullanıcı oluştur
user = await User.create({
email: sessionData.email,
phone: sessionData.phone,
verified: true,
verifiedAt: sessionData.verifiedAt
});
}
// Session'a kaydet
req.session.userId = user._id;
req.session.email = sessionData.email;
// Dashboard'a yönlendir
res.redirect('/dashboard');
} catch (error) {
console.error('OAuth callback error:', error);
res.status(500).send('Callback error: ' + error.message);
}
});
Verify API Response
{
"success": true,
"data": {
"status": "verified",
"method": "email",
"email": "[email protected]",
"phone": null,
"recipientContact": "[email protected]",
"sessionId": "abc-123-def-456",
"verifiedAt": "2024-01-01T12:00:00.000Z"
}
}
4. Tam Entegrasyon Örneği
Frontend (HTML)
<!DOCTYPE html>
<html>
<head>
<title>Login with Verifly</title>
<script src="https://www.verifly.net/js/verifly-oauth.js"></script>
</head>
<body>
<h1>Welcome</h1>
<!-- SDK butonun oluşturulacağı container -->
<div id="verifly-signin-btn"></div>
<script>
VeriflyOAuth.init({
initiateUrl: '/oauth/verifly',
siteName: 'My Awesome Site',
buttonId: 'verifly-signin-btn',
buttonText: 'Sign in with Verifly',
buttonStyle: 'default'
});
</script>
</body>
</html>
Backend (Node.js/Express)
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const router = express.Router();
// Environment variables
const API_KEY = process.env.VERIFLY_API_KEY;
const SECRET_KEY = process.env.VERIFLY_SECRET_KEY;
// Initiate route
router.get('/oauth/verifly', async (req, res) => {
const timestamp = Date.now();
const signature = crypto
.createHmac('sha256', SECRET_KEY)
.update(`${timestamp}`)
.digest('hex');
const baseUrl = req.protocol + '://' + req.get('host');
const callbackUrl = `${baseUrl}/oauth/verifly/callback`;
const theme = req.query.theme || 'default';
const site = req.query.site || 'My Site';
const oauthUrl = `https://www.verifly.net/oauth?client_key=${API_KEY}×tamp=${timestamp}&signature=${signature}&callback_url=${encodeURIComponent(callbackUrl)}&site=${site}&theme=${theme}`;
res.redirect(oauthUrl);
});
// Callback route
router.get('/oauth/verifly/callback', async (req, res) => {
const { session_id } = req.query;
const timestamp = Date.now();
const signatureData = `${timestamp}${session_id}`;
const signature = crypto
.createHmac('sha256', SECRET_KEY)
.update(signatureData)
.digest('hex');
const baseUrl = `${req.protocol}://${req.get('host')}`;
const verifyResponse = await axios.post(
`${baseUrl}/api/oauth/${session_id}/verify`,
{},
{
headers: {
'X-API-Key': API_KEY,
'X-Signature': signature,
'X-Timestamp': timestamp.toString()
}
}
);
const { email, phone } = verifyResponse.data.data;
// Kullanıcıyı giriş yap
req.session.userEmail = email;
req.session.userPhone = phone;
res.redirect('/dashboard');
});
module.exports = router;
💡 En İyi Uygulamalar
- ✓ API Key ve Secret Key'i environment variables'da saklayın
- ✓ Secret key'i asla frontend'e göndermeyin
- ✓ Callback endpoint'te mutlaka signature doğrulaması yapın
- ✓ Session verilerini güvenli bir şekilde saklayın
- ✓ HTTPS kullanın ve callback URL'leri doğru yapılandırın
Kod Örnekleri
Farklı programlama dilleri ve framework'ler için tam çalışan entegrasyon örnekleri.
Node.js / Express - Tam Entegrasyon
// server.js
const express = require('express');
const axios = require('axios');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const API_KEY = 'vf_your_api_key';
const SECRET_KEY = 'your_secret_key';
// Signature oluştur
function createSignature(payload) {
const timestamp = Date.now().toString();
const data = timestamp + JSON.stringify(payload);
const signature = crypto.createHmac('sha256', SECRET_KEY).update(data).digest('hex');
return { signature, timestamp };
}
// Session oluştur
app.post('/api/verify', async (req, res) => {
const payload = {
phone: req.body.phone,
methods: ['sms', 'whatsapp'],
lang: 'tr',
webhookUrl: 'https://yoursite.com/webhook'
};
const { signature, timestamp } = createSignature(payload);
const response = await axios.post('https://www.verifly.net/api/verify/create', payload, {
headers: {
'X-API-Key': API_KEY,
'X-Signature': signature,
'X-Timestamp': timestamp
}
});
res.json(response.data);
});
// Webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-verifly-signature'];
const timestamp = req.headers['x-verifly-timestamp'];
// Signature doğrula
const data = timestamp + JSON.stringify(req.body);
const expected = crypto.createHmac('sha256', SECRET_KEY).update(data).digest('hex');
if (signature !== expected) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Event işle
if (req.body.event === 'verification.success') {
console.log('✅ Verified:', req.body.sessionId);
}
res.json({ received: true });
});
app.listen(3000);
PHP / Laravel - Service + Controller
<?php
// app/Services/VeriflyService.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class VeriflyService {
private $apiKey;
private $secretKey;
public function __construct() {
$this->apiKey = config('services.verifly.api_key');
$this->secretKey = config('services.verifly.secret_key');
}
public function createSession($phone = null) {
$payload = [
'phone' => $phone,
'methods' => ['sms', 'whatsapp'],
'lang' => 'tr',
'webhookUrl' => route('webhook.verifly')
];
$timestamp = (string)(time() * 1000);
$data = $timestamp . json_encode($payload);
$signature = hash_hmac('sha256', $data, $this->secretKey);
return Http::withHeaders([
'X-API-Key' => $this->apiKey,
'X-Signature' => $signature,
'X-Timestamp' => $timestamp
])->post('https://www.verifly.net/api/verify/create', $payload)->json();
}
public function verifyWebhook($signature, $timestamp, $payload) {
$data = $timestamp . json_encode($payload);
$expected = hash_hmac('sha256', $data, $this->secretKey);
return hash_equals($expected, $signature);
}
}
// app/Http/Controllers/WebhookController.php
namespace App\Http\Controllers;
use App\Services\VeriflyService;
class WebhookController extends Controller {
public function handle(Request $request, VeriflyService $verifly) {
$sig = $request->header('X-Verifly-Signature');
$ts = $request->header('X-Verifly-Timestamp');
if (!$verifly->verifyWebhook($sig, $ts, $request->all())) {
return response()->json(['error' => 'Invalid'], 401);
}
if ($request->event === 'verification.success') {
// Kullanıcıyı doğrulanmış işaretle
}
return response()->json(['received' => true]);
}
}
?>
Python / Flask - Basit Entegrasyon
from flask import Flask, request, jsonify
import requests
import hmac
import hashlib
import json
import time
app = Flask(__name__)
API_KEY = 'vf_your_api_key'
SECRET_KEY = 'your_secret_key'
def create_signature(payload):
timestamp = str(int(time.time() * 1000))
data = timestamp + json.dumps(payload, separators=(',', ':'))
signature = hmac.new(
SECRET_KEY.encode(),
data.encode(),
hashlib.sha256
).hexdigest()
return {'signature': signature, 'timestamp': timestamp}
@app.route('/api/verify', methods=['POST'])
def create_session():
payload = {
'phone': request.json.get('phone'),
'methods': ['sms', 'whatsapp'],
'lang': 'tr',
'webhookUrl': 'https://yoursite.com/webhook'
}
auth = create_signature(payload)
response = requests.post(
'https://www.verifly.net/api/verify/create',
json=payload,
headers={
'X-API-Key': API_KEY,
'X-Signature': auth['signature'],
'X-Timestamp': auth['timestamp']
}
)
return jsonify(response.json())
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Verifly-Signature')
timestamp = request.headers.get('X-Verifly-Timestamp')
data = timestamp + json.dumps(request.json, separators=(',', ':'))
expected = hmac.new(SECRET_KEY.encode(), data.encode(), hashlib.sha256).hexdigest()
if signature != expected:
return jsonify({'error': 'Invalid'}), 401
if request.json['event'] == 'verification.success':
print('✅ Verified:', request.json['sessionId'])
return jsonify({'received': True})
app.run(port=5000)
React Native - Iframe ile WebView Entegrasyonu
💡 Önerilen Yaklaşım: React Native'de iframe URL'ini WebView ile gösterin. Custom UI için API Endpoints bölümündeki detayları inceleyin.
// VeriflyService.js
import CryptoJS from 'crypto-js';
const API_KEY = 'vf_your_api_key';
const SECRET_KEY = 'your_secret_key';
const BASE_URL = 'https://www.verifly.net/api';
function createSignature(payload) {
const timestamp = Date.now().toString();
const data = timestamp + JSON.stringify(payload);
const signature = CryptoJS.HmacSHA256(data, SECRET_KEY).toString();
return { signature, timestamp };
}
export async function createVerification(phone) {
const payload = {
phone,
methods: ['sms', 'whatsapp'],
lang: 'tr',
webhookUrl: 'https://yourapi.com/webhook'
};
const { signature, timestamp } = createSignature(payload);
const response = await fetch(`${BASE_URL}/verify/create`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
'X-Signature': signature,
'X-Timestamp': timestamp
},
body: JSON.stringify(payload)
});
return await response.json();
}
// VerificationScreen.js
import React, { useState, useRef } from 'react';
import { View, StyleSheet } from 'react-native';
import { WebView } from 'react-native-webview';
import { createVerification } from './VeriflyService';
export default function VerificationScreen({ userPhone }) {
const [iframeUrl, setIframeUrl] = useState(null);
const webViewRef = useRef(null);
React.useEffect(() => {
// Session oluştur ve iframe URL al
createVerification(userPhone).then(result => {
setIframeUrl(result.data.iframeUrl);
});
}, [userPhone]);
const handleWebViewMessage = (event) => {
const data = JSON.parse(event.nativeEvent.data);
if (data.event === 'verification.success') {
console.log('✅ Doğrulama başarılı!', data.sessionId);
// Backend'e bildir veya navigation yap
}
};
if (!iframeUrl) {
return <View style={styles.loading} />;
}
return (
<View style={styles.container}>
<WebView
ref={webViewRef}
source={{ uri: iframeUrl }}
style={styles.webview}
onMessage={handleWebViewMessage}
javaScriptEnabled={true}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
webview: {
flex: 1,
},
loading: {
flex: 1,
backgroundColor: '#f5f5f5',
},
});
📦 Gerekli Paketler:
npm install react-native-webview crypto-js
Swift (iOS) - WKWebView ile Iframe Entegrasyonu
💡 Önerilen Yaklaşım: WKWebView ile iframe URL'ini gösterin. Custom UI için API Endpoints bölümündeki detayları inceleyin.
// VeriflyService.swift
import Foundation
import CryptoKit
class VeriflyService {
let apiKey = "vf_your_api_key"
let secretKey = "your_secret_key"
let baseURL = "https://www.verifly.net/api"
func createSignature(payload: [String: Any]) -> (signature: String, timestamp: String) {
let timestamp = String(Int(Date().timeIntervalSince1970 * 1000))
let jsonData = try! JSONSerialization.data(withJSONObject: payload)
let jsonString = String(data: jsonData, encoding: .utf8)!
let data = timestamp + jsonString
let key = SymmetricKey(data: Data(secretKey.utf8))
let signature = HMAC<SHA256>.authenticationCode(for: Data(data.utf8), using: key)
let signatureHex = signature.map { String(format: "%02x", $0) }.joined()
return (signatureHex, timestamp)
}
func createVerification(phone: String, completion: @escaping (Result<String, Error>) -> Void) {
let payload: [String: Any] = [
"phone": phone,
"methods": ["sms", "whatsapp"],
"lang": "tr",
"webhookUrl": "https://yourapi.com/webhook"
]
let (signature, timestamp) = createSignature(payload: payload)
var request = URLRequest(url: URL(string: "\\(baseURL)/verify/create")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
request.setValue(signature, forHTTPHeaderField: "X-Signature")
request.setValue(timestamp, forHTTPHeaderField: "X-Timestamp")
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let sessionData = json["data"] as? [String: Any],
let iframeUrl = sessionData["iframeUrl"] as? String {
completion(.success(iframeUrl))
}
}.resume()
}
}
// VerificationViewController.swift
import UIKit
import WebKit
class VerificationViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
let veriflyService = VeriflyService()
override func viewDidLoad() {
super.viewDidLoad()
// WKWebView setup
let configuration = WKWebViewConfiguration()
configuration.userContentController.add(self, name: "verifly")
webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(webView)
// Session oluştur ve iframe yükle
loadVerification()
}
func loadVerification() {
veriflyService.createVerification(phone: "05551234567") { result in
switch result {
case .success(let iframeUrl):
DispatchQueue.main.async {
if let url = URL(string: iframeUrl) {
self.webView.load(URLRequest(url: url))
}
}
case .failure(let error):
print("Error:", error)
}
}
}
// WebView message handler
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
if message.name == "verifly",
let dict = message.body as? [String: Any],
let event = dict["event"] as? String {
if event == "verification.success" {
print("✅ Doğrulama başarılı!")
// Backend'e bildir veya navigation yap
}
}
}
deinit {
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "verifly")
}
}
Kotlin (Android) - WebView ile Iframe Entegrasyonu
💡 Önerilen Yaklaşım: WebView ile iframe URL'ini gösterin. Custom UI için API Endpoints bölümündeki detayları inceleyin.
// VeriflyService.kt
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
class VeriflyService {
private val apiKey = "vf_your_api_key"
private val secretKey = "your_secret_key"
private val baseURL = "https://www.verifly.net/api"
private val client = OkHttpClient()
private fun createSignature(payload: JSONObject): Pair<String, String> {
val timestamp = System.currentTimeMillis().toString()
val data = timestamp + payload.toString()
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(secretKey.toByteArray(), "HmacSHA256"))
val signature = mac.doFinal(data.toByteArray()).joinToString("") { "%02x".format(it) }
return Pair(signature, timestamp)
}
fun createVerification(phone: String, callback: (String?) -> Unit) {
val payload = JSONObject().apply {
put("phone", phone)
put("methods", listOf("sms", "whatsapp"))
put("lang", "tr")
put("webhookUrl", "https://yourapi.com/webhook")
}
val (signature, timestamp) = createSignature(payload)
val request = Request.Builder()
.url("$baseURL/verify/create")
.post(payload.toString().toRequestBody("application/json".toMediaType()))
.addHeader("X-API-Key", apiKey)
.addHeader("X-Signature", signature)
.addHeader("X-Timestamp", timestamp)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback(null)
}
override fun onResponse(call: Call, response: Response) {
val json = response.body?.string()?.let { JSONObject(it) }
val iframeUrl = json?.getJSONObject("data")?.getString("iframeUrl")
callback(iframeUrl)
}
})
}
}
// VerificationActivity.kt
import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import android.webkit.JavascriptInterface
import androidx.appcompat.app.AppCompatActivity
class VerificationActivity : AppCompatActivity() {
private val veriflyService = VeriflyService()
private lateinit var webView: WebView
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
webView = WebView(this)
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.webViewClient = WebViewClient()
webView.addJavascriptInterface(WebAppInterface(), "Android")
setContentView(webView)
// Session oluştur ve iframe yükle
loadVerification()
}
private fun loadVerification() {
veriflyService.createVerification("05551234567") { iframeUrl ->
runOnUiThread {
iframeUrl?.let {
webView.loadUrl(it)
}
}
}
}
inner class WebAppInterface {
@JavascriptInterface
fun onVerificationSuccess(sessionId: String) {
runOnUiThread {
println("✅ Doğrulama başarılı: $sessionId")
// Backend'e bildir veya navigation yap
}
}
}
}
📦 Gradle Dependencies:
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
Go - Web Server ile Iframe Entegrasyonu
💡 Önerilen Yaklaşım: Backend'de session oluşturup iframe URL'ini HTML template'e gönderin.
// main.go
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"html/template"
"io/ioutil"
"net/http"
"strconv"
"time"
)
const (
APIKey = "vf_your_api_key"
SecretKey = "your_secret_key"
BaseURL = "https://www.verifly.net/api"
)
type VerificationPayload struct {
Phone string `json:"phone"`
Methods []string `json:"methods"`
Lang string `json:"lang"`
WebhookURL string `json:"webhookUrl,omitempty"`
}
type VerificationResponse struct {
Success bool `json:"success"`
Data map[string]interface{} `json:"data"`
}
func createSignature(payload interface{}) (string, string, error) {
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
jsonData, _ := json.Marshal(payload)
data := timestamp + string(jsonData)
h := hmac.New(sha256.New, []byte(SecretKey))
h.Write([]byte(data))
signature := hex.EncodeToString(h.Sum(nil))
return signature, timestamp, nil
}
func createVerification(phone string) (string, error) {
payload := VerificationPayload{
Phone: phone,
Methods: []string{"sms", "whatsapp"},
Lang: "tr",
WebhookURL: "https://yoursite.com/webhook",
}
signature, timestamp, _ := createSignature(payload)
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", BaseURL+"/verify/create", bytes.NewBuffer(jsonData))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", APIKey)
req.Header.Set("X-Signature", signature)
req.Header.Set("X-Timestamp", timestamp)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var result VerificationResponse
json.Unmarshal(body, &result)
// Return iframe URL
return result.Data["iframeUrl"].(string), nil
}
// Verification page handler
func verifyHandler(w http.ResponseWriter, r *http.Request) {
phone := r.URL.Query().Get("phone")
if phone == "" {
phone = "05551234567" // Default
}
iframeURL, err := createVerification(phone)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl := `
<!DOCTYPE html>
<html>
<head>
<title>Telefon Doğrulama</title>
<style>
body { margin: 0; padding: 20px; font-family: Arial; }
iframe { width: 100%; height: 600px; border: 1px solid #ddd; border-radius: 8px; }
</style>
</head>
<body>
<h1>Telefon Numaranızı Doğrulayın</h1>
<iframe src="{{.IframeURL}}" title="Verifly Verification"></iframe>
</body>
</html>
`
t, _ := template.New("verify").Parse(tmpl)
t.Execute(w, map[string]string{"IframeURL": iframeURL})
}
// Webhook handler
func webhookHandler(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-Verifly-Signature")
timestamp := r.Header.Get("X-Verifly-Timestamp")
body, _ := ioutil.ReadAll(r.Body)
// Signature doğrula
data := timestamp + string(body)
h := hmac.New(sha256.New, []byte(SecretKey))
h.Write([]byte(data))
expected := hex.EncodeToString(h.Sum(nil))
if signature != expected {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
var payload map[string]interface{}
json.Unmarshal(body, &payload)
if payload["event"] == "verification.success" {
// Kullanıcının veritabanında verified olarak işaretle
println("✅ Verified:", payload["sessionId"])
}
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
func main() {
http.HandleFunc("/verify", verifyHandler)
http.HandleFunc("/webhook", webhookHandler)
println("Server running on :8080")
http.ListenAndServe(":8080", nil)
}
🚀 Çalıştırma:
go run main.go
# Tarayıcıda: http://localhost:8080/verify?phone=05551234567
✅ Tüm örnekler production-ready! Kendi API key'lerinizi ekleyip hemen kullanmaya başlayabilirsiniz.