Garanti BBVA Virtual POS
Laravel Paketi Dokümantasyonu
Bu paket, Laravel projelerinde Garanti BBVA GVP Sanal POS entegrasyonunu sağlar. XML tabanlı doğrudan ödemeler, 3D Secure, OOS (Ortak Ödeme Sayfası), GarantiPay, puan/bonus kullanımı, tekrarlı ödemeler ve 8 farklı sorgu tipi desteklenmektedir.
Help/GVP örnekleriyle fixture/test seviyesinde karşılaştırılmıştır. Madde madde kanıt listesi için GVP Compatibility Checklist dosyasına bakın.
developertugrul/garanti-posKurulum
Composer ile paketi projenize ekleyin, ardından servis sağlayıcısını ve yapılandırma dosyasını yayınlayın.
composer require developertugrul/garanti-pos
php artisan vendor:publish --provider="Developertugrul\GarantiPos\GarantiPosServiceProvider"
Bu komut config/garanti-pos.php dosyasını oluşturur. Tüm ayarlar .env üzerinden yönetilir.
Facade Kullanımı
use Developertugrul\GarantiPos\Facades\GarantiPos;
// Artık her yerden statik olarak çağrılabilir:
$response = GarantiPos::pay($orderData, $cardData);
Dependency Injection
use Developertugrul\GarantiPos\Services\GarantiPosService;
class PaymentController extends Controller
{
public function __construct(private GarantiPosService $pos) {}
public function charge(Request $request): array
{
return $this->pos->pay(
['order_id' => $request->order_id, 'amount' => $request->amount],
['number' => $request->card_number, ...]
);
}
}
Yapılandırma
Garanti BBVA tarafından sağlanan terminal, üye işyeri ve şifre bilgilerini .env dosyasına girin.
# ===== Ortam =====
GARANTI_POS_MODE=TEST # TEST veya PROD
# ===== Terminal Bilgileri =====
GARANTI_POS_TERMINAL_ID=12345678 # 8 haneli terminal kimliği
GARANTI_POS_TERMINAL_USER_ID=DENEME # Terminal kullanıcı adı
GARANTI_POS_MERCHANT_ID=7000679 # Üye işyeri numarası (MerchantID)
GARANTI_POS_STORE_KEY=3DSecureAnahtari # 3D Secure şifresi
# ===== Para Birimi =====
GARANTI_POS_CURRENCY=949 # 949=TRY, 840=USD, 978=EUR
# ===== PROVAUT — Standart ödeme, ön provizyon, sorgular =====
GARANTI_POS_PROV_USER_ID=PROVAUT
GARANTI_POS_PROV_PASSWORD=SifreniziGirin
# ===== PROVRFN — İptal ve iade işlemleri =====
GARANTI_POS_REFUND_USER_ID=PROVRFN
GARANTI_POS_REFUND_PASSWORD= # Boş bırakılırsa PROV_PASSWORD kullanılır
# ===== PROVOOS — OOS / GarantiPay form akışları =====
GARANTI_POS_PROV_OOS_USER_ID=PROVOOS
GARANTI_POS_PROV_OOS_PASSWORD= # Boş bırakılırsa PROV_PASSWORD kullanılır
GARANTI_POS_OOS_USER_ID=oosuser
GARANTI_POS_OOS_FORM_CREDENTIAL_ROLE=oos # 'oos' veya 'aut' (güncel portal için)
# ===== API Ayarları =====
GARANTI_POS_API_VERSION=v0.01 # 'v0.01' (SHA1) veya '512' (SHA512)
GARANTI_POS_CHANNEL_CODE= # Kanal kodu (opsiyonel)
GARANTI_POS_HASH_ALGORITHM=sha1 # 'sha1' veya 'sha512'
# ===== Endpoint'ler =====
GARANTI_POS_TEST_ENDPOINT=https://sanalposprovtest.garanti.com.tr/VPServlet
GARANTI_POS_PROD_ENDPOINT=https://sanalposprov.garanti.com.tr/VPServlet
GARANTI_POS_TEST_3D_ENDPOINT=https://sanalposprovtest.garanti.com.tr/servlet/gt3dengine
GARANTI_POS_PROD_3D_ENDPOINT=https://sanalposprov.garanti.com.tr/servlet/gt3dengine
Kullanıcı Rol Tablosu
| Rol | Varsayılan Kullanıcı | Kapsam |
|---|---|---|
| AUT | PROVAUT | Satış, 3D Pay, 3D Model, preauth, postauth, tüm sorgular, recurringvoid |
| REFUND | PROVRFN | cancel(), refund(), refundVoid(), postAuthVoid() |
| OOS | PROVOOS | OOS, 3D OOS, GarantiPay/CUSTOM_PAY form hash'leri |
GARANTI_POS_REFUND_PASSWORD veya GARANTI_POS_PROV_OOS_PASSWORD boş bırakılırsa paket otomatik olarak GARANTI_POS_PROV_PASSWORD değerini kullanır. OOS/GarantiPay formlarında gönderilen terminalprovuserid hangi kullanıcıysa, hash hesabı o kullanıcının şifresiyle yapılır.
Dinamik Konfigürasyon
Çalışma zamanında belirli bir işlem için config'i geçici değiştirmek mümkündür:
GarantiPos::setConfig([
'mode' => 'PROD',
'terminal_id' => '99999999',
'prov_password' => 'YeniSifre',
]);
Hash & Güvenlik
SecurityData Hesabı
Her GVP isteğinin HashData alanı, önce SecurityData türetilerek oluşturulur:
// SecurityData = SHA1(provPassword + 9 haneli terminalId)
// Örnek: terminal_id = "12345678" → "012345678"
use Developertugrul\GarantiPos\Services\HashGenerator;
$securityData = HashGenerator::generateSecurityData('ProvSifrem', '12345678');
// Çıktı: "D3A1F91A20C..." (40 karakter büyük harf hex)
XML Hash Hesabı (Non-3D)
| Algoritma | Formül |
|---|---|
| SHA1 (Legacy) | orderId + terminalId + cardNumber + amount + securityData |
| SHA512 (Güncel) | orderId + terminalId + cardNumber + amount + currencyCode + securityData |
$hash = HashGenerator::generateHashData(
orderId: 'SIPARIS-001',
terminalId: '12345678',
cardNumber: '5400111111111111',
amount: '10000', // Kuruş cinsinden, nokta/virgül olmadan
securityData: $securityData,
algorithm: 'sha1', // veya 'sha512'
currencyCode: '949' // SHA512 için gerekli
);
3D/OOS Form Hash Hesabı
| Algoritma | Formül |
|---|---|
| SHA1 (Legacy) | terminalId + orderId + amount + successUrl + errorUrl + txntype + installment + storeKey + securityData |
| SHA512 | Aynı + currencyCode (amount'tan sonra) |
Algoritma Seçimi
Repo içindeki resmi
Help/GVP örnekleri SHA1 kullanır. Güncel Garanti BBVA geliştirici portali SHA512 ve apiversion=512 gerektirebilir. Terminaliniz hangi akışa kayıtlıysa o ayarı seçin.SHA512 için:
GARANTI_POS_HASH_ALGORITHM=sha512 ve GARANTI_POS_API_VERSION=512
GarantiPay Hash Notu
txntype=gpdatarequest değeriyle hesaplanır; satış tipi ise txnsubtype=sales olarak ayrı gönderilir. Paket bunu otomatik yönetir.
Doğrudan Ödeme (Non-3D XML)
Kart bilgilerini doğrudan bankaya gönderir; 3D Secure yönlendirmesi yapılmaz. PCI-DSS kapsamınız varsa veya MOTO işlemleri için uygundur.
pay(array $orderData, array $cardData, string $type = 'sales'): array PROVAUT
Standart satış işlemi. Taksitli satış için installment alanını doldurun.
Parametreler
| Alan | Tür | Açıklama |
|---|---|---|
order_id | string | Sipariş kimliği (benzersiz olmalı) |
amount | string | Tutar — kuruş cinsinden, nokta/virgülsüz ("10000" = 100,00 TL) |
installment | string | Taksit sayısı — taksitsiz için boş string "" |
currency | string | Para birimi kodu (varsayılan: config'deki değer, örn. "949") |
ip_address | string | Müşteri IP adresi |
email | string | Müşteri e-posta |
number | string | Kart numarası |
expire_month | string | Son kullanma ayı ("12") |
expire_year | string | Son kullanma yılı — 2 hane ("28") |
cvv | string | CVV2/CVC2 kodu |
Örnek — Peşin Satış
use Developertugrul\GarantiPos\Facades\GarantiPos;
$response = GarantiPos::pay(
[
'order_id' => 'SIPARIS-' . uniqid(),
'amount' => '10000', // 100,00 TL
'installment' => '', // Peşin
'ip_address' => request()->ip(),
'email' => 'musteri@ornek.com',
],
[
'number' => '5400111111111111',
'expire_month' => '12',
'expire_year' => '28',
'cvv' => '123',
]
);
if ($response['ProcReturnCode'] === '00') {
// Ödeme başarılı
$authCode = $response['AuthCode'];
$retrefNum = $response['RetrefNum'];
}
Örnek — Taksitli Satış (3 Taksit)
$response = GarantiPos::pay(
[
'order_id' => 'SIPARIS-TAK-001',
'amount' => '30000', // 300,00 TL
'installment' => '3',
],
$cardData
);
Örnek Başarılı Yanıt
'ResponseCode' => '00',
'ResponseMessage' => 'Onaylandı',
'ProcReturnCode' => '00',
'OrderID' => 'SIPARIS-001',
'RetrefNum' => '406310073566',
'AuthCode' => '304919',
'BatchNum' => '004063',
'SequenceNum' => '000001',
'HostRefNum' => '123456789012',
'ProvDate' => '20260614 15:22:07',
]
Karşılık Gelen GVP XML — Type
<Type>sales</Type>
<InstallmentCnt></InstallmentCnt>
<Amount>10000</Amount>
<CurrencyCode>949</CurrencyCode>
<CardholderPresentCode>0</CardholderPresentCode>
</Transaction>
preAuth(array $orderData, array $cardData): array PROVAUT
Ön provizyon — kart limitini bloke eder ancak tahsilat yapmaz. Otel, araç kiralama gibi gecikmiş tahsilat senaryolarında kullanılır.
// Adım 1: Ön provizyon al
$preResponse = GarantiPos::preAuth(
['order_id' => 'PREAUTH-001', 'amount' => '50000'],
['number' => '5400111111111111', 'expire_month' => '12', 'expire_year' => '28', 'cvv' => '123']
);
$retrefNum = $preResponse['RetrefNum'];
postAuth(string $orderId, string $amount): array PROVAUT
Ön provizyon kapama — gerçek tahsilatı gerçekleştirir. Tutar, ön provizyon tutarından küçük veya eşit olabilir.
// Adım 2: Ön provizyonu kapat (örn. 3 gün sonra)
$postResponse = GarantiPos::postAuth(
orderId: 'PREAUTH-001',
amount: '45000' // Gerçek harcama — ön provizyon tutarından az olabilir
);
GVP XML Karşılıkları
<!-- postAuth --> <Type>postauth</Type>
cancel(string $orderId, string $originalRetrefNum = '', string $amount = '1'): array PROVRFN
Aynı gün içinde gerçekleşen bir işlemi iptal eder. Garanti GVP, iptal için Type=void kullanır (cancel değil).
$response = GarantiPos::cancel(
orderId: 'SIPARIS-001',
originalRetrefNum: '406310073566', // preResponse'dan alınan RetrefNum
amount: '10000'
);
if ($response['ProcReturnCode'] === '00') {
// İptal başarılı
}
Type=void gönderilir, cancel değil. Paket bunu otomatik halleder.
refund(string $orderId, string $amount, string $originalRetrefNum = ''): array PROVRFN
Önceki günlere ait bir işlemi iade eder. Kısmi iade desteklenir — orijinal tutardan az bir miktar gönderilebilir.
// Tam iade
$response = GarantiPos::refund(
orderId: 'SIPARIS-001',
amount: '10000',
originalRetrefNum: '406310073566'
);
// Kısmi iade (100 TL'lik işlemden 30 TL iade)
$response = GarantiPos::refund('SIPARIS-001', '3000', '406310073566');
if ($response['ProcReturnCode'] === '00') {
// İade başarılı
}
postAuthVoid(string $orderId, string $originalRetrefNum = '', string $amount = '1'): array PROVRFN
Ön provizyon kapamanın iptali.
$response = GarantiPos::postAuthVoid('PREAUTH-001', $retrefNum);
refundVoid(string $orderId, string $originalRetrefNum = '', string $amount = '1'): array PROVRFN
Yapılmış bir iadenin iptali.
$response = GarantiPos::refundVoid('SIPARIS-001', $retrefNum);
3D Secure Ödeme
3D Secure ödeme akışı iki adımdan oluşur: (1) kullanıcıyı banka 3D sayfasına yönlendiren form oluşturma, (2) geri dönüşte hash/status kontrolü ve provizyonun alınması.
security_level alanına 3D_PAY, 3D_FULL veya 3D_HALF geçilebilir. 3D_PAY'de provizyon banka tarafından alınır (model A); 3D_FULL/3D_HALF'te siz alırsınız (model B — pay3DModel()).
build3DForm(array $orderData, array $cardData, string $successUrl, string $errorUrl, string $type = 'sales'): string
Kullanıcıyı bankanın 3D kimlik doğrulama sayfasına yönlendiren, otomatik gönderimli HTML form döner. Bu formu echo ile sayfaya basın; JavaScript otomatik submit yapar.
// routes/web.php
Route::get('/odeme/baslat', [PaymentController::class, 'start3D']);
Route::post('/odeme/basarili', [PaymentController::class, 'success3D'])->name('payment.success');
Route::post('/odeme/hata', [PaymentController::class, 'error3D'])->name('payment.error');
// app/Http/Controllers/PaymentController.php
public function start3D(Request $request): string
{
return GarantiPos::build3DForm(
[
'order_id' => 'ORDER-' . uniqid(),
'amount' => '15000', // 150,00 TL
'installment' => '',
'security_level' => '3D_PAY', // 3D_PAY | 3D_FULL | 3D_HALF
'ip_address' => $request->ip(),
'email' => 'musteri@ornek.com',
],
[
'number' => '5400111111111111',
'expire_month' => '12',
'expire_year' => '28',
'cvv' => '123',
],
route('payment.success'), // Başarı URL'i (POST ile geri döner)
route('payment.error') // Hata URL'i
);
}
<form action="https://...gt3dengine..."> ve gizli input'lar bulunur. Sayfa yüklenince JavaScript otomatik submit yapar. Sunucu tarafında bu string'i doğrudan döndürmek yeterlidir.
parse3DResponse(array $postData, array $expected = []): array
Garanti'nin geri POST ettiği callback verilerini doğrular. Hash, MD status, işlem kodu, sipariş kimliği ve tutarı ayrı ayrı raporlar.
public function success3D(Request $request): Response
{
$check = GarantiPos::parse3DResponse(
$request->all(),
[
'order_id' => session('order_id'),
'amount' => session('order_amount'), // Kuruş cinsinden
]
);
// Tüm kontroller
if (! $check['hash_valid']) {
abort(400, 'Hash doğrulama başarısız');
}
if (! $check['md_status_accepted']) {
abort(400, '3D kimlik doğrulama reddedildi: mdstatus=' . $check['md_status']);
}
if (! $check['order_matches']) {
abort(400, 'Sipariş uyuşmazlığı');
}
// Buraya kadar her şey tamam — provizyona geçin
return $this->finalizePayment($request->all());
}
Dönüş Değerleri
'hash_valid' => true,
'hash_source' => 'hashparams', // 'hashparams' | 'secure3dhash' | 'missing'
'approved' => true,
'procreturncode' => '00',
'md_status' => '1', // 1-4 kabul, 5-9 ret
'md_status_accepted' => true,
'order_id' => 'ORDER-001',
'amount' => '15000',
'txntype' => 'sales',
'order_matches' => true,
'amount_matches' => true,
'errors' => [],
]
pay3DModel(array $orderData, array $cardData, array $threeDResponse): array
3D_FULL veya 3D_HALF güvenlik seviyesinde, banka callback'inden sonra provizyonu siz alırsınız. Bu metod callback verilerini kullanarak bankaya ikinci XML isteği gönderir.
// parse3DResponse kontrollerinden geçtikten sonra:
$response = GarantiPos::pay3DModel(
[
'order_id' => session('order_id'),
'amount' => session('order_amount'),
],
[], // Kart bilgisi gerekmez — bankadan gelen mddata kullanılır
$request->all() // Tüm 3D callback POST verisi
);
if ($response['ProcReturnCode'] === '00') {
// Provizyon başarılı
$authCode = $response['AuthCode'];
}
pay3DModel() çağrısından önce parse3DResponse() ile md_status kontrolü yapılmalıdır. MD status geçerli olmadan provizyon çağrısı yapılırsa GarantiPosException fırlatılır.
OOS / Ortak Ödeme Sayfası
Kart bilgileri sitenizden alınmaz; müşteri bankanın kendi ödeme sayfasına yönlendirilir. PCI-DSS yükünü azaltır.
buildOOSForm(array $orderData, string $successUrl, string $errorUrl, string $type = 'sales'): string PROVOOS
$formHtml = GarantiPos::buildOOSForm(
[
'order_id' => 'OOS-001',
'amount' => '10000',
'security_level' => 'OOS_PAY',
'ip_address' => request()->ip(),
],
route('payment.success'),
route('payment.error')
);
echo $formHtml;
Ticari Kart OOS
use Developertugrul\GarantiPos\Enums\TransactionType;
$formHtml = GarantiPos::buildOOSForm(
['order_id' => 'COMMERCIAL-001', 'amount' => '50000'],
route('payment.success'),
route('payment.error'),
TransactionType::COMMERCIAL_CARD // txntype=commercialcard
);
build3DOOSForm(array $orderData, string $successUrl, string $errorUrl, string $type = 'sales'): string PROVOOS
3D doğrulama ile birleştirilmiş OOS akışı.
$formHtml = GarantiPos::build3DOOSForm(
[
'order_id' => '3DOOS-001',
'amount' => '20000',
'security_level' => '3D_OOS_PAY', // 3D_OOS_PAY | 3D_OOS_FULL | 3D_OOS_HALF
'installment' => '',
],
route('payment.success'),
route('payment.error')
);
terminalprovuserid alanında gönderilen kullanıcı adının şifresi kullanılır. GARANTI_POS_OOS_FORM_CREDENTIAL_ROLE=oos (legacy) veya aut (güncel portal) olarak ayarlayın.
GarantiPay
GarantiPay, müşterilerin Garanti BBVA hesaplarıyla ödeme yapmasını sağlayan bir ödeme yöntemidir. İki akış desteklenmektedir: hosted form ve XML DataRequest.
buildGarantiPayForm(array $orderData, string $successUrl, string $errorUrl): string PROVOOS
GarantiPay hosted formunu oluşturur. Güvenlik seviyesi CUSTOM_PAY olarak gönderilir. Hash txntype=gpdatarequest ile hesaplanır.
$formHtml = GarantiPos::buildGarantiPayForm(
[
'order_id' => 'GP-' . uniqid(),
'amount' => '25000', // 250,00 TL
'company_name' => 'Örnek Mağaza',
'bnsuseflag' => 'Y', // Bonus kullanım izni
'installments' => [
['number' => '1', 'amount' => '25000'],
['number' => '2', 'amount' => '25000'],
['number' => '3', 'amount' => '25000'],
],
'items' => [
[
'number' => '1',
'product_id' => 'SKU-001',
'quantity' => '1',
'price' => '25000',
'total_amount' => '25000',
'name' => 'Ürün Adı',
],
],
],
route('payment.garantipay.success'),
route('payment.garantipay.error')
);
echo $formHtml;
garantiPayDataRequest(array $orderData): array PROVAUT
GarantiPay XML DataRequest — bankanın ödeme sayfasını açmak için gerekli bağlantıyı döner. Type=gpdatarequest, SubType=sales ile çalışır.
$response = GarantiPos::garantiPayDataRequest([
'order_id' => 'GP-DATA-001',
'amount' => '25000',
'company_name' => 'Örnek Mağaza',
'return_server_url' => route('payment.garantipay.server'),
'return_url' => route('payment.garantipay.return'),
'gsm_number' => '5XXXXXXXXX',
'total_installment_count' => '3',
'items' => [
['number' => '1', 'product_id' => 'SKU-001', 'quantity' => '1', 'price' => '25000'],
],
]);
// Yanıt içindeki GarantiPay bağlantısını müşteriye gönderin
$garantiPayUrl = $response['GarantiPaY']['Url'] ?? null;
/api/garantipay/v0/init akışı bu paket kapsamı dışındadır. Bu paket, GVP dokümanındaki hosted form ve XML DataRequest akışını destekler.
Puan & Bonus
pointInquiry(array $cardData): array PROVAUT
Kartın mevcut bonus/puan bakiyesini sorgular. Type=rewardinq ile çalışır.
$response = GarantiPos::pointInquiry([
'order_id' => 'PUAN-SORGU-' . uniqid(),
'number' => '4282209004348015',
'expire_month' => '05',
'expire_year' => '28',
'cvv' => '123',
]);
// Yanıtta puan bilgileri:
$bonusAmount = $response['RewardInqResult']['ChequeInfo'] ?? null;
rewardUsage(array $orderData, array $cardData, string $pointAmount): array PROVAUT
Ödeme sırasında bonus/puan kullanımı. Type=sales + RewardList/Reward bloğu ile çalışır.
$response = GarantiPos::rewardUsage(
[
'order_id' => 'BONUS-001',
'amount' => '20000', // 200,00 TL
'reward_type' => 'BNS', // BNS=Bonus, CHQ=Çek, PTS=Puan
],
[
'number' => '4282209004348015',
'expire_month' => '05',
'expire_year' => '28',
'cvv' => '123',
],
'5000' // Kullanılacak puan (50,00 TL değerinde)
);
// Kalan tutar kart ile tahsil edilir: 200 - 50 = 150 TL
pay() metodunda reward_list dizisi kullanın:
$response = GarantiPos::pay(
[
'order_id' => 'FBB-001',
'amount' => '50000',
'reward_list' => [
['type' => 'BNS', 'used_amount' => '5000', 'gained_amount' => '0'],
['type' => 'CHQ', 'used_amount' => '2000', 'gained_amount' => '0'],
],
],
$cardData
);
DCC — Dinamik Kur Dönüşümü
Yabancı uyruklu kartlara kendi para biriminde ödeme imkânı sunar.
dccInquiry(string $orderId, string $cardNumber, string $amount): array PROVAUT
Kartın yabancı para birimi kurunu sorgular. Type=dccinq ile çalışır.
$dccInfo = GarantiPos::dccInquiry(
orderId: 'DCC-SORGU-001',
cardNumber: '4111111111111111', // Yabancı kart numarası
amount: '10000' // TL cinsinden tutar
);
// Yanıtta kur ve yabancı para tutarı gelir
$foreignAmount = $dccInfo['DccInfo']['Amount'] ?? null;
$foreignCurrency = $dccInfo['DccInfo']['CurrencyCode'] ?? null;
payDcc(array $orderData, array $cardData): array PROVAUT
DCC ödemesi gerçekleştirir. SubType=dcc ve DCC/Currency bloğu ile çalışır.
$response = GarantiPos::payDcc(
[
'order_id' => 'DCC-001',
'amount' => '10000', // TL tutarı
'dcc_currency' => '840', // Yabancı para birimi kodu (840=USD)
],
[
'number' => '4111111111111111',
'expire_month' => '12',
'expire_year' => '28',
'cvv' => '456',
]
);
SMS Doğrulama
İki adımlı ödeme akışı: önce SMS gönderilir, ardından müşterinin girdiği kod ile işlem tamamlanır.
Adım 1: paySms(array $orderData, array $cardData): array
SubType=sms ile preauth/sales isteği gönderir; banka müşteriye SMS atar.
// Adım 1: SMS gönder
$response = GarantiPos::paySms(
['order_id' => 'SMS-001', 'amount' => '10000'],
['number' => '5400111111111111', 'expire_month' => '12', 'expire_year' => '28', 'cvv' => '123']
);
Adım 2: smsPostAuth(array $orderData, string $smsPassword): array
Müşterinin girdiği SMS kodunu bankaya doğrulatır ve provizyonu tamamlar.
// Adım 2: Müşteri SMS kodunu girdi → tamamla
$response = GarantiPos::smsPostAuth(
['order_id' => 'SMS-001', 'amount' => '10000'],
'123456' // Müşterinin girdiği SMS şifresi
);
if ($response['ProcReturnCode'] === '00') {
// SMS doğrulama + ödeme başarılı
}
Ekstre Doğrulama
Kart sahibinin kimliğini hesap ekstresi bilgisiyle doğrular. SubType=extre + Verification/ExtreInfo bloğu kullanılır.
payExtre(array $orderData, array $cardData, string $extreInfo): array
// Ekstre doğrulama ile satış
$response = GarantiPos::payExtre(
['order_id' => 'EXTRE-001', 'amount' => '10000'],
$cardData,
'123456789' // Ekstre/hesap bilgisi
);
preAuthExtre(array $orderData, array $cardData, string $extreInfo): array
// Ekstre doğrulama ile ön provizyon
$response = GarantiPos::preAuthExtre(
['order_id' => 'EXTRE-002', 'amount' => '10000'],
$cardData,
'123456789'
);
postAuthExtre(array $orderData, string $extreInfo, array $cardData = []): array
// Ekstre doğrulama ile ön provizyon kapama
$response = GarantiPos::postAuthExtre(
['order_id' => 'EXTRE-002', 'amount' => '10000'],
'123456789'
);
TCKN / Kimlik Doğrulama
Kart sahibinin TC Kimlik Numarası ile kimlik doğrulaması yapar. Type=identifyinq ve Verification/Identity bloğu kullanılır.
identifyInquiry(array $orderData, array $cardData, string $tckn): array PROVAUT
$response = GarantiPos::identifyInquiry(
['order_id' => 'TCKN-001', 'amount' => '100'],
[
'number' => '5400111111111111',
'expire_month' => '12',
'expire_year' => '28',
'cvv' => '123',
],
'12345678901' // TC Kimlik Numarası
);
$matched = $response['ProcReturnCode'] === '00';
CepBank
Garanti BBVA'nın mobil ödeme çözümü. Müşterinin GSM numarası ile ödeme yapmasını sağlar.
payCepBank(array $orderData, array $cepBankData): array PROVAUT
CepBank/GSMNumber/PaymentType/HashDate/HashValue XML bloğu ile çalışır.
$response = GarantiPos::payCepBank(
[
'order_id' => 'CEP-001',
'amount' => '10000',
],
[
'gsm_number' => '5XXXXXXXXX',
'payment_type' => 'K', // K=Kredi kartı bakiye
'hash_date' => date('Ymd'), // YYYYMMDD
'hash_value' => 'BANKA_TARAFINDAN_URETILMIS_HASH',
]
);
Fatura & Özel Ödemeler
payUtility(array $orderData, array $cardData, array $utilityPaymentData): array PROVAUT
Su, elektrik, doğalgaz gibi fatura ödemeleri. UtilityPayment XML bloğu kullanılır.
$response = GarantiPos::payUtility(
['order_id' => 'FATDIR-001', 'amount' => '25000'],
$cardData,
[
'invoice_id' => 'FAT-2026-001',
'invoice_type' => '1', // 1=Elektrik, 2=Su, 3=Doğalgaz
'subscriber_no' => '1234567890',
]
);
payGsmUnitSales(array $orderData, array $cardData, array $gsmUnitSalesData): array PROVAUT
GSM kontör/paket satışı. GSMUnitSales XML bloğu kullanılır.
$response = GarantiPos::payGsmUnitSales(
['order_id' => 'GSM-001', 'amount' => '5000'],
$cardData,
[
'gsm_quantity' => '2',
'operator_code' => 'TURKCELL',
'subscriber_msisdn' => '5XXXXXXXXX',
]
);
payMoneyCard(array $orderData, array $cardData, array $moneyCardData): array PROVAUT
MoneyCard / hediye kartı ödemesi. MoneyCard XML bloğu kullanılır.
$response = GarantiPos::payMoneyCard(
['order_id' => 'MONEY-001', 'amount' => '10000'],
$cardData,
[
'money_invoice' => '10000',
'money_card_no' => 'HEDIYE-KART-12345',
]
);
Tekrarlı Ödemeler (Recurring)
Abonelik, taksit veya periyodik tahsilat için kullanılır. Order/Recurring XML bloğu ile çalışır.
payRecurring(array $orderData, array $cardData, array $recurringData): array PROVAUT
Sabit Tutarlı Tekrarlı Satış
$response = GarantiPos::payRecurring(
[
'order_id' => 'REC-001',
'amount' => '9900', // Her ay çekilecek tutar (99,00 TL)
],
$cardData,
[
'type' => 'R', // R=Tekrarlı
'total_payment_num' => '12', // Toplam taksit sayısı
'frequency_type' => 'MONTHLY', // MONTHLY | WEEKLY | DAILY
'frequency_interval' => '1', // Her 1 ayda bir
'start_date' => '20260701', // İlk çekim tarihi YYYYMMDD
]
);
Değişken Tutarlı Tekrarlı Satış
$response = GarantiPos::payRecurring(
['order_id' => 'REC-VAR-001', 'amount' => '1000'],
$cardData,
[
'type' => 'G', // G=Değişken
'total_payment_num' => '3',
'frequency_type' => 'MONTHLY',
'frequency_interval' => '1',
'start_date' => '20260701',
]
);
recurringUpdate(string $orderId, array $paymentList): array PROVAUT
Bekleyen tekrarlı taksit tutarlarını günceller. Type=recurringupdate kullanılır.
// Bekleyen 2 taksitin tutarını güncelle
$response = GarantiPos::recurringUpdate(
'REC-VAR-001',
[
['Amount' => '12000'], // 1. taksit: 120 TL
['Amount' => '15000'], // 2. taksit: 150 TL
]
);
recurringCancel(string $orderId, string $amount = '100'): array PROVAUT
Bekleyen tüm tekrarlı taksitleri iptal eder. Type=recurringvoid, PROVAUT (PROVRFN değil) kullanılır.
$response = GarantiPos::recurringCancel('REC-001');
recurringCancel() standart cancel()'dan farklı olarak PROVAUT kullanır. Bu, resmi GVP dökümanındaki davranışla örtüşür.
Kredili & Vadeli Satışlar
payExtendedCredit(array $orderData, array $cardData): array PROVAUT
Tüketici kredisi / vadeli taksit. Type=extendedcredit ile çalışır.
$response = GarantiPos::payExtendedCredit(
[
'order_id' => 'KREDIT-001',
'amount' => '100000', // 1.000,00 TL
'installment' => '12',
],
$cardData
);
payDownPaymentSale(array $orderData, array $cardData): array PROVAUT
Peşinatlı taksitli satış. Type=sales + DownPaymentRate alanı ile çalışır.
$response = GarantiPos::payDownPaymentSale(
[
'order_id' => 'PESINAT-001',
'amount' => '50000',
'installment' => '6',
'down_payment_rate' => '20', // %20 peşinat
],
$cardData
);
payDelayedSale(array $orderData, array $cardData): array PROVAUT
Otelemeli satış — tahsilat belirli gün sonra yapılır. Type=sales + DelayDayCount ile çalışır.
$response = GarantiPos::payDelayedSale(
[
'order_id' => 'OTELEME-001',
'amount' => '30000',
'delay_day_count' => '7', // 7 gün sonra tahsil et
],
$cardData
);
Ticari Kart Vadeli İşlem
payCommercialCardExtendedCredit(array $orderData, array $cardData): array PROVAUT
Ticari kart ile vadeli işlem. Type=commercialcardextendedcredit ve CommercialCardExtendedCredit/PaymentList XML bloğu kullanılır.
$response = GarantiPos::payCommercialCardExtendedCredit(
[
'order_id' => 'TIC-001',
'amount' => '60000',
'payments' => [
['number' => '1', 'amount' => '20000'], // 1. ödeme: 200 TL
['number' => '2', 'amount' => '20000'], // 2. ödeme: 200 TL
['number' => '3', 'amount' => '20000'], // 3. ödeme: 200 TL
],
],
$cardData
);
Sorgular
Tüm sorgu metodları PROVAUT kimlik bilgileriyle çalışır.
orderInquiry(string $orderId, string $amount = '100'): array
Belirli bir siparişin son durumunu sorgular. Type=orderinq
$response = GarantiPos::orderInquiry('SIPARIS-001');
$status = $response['ProcReturnCode'];
$authCode = $response['AuthCode'] ?? null;
$retrefNum = $response['RetrefNum'] ?? null;
Örnek Yanıt
'ProcReturnCode' => '00',
'OrderID' => 'SIPARIS-001',
'AuthCode' => '304919',
'RetrefNum' => '406310073566',
'TransactionType' => 'sales',
'Amount' => '10000',
]
orderHistoryInquiry(string $orderId, string $amount = '100'): array
Bir siparişin tüm işlem geçmişini listeler (iade, iptal vb.). Type=orderhistoryinq
$response = GarantiPos::orderHistoryInquiry('SIPARIS-001');
orderListInquiry(?string $startDate, ?string $endDate, int $listPageNum = 1, string $orderId = '', string $amount = '100'): array
Tarih aralığına göre sipariş listesi sorgular. Type=orderlistinq — StartDate/EndDate Order altında, ListPageNum Transaction altında gönderilir.
// Belirli tarih aralığı
$response = GarantiPos::orderListInquiry(
startDate: '01/06/2026', // GG/AA/YYYY formatı
endDate: '14/06/2026',
listPageNum: 1
);
// İkinci sayfa
$response = GarantiPos::orderListInquiry('01/06/2026', '14/06/2026', 2);
batchInquiry(?string $batchNum = null, int $listPageNum = 1, string $orderId = '', string $amount = '100'): array
Günsonu (batch) sorgulama. Type=batchinq — BatchNum ve ListPageNum Transaction altında.
// Mevcut batch (bugünkü)
$response = GarantiPos::batchInquiry();
// Belirli batch numarası
$response = GarantiPos::batchInquiry('004063');
// Sayfalı listeleme
$response = GarantiPos::batchInquiry(null, 2);
binInquiry(string $binNumber = '', string $amount = '100'): array
Kart BIN (ilk 6-8 hane) bilgisini sorgular; kart tipi, banka, yurt içi/dışı bilgisi döner. Type=bininq
$response = GarantiPos::binInquiry('540011');
$cardType = $response['CardInfo']['CardType'] ?? null; // 'KREDI' / 'DEBIT'
$bankName = $response['CardInfo']['BankName'] ?? null;
$issuerId = $response['CardInfo']['IssuerID'] ?? null;
campaignCodeInquiry(string $campaignCode, string $amount = '100'): array
Kampanya kodu ile kampanya detaylarını sorgular. Type=campaigncodeinq
CampaingCode şeklindedir (typo — tek 'i'). Paket resmi yazımı aynen korur.
$response = GarantiPos::campaignCodeInquiry('KAMPANYA2026');
extendedCreditInquiry(string $orderId, string $amount = '100'): array
Tüketici kredisi / vadeli taksit sorgusu. Type=extendedcreditinq
$response = GarantiPos::extendedCreditInquiry('KREDIT-001');
settlementInquiry(string $date, array $transactionSummaries = [], array $options = []): array
Mutabakat sorgusu. Root SettlementInq bloğu ile çalışır (diğer sorgulardan farklı yapı).
$response = GarantiPos::settlementInquiry(
date: '20260614', // YYYYMMDD
transactionSummaries: [
['Type' => 'sales', 'Count' => '5', 'Amount' => '50000', 'CurrencyCode' => '949'],
['Type' => 'refund', 'Count' => '1', 'Amount' => '10000', 'CurrencyCode' => '949'],
]
);
Form Ek Alanları
3D / OOS formlarına ek veri göndermek için orderData dizisine aşağıdaki alanlar eklenebilir. Tüm alan isimleri hem snake_case hem de orijinal GVP adıyla kabul edilir.
Ürün Listesi (ItemList)
GarantiPos::build3DForm(
[
'order_id' => 'ORDER-001',
'amount' => '15000',
'items' => [
[
'number' => '1',
'product_code' => 'SKU-001',
'quantity' => '1',
'price' => '10000',
'total_amount' => '10000',
'name' => 'Ürün A',
'description' => 'Ürün açıklaması',
],
[
'number' => '2',
'product_code' => 'SKU-002',
'quantity' => '2',
'price' => '2500',
'total_amount' => '5000',
'name' => 'Ürün B',
],
],
],
$cardData, $successUrl, $errorUrl
);
Adres Listesi (AddressList)
'addresses' => [
[
'type' => 'B', // B=Fatura, S=Teslimat
'name' => 'Ahmet',
'lastname' => 'Yılmaz',
'company' => 'Firma A.Ş.',
'address' => 'Atatürk Cad. No:1',
'district' => 'Şişli',
'city' => 'Istanbul',
'postal_code' => '34000',
'country' => 'TR',
'phone_number' => '02121234567',
'gsm_number' => '5XXXXXXXXX', // GVP: GsmNumber (büyük G, küçük sm)
],
[
'type' => 'S', // Teslimat adresi
'name' => 'Ahmet',
'address' => 'Farklı Teslimat Adresi No:5',
'city' => 'Ankara',
],
],
GsmNumber'dır (büyük G, küçük sm). Paket bu yazımı korur.
Yorum Listesi (CommentList)
'comments' => [
['number' => '1', 'text' => 'Özel sipariş notu'],
['number' => '2', 'text' => 'Kargo talimatı'],
],
Bonus/Puan Kullanımı (RewardList)
'reward_list' => [
['type' => 'BNS', 'used_amount' => '5000', 'gained_amount' => '0'],
['type' => 'CHQ', 'used_amount' => '2000', 'gained_amount' => '0'],
],
Çek Listesi (ChequeList)
'cheque_list' => [
['type' => 'P', 'amount' => '5000', 'count' => '1'],
],
Özel Form Alanları (Passthrough)
GVP'nin desteklediği ancak paket tarafından özel olarak işlenmeyen alanları doğrudan form'a eklemek için:
'form_fields' => [
'customfield1' => 'deger1',
'customfield2' => 'deger2',
],
Tam Alan Adı Tablosu
| Paket Alanı (snake_case) | GVP XML / Form Adı | Açıklama |
|---|---|---|
company_name | companyname | Firma adı |
group_id | ordergroupid | Sipariş grup ID |
down_payment_rate | txndownpayrate | Peşinat oranı (%) |
delay_day_count | txndelaydaycnt | Ötelem gün sayısı |
moto_ind | txnmotoind | MOTO göstergesi |
utility_pay_invoice_id | utilitypayinvoiceid | Fatura no |
gsm_quantity | gsmquantity | GSM kontör adedi |
money_invoice | moneyinvoice | MoneyCard fatura |
security_level | secure3dsecuritylevel | 3D güvenlik seviyesi |
installment | txninstallmentcount | Taksit sayısı |
ip_address | customeripaddress | Müşteri IP |
email | customeremailaddress | Müşteri e-posta |
Enum Referansı
Currency (Para Birimi)
use Developertugrul\GarantiPos\Enums\Currency;
Currency::TRY // '949' — Türk Lirası
Currency::USD // '840' — Amerikan Doları
Currency::EUR // '978' — Euro
Currency::GBP // '826' — İngiliz Sterlini
Currency::JPY // '392' — Japon Yeni
Currency::RUB // '643' — Rus Rublesi
// Kullanım örneği
GarantiPos::pay(
['order_id' => 'USD-001', 'amount' => '10000', 'currency' => Currency::USD],
$cardData
);
TransactionType (İşlem Tipi)
| Sabit | Değer | Açıklama |
|---|---|---|
SALE | 'sales' | Standart satış |
CANCEL / VOID | 'void' | İptal |
REFUND | 'refund' | İade |
PRE_AUTH | 'preauth' | Ön provizyon |
POST_AUTH | 'postauth' | Ön provizyon kapama |
REWARD_INQUIRY | 'rewardinq' | Puan sorgu |
ORDER_INQUIRY | 'orderinq' | Sipariş sorgu |
ORDER_HISTORY_INQUIRY | 'orderhistoryinq' | Sipariş geçmişi sorgusu |
ORDER_LIST_INQUIRY | 'orderlistinq' | Sipariş listesi sorgusu |
BATCH_INQUIRY | 'batchinq' | Günsonu sorgusu |
BIN_INQUIRY | 'bininq' | BIN sorgusu |
DCC_INQUIRY | 'dccinq' | DCC kur sorgusu |
CAMPAIGN_CODE_INQUIRY | 'campaigncodeinq' | Kampanya sorgusu |
RECURRING_VOID | 'recurringvoid' | Tekrarlı iptal |
RECURRING_UPDATE | 'recurringupdate' | Tekrarlı güncelleme |
IDENTIFY_INQUIRY | 'identifyinq' | TCKN sorgusu |
EXTENDED_CREDIT | 'extendedcredit' | Tüketici kredisi |
COMMERCIAL_CARD | 'commercialcard' | Ticari kart (OOS form) |
COMMERCIAL_CARD_EXTENDED_CREDIT | 'commercialcardextendedcredit' | Ticari kart vadeli |
CEPBANK | 'cepbank' | CepBank ödemesi |
GARANTI_PAY_DATA_REQUEST | 'gpdatarequest' | GarantiPay DataRequest |
Hata Yönetimi
GarantiPosException
Paket, geçersiz parametre, cURL hatası veya XML ayrıştırma hatası durumunda GarantiPosException fırlatır:
use Developertugrul\GarantiPos\Exceptions\GarantiPosException;
try {
$response = GarantiPos::pay($orderData, $cardData);
} catch (GarantiPosException $e) {
Log::error('GarantiPos hatası: ' . $e->getMessage());
// Kullanıcıya hata göster
}
ProcReturnCode Değerleri
| Kod | Anlam |
|---|---|
00 | Başarılı |
01 | Kart sahibini arayın |
05 | İşlem onaylanmadı (genel red) |
12 | Geçersiz işlem |
51 | Yetersiz bakiye / limit |
54 | Kartın son kullanma tarihi geçmiş |
57 | Kart sahibine izin verilmemiş işlem |
62 | Kısıtlı kart |
91 | Banka kartı veren sisteminde arıza |
96 | Sistem arızası |
Yanıt Kontrol Örüntüsü
$response = GarantiPos::pay($orderData, $cardData);
$success = isset($response['ProcReturnCode']) && $response['ProcReturnCode'] === '00';
if ($success) {
$order->update([
'payment_status' => 'paid',
'auth_code' => $response['AuthCode'],
'retref_num' => $response['RetrefNum'],
'batch_num' => $response['BatchNum'],
'sequence_num' => $response['SequenceNum'],
'host_ref_num' => $response['HostRefNum'],
]);
} else {
Log::warning('Ödeme reddedildi', [
'order_id' => $orderData['order_id'],
'return_code' => $response['ProcReturnCode'] ?? 'N/A',
'message' => $response['ResponseMessage'] ?? 'Bilinmiyor',
]);
}
Yanıt Yapısı
Tüm metodlar aşağıdaki temel alanları içeren bir dizi döner. İşlem tipine göre ek alanlar bulunabilir:
'ResponseCode' => '00',
'ResponseMessage' => 'Onaylandı',
'TerminalProvUserID' => 'PROVAUT',
'ProcReturnCode' => '00',
'ProvDate' => '20260614 15:22:07',
'IsEnrolled' => 'Y',
'OrderID' => 'SIPARIS-001',
'RetrefNum' => '406310073566',
'BatchNum' => '004063',
'SequenceNum' => '000001',
'AuthCode' => '304919',
'HostRefNum' => '123456789012',
]
Test
Birim Testleri Çalıştırma
composer install
vendor/bin/phpunit --configuration phpunit.xml.dist
WSL / XAMPP ortamında:
cmd.exe /c "cd /d C:\xampp\htdocs\libs\garanti-pos && C:\xampp\php\php.exe vendor\bin\phpunit --configuration phpunit.xml.dist"
Test Kapsamı
| Test Dosyası | Kapsam |
|---|---|
HashGeneratorTest | SecurityData, SHA1/SHA512 XML hash, 3D form hash, callback hashparams doğrulaması, secure3dhash doğrulaması |
XmlBuilderTest | Tekrarlayan liste düğümleri (AddressList/Address vb.), XML değer tek encode |
GarantiPosServicePayloadTest | 16 senaryo: SHA512 mod, credential routing, özel XML blokları, form alanları, sorgu payload'ları, 3D callback işleme |
XML Payload İncelemesi (Canlı Banka İsteği Göndermeden)
// Test ortamında banka isteği göndermeden oluşturulan XML'i görmek için:
$service = app(\Developertugrul\GarantiPos\Services\GarantiPosService::class);
$xml = $service->buildRequestXml([
'GVPSRequest' => [
'Mode' => 'TEST',
'Version' => 'v0.01',
// ...
],
]);
echo $xml;
Test Ortamı Bilgileri
https://sanalposprovtest.garanti.com.tr/VPServlet3D test endpoint'i:
https://sanalposprovtest.garanti.com.tr/servlet/gt3dengineTest kart ve terminal bilgileri için Garanti BBVA entegrasyon desteğine başvurun.
Paket: developertugrul/garanti-pos — v1.0.17 — MIT Lisansı
Yazar: Tuğrul Yıldırım <contact@tugrulyildirim.com>
GVP Uyumluluk: GVP_COMPATIBILITY_CHECKLIST.md