ExtraPayTR
Türk ödeme sağlayıcıları için framework'ten bağımsız, asenkron bir Rust SDK'sı. Sadece resmi sağlayıcı dokümantasyonlarından, sıfırdan ("clean-room") yazıldı — bu kodu üretmek için mevcut hiçbir Node.js/TypeScript/PHP ödeme SDK'sı okunmadı veya kopyalanmadı.
Durum: erken geliştirme aşaması. Prodüksiyona hazır değil, PCI denetimi
yapılmamış. Tek bir sağlayıcının (iyzico) uygulanan tüm işlemleri —
Charge (3DS'siz ve 3DS'li), CallbackVerification, Query, Refund,
Cancel — gerçek bir sandbox'a karşı çalıştırıldı; geri kalan her şey
çalıştırılmadı. Aşağıdaki Doğrulama durumu bölümüne
ve her sağlayıcının docs/providers/*.md dosyasına bakarak tam olarak
neyin test edilip neyin edilmediğini görebilirsiniz.
Workspace düzeni
extrapaytr/
├── crates/
│ ├── extrapaytr-core/ domain tipleri: Money, request/response'lar, Gateway trait'leri, hatalar, secret'lar
│ ├── extrapaytr-http/ HttpTransport trait'i + reqwest/rustls implementasyonu
│ ├── extrapaytr-crypto/ HMAC-SHA256/SHA-512, base64, hex, sabit-zamanlı karşılaştırma
│ ├── extrapaytr-gateways/ gerçek sağlayıcı adaptörleri, sağlayıcı başına bir Cargo feature'ı
│ ├── extrapaytr/ yukarıdakileri yeniden export eden ince bir facade
│ └── extrapaytr-node/ napi-rs Node.js bindings (JS'ten ayrı bir paket, bkz. aşağıdaki JS bölümü)
└── docs/providers/ sağlayıcı başına bir dosya: incelenen dokümanlar, endpoint'ler, eksikler, durum
extrapaytr-core, reqwest, serde_json veya herhangi bir
sağlayıcıya özel crate'e bağımlı değildir — sağlayıcıya özgü wire
formatları tamamen extrapaytr-gateways içinde yaşar.
Sağlayıcılar
| Sağlayıcı | Protokol | 3DS | Refund | Cancel | Query | Doğrulama |
|---|---|---|---|---|---|---|
| iyzico | REST/JSON | Var (init+complete+callback, hepsi SandboxVerified) | Var | Var | Var | Uygulanan her işlem için (Charge 3DS'siz, Charge 3DS'li, CallbackVerification, Query, Refund, Cancel) SandboxVerified — gerçek sandbox çalıştırması 2026-08-12 (bkz. docs/providers/iyzico.md) |
| PayTR | Form-post + host edilen 3DS yönlendirmesi | Var (HTML challenge + notify_url callback'i, ayrı bir "complete" çağrısı yok) |
Var | Yok (ayrı endpoint yok; tam tutarlı iade kullanılıyor) | Var | FixtureTested (bkz. docs/providers/paytr.md) |
| Paratika | Sunucudan sunucuya, düz metin kimlik bilgileri | Yok (bloklandı — dökümana bakın) | Yok (bloklandı — dökümana bakın) | Yok (bloklandı — dökümana bakın) | Yok (bloklandı — dökümana bakın) | Sadece response-hash (sdSha512) doğrulaması: FixtureTested; geri kalan her şey: Skeleton (bkz. docs/providers/paratika.md) |
| Moka | REST/JSON, sunucudan sunucuya | Var (sadece yönlendirme; son-callback hash'i doğrulanmadı) | Yok (sadece pazaryeri'ne özel bir endpoint bulundu) | Yok (endpoint doğrulandı ama response'ta amount alanı yok) | Var (status kodları yorumlanmadı) | Charge/Query için FixtureTested; Refund/Cancel uygulanmadı (bkz. docs/providers/moka.md) |
| Garanti BBVA (GVPS) | XML sunucudan sunucuya + 3DS tarayıcı form-post'u | Var (sadece form-post başlatma; son-callback hash'i doğrulanmadı) | Var (bir doğrulanmamış hash-alan varsayımı — dökümana bakın) | Yok (endpoint doğrulandı ama core'un CancelRequest'inin taşımadığı bir amount alanı gerekiyor) |
Yok (order-inquiry Type değeri doğrulanmadı) |
Charge/Refund için FixtureTested (bkz. docs/providers/garanti.md) |
| NestPay/EST (Ziraat profili) | 3D Pay Hosting tarayıcı form-post'u | Var (form-post başlatma + callback doğrulaması; 3DS'siz akış doğrulanmadı) | Yok (sunucudan sunucuya /fim/api şekli doğrulanmadı) |
Yok (aynı) | Yok (aynı) | Charge/CallbackVerification için FixtureTested (bkz. docs/providers/nestpay.md). Paylaşılan bir motor — birçok başka banka tarafından da kullanılıyor, ama sadece Ziraat'in host'u doğrulandı; QNB bu motoru kullanmıyor (kendine ait ayrı bir gateway'i var, araştırılmadı). |
| Kuveyt Türk (Freepos) | XML sunucudan sunucuya, sadece 3D Secure Model | Var (Request 1 → challenge → callback → Request 2, hepsi uygulandı) | Yok (endpoint/alan şekli doğrulanmadı) | Yok (aynı) | Yok (aynı) | Charge/complete_three_ds/CallbackVerification için FixtureTested — resmi dokümanın kendi 5 çalışan hash örneğinden 4'ü birebir yeniden üretildi (bkz. docs/providers/kuveytturk.md) |
| Craftgate | — | — | — | — | — | Bloklandı: geliştirici portalı tamamen giriş gerektiriyor (headless fetch ve gerçek bir render edilmiş tarayıcı ile doğrulandı); herkese açık döküman veya OpenAPI spec'i bulunamadı. Bu turda atlandı. |
| PosNet (Yapı Kredi) | — | — | — | — | — | Bloklandı: bulunan tek resmi PDF entegrasyon kılavuzu (m.yapikredipos.com.tr) süresi dolmuş bir TLS sertifikası üzerinden sunuluyor — iki bağımsız araçla doğrulandı (WebFetch, tarayıcı navigasyonu), kullanılabilir bir yansı (mirror) bulunamadı. Bu turda atlandı. |
| Akbank Sanal Pos | — | — | — | — | — | Bloklandı: web araması üzerinden erişilebilir resmi entegrasyon dokümantasyonu bulunamadı. Bu turda atlandı. |
Orijinal proje kontrol listesinde adı geçen diğer tüm sağlayıcılar (PayFor/PayFlex aileleri, ...) başlanmadı.
Hızlı başlangıç
use Arc;
use ;
use ;
use ;
# async
Sağlayıcı başına ilgili feature gerekir (gateway-iyzico,
gateway-paytr, gateway-paratika, gateway-moka, gateway-garanti,
gateway-nestpay, gateway-kuveytturk, ya da uygulanan hepsi için
all-gateways):
Sağlayıcıyı çalışma zamanında seçmek
Yukarıdaki hızlı başlangıçta IyzicoGateway kaynak kodda doğrudan
isimlendirilir — bu, sağlayıcı derleme zamanında biliniyorsa doğru
seçimdir: somut tip yalnızca uyguladığı işlemleri açığa çıkarır, bu
yüzden desteklenmeyen bir çağrı derleme hatasıdır. Sağlayıcı bunun
yerine yapılandırmadan geliyorsa (bir env değişkeni, kiracı başına bir
veritabanı kolonu), registry'yi kullanın:
use ;
let registry = with_builtin;
let settings = new
.with
.with
.with;
let gateway = registry.build?;
let response = gateway.charge.await?;
build, her işlemi tek biçimde açığa çıkaran bir GatewayHandle
döndürür. Dispatch'ten önce adaptörün beyan ettiği yetenekleri
(capabilities) kontrol eder, böylece bir sağlayıcının yapmadığı bir
işlem her zaman UnsupportedOperation ile cevap verir — adaptör
trait'i tamamen atlamış olsun ya da hata veren bir stub olarak
uygulamış olsun fark etmez (PayTR'ın Cancel'i ikincisi). Anahtar
isimlerinin koda gömülü olmasına gerek kalmasın diye
ProviderRegistry::spec, her sağlayıcının hangi ayarları kabul
ettiğini raporlar. Bkz. docs/registry.md.
JavaScript / Node.js
crates/extrapaytr-node, ince bir napi-rs
bağlama (binding) katmanıdır — burada hiçbir ödeme mantığı yaşamaz, her
metod bir JS değerini içeri alır, yukarıda dokümante edilen aynı Rust
API'sini çağırır ve sonucu geri dönüştürür. Rust API'si gibi
registry-tabanlıdır: JS yüzeyi koda gömülü bir Iyzico tipi yerine bir
sağlayıcı id string'i alır.
const = require;
const registry = ;
const gateway = registry.;
const response = await gateway.;
Para birimi, sınırı her zaman bir decimal string artı bir ISO para
birimi kodu olarak geçer — asla bir JS number değil — Rust API'sinin
hiçbir zaman float kullanmamasıyla aynı sebepten. Gateway, tam işlem
setini açığa çıkarır (charge, refund, cancel, query,
completeThreeDs, verifyCallback, storeCard, listCards,
deleteCard); bir sağlayıcının desteklemediği işlem, Rust tarafındaki
gibi throw eder.
Bu pakette sadece "iyzico" SandboxVerified — yukarıdaki
sağlayıcı tablosuyla aynı iddia, aynı çekince; bindings yeni bir
yetenek, yeni bir doğrulama değil. Desteklenen platformlar: sadece
Linux ve Windows — macOS bilinçli olarak kapsam dışı bırakıldı. Bu
paket bu geliştirme makinesinde hiç derlenmedi (aktif Windows
toolchain'i napi-rs'in yerelde ihtiyaç duyduğu parçalardan yoksun —
crate'in kendi notlarına bakın), ama
.github/workflows/napi-build.yml
üzerinden gerçek CI'da hem windows-latest (MSVC) hem
ubuntu-latest'te derlendi ve kendi JS test suite'i geçti — asıl
doğrulama bu, yukarıdaki açıklama değil.
Build ve test
.github/workflows/ci.yml, yukarıdakilerin
hepsini her push/PR'da çalıştırır, ayrıca EmbarkStudios/cargo-deny-action
üzerinden cargo-deny (lisans/advisory/yinelenen-bağımlılık
kontrolleri) çalıştırır. deny.toml yapılandırması bu turda yeni ve
yerelde hiç çalıştırılmadı — bu geliştirme ortamında cargo-deny
kurulu değil — bu yüzden ilk CI çalıştırmasını bir formalite değil, asıl
ilk kontrol olarak kabul edin.
Tasarım ilkeleri
- Para asla float değildir.
Money, para birimi başına tam sayı minor-unit sayısı (kuruş/cent) tutar; bkz.extrapaytr-core::money. - Secret'lar tiplidir. API anahtarları, secret anahtarlar, PAN ve
CVV, redakte edilmiş
Debugçıktısına sahipsecrecy::SecretStringtipindedir. success: true'ya kör güven yok. Bu SDK'nın onaylanmış bir charge/refund/query sonucu olarak kabul ettiği her response, önce sağlayıcının verdiği imza doğrulamasından geçer (istisnalar için her sağlayıcının dökümanına bakın, örn. iyzico'nun/payment/cancel'i — bu bir gözden kaçırma değil, dokümante edilmiş bir eksik).- Belirsiz sağlayıcı response'ları hiçbir zaman tahmini bir
Succeeded'a değil,PaymentStatus::Unknown'a eşlenir. - Uydurulmuş protokol detayı yok. Resmi dokümanların bir alanın
formatını/zorunluluğunu belirtmediği yerlerde, kod ya kapalı şekilde
başarısız olur (bir hata döner) ya da
TODO(PROVIDER-DOC-GAP)ile işaretlenir — bkz. her sağlayıcının dökümanı.
Doğrulama durumu
extrapaytr_core::VerificationStatus'a göre:
MockOnly sadece repo içi bir sahte (fake) implementasyona karşı kullanılabilir, gerçek protokol yok
Skeleton tipler/imzalar var, request/response eşlemesi yok
ProtocolImplemented eşleme + imzalama resmi dokümanları takip eder, doğrulanmadı
FixtureTested wiremock + golden/pinlenmiş vektörlere karşı çalıştırıldı
SandboxVerified sağlayıcının gerçek sandbox'ına karşı çalıştırıldı
ProductionVerified prodüksiyonda çalıştırıldı
iyzico'nun uyguladığı her işlem — Charge (3DS'siz ve tam 3DS'li),
CallbackVerification, Query, Refund ve Cancel — SandboxVerified:
2026-08-12'de iyzico'nun gerçek sandbox'ına karşı uçtan uca çalıştırıldı,
buna iyzico'nun sahte 3DS SMS challenge'ını tamamlayan gerçek bir
tarayıcı ve yakalanmış, imzası doğrulanmış bir callback de dahil. Bunun
ortaya çıkardığı ve düzeltilen gerçek protokol eksiklikleri için —
bunlara bir threeDSHtmlContent base64-decode hatası, dokümanların
var olduğunu ima etmesine rağmen aslında var olmadığı ortaya çıkan bir
CallbackVerification implementasyonu ve iyzico'nun hata-üretici test
kartlarından yakalanan tam errorGroup sözlüğü dahil — bkz.
docs/providers/iyzico.md.
Bu repodaki diğer tüm sağlayıcı/işlem en fazla FixtureTested —
gerçek bir sandbox veya prodüksiyon endpoint'ine karşı çalıştırılmadı.
PCI-DSS kapsam uyarısı
Bir RawCard (düz metin PAN/CVV) oluşturan, saklayan veya ileten her
kod yolu PCI-DSS kapsamındadır. Bu SDK PCI uyumluluğu sağlamaz — bu,
onu kullanan sistemlerin sorumluluğundadır. Bir sağlayıcı destekliyorsa
tokenize edilmiş kart saklamayı (TokenizedCard) tercih edin.
Somut olarak, CardStorage ile (bugün iyzico): PAN, store_card'da
bir kez tel üzerinden geçer ve asla geri döndürülmez — sonrasında
sadece bir token artı görüntüleme parçaları (BIN, son dört hane,
marka) elinizde kalır, böylece saklanan bir kartı göstermek kart
numarasına ihtiyaç duymaz.
Ama token'ı bir referans değil, bir kimlik bilgisi (credential)
olarak muamele edin. iyzico'da saklı-kart ile yapılan bir ödeme ne
CVV ne de ikinci faktör ister, bu yüzden (cardUserKey, cardToken)
çiftine sahip olan herkes o kartı çekebilir. Bunu dinlenme halindeyken
şifreleyin ve erişimini bir API anahtarına yaklaşacağınız şekilde
kapsamlandırın — sealing feature'ı tam olarak bunun için AES-256-GCM
sağlar:
use SealingKey;
let key = from_hex?;
let sealed = key.seal?;
// ...`sealed`'ı kaydedin; geri almak için `key.open(&sealed)?`.
Tam tehdit modeli, cardUserKey/cardToken eşleştirme tehlikesi ve
hangi sağlayıcı response'larının imza doğrulaması yapılmadığı için bkz.
SECURITY.md.
Bu turdaki bilinen eksikler
- CI (
.github/workflows/ci.yml) ve bircargo-denyyapılandırması (deny.toml) artık mevcut ama hiç gerçekten çalışmadı (bu turda henüz bir remote'a push yapılmadı, vecargo-denyyerelde kurulu değil) — ilk gerçek CI çalıştırmasını bir formalite değil, ilk kontrol olarak kabul edin. Henüz coverage tooling'i yok. - Card-on-file sadece iyzico için uygulandı (sandbox-verified);
başka hiçbir adaptörün kart saklaması araştırılmadı, bu yüzden
PaymentMethod::Tokenizedgeri kalanında hâlâUnsupportedOperationdöndürüyor. iyzico'nun kart-saklama response'ları sağlayıcı tarafından imzalanmamış — dokümante edilmiş bir eksik, gözden kaçırma değil. - İki fazlı auth:
Authorize/Capturetrait'leri core'da var ama hiçbir adaptör bunları uygulamıyor (her biriauthorize: falsebeyan ediyor), bu yüzden pre-auth/settle akışları kullanılamaz. - crates.io'ya veya npm'e yayınlanmadı.
- Node.js bindings'i (
crates/extrapaytr-node) bu turda yeni; yazan geliştirme makinesinde hiç derlenemedi (bkz. crate'in kendi notları) ama gerçek CI'da (windows-latest/MSVC veubuntu-latest) derlendi ve kendi JS test suite'i geçti. Desteklenen platformlar bilinçli olarak sadece Linux ve Windows — macOS kapsam dışı. - Gerçek iş yapılan yedi sağlayıcı (iyzico, PayTR ve Kuveyt Türk tam; Paratika, Moka, Garanti BBVA ve NestPay/EST kısmi — tam olarak neyin eksik olduğu ve nedeni için kendi dökümanlarına bakın); Craftgate, PosNet (Yapı Kredi) ve Akbank bloklandı (sırasıyla giriş-gerektiren dokümanlar / süresi dolmuş TLS sertifikası / herkese açık döküman bulunamadı); bkz. yukarıdaki sağlayıcı tablosu. Bunlardan sadece iyzico gerçek bir sandbox'a karşı çalıştırıldı — bkz. Doğrulama durumu.