emre-tarhan/kuveytturk-vpos-laravel-sdk
Composer 安装命令:
composer require emre-tarhan/kuveytturk-vpos-laravel-sdk
包简介
Kuveyt Türk Sanal Pos (Virtual POS) Laravel SDK with 3D Secure 2.0 support
README 文档
README
Kuveyt Turk Sanal POS entegrasyonu icin kapsamli Laravel SDK. Tam 3D Secure 2.0 destegi.
Ozellikler
- 3D Secure 2.0 Tam Destek — Iki asamali odeme akisi
- Iki Asamali Odeme: Kart Dogrulama + Provizyon (Odeme Alma)
- Taksit Destegi — 24 aya kadar taksit imkani
- Ertelemeli Odeme (Harcama Oteleme) — Esnek odeme planlama
- Hash Veri Dogrulama — SHA1 tabanli istek dogrulama
- Test & Produksiyon Ortamlari — Ayri endpoint'ler
- Satis / Iptal / Iade / Kismi Iade Islemleri — Tam islem yasam dongusu
- WCF SOAP Servis Entegrasyonu — Iptal/iade islemleri icin
- Kapsamli Hata Yonetimi — Tum Kuveyt Turk hata kodlari
- Laravel 12.x & 13.x Uyumlu
- PHP 8.1, 8.2, 8.3, 8.4 Destegi
Gereksinimler
- PHP: 8.1, 8.2, 8.3 veya 8.4
- Laravel: 12.x veya 13.x
- PHP Eklentileri: curl, libxml, openssl
Kurulum
composer require emre-tarhan/kuveytturk-vpos-laravel-sdk
Ayarlari Yayinlama
php artisan vendor:publish --tag=kuveytturk-vpos-config
Veya kurulum komutunu kullanin:
php artisan kuveytturk:install
Bu islem ayar dosyasini config/kuveytturk-vpos.php konumuna yayinlayacaktir.
Yapilandirma
Kuveyt Turk kimlik bilgilerinizi .env dosyasina ekleyin:
KUVEYTTURK_MERCHANT_ID=uye_isyeri_numaraniz KUVEYTTURK_CUSTOMER_ID=musteri_numaraniz KUVEYTTURK_USERNAME=api_kullanici_adiniz KUVEYTTURK_PASSWORD=api_sifreniz KUVEYTTURK_ENVIRONMENT=test # veya 'production'
Veya config/kuveytturk-vpos.php dosyasindan yapilandirin:
return [ 'merchant_id' => env('KUVEYTTURK_MERCHANT_ID', ''), 'customer_id' => env('KUVEYTTURK_CUSTOMER_ID', ''), 'username' => env('KUVEYTTURK_USERNAME', ''), 'password' => env('KUVEYTTURK_PASSWORD', ''), 'environment' => env('KUVEYTTURK_ENVIRONMENT', 'test'), 'timeout' => env('KUVEYTTURK_TIMEOUT', 60), 'connect_timeout' => env('KUVEYTTURK_CONNECT_TIMEOUT', 30), ];
Kullanim
Temel Satis (Tam 3D Akis)
use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos; use EmreTarhan\KuveytTurkVPos\Dto\SaleRequest; use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode; // Servis konteynerinden enjekte et veya app'ten cozumle $vpos = app(KuveytTurkVPos::class); $request = new SaleRequest( merchantOrderId: 'ORDER-' . time(), amount: 100.00, // 100 TL - dahili olarak 10000'e donusturulur okUrl: 'https://siteniz.com/odeme/basarili', failUrl: 'https://siteniz.com/odeme/basarisiz', cardHolderName: 'Ahmet Yilmaz', cardNumber: '5188961939192544', cardExpireDateYear: '25', cardExpireDateMonth: '06', cardCVV2: '929', email: 'musteri@ornek.com', clientIp: request()->ip(), billAddrCity: 'Istanbul', billAddrCountry: '792', // Turkiye ulke kodu billAddrLine1: 'Ornek Sokak No:123', billAddrPostCode: '34000', billAddrState: '34', Cc: 'Ahmet Yilmaz', subscriber: 'musteri@ornek.com', currencyCode: CurrencyCode::TRY, installmentCount: 0, // 0 = taksitsiz, 1-24 arasi taksit ); $response = $vpos->sale($request); if ($response->isSuccessful()) { // Odeme basarili echo "Islem onaylandi! Siparis No: " . $response->orderId; } else { // Odeme basarisiz echo "Odeme basarisiz: " . $response->responseMessage; }
Iki Asamali Odeme (Manuel Kontrol)
Odeme akisi uzerinde daha fazla kontrole ihtiyaciniz varsa:
Asama 1: Kart Dogrulama
use EmreTarhan\KuveytTurkVPos\Dto\VerifyCardRequest; $verifyRequest = new VerifyCardRequest( merchantOrderId: 'ORDER-' . time(), amount: 150.00, okUrl: 'https://siteniz.com/odeme/basarili', failUrl: 'https://siteniz.com/odeme/basarisiz', cardHolderName: 'Ahmet Yilmaz', cardNumber: '5188961939192544', cardExpireDateYear: '25', cardExpireDateMonth: '06', cardCVV2: '929', email: 'musteri@ornek.com', clientIp: request()->ip(), billAddrCity: 'Istanbul', billAddrCountry: '792', billAddrLine1: 'Ornek Sokak No:123', billAddrPostCode: '34000', billAddrState: '34', Cc: 'Ahmet Yilmaz', subscriber: 'musteri@ornek.com', currencyCode: CurrencyCode::TRY, installmentCount: 3, // 3 ay taksit ); $verifyResponse = $vpos->verifyCard($verifyRequest); // Asama 2 icin MD degerini saklayin $mdValue = $verifyResponse->md; // Provizyon icin gerekli $orderId = $verifyResponse->orderId;
Asama 2: Provizyon (Odeme Tamamlama)
use EmreTarhan\KuveytTurkVPos\Dto\ProvisionRequest; $provisionRequest = new ProvisionRequest( merchantOrderId: 'ORDER-' . time(), amount: 150.00, md: $asama1denGelenMdDegeri, okUrl: 'https://siteniz.com/odeme/basarili', failUrl: 'https://siteniz.com/odeme/basarisiz', currencyCode: CurrencyCode::TRY, installmentCount: 3, ); $provisionResponse = $vpos->provision($provisionRequest); if ($provisionResponse->isSuccessful()) { // Odeme tamamlandi echo "Provizyon basarili! RRN: " . $provisionResponse->rrn; }
Islem Iptali (Ayni Gun)
use EmreTarhan\KuveytTurkVPos\Dto\CancelRequest; use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode; $cancelRequest = new CancelRequest( merchantOrderId: 'ORDER-12345', amount: 100.00, provisionNumber: '123456', // Orijinal satis isleminden rrn: '789012345', // Referans numarasi stan: '654321', // Sistem iz numarasi orderId: 'orijinal-siparis-no', currencyCode: CurrencyCode::TRY, ); $cancelResponse = $vpos->cancel($cancelRequest); if ($cancelResponse->isSuccessful()) { echo "Islem basariyla iptal edildi!"; }
Iade (Gun Sonu Sonrasi)
use EmreTarhan\KuveytTurkVPos\Dto\RefundRequest; $refundRequest = new RefundRequest( merchantOrderId: 'ORDER-12345', amount: 100.00, provisionNumber: '123456', rrn: '789012345', stan: '654321', orderId: 'orijinal-siparis-no', currencyCode: CurrencyCode::TRY, ); $refundResponse = $vpos->refund($refundRequest); if ($refundResponse->isSuccessful()) { echo "Iade basariyla gerceklestirildi!"; }
Kismi Iade
use EmreTarhan\KuveytTurkVPos\Dto\PartialRefundRequest; $partialRefundRequest = new PartialRefundRequest( merchantOrderId: 'ORDER-12345', amount: 50.00, // Kismi tutar provisionNumber: '123456', rrn: '789012345', stan: '654321', orderId: 'orijinal-siparis-no', currencyCode: CurrencyCode::TRY, ); $partialRefundResponse = $vpos->partialRefund($partialRefundRequest); if ($partialRefundResponse->isSuccessful()) { echo "Kismi iade basariyla gerceklestirildi!"; }
Gercek Entegrasyon Ornegi (3D Secure Akisi)
Asagida produksiyon ortaminda kullanilan, tam 3D Secure odeme akisi ornegi bulunmaktadir. Bu akis 5 asamadan olusur: odeme baslatma, bankaya yonlendirme, callback karsilama, provizyon tamamlama ve siparisi sonuclandirma.
Asama 1: Servis Konteynerine Kayit
// App\Providers\AppServiceProvider::register() use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos; $this->app->singleton(KuveytTurkVPos::class, function () { return KuveytTurkVPos::fromConfig(config('kuveytturk-vpos')); });
Asama 2: Odeme Baslatma (Controller)
Kart dogrulama islemi bankadan HTML dondurur. Bu HTML'i tarayicida render etmeniz gerekir — otomatik olarak bankanin 3D Secure sayfasina yonlendiren bir form icerir.
use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos; use EmreTarhan\KuveytTurkVPos\Dto\VerifyCardRequest; use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode; public function odeme(Request $request, KuveytTurkVPos $vpos) { $verifyRequest = new VerifyCardRequest( merchantOrderId: 'ORDER-' . time(), amount: 100.00, okUrl: route('odeme.callback.basarili'), failUrl: route('odeme.callback.basarisiz'), cardHolderName: $request->input('kart_sahibi'), cardNumber: $request->input('kart_numarasi'), cardExpireDateYear: $request->input('kart_yil'), // 2 haneli: '28' cardExpireDateMonth: $request->input('kart_ay'), // 2 haneli: '12' cardCVV2: $request->input('kart_cvv'), email: $request->input('email'), clientIp: $request->ip(), billAddrCity: 'Istanbul', billAddrCountry: '792', billAddrLine1: 'Ornek Sokak', billAddrPostCode: '34000', billAddrState: '34', Cc: $request->input('kart_sahibi'), subscriber: $request->input('email'), currencyCode: CurrencyCode::TRY, installmentCount: 0, ); $hashCalculator = $vpos->getHashCalculator(); $hashData = $verifyRequest->generateHash($hashCalculator); $xml = $verifyRequest->toXml($hashData); // Bankanin kart dogrulama endpoint'ine gonder $response = Http::withHeaders([ 'Content-Type' => 'application/xml', ])->withBody($xml, 'application/xml') ->post($vpos->getCardVerificationUrl()); $body = $response->body(); // Banka 3D Secure yonlendirme HTML'i dondurur — session'a kaydet ve tarayicida render et if (str_contains($body, '<html') || str_contains($body, '<form')) { session(['secure3d_html' => $body]); return redirect()->route('odeme.secure3d'); } // Dogrudan basarisizlik (3D Secure yonlendirmesi yok) return back()->withError('Odeme baslatma basarisiz.'); }
Asama 3: 3D Secure Sayfasini Render Etme (Frontend)
Bankanin HTML'i otomatik gonderilen bir form icerir. Gizli bir div'de gosterip otomatik gonderin:
<!-- resources/views/odeme/secure3d.blade.php --> <div id="secure3d-container" style="display:none;"> {!! session('secure3d_html') !!} </div> <script> setTimeout(function() { document.getElementById('secure3d-container').querySelector('form').submit(); }, 500); </script> <p>3D Secure dogrulamasina yonlendiriliyorsunuz...</p>
Asama 4: Banka Callback'inin Karsilanmasi (CSRF/Session Middleware Haric)
Onemli: Banka callback URL'lerinize cross-site POST gonderir. Bu route'lar middleware gruplarinin disinda olmalidir (CSRF ve session yok):
// bootstrap/app.php veya routes/web.php — middleware gruplarinin DISINDA Route::post('/odeme/callback/basarili', [OdemeCallbackController::class, 'basarili']) ->name('odeme.callback.basarili'); Route::post('/odeme/callback/basarisiz', [OdemeCallbackController::class, 'basarisiz']) ->name('odeme.callback.basarisiz');
Asama 5: Provizyon (Odeme Tamamlama)
use EmreTarhan\KuveytTurkVPos\Dto\ProvisionRequest; use EmreTarhan\KuveytTurkVPos\Enums\CurrencyCode; public function basarili(Request $request, KuveytTurkVPos $vpos) { // Banka URL-encoded XML olarak AuthenticationResponse gonderir $rawXml = urldecode($request->getContent()); // XML'i guvenli sekilde cozumle libxml_use_internal_errors(true); $dom = new \DOMDocument(); $dom->loadXML($rawXml, LIBXML_NONET | LIBXML_NOCDATA); libxml_clear_errors(); $xpath = new \DOMXPath($dom); $getir = fn (string $tag): ?string => ($nodes = $xpath->query("//*[local-name()='{$tag}']")) && $nodes->length > 0 ? $nodes->item(0)->textContent : null; $md = $getir('MD'); $orderId = $getir('OrderId'); $responseCode = $getir('ResponseCode'); $merchantOrderId = $getir('MerchantOrderId'); // Hash dogrulama: SHA1_base64(MerchantOrderId + ResponseCode + OrderId + HashPassword) $hashCalculator = $vpos->getHashCalculator(); $hashPassword = $hashCalculator->getHashPassword(); $beklenenHash = base64_encode(sha1($merchantOrderId . $responseCode . $orderId . $hashPassword, true)); $gelenHash = $getir('HashData'); if (!hash_equals($beklenenHash, $gelenHash)) { // Hash uyumsuzlugu — callback'i reddet return response('Gecersiz hash', 400); } // Asama 2: Provizyon $provisionRequest = new ProvisionRequest( merchantOrderId: $merchantOrderId, amount: 100.00, md: $md, okUrl: route('odeme.callback.basarili'), failUrl: route('odeme.callback.basarisiz'), currencyCode: CurrencyCode::TRY, installmentCount: 0, ); $hashData = $provisionRequest->generateHash($hashCalculator); $provisionXml = $provisionRequest->toXml($hashData); $response = Http::withHeaders([ 'Content-Type' => 'application/xml', ])->withBody($provisionXml, 'application/xml') ->post($vpos->getProvisionUrl()); // Provizyon yanitini cozumle ve siparisi sonuclandir... if ($responseCode === '00') { // Odeme basarili — siparis durumunu guncelle } }
CSP Basliklari (Gerekli)
3D Secure yonlendirme formunun engellenmemesi icin Kuveyt Turk domainlerini Content Security Policy'nize ekleyin:
// Middleware veya yapilandirma 'connect-src' => [..., 'https://*.kuveytturk.com.tr'], 'form-action' => [..., 'https://*.kuveytturk.com.tr'],
Yanit Nesneleri
SaleResponse
| Ozellik | Aciklama |
|---|---|
isSuccessful() |
Boolean — islem onaylandiysa true |
responseCode |
Kuveyt Turk yanit kodu ("00" = basarili) |
responseMessage |
Okunabilir yanit mesaji |
orderId |
Banka siparis numarasi |
provisionNumber |
Provizyon numarasi |
rrn |
Referans numarasi |
stan |
Sistem iz numarasi |
transactionTime |
Islem zaman damgasi |
merchantOrderId |
Sizin siparis numaraniz |
md |
3D Secure MD degeri |
Hata Yonetimi
use EmreTarhan\KuveytTurkVPos\Services\KuveytTurkVPos; use EmreTarhan\KuveytTurkVPos\Exceptions\KuveytTurkVPosException; use EmreTarhan\KuveytTurkVPos\Enums\ErrorCode; try { $response = $vpos->sale($request); if ($response->isSuccessful()) { // Basarili islemi ele al } else { // Is hatasini ele al $errorCode = ErrorCode::fromString($response->responseCode); echo "Hata: " . $errorCode->label(); } } catch (KuveytTurkVPosException $e) { // Baglanti/dogrulama hatalarini ele al echo "Hata: " . $e->getMessage(); }
Hata Kodlari
| Kod | Aciklama |
|---|---|
| 00 | Otorizasyon verildi / Islem basarili |
| 01 | Gecersiz kart numarasi |
| 05 | Yetersiz bakiye |
| 12 | Gecersiz uye isyeri |
| 14 | Gecersiz islem / CVV |
| 17 | Kart limiti asildi |
| 54 | Kart suresi dolmus |
| 59 | Sahtekarlik suphesi |
| 70 | Mukerrer siparis |
| 91 | Zaman asimi |
| 96 | Sistem hatasi |
| 99 | Hashdata uyusmazligi |
Tutar Formatı
Tum tutarlar gercek deger olarak belirtilmelidir (ornegin 100.50 = 100 TL 50 kurus).
SDK bankanin formatina otomatik donusturur (tutar x 100, ornegin 100.50 TL = 10050).
// Hepsi ayni sonucu verir: $request = new SaleRequest(..., amount: 100.50, ...); $request = new SaleRequest(..., amount: '100.50', ...); $request = new SaleRequest(..., amount: 10050, ...); // Zaten banka formatinda
Test Ortami
Sandbox testleri icin asagidaki test kartini kullanin:
| Alan | Deger |
|---|---|
| Kart Numarasi | 5188 9619 3919 2544 |
| CVV | 929 |
| Son Kullanma | 06/25 |
| 3D Sifre | 123456 |
Test Endpoint'leri:
- Kart Dogrulama:
https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelPayGate - Provizyon:
https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelProvisionGate
Produksiyon Endpoint'leri:
- Kart Dogrulama:
https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelPayGate - Provizyon:
https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelProvisionGate
Test Calistirma
composer test
Katkida Bulunma
Katkilar memnuniyetle karsilanir! Lutfen bir Pull Request gonderin.
Lisans
MIT Lisansi. Detaylar icin LICENSE dosyasina bakin.
Destek
Sorular ve sorunlar icin lutfen GitHub'da issue acin: https://github.com/emre-tarhan/kuveytturk-vpos-laravel-sdk
emre-tarhan/kuveytturk-vpos-laravel-sdk 适用场景与选型建议
emre-tarhan/kuveytturk-vpos-laravel-sdk 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 06 月 12 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「payment」 「laravel」 「Bank」 「turkey」 「pos」 「kuveytturk」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 emre-tarhan/kuveytturk-vpos-laravel-sdk 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 emre-tarhan/kuveytturk-vpos-laravel-sdk 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 emre-tarhan/kuveytturk-vpos-laravel-sdk 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Symfony integration for Czech bank account library
Check for holidays - localeaware
A basic wrapper for citco/carbon which returns business days between two given dates.
Iranian payment gateways handler for laravel applicationss
Alfabank REST API integration
PHP library to handle FinanzOnline web services.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 44
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-12