npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@voxyfy/anadolupay

v1.4.2

Published

Türk banka ve ödeme sağlayıcıları için tek arayüzlü, framework-bağımsız ödeme kütüphanesi (Node.js/TypeScript)

Readme

@voxyfy/anadolupay (Node.js / TypeScript)

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 (param hariç — 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, paratika ve tami. Hiçbiri henüz gerçek sandbox/test ortamına karşı ölçülmeditami için ayrıca dokümantasyonun kendi içinde çelişkili olduğu bilinen bir imza sorunu var, bkz. Durum ve Kapsam.

Amacımız

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-v3 gibi) 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.

Kurulum

npm install @voxyfy/anadolupay

Paket 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.

İlgili projeler

  • 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ı .env değ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.

Mimari

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, prmstr adlı tek bir application/x-www-form-urlencoded alanı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 ve PaReq/MD geri döner, 3D formu o adrese POST edilir. Bazı kurulumlarda (BKM GO) PaReq dü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 jeneriktirziraat-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 metotlar iconv-lite ile gerçek bayt dizisi (Buffer) üretir/okur.
  • BankHttpClient.postXml() artık gövdeyi Buffer olarak gönderir ve yanıtı da response.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: İşyeri gibi 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üz postForm istekleri kullanır; standart createPayment/verify akışını override etmez.
  • PaycellGateway, Tosla/Moka/PayFlex gibi createPayment/verify'ı tamamen override eder: kart bilgisi ödeme ucuna hiç gitmez, önce ayrı bir uçtan (token_api) cardToken alı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:

  1. oosRequestData — kart ve sipariş bilgisi bankaya gönderilir, banka 3D formunda kullanılacak data1/data2/sign paketlerini döner.
  2. Bu paketler 3D geçidine POST edilir, müşteri kimlik doğrular.
  3. Dönüşteki MerchantPacket/BankPacket/Sign üçlüsü oosResolveMerchantData ile çözülür, mac doğrulanır ve oosTranData ile provizyon tamamlanır — bu yüzden verify() (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çin BankHttpClient.postXmlForRawBody() eklendi: postXml()'den farkı, yanıtı JSON/XML olarak çözümlemeden ham dizgi olarak dönmesi.
  • Dönüşteki AuthenticationResponse alanı 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 hepsini payment_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. İmza hmac_sha256_b64; bildirim (webhook) doğrulaması düz metin OK yanı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 bir SESSIONTOKEN ile başladığı için createPayment() tamamen override edilir. Dönüş imzasında bilinen bir tuzak var: SD_SHA512 dokü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 olan sdSha512'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ı

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 6
new 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.

Durum

| Alan | Durum | |---|---| | Mimari (DTO'lar, contract'lar, hata hiyerarşisi, Money) | ✅ Kuruldu, tip kontrolünden ve testlerden geçiyor | | FakeGateway | ✅ Çalışıyor, testli | | IyzicoGateway | ⚠️ Protokol taşındı, mock 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 | ⚠️ Şablon-metot tabanı ve Tosla protokolü taşındı, birim testlerden geçiyor — gerçek Tosla test ortamına karşı henüz ölçülmedi. Not: Laravel'e özgü event yayını ve mükerrer-ödeme koruması bilerek bu portta yok (bkz. Mimari) | | AkbankPosGateway | ⚠️ Protokol taşındı, birim testlerden geçiyor — gerçek Akbank test ortamına karşı henüz ölçülmedi | | MokaGateway | ⚠️ Protokol taşındı, birim testlerden geçiyor — gerçek Moka test servisine karşı henüz ölçülmedi | | Xml + BankHttpClient.postXml() + PayForGateway | ⚠️ İlk XML tabanlı sürücü taşındı, birim testlerden geçiyor — gerçek QNB PayFor demo ortamına karşı henüz ölçülmedi. encoding parametresi şimdilik yalnızca UTF-8 için doğru (bkz. Mimari) | | BankHttpClient.postForm() + PayFlexGateway | ⚠️ İki aşamalı MPI/ACS akışı ve prmstr form gövdesi taşındı, birim testlerden geçiyor — gerçek VakıfBank sandbox'ına karşı henüz ölçülmedi | | GarantiGateway | ⚠️ Protokol taşındı, birim testlerden geçiyor — gerçek Garanti test terminaline karşı henüz ölçülmedi | | 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 — ⚠️ ama 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 | ⚠️ İki aşamalı büyük-harf hash + kart token + 3D oturum akışı taşındı, birim testlerden geçiyor — gerçek Paycell test ortamına karşı henüz ölçülmedi | | BankHttpClient.postXmlAsFormField() + PosNetGateway (yapikredi) | ⚠️ Üç adımlı 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) | ⚠️ Protokol taşındı, birim testlerden geçiyor — gerçek Albaraka Türk test ortamına karşı henüz ölçülmedi | | BankHttpClient.postXmlForRawBody() + KuveytPosGateway/VakifKatilimGateway | ⚠️ BOA/TDV2.0 (hazır HTML dönen 3D akışı + URL kodlu 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 | ⚠️ Protokol taşındı, birim testlerden geçiyor — gerçek PayTR test ortamına karşı henüz ölçülmedi | | BankHttpClient.get() + CraftgateGateway | ⚠️ İlk ödeme orkestrasyonu sürücüsü (banka değil, PSP); createPayment() tamamen override edildi. Birim testlerden geçiyor — gerçek Craftgate sandbox'ına karşı henüz ölçülmedi | | ParatikaGateway | ⚠️ Oturum anahtarlı (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.

Kapsam (banka ve ödeme kuruluşları)

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).

Bankalar

| 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 |

Ödeme kuruluşları

| 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 | ⏳ | ⚠️ TMSF kayyımlığında, aktif sürdürülmüyor | | 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 |

Yol haritası

  1. 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
  2. Express/Next.js için ince adapter paketleri
  3. npm'e yayınla

Geliştirme

npm install
npm run typecheck
npm test
npm run build

Lisans

MIT