Türk banka ve ödeme sağlayıcıları (NestPay/Asseco, PayFor, PayFlex, GVPS/Garanti, PosNet, iyzico, PayTR, Craftgate, Moka, Tosla, Paratika ve daha fazlası) için tek arayüzlü, framework'e bağımlı olmayan bir ödeme kütüphanesi.
⚠️ Erken aşama. PHP paketindeki (paramhariç — TMSF kayyımlığında) tüm banka ve ödeme kuruluşu sürücüleri artık protokol seviyesinde taşındı:fake(sahte),iyzico,tosla,akbank-pos,moka,qnb-payfor,vakifbank,ziraat-payflex,garanti,ziraat-katilim,akbank(NestPay),denizbank,paycell,yapikredi(PosNet),albaraka(PosNet V1),kuveytturk,vakif-katilim,paytr,craftgate,paratikavetami. Hiçbiri henüz gerçek sandbox/test ortamına karşı ölçülmedi —tamiiçin ayrıca dokümantasyonun kendi içinde çelişkili olduğu bilinen bir imza sorunu var, bkz. Durum ve Kapsam.
AnadoluPay, Laravel projeleri için 30'dan fazla Türk banka ve ödeme sağlayıcısını tek bir arayüzde toplayan, gerçek banka test ortamlarına karşı ölçülerek doğrulanmış bir PHP paketidir. Bu depo, aynı deneyimi Node.js/TypeScript ekosistemine taşıma girişimidir.
Neden bu işe değer bulduk:
- Node/TS ekosisteminde bu paketin dengi yok. Gördüğümüz NestPay
kütüphaneleri (
node-nestpay,node-nestpay-v3gibi) eski, bakımsız ve tek bir bankayı/protokolü kapsıyor. Onlarca sağlayıcıyı tek arayüzde toplayan, testli bir paket bu ekosistemde henüz yok — yani doldurmaya çalıştığımız boşluk gerçekten var, varsayım değil. - Protokolleri sıfırdan öğrenmiyoruz. AnadoluPay'i gerçek banka test ortamlarına karşı (Akbank, İş Bankası, Ziraat, Garanti, QNB, VakıfBank, Kuveyt Türk, iyzico ve daha fazlası) tek tek ölçerek doğrulamıştık — hash sırası, alan adları, 3D Secure akışının dokümanlarda yazmayan gerçek davranışı elimizde.
- Ama kod çevirmek, protokolü tekrar ölçmek anlamına gelmiyor. PHP tarafında öğrendiğimiz en kalıcı ders şu: bir sürücünün "doğru yazılmış olması" ile "gerçekten bir bankaya karşı çalışması" ayrı şeyler. Bu portta da her sürücüyü ilgili bankanın test ortamına karşı yeniden doğrulayacağız — dil değişse de bu adım atlanmıyor.
Kısacası: PHP tarafındaki mimariyi ve banka bilgisini temel alan, ama Laravel'e değil düz Node.js'e (Express/NestJS/Next.js ile kullanılabilecek şekilde) bağlı, TypeScript-first bir ödeme kütüphanesi kurmaya çalışıyoruz.
npm install @voxyfy/anadolupayPaket npm'de yayında ve CommonJS/ESM ikisini de destekler:
// ESM / TypeScript
import { createAnadoluPay, FakeGateway } from '@voxyfy/anadolupay';// CommonJS
const { createAnadoluPay, FakeGateway } = require('@voxyfy/anadolupay');Node.js 18 veya üzeri gerekir (fetch global olarak kullanılır, ek bir HTTP
istemci bağımlılığı yoktur). Kütüphane framework'e bağımlı değildir; hangi
sürücüleri hangi kimlik bilgileriyle kuracağınızı createAnadoluPay({ drivers })
çağrısında siz belirlersiniz — aşağıdaki sürücü örneklerine bakın.
- Voxyfy/anadolupay — bu paketin taşındığı kaynak: Laravel için PHP ödeme kütüphanesi. Desteklenen bankaların tam listesi, doğrulama durumu ve protokol ayrıntıları için oradaki README'ye bakın.
- Voxyfy/anadolupay-laravel — PHP paketinin gerçek banka test ortamlarına karşı denendiği örnek Laravel projesi. Her sürücünün 3D Secure akışı tarayıcıdan burada koşturulup ölçüldü.
- Voxyfy/anadolupay-node-example
— bu paketin Express + React ile hazırlanmış örnek test projesi; yukarıdaki
Laravel örneğinin Node.js karşılığı. Aynı
.envdeğişken adlarını kullanır. - Voxyfy/anadoluship (npm) — aynı driver mimarisinin kargo firmaları (MNG, UPS, Yurtiçi, Aras, PTT, Sürat) için Node.js/TypeScript karşılığı.
- Voxyfy/anadolushield (npm) — LLM API'lerine göndermeden önce TCKN/VKN/IBAN/isim gibi kişisel verileri maskeleyen, KVKK riskini azaltan bağımsız bir kütüphane.
- Voxyfy/anadolucookie — KVKK/GDPR uyumlu, framework'e bağımlı olmayan çerez rıza (cookie consent) banner kütüphanesi.
PHP/Laravel mimarisiyle eşleşme, ama Laravel'e (facade, service container,
config()) bağımlı olmadan:
| PHP/Laravel | Node/TS karşılığı |
|---|---|
PaymentGatewayInterface + Supports* contract'ları |
PaymentGateway interface'i + contracts/capabilities.ts'teki tip-koruyucu (supportsCancellation(gateway)) fonksiyonları — TS'te interface'ler runtime'da olmadığı için instanceof yerine bunlar kullanılır |
DTO'lar (CreatePaymentData, PaymentResponse, …) |
Aynı adlarla TS sınıfları, dto/ altında |
config('anadolupay.banks') / Laravel service container |
createAnadoluPay({ drivers }) — tipli bir fabrika, framework'e bağımlı değil |
Support/Money.php |
support/Money.ts — kuruş cinsinden tam sayı, float aritmetiği yok |
Gateways/Bank/AbstractBankGateway.php |
gateways/bank/AbstractBankGateway.ts — aynı şablon-metot akışı (createPayment/verify/refund + soyut kancalar); Laravel'e özgü event yayını ve mükerrer-ödeme koruması bilerek yok |
Support/Bank/BankConfig.php, BankHttpClient.php |
support/bank/BankConfig.ts, BankHttpClient.ts |
| Pest (405 test) | Vitest (261 test) |
İlk sürücü FakeGateway — ağ çağrısı yapmaz, işlemleri bellekte tutar.
Bilerek en başta seçildi: mimarinin (DTO'lar, contract'lar, yetenek tespiti,
hata hiyerarşisi) doğru kurulduğunu kanıtlar ve gerçek bir banka kimliği
gerektirmez.
import { createAnadoluPay, FakeGateway, CreatePaymentData } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
fake: () => new FakeGateway(),
},
});
const gateway = anadolupay.driver('fake');
const payment = await gateway.createPayment(
new CreatePaymentData({
amount: 100,
currency: 'TRY',
orderId: 'SIPARIS-123', // boş bırakılırsa ön ekle üretilir
customer: {},
}),
);İkinci sürücü IyzicoGateway — PHP tarafındaki IyzicoGateway +
IyzicoHttpClient (IYZWSv2 kimlik doğrulama) + IyzicoMapper +
IyzicoSignatureValidator'ın (HMAC-SHA256 imza şeması) birebir TS karşılığı.
3DS başlatma, callback/webhook doğrulama, iade, durum sorgusu, BIN sorgusu ve
taksit sorgusunu kapsıyor.
import { createAnadoluPay, IyzicoGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
iyzico: () =>
new IyzicoGateway({
baseUrl: process.env.IYZICO_BASE_URL!,
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
defaultCallbackUrl: process.env.IYZICO_CALLBACK_URL,
}),
},
});Üçüncü sürücü ToslaGateway — ilk "banka ailesi" sürücüsü. PHP'de
Tosla, NestPay/PayFor gibi bankalarla aynı şablon-metot tabanını
(AbstractBankGateway) paylaşıyordu; bu yüzden Tosla ile birlikte o
tabanı da taşıdık (AbstractBankGateway, BankConfig, BankHttpClient).
NestPay/PayFor/PayFlex gibi sonraki sürücüler bu tabanı genişletecek.
import { createAnadoluPay, ToslaGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
tosla: () =>
new ToslaGateway({
merchantId: process.env.TOSLA_MERCHANT_ID!,
username: process.env.TOSLA_USERNAME!,
secretKey: process.env.TOSLA_SECRET_KEY!,
endpoints: {
payment_api: process.env.TOSLA_PAYMENT_API!,
gateway_3d: process.env.TOSLA_GATEWAY_3D!,
},
}),
},
});Dördüncü sürücü AkbankPosGateway — Akbank'ın yeni JSON tabanlı sanal
POS API'si (Asseco tabanlı eski akbank sürücüsünden farklı, ayrı bir
protokol). AbstractBankGateway'i genişletiyor; kendine özgü kısmı
auth-hash başlığı ile gövdenin tamamının imzalanması — bu yüzden
BankHttpClient'a genel bir send(url, body, headers) metodu eklendi
(postJson da artık onu kullanıyor).
import { createAnadoluPay, AkbankPosGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
'akbank-pos': () =>
new AkbankPosGateway({
merchantId: process.env.AKBANK_POS_MERCHANT_SAFE_ID!,
terminalId: process.env.AKBANK_POS_TERMINAL_SAFE_ID!,
secretKey: process.env.AKBANK_POS_SECRET_KEY!,
endpoints: {
payment_api: process.env.AKBANK_POS_PAYMENT_API!,
gateway_3d: process.env.AKBANK_POS_GATEWAY_3D!,
gateway_3d_host: process.env.AKBANK_POS_GATEWAY_3D_HOST!,
},
}),
},
});Beşinci sürücü MokaGateway — üçüncü "banka ailesi" sürücüsü.
Moka'nın en tuhaf tarafı: 3D dönüşünde başarı/başarısızlık ayrı bir alanda
bildirilmez, CodeForHash değerine T/F eklenip sha256'sı alınır ve
sonuç hashValue olarak karşılaştırılır — bu yüzden verify()'ı
override edip sipariş bağlamından (order.code_for_hash) gelen değeri
callback yüküne enjekte ediyor, sonra temel akışı çağırıyor.
import { createAnadoluPay, MokaGateway, VerifyPaymentData } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
moka: () =>
new MokaGateway({
merchantId: process.env.MOKA_DEALER_CODE!,
username: process.env.MOKA_USERNAME!,
password: process.env.MOKA_PASSWORD!,
endpoints: { payment_api: process.env.MOKA_PAYMENT_API! },
}),
},
});
const payment = await anadolupay.driver('moka').createPayment(/* ... */);
const codeForHash = payment.raw['code_for_hash']; // siparişle birlikte saklayın
// Callback geldiğinde:
await anadolupay.driver('moka').verify(
new VerifyPaymentData({ payload: callbackBody, order: { code_for_hash: codeForHash } }),
);Altıncı sürücü PayForGateway (qnb-payfor) — ilk XML tabanlı
sürücü. Bununla birlikte Xml yardımcı modülü (fast-xml-parser ile
encode/decode) ve BankHttpClient.postXml() eklendi. PayFor sınıfı
generiktir (PHP tarafında da öyleydi): bank anahtarını constructor'a
parametre olarak alır, böylece aynı sınıf ziraat-katilim gibi diğer
PayFor tabanlı bankalar için de kullanılabilir.
import { createAnadoluPay, PayForGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
'qnb-payfor': () =>
new PayForGateway('qnb-payfor', {
merchantId: process.env.QNB_PAYFOR_MERCHANT_ID!,
username: process.env.QNB_PAYFOR_USERNAME!,
password: process.env.QNB_PAYFOR_PASSWORD!,
secretKey: process.env.QNB_PAYFOR_SECRET_KEY!,
extra: { mbr_id: process.env.QNB_PAYFOR_MBR_ID ?? '5' },
endpoints: {
payment_api: process.env.QNB_PAYFOR_PAYMENT_API!,
gateway_3d: process.env.QNB_PAYFOR_GATEWAY_3D!,
gateway_3d_host: process.env.QNB_PAYFOR_GATEWAY_3D_HOST!,
},
}),
},
});Xml'in bilinen sınırı: encode()'daki encoding parametresi şu an
yalnızca UTF-8 için tam doğru çalışıyor. PHP tarafı ISO-8859-9 gibi
kodlamalarda gövdeyi bayt dizisine çeviriyordu; bu port henüz o adımı
(Node'da Buffer gövde desteği) eklemedi — NestPay ailesi taşınırken bu
netleşecek.
Yedinci sürücü PayFlexGateway (vakifbank) — VakıfBank/Ziraat/İş
Bankası'nın PayFlex V4 (MPI VPOS) altyapısı. İki yeni ihtiyaç bununla
geldi:
BankHttpClient.postForm()— PayFlex, XML'i JSON/XML gövdesi olarak değil,prmstradlı tek birapplication/x-www-form-urlencodedalanının içinde bekler.- İki aşamalı 3D akışı — kart önce bankaya değil MPI'ya
(
Enrollment.aspx) gönderilir; kartı çıkaran bankanın ACS adresi vePaReq/MDgeri döner, 3D formu o adrese POST edilir. Bazı kurulumlarda (BKM GO)PaReqdüz bir 3DS bloğu değil, kendi kendini gönderen base64 kodlu bir HTML sayfasıdır — bu port o sayfayı regex'le ayrıştırıp gerçek form hedefini çıkarıyor (PHP'deki davranışın aynısı).
import { createAnadoluPay, PayFlexGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
vakifbank: () =>
new PayFlexGateway('vakifbank', {
merchantId: process.env.VAKIFBANK_MERCHANT_ID!,
password: process.env.VAKIFBANK_PASSWORD!,
terminalId: process.env.VAKIFBANK_TERMINAL_ID!,
endpoints: {
payment_api: process.env.VAKIFBANK_PAYMENT_API!,
gateway_3d: process.env.VAKIFBANK_GATEWAY_3D!,
query_api: process.env.VAKIFBANK_QUERY_API!,
},
}),
},
});PayFlexGateway jeneriktir — PHP'de olduğu gibi bank adı constructor
parametresi. Bu sayede ziraat-payflex için hiç yeni kod yazmadan,
sadece farklı kimlik/uçlarla aynı sınıf kullanılıyor:
'ziraat-payflex': () =>
new PayFlexGateway('ziraat-payflex', {
merchantId: process.env.ZIRAAT_PAYFLEX_MERCHANT_ID!,
password: process.env.ZIRAAT_PAYFLEX_PASSWORD!,
terminalId: process.env.ZIRAAT_PAYFLEX_TERMINAL_ID!,
endpoints: {
payment_api: process.env.ZIRAAT_PAYFLEX_PAYMENT_API!,
gateway_3d: process.env.ZIRAAT_PAYFLEX_GATEWAY_3D!,
query_api: process.env.ZIRAAT_PAYFLEX_QUERY_API!,
},
}),Sekizinci sürücü GarantiGateway — standart akışa dönen (Tosla/Moka/
PayFlex gibi createPayment/verify'ı override etmiyor) ikinci XML
tabanlı sürücü. Kendine özgü noktaları: tutarlar kuruş cinsinden tam sayı,
imzalar sha512/sha1 büyük harf hex, ve securityData (şifre +
9 haneye sıfır dolgulu terminal no) — iade/iptalde ayrı bir refund_username
kullanabiliyor (extra.refund_username).
Üye işyeri banka tarafında bayi (alt üye işyeri) yapılandırmasıyla açıldıysa
her finansal istekte bayi kodu zorunludur; gitmezse işlem 0809 ile reddedilir.
extra.sub_merchant_id verildiğinde alan provizyon, 3D form, provizyon kapama,
iptal/iade ve sorgu isteklerine eklenir — boş bırakılırsa istekler alanı hiç
içermez ve imza değişmez. XML isteklerinde alan bankanın dokümanına uygun
olarak Terminal düğümünün içine, 3D form post'unda submerchantid alanı
olarak yazılır; banka farklı bir düğüm isterse extra.sub_merchant_id_path
ile taşınabilir.
Bankanın bayi tanımında her bayinin kullanacağı kart numaraları da tanımlanır: gönderilen kart o bayi altında kayıtlı değilse işlem reddedilir.
import { createAnadoluPay, GarantiGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
garanti: () =>
new GarantiGateway({
merchantId: process.env.GARANTI_MERCHANT_ID!,
terminalId: process.env.GARANTI_TERMINAL_ID!,
username: process.env.GARANTI_USERNAME!,
password: process.env.GARANTI_PASSWORD!,
secretKey: process.env.GARANTI_SECRET_KEY!,
refundPassword: process.env.GARANTI_REFUND_PASSWORD,
extra: {
refund_username: process.env.GARANTI_REFUND_USERNAME,
// Yalnızca bayi yapılandırmalı terminaller için.
sub_merchant_id: process.env.GARANTI_SUB_MERCHANT_ID,
},
endpoints: {
payment_api: process.env.GARANTI_PAYMENT_API!,
gateway_3d: process.env.GARANTI_GATEWAY_3D!,
},
}),
},
});PayForGateway de jeneriktir — ziraat-katilim için yine yeni kod
gerekmedi, sadece farklı kimlik/uçlarla. Tek fark: Ziraat Katılım'ın
dönüş hash'i tutarsız üretildiği için PHP'de olduğu gibi verifyHash
varsayılan olarak false önerilir:
'ziraat-katilim': () =>
new PayForGateway('ziraat-katilim', {
merchantId: process.env.ZIRAAT_KATILIM_MERCHANT_ID!,
username: process.env.ZIRAAT_KATILIM_USERNAME!,
password: process.env.ZIRAAT_KATILIM_PASSWORD!,
secretKey: process.env.ZIRAAT_KATILIM_SECRET_KEY!,
verifyHash: process.env.ZIRAAT_KATILIM_VERIFY_HASH === 'true',
endpoints: {
payment_api: process.env.ZIRAAT_KATILIM_PAYMENT_API!,
gateway_3d: process.env.ZIRAAT_KATILIM_GATEWAY_3D!,
},
}),Dokuzuncu sürücü AssecoGateway (akbank, NestPay/EST ailesi) —
roadmap'te en başından beklettiğimiz parça, çünkü NestPay gövdeyi
ISO-8859-9 ister. Bu, bu porttaki en köklü altyapı değişikliğiyle
geldi:
Xml.encodeBytes()/Xml.decodeBytes()—encode()/decode()hâlâ UTF-8 dizgisiyle çalışır (diğer sürücüler değişmeden çalışmaya devam eder); yeni metotlariconv-liteile gerçek bayt dizisi (Buffer) üretir/okur.BankHttpClient.postXml()artık gövdeyiBufferolarak gönderir ve yanıtı daresponse.arrayBuffer()üzerinden aynı kodlamayla çözümler —response.text()her zaman UTF-8 varsaydığı için Türkçe karakterleri (İ, Ş, Ğ, ı, ü, ö, ç) bozuyordu. Bunu bir testle kanıtladık:İşyerigibi bir alanın isteğe tam olarak ISO-8859-9 baytlarıyla gittiğini ve yanıttaki Türkçe karakterlerin bozulmadan geri okunduğunu doğruluyor.- Diğer XML tabanlı sürücüler (
PayForGateway,PayFlexGateway,GarantiGateway) UTF-8 kullandığı için davranışları değişmedi — regresyon testleriyle doğrulandı.
AssecoGateway de jeneriktir; aynı sınıf isbank, ziraat, halkbank,
qnb, teb, sekerbank, ing, alternatifbank için de kullanılabilir.
import { createAnadoluPay, AssecoGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
akbank: () =>
new AssecoGateway('akbank', {
merchantId: process.env.AKBANK_MERCHANT_ID!,
username: process.env.AKBANK_USERNAME!,
password: process.env.AKBANK_PASSWORD!,
secretKey: process.env.AKBANK_SECRET_KEY!,
endpoints: {
payment_api: process.env.AKBANK_PAYMENT_API!,
gateway_3d: process.env.AKBANK_GATEWAY_3D!,
},
}),
},
});Onuncu ve on birinci sürücüler InterPosGateway (denizbank) ve
PaycellGateway — ikisi de standart olmayan akışlarda.
InterPosGateway, form tabanlı (XML değil) düzpostFormistekleri kullanır; standartcreatePayment/verifyakışını override etmez.PaycellGateway, Tosla/Moka/PayFlex gibicreatePayment/verify'ı tamamen override eder: kart bilgisi ödeme ucuna hiç gitmez, önce ayrı bir uçtan (token_api)cardTokenalınır, sonra 3D oturumu açılır. İmzası iki aşamalıdır ve tamamı büyük harfe çevrilerek hesaplanır — bu adım atlanırsa imza hiçbir zaman tutmaz.
Bu ikisini taşırken gerçek bir hata bulup düzelttik: BankHttpClient.decode(),
PHP'deki parse_str() geri dönüşünü (banka JSON/XML değil düz
key=value&... query-string döndürdüğünde) hiç portlamamıştı — InterPos'un
form-tabanlı yanıtları bu yüzden "çözümlenemedi" hatasıyla patlıyordu.
Şimdi PHP'nin tam sırasını izliyor: JSON → XML → (2xx değilse hata) →
query-string → { raw_body }.
import { createAnadoluPay, InterPosGateway, PaycellGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
denizbank: () =>
new InterPosGateway('denizbank', {
merchantId: process.env.DENIZBANK_MERCHANT_ID!,
username: process.env.DENIZBANK_USERNAME!,
password: process.env.DENIZBANK_PASSWORD!,
secretKey: process.env.DENIZBANK_SECRET_KEY!,
endpoints: {
payment_api: process.env.DENIZBANK_PAYMENT_API!,
gateway_3d: process.env.DENIZBANK_GATEWAY_3D!,
gateway_3d_host: process.env.DENIZBANK_GATEWAY_3D_HOST!,
},
}),
paycell: () =>
new PaycellGateway({
merchantId: process.env.PAYCELL_MERCHANT_ID!,
username: process.env.PAYCELL_USERNAME!,
password: process.env.PAYCELL_PASSWORD!,
secretKey: process.env.PAYCELL_SECRET_KEY!,
extra: { msisdn: process.env.PAYCELL_MSISDN },
endpoints: {
payment_api: process.env.PAYCELL_PAYMENT_API!,
token_api: process.env.PAYCELL_TOKEN_API!,
gateway_3d: process.env.PAYCELL_GATEWAY_3D!,
},
}),
},
});On ikinci sürücü PosNetGateway (yapikredi) — bugüne kadarki en
katmanlı 3D akışı. PosNet doğrulamayı üç sunucu isteğine yayar:
oosRequestData— kart ve sipariş bilgisi bankaya gönderilir, banka 3D formunda kullanılacakdata1/data2/signpaketlerini döner.- Bu paketler 3D geçidine POST edilir, müşteri kimlik doğrular.
- Dönüşteki
MerchantPacket/BankPacket/SignüçlüsüoosResolveMerchantDataile çözülür,macdoğrulanır veoosTranDataile provizyon tamamlanır — bu yüzdenverify()(Moka/PayFlex/Paycell gibi) tamamen override edilir.
Bununla birlikte gelen yeni ihtiyaç: BankHttpClient.postXmlAsFormField().
PosNet, XML'i postXml()'deki gibi gövdenin tamamı olarak değil,
xmldata adlı tek bir form alanının değeri olarak ister — ama bu
değerin ISO-8859-9 baytları bozulmadan gitmesi gerekir. URLSearchParams
burada kullanılamaz (JS string'ini kodlamadan önce UTF-8'e çevirir);
bunun yerine XML baytları doğrudan, byte-safe bir yüzde-kodlamayla
(percentEncodeBytes()) forma yazılıyor.
PosNet'in diğer kendine özgü noktaları: para birimini ISO sayısal kodla
değil kendi iki harfli kısaltmasıyla ister (TL/US/EU — sayısal kod
gönderildiğinde E190 CurrencyCode hatalı döner), zorunlu bir
extra.posnet_id alanı vardır, ve iade/iptal/provizyon-kapama işlemleri
sipariş numarası yerine mümkünse hostLogKey ile eşlenir (yoksa 24
haneli, 3D siparişlerde TDSC önekli sipariş numarasına düşer).
import { createAnadoluPay, PosNetGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
yapikredi: () =>
new PosNetGateway({
merchantId: process.env.YAPIKREDI_MERCHANT_ID!,
terminalId: process.env.YAPIKREDI_TERMINAL_ID!,
secretKey: process.env.YAPIKREDI_SECRET_KEY!,
extra: { posnet_id: process.env.YAPIKREDI_POSNET_ID! },
endpoints: {
payment_api: process.env.YAPIKREDI_PAYMENT_API!,
gateway_3d: process.env.YAPIKREDI_GATEWAY_3D!,
},
}),
},
});On üçüncü sürücü PosNetV1Gateway (albaraka) — PosNet'in JSON tabanlı
yeni sürümü. Yapı Kredi'nin XML tabanlı PosNetGateway'inden farklı olarak
paket (data1/data2/sign) mekanizması yoktur; standart createPayment/
verify akışını kullanır (Garanti/Asseco gibi, override gerekmez). Her
istek MacParams/MACParams alanında MAC hesabına giren alan adlarını
iki nokta ile bildirir (sha256_b64, ayraçsız).
import { createAnadoluPay, PosNetV1Gateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
albaraka: () =>
new PosNetV1Gateway({
merchantId: process.env.ALBARAKA_MERCHANT_ID!,
terminalId: process.env.ALBARAKA_TERMINAL_ID!,
secretKey: process.env.ALBARAKA_SECRET_KEY!,
extra: { posnet_id: process.env.ALBARAKA_POSNET_ID! },
endpoints: {
payment_api: process.env.ALBARAKA_PAYMENT_API!,
gateway_3d: process.env.ALBARAKA_GATEWAY_3D!,
},
}),
},
});On dördüncü ve on beşinci sürücüler KuveytPosGateway (kuveytturk)
ve VakifKatilimGateway (vakif-katilim) — BOA/TDV2.0 protokolü. İkisi
de aynı imza şemasını (sha1_b64, aynı alan sırası) paylaşır ama PHP
tarafında da ayrı sınıflardır (kod tekrarı var, ortak bir taban sınıf yok);
bu port da aynı şekilde ayrı tutar. İkisinin de akışı standart akıştan
sapar, bu yüzden createPayment/verify tamamen override edilir:
- 3D adımında banka form alanları değil, doğrudan tarayıcıya basılacak
bir HTML sayfası döner (
PaymentResponse.htmlContent) — bunun içinBankHttpClient.postXmlForRawBody()eklendi:postXml()'den farkı, yanıtı JSON/XML olarak çözümlemeden ham dizgi olarak dönmesi. - Dönüşteki
AuthenticationResponsealanı URL kodlanmış bir XML belgesidir; önce çözülür, sonra provizyon isteği yapılır. - Kuveyt Türk sorgu/iade/iptali ayrı bir BOA servisinden (
query_api) yürütür; Vakıf Katılım hepsinipayment_apiüzerinden yapar.
import { createAnadoluPay, KuveytPosGateway, VakifKatilimGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
kuveytturk: () =>
new KuveytPosGateway({
merchantId: process.env.KUVEYTTURK_MERCHANT_ID!,
username: process.env.KUVEYTTURK_USERNAME!,
secretKey: process.env.KUVEYTTURK_SECRET_KEY!,
extra: { customer_id: process.env.KUVEYTTURK_CUSTOMER_ID },
endpoints: {
payment_api: process.env.KUVEYTTURK_PAYMENT_API!,
query_api: process.env.KUVEYTTURK_QUERY_API!,
},
}),
'vakif-katilim': () =>
new VakifKatilimGateway({
merchantId: process.env.VAKIF_KATILIM_MERCHANT_ID!,
username: process.env.VAKIF_KATILIM_USERNAME!,
secretKey: process.env.VAKIF_KATILIM_SECRET_KEY!,
extra: {
customer_id: process.env.VAKIF_KATILIM_CUSTOMER_ID,
sub_merchant_id: process.env.VAKIF_KATILIM_SUB_MERCHANT_ID ?? '0',
},
endpoints: {
payment_api: process.env.VAKIF_KATILIM_PAYMENT_API!,
gateway_3d_host: process.env.VAKIF_KATILIM_GATEWAY_3D_HOST!,
},
}),
},
});On altıncı, on yedinci ve on sekizinci sürücüler — ilk üç ödeme kuruluşu sürücüsü, artık bir bankanın sanal POS'u değil, birden çok bankayı tek API arkasında toplayan platformlar:
PayTrGateway(paytr) — standart akışı kullanır. İmzahmac_sha256_b64; bildirim (webhook) doğrulaması düz metinOKyanıtı bekler (ProvidesWebhookAcknowledgement), aksi hâlde PayTR bildirimi saatlerce yeniden gönderir. İptal (void) desteklemez, yalnızca iade eder.CraftgateGateway(craftgate) —createPayment()tamamen override edilir: 3D adımı form POST değil, hazır bir HTML sayfası (base64) döner. API imzası (x-signature, gövde baytları üzerinden) ile 3D dönüş imzası (ayrı bir 3D Secure Callback Key,sha256_hex+###ayracı) birbirinden tamamen farklı anahtar/algoritma kullanır — bu ikisini karıştırmak "Signature is not equal!" hatasının en yaygın sebebidir.ParatikaGateway(paratika) — form-encoded POST, istek imzası yok (kimlik doğrulama üç düz alanla:MERCHANT/MERCHANTUSER/MERCHANTPASSWORD); yalnızca 3D dönüşü imzalı. Akış her modelde birSESSIONTOKENile başladığı içincreatePayment()tamamen override edilir. Dönüş imzasında bilinen bir tuzak var:SD_SHA512dokümanda "Deprecated / Legacy — Do not use!" ama örnek yanıtlarda önce göründüğü için yanlışlıkla kullanılıyor; bu sürücü güncel olansdSha512'yi doğrular.
import { createAnadoluPay, CraftgateGateway, ParatikaGateway, PayTrGateway } from '@voxyfy/anadolupay';
const anadolupay = createAnadoluPay({
drivers: {
paytr: () =>
new PayTrGateway({
secretKey: process.env.PAYTR_MERCHANT_KEY!,
password: process.env.PAYTR_MERCHANT_SALT!,
merchantId: process.env.PAYTR_MERCHANT_ID!,
endpoints: {
payment_api: process.env.PAYTR_PAYMENT_API!,
gateway_3d: process.env.PAYTR_GATEWAY_3D!,
},
}),
craftgate: () =>
new CraftgateGateway({
username: process.env.CRAFTGATE_API_KEY!,
secretKey: process.env.CRAFTGATE_SECRET_KEY!,
password: process.env.CRAFTGATE_CALLBACK_KEY!,
extra: { merchant_hook_key: process.env.CRAFTGATE_HOOK_KEY },
endpoints: { payment_api: process.env.CRAFTGATE_PAYMENT_API! },
}),
paratika: () =>
new ParatikaGateway({
merchantId: process.env.PARATIKA_MERCHANT!,
username: process.env.PARATIKA_MERCHANT_USER!,
password: process.env.PARATIKA_MERCHANT_PASSWORD!,
secretKey: process.env.PARATIKA_SECRET_KEY!,
endpoints: {
payment_api: process.env.PARATIKA_PAYMENT_API!,
gateway_3d: process.env.PARATIKA_GATEWAY_3D!,
gateway_3d_auth: process.env.PARATIKA_GATEWAY_3D_AUTH!,
gateway_3d_host: process.env.PARATIKA_GATEWAY_3D_HOST!,
},
}),
},
});Sipariş numarasını kendiniz veriyorsanız hiçbir şey değişmez. Vermek
istemiyorsanız orderId'yi boş bırakın; numara ön ekiyle birlikte üretilir:
ANADOLUPAY_ORDER_PREFIX=ODM-
ANADOLUPAY_ORDER_LENGTH=10 # rastgele bölümün uzunluğu, en az 6new CreatePaymentData({ amount: 199.9, currency: 'TRY', customer: {} });
// orderId → ODM-4KX9AB2Q7T
anadolupay.orderId(); // ödemeyi başlatmadan önce gerekirse
makeOrderNumber({ prefix: 'ODM-' }); // istemciye ihtiyaç duymadanÖn eki ortam değişkeni yerine kod içinde vermek isterseniz istemciye geçirin; açık seçenek ortam değişkenini ezer:
const anadolupay = createAnadoluPay({
drivers: { ... },
order: { prefix: 'ODM-', length: 10 },
});Bu, paketin ortam değişkeni okuduğu tek yerdir; değişken tanımlı değilse
davranış değişmez (ön eksiz, 10 karakter). CreatePaymentData içindeki
otomatik üretim istemciyi görmediği için yalnızca ortam değişkenine bakar —
ön eki createAnadoluPay({ order }) ile veriyorsanız numarayı
anadolupay.orderId() ile üretip DTO'ya geçirin.
Numara A-Z0-9 ile sınırlıdır ve rastgeledir; sayaç tutulmaz. Sebebi: sipariş
numarası bankada kalıcı bir anahtardır — aynı numara ikinci kez gönderilirse
işlem reddedilir ve numara iade/sorgulamada da kullanıldığı için sonradan
değiştirilemez. Sayaç bunun için kalıcı depolama ve kilit gerektirir.
İki sınırı bilerek seçin:
- PosNet (Yapı Kredi, Albaraka) ve Paycell numarayı 20 karaktere sığdırır. Ön ek bu bütçeden düşer; taştığında driver sessizce kesmek yerine hata verir.
- Paycell ön eki tamamen atar. Referans numarasını üretirken rakam dışındaki her karakteri siler, yani benzersizlik tamamen rastgele bölümdedir.
| Alan | Durum |
|---|---|
Mimari (DTO'lar, contract'lar, hata hiyerarşisi, Money) |
✅ Kuruldu, tip kontrolünden ve testlerden geçiyor |
FakeGateway |
✅ Çalışıyor, testli |
IyzicoGateway |
fetch ile birim testlerden geçiyor — gerçek iyzico sandbox'ına karşı henüz ölçülmedi. PHP tarafında öğrenilen ders burada da geçerli: kodun doğru yazılmış olması, bankaya/sağlayıcıya karşı çalıştığı anlamına gelmez |
AbstractBankGateway + ToslaGateway |
|
AkbankPosGateway |
|
MokaGateway |
|
Xml + BankHttpClient.postXml() + PayForGateway |
encoding parametresi şimdilik yalnızca UTF-8 için doğru (bkz. Mimari) |
BankHttpClient.postForm() + PayFlexGateway |
prmstr form gövdesi taşındı, birim testlerden geçiyor — gerçek VakıfBank sandbox'ına karşı henüz ölçülmedi |
GarantiGateway |
|
Xml/BankHttpClient ISO-8859-9 desteği + AssecoGateway (NestPay) |
✅ Gerçek bayt-dizisi encode/decode çalışıyor (testle kanıtlandı), diğer XML sürücülerinde regresyon yok — AssecoGateway'in kendisi gerçek bir NestPay bankasına karşı henüz ölçülmedi |
InterPosGateway (denizbank) + BankHttpClient.decode() query-string fallback'i |
✅ Fallback eklendi ve testlerle kanıtlandı — InterPosGateway'in kendisi gerçek DenizBank test ortamına karşı henüz ölçülmedi |
PaycellGateway |
|
BankHttpClient.postXmlAsFormField() + PosNetGateway (yapikredi) |
oosRequestData/oosResolveMerchantData/oosTranData akışı ve byte-safe form-alanı yüzde-kodlaması taşındı, birim testlerden geçiyor — gerçek Yapı Kredi PosNet test ortamına karşı henüz ölçülmedi |
PosNetV1Gateway (albaraka) |
|
BankHttpClient.postXmlForRawBody() + KuveytPosGateway/VakifKatilimGateway |
AuthenticationResponse çözümleme) taşındı, birim testlerden geçiyor — gerçek Kuveyt Türk/Vakıf Katılım test ortamına karşı henüz ölçülmedi. Kuveyt Türk'ün sorgu/iade/iptal servisi (query_api) PHP tarafında WCF basicHttpBinding uyumsuzluğuyla ölçülmüştü — bu port da o bilinen sınırı taşıyor |
PayTrGateway |
|
BankHttpClient.get() + CraftgateGateway |
createPayment() tamamen override edildi. Birim testlerden geçiyor — gerçek Craftgate sandbox'ına karşı henüz ölçülmedi |
ParatikaGateway |
SESSIONTOKEN) üç modelli akış taşındı, birim testlerden geçiyor — gerçek Paratika test ortamına karşı henüz ölçülmedi |
| npm yayını | ✅ @voxyfy/anadolupay yayında |
Bu paketi PHP'den tek seferde değil, sürücü sürücü taşıyoruz; sürüm
numarası bu yüzden 0.1.0'dan başlayıp 1.0.0'a atlamış, en son 1.4.2'ye
ulaşmıştır (aradaki bazı sürücü ekleri henüz yayınlanmadığı için tek bir
sürümde toplandı; 1.4.0 sürücü değil sipariş numarası üretimini,
1.4.1 Garanti bayi kodunu ekler, 1.4.2 bayi kodunun yazıldığı düğümü
banka dokümanına göre Terminal içine düzeltir).
param hariç (TMSF kayyımlığında, aktif sürdürülmüyor) PHP paketindeki
tüm sürücüler artık protokol seviyesinde taşındı.
Aşağıdaki tablo hangi sürümde hangi sürücünün eklendiğini değil, şu anki
kapsamı gösterir.
PHP paketindeki (Voxyfy/anadolupay) tam liste, hangilerinin bu depoya
taşındığını gösteren bir sütunla. "Node taşıması" sütunu bu deponun
durumudur; "PHP'de doğrulama" sütunu ise kaynak pakette o sürücünün gerçek
bir banka/sağlayıcıya karşı ne kadar ölçüldüğünü özetler (ayrıntı için
PHP README'sindeki Doğrulama durumu
tablosuna bakın).
| Driver | Banka | Altyapı | Node taşıması | PHP'de doğrulama |
|---|---|---|---|---|
akbank |
Akbank (NestPay) | Asseco / Payten | ✅ Taşındı (AssecoGateway jenerik — bkz. Durum) |
Uçtan uca |
isbank |
İş Bankası | Asseco / Payten | ✅ Taşındı (aynı sınıf, farklı kimlikle test edildi) | Uçtan uca |
ziraat |
Ziraat Bankası (NestPay) | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Uçtan uca |
halkbank |
Halkbank | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Dokümana göre — test kimliği bekleniyor |
qnb |
QNB Finansbank (NestPay) | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Kısmen — 3D geçti, provizyona yetkisiz |
teb |
TEB | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Dokümana göre — test kimliği bekleniyor |
sekerbank |
Şekerbank | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Dokümana göre — test kimliği bekleniyor |
ing |
ING | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Dokümana göre — test kimliği bekleniyor |
alternatifbank |
Alternatif Bank | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Dokümana göre — test kimliği bekleniyor |
turkiyefinans |
Türkiye Finans | Asseco / Payten | ✅ Taşındı (aynı sınıf) | Kısmen — 3D geçti, provizyona yetkisiz |
garanti |
Garanti BBVA | GVPS | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
yapikredi |
Yapı Kredi | PosNet (XML) | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Kısmen |
albaraka |
Albaraka Türk | PosNet V1 (JSON) | ✅ Taşındı (PosNetV1Gateway, protokol seviyesinde — bkz. Durum) |
Test erişimi bekleniyor |
vakifbank |
VakıfBank | PayFlex V4 | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
ziraat-payflex |
Ziraat Bankası (PayFlex) | PayFlex V4 | ✅ Taşındı (PayFlexGateway jenerik, aynı sınıf farklı kimlikle test edildi) |
Kısmen |
denizbank |
DenizBank | InterPos | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Dokümana göre — IP kısıtlı |
qnb-payfor |
QNB Finansbank / Enpara (PayFor) | PayFor | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
ziraat-katilim |
Ziraat Katılım | PayFor | ✅ Taşındı (PayForGateway jenerik, aynı sınıf farklı kimlikle test edildi) |
Ortak driver |
kuveytturk |
Kuveyt Türk | BOA / TDV2.0 | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Kısmen (yalnızca ödeme) |
vakif-katilim |
Vakıf Katılım | BOA | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Test erişimi bekleniyor |
| Driver | Kuruluş | Node taşıması | PHP'de doğrulama |
|---|---|---|---|
iyzico |
iyzico | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
tosla |
Tosla (AkÖde) | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
akbank-pos |
Akbank (yeni JSON API) | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
moka |
Moka United | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Uçtan uca |
paytr |
PayTR | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Test erişimi bekleniyor |
param |
Param | ⏳ | |
craftgate |
Craftgate | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Test vektörü |
paratika |
Paratika (Payten) | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Dokümana göre |
paycell |
Paycell (Turkcell) | ✅ Taşındı (protokol seviyesinde — bkz. Durum) | Kısmen |
- Her taşınan sürücüyü ilgili banka/sağlayıcının gerçek test ortamına karşı yeniden doğrula (API kimlikleri gerekiyor) — PHP tarafında Akbank/İşbank/QNB'de gördüğümüz gibi, kod doğru görünse de banka tarafında sürpriz çıkabilir; sonuçlara göre README/Durum tablosu kesinleştirilecek
- Express/Next.js için ince adapter paketleri
- npm'e yayınla
npm install
npm run typecheck
npm test
npm run buildMIT
