Hizmetler Hosting & Sunucu Araçlar Blog Ara Kurumsal EnglishEN
Teklif Alın

Resmi iyzipay SDK'ları imzalama işini sizin için yapar; ama bazen bağımlılık eklemeden, ham REST API'yi anlayarak entegre etmek istersiniz — örneğin paylaşımlı bir hosting'de Composer kullanamadığınızda veya isteğin tam olarak ne gönderdiğini görmek istediğinizde. Bu rehber, SDK'sız, saf PHP + cURL ile yazılmış açık kaynak bir iyzico entegrasyon örneğini baştan sona inceliyor: IYZWSv2 imza şeması, NON-3DS, 3D Secure, Checkout Form ve PWI akışlarının tamamı.

İlgili içerikler: iyzico Node.js entegrasyon rehberi · REST API güvenlik rehberi

Açık Kaynak Örnek Proje

Bu rehberdeki tüm kod örnekleri, github.com/EgemenKEYDAL/Iyzico-Payment-Samples adresindeki açık kaynak projeden alınmıştır — NON-3DS, 3DS, PWI, Checkout Form, BIN sorgulama ve webhook için tamamen Türkçe açıklamalı, kopyala-çalıştır PHP kodları içerir. Projeyi klonlayıp kendi apiKey/secretKey bilgilerinizle doğrudan test edebilirsiniz.

IYZWSv2: Manuel İmza Oluşturma

Resmi SDK kullanmadığınızda, her isteğin Authorization header'ını kendiniz üretmeniz gerekir. iyzico'nun IYZWSv2 şeması şu adımları izler: rastgele bir randomKey üretilir, randomKey + uri + JSON-encode edilmiş istek gövdesi birleştirilip secretKey ile HMAC-SHA256'dan geçirilir, sonuç apiKey:...&randomKey:...&signature:... formatında birleştirilip Base64'e çevrilir.

public function generateAuthorizationHeader($uri, $requestBody = [])
{
    $randomKey = (string)(microtime(true) * 10000) . rand(100000, 999999);
    $jsonBody = empty($requestBody) ? '' : json_encode($requestBody, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

    $dataToEncrypt = $randomKey . $uri . $jsonBody;
    $signature = hash_hmac('sha256', $dataToEncrypt, $this->secretKey);

    $authString = "apiKey:" . $this->apiKey .
                  "&randomKey:" . $randomKey .
                  "&signature:" . $signature;

    return base64_encode($authString);
}

// İstek başlığı:
// Authorization: IYZWSv2 <base64-encoded-auth-string>
Uyarı
randomKey her istekte benzersiz olmalıdır (timestamp + rastgele sayı yeterlidir). Aynı randomKey'in tekrar kullanılması veya sabit bir değer olması imza doğrulamasının güvenlik amacını ortadan kaldırır.

Dört Ödeme Yöntemi: Hangisini Seçmeli?

YöntemAkışNe Zaman Tercih Edilir
NON-3DSTek istekle tamamlanır, 3DS yokDüşük tutarlı, düşük riskli işlemler
3DSİki adımlı: initialize → auth, banka OTP'si gerekirChargeback riskini azaltmak istediğiniz işlemler
Checkout Form4 görüntüleme modu (redirect/responsive/popup/iframe), kart verisi sizde değilÖzelleştirilebilir, PCI kapsamını küçültmek isteyenler
PWI (iyzico ile Öde)Kullanıcı iyzico hesabıyla tek tıkla öder, sadece redirectAlıcı koruma programından faydalanmak isteyenler

NON-3DS Ödeme

En basit akıştır: kart bilgileri, alıcı ve sepet bilgileriyle birlikte tek bir /payment/auth isteği atılır, yanıt anında gelir.

$paymentRequest = [
    'locale' => 'tr',
    'conversationId' => 'order-' . uniqid(),
    'price' => '100.00',
    'paidPrice' => '100.00',
    'currency' => 'TRY',
    'installment' => 1,
    'basketId' => 'B' . time(),
    'paymentChannel' => 'WEB',
    'paymentGroup' => 'PRODUCT',
    'paymentCard' => [
        'cardHolderName' => $cardHolderName,
        'cardNumber' => $cardNumber,
        'expireMonth' => $expireMonth,
        'expireYear' => $expireYear,
        'cvc' => $cvc,
        'registerCard' => 0
    ],
    'buyer' => $buyer,
    'shippingAddress' => $shippingAddress,
    'billingAddress' => $billingAddress,
    'basketItems' => $basketItems
];

$response = $iyzico->sendRequest('/payment/auth', $paymentRequest);

if ($response['status'] == 'success') {
    // paymentId'yi kaydet, siparişi onayla
}

3D Secure Akışı: Initialize + Auth

3DS ödemeler iki ayrı isteğe bölünür. Initialize adımı bir threeDSHtmlContent (Base64) döner — bu HTML, kullanıcının bankasından gelen OTP formunu içerir ve doğrudan tarayıcıya basılmalıdır:

// callback.php — banka yönlendirmesi sonrası
$authRequest = [
    'locale' => 'tr',
    'conversationId' => 'auth-' . uniqid(),
    'paymentId' => $_POST['paymentId'],
    'conversationData' => $_POST['conversationData'] ?? ''
];

$authResponse = $iyzico->sendRequest('/payment/3dsecure/auth', $authRequest);

if ($authResponse['status'] == 'success' && $authResponse['fraudStatus'] == 1) {
    // ödeme kesinleşti
}

mdStatus = 1 başarılı 3DS doğrulamasını gösterir; farklı bir değer banka tarafında doğrulamanın tamamlanmadığı anlamına gelir ve auth isteği başarısız döner.

Checkout Form: 4 Görüntüleme Modu

Checkout Form'u başlattığınızda hem bir token + paymentPageUrl, hem de gömülebilir bir checkoutFormContent (Base64 script) alırsınız. Bunu dört farklı şekilde kullanabilirsiniz:

  • Redirect (en yaygın) — header('Location: ' . $paymentPageUrl);
  • Responsive — sayfanıza gömülü: <div id="iyzipay-checkout-form" class="responsive"></div> + script
  • Popup — aynı script, class="popup" ile açılır pencere olarak
  • iFrame<iframe src="{paymentPageUrl}&iframe=true">

Token 30 dakika geçerlidir. Kullanıcı bu süre içinde ödemeyi tamamlamazsa yeniden initialize etmeniz gerekir. Callback'te token ile sonucu sorgularsınız:

$retrieveRequest = [
    'locale' => 'tr',
    'conversationId' => 'cf-retrieve-' . uniqid(),
    'token' => $_POST['token']
];

$result = $iyzico->sendRequest('/payment/iyzipos/checkoutform/auth/ecom/detail', $retrieveRequest);

if ($result['status'] == 'success' && $result['paymentStatus'] == 'SUCCESS' && $result['fraudStatus'] == 1) {
    // siparişi onayla
}

Yanıt İmzasının Doğrulanması

İstek imzalamak yeterli değildir — gelen yanıtın da gerçekten iyzico'dan geldiğini doğrulamalısınız. Burada parametre sırası endpoint'e göre değişir; örneğin Checkout Form sonuç sorgulamasında sıra paymentStatus, paymentId, currency, basketId, conversationId, paidPrice, price, token'dır. Parametreler : ile birleştirilip aynı secretKey ile HMAC-SHA256'dan geçirilir ve hash_equals() ile sabit zamanlı karşılaştırılır:

public function verifyResponseSignature($response, $parameterOrder)
{
    $params = [];
    foreach ($parameterOrder as $param) {
        if (isset($response[$param])) {
            $value = $response[$param];
            if (in_array($param, ['price', 'paidPrice'])) {
                $value = rtrim(rtrim((string)$value, '0'), '.'); // trailing zero temizliği
            }
            $params[] = $value;
        }
    }
    $dataToEncrypt = implode(':', $params);
    $calculated = hash_hmac('sha256', $dataToEncrypt, $this->secretKey);

    return hash_equals($calculated, $response['signature']);
}
Uyarı
price ve paidPrice alanlarındaki trailing zero'lar (10.5010.5) imza hesabından önce temizlenmelidir; aksi halde doğru bir yanıt için bile imza eşleşmez. Bu en sık karşılaşılan "signature geçersiz" hatasının kaynağıdır.

Fraud ve 3DS Zorunluluğu Kontrolü

Bir ödemeyi onayladıktan sonra ürünü göndermeden önce mutlaka fraudStatus alanını kontrol edin; bazı bankalar işlemi anlık onaylasa da iyzico'nun fraud motoru ek inceleme isteyebilir.

fraudStatusAnlamıAksiyon
1OnaylandıÜrünü kargoya verebilirsiniz
0İncelemedeBekleyin, otomatik sonuçlanır
-1ReddedildiÜrünü göndermeyin, siparişi iptal edin

Benzer şekilde, BIN sorgulama (/payment/bin/check) yanıtındaki force3ds alanı kartın 3DS zorunlu olup olmadığını söyler — 1 ise yalnızca 3DS akışıyla ödeme alabilirsiniz, NON-3DS isteği reddedilir.

Webhook: Event Tipleri ve İdempotency

iyzico, ödeme tamamlandığında sunucunuza bir POST bildirimi gönderir; sunucunuz 2xx ile yanıt verene kadar 10 dakikada bir, en fazla 3 kez tekrar dener. Webhook'taki iyziEventType alanı, hangi ödeme yönteminin tetiklediğini söyler:

iyziEventTypeÖdeme Yöntemi
API_AUTHNON-3DS ödeme
THREE_DS_AUTH3DS ödeme
CHECKOUTFORM_AUTHCheckout Form / PWI ödeme
BKM_AUTHBKM Express ödeme

Webhook'u callback'le birlikte kullanırken aynı ödemeyi iki kez işlemediğinizden emin olun — paymentId üzerinden veritabanında bir tekillik (unique) kısıtı tanımlamak en güvenli yöntemdir.

Sıkça Sorulan Sorular

SDK kullanmadan entegrasyon yapmak güvenli mi?

Evet, doğru uygulandığında güvenlidir — imzalama mantığı (HMAC-SHA256) açık ve dokümante edilmiştir. Avantajı bağımlılık eklememek ve isteğin tam içeriğini kontrol etmektir; dezavantajı imzalama/doğrulama kodunu siz yazıp test etmeniz gerektiğidir.

"Signature geçersiz" hatası en çok neden alınır?

En sık nedenler: parametre sırasının endpoint'e uymaması, price/paidPrice alanlarında trailing zero temizliğinin yapılmaması, veya JSON body'nin Türkçe karakterler/slash'lar farklı escape edilerek üretilmesi (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE flag'leri bu yüzden kritiktir).

NON-3DS mi 3DS mi tercih edilmeli?

Mümkünse 3DS tercih edin: chargeback (ters ibraz) riskini bankaya devreder ve PCI sorumluluğunuzu azaltır. Bazı kart tipleri (BIN sorgulamada force3ds=1) zaten yalnızca 3DS ile çalışır.

Ödeme Entegrasyonu Desteği

Kendi ödeme akışınız için PHP, Node.js veya başka bir stack'te profesyonel iyzico entegrasyonu desteği alın. Teklif Alın

WhatsApp