Unified API surface
One method set across every provider. createPayment, refund, cancel — same shapes everywhere.
§01 — The Problem
Different auth schemes, different signing algorithms, different amount units (cents vs minor-units vs decimal strings), even different currency codes for the same money. Cross-region stacks multiply the pain — every gateway you add means another mental model and another integration to maintain.
import Iyzipay from "iyzipay";
const iyzico = new Iyzipay({
apiKey: process.env.IYZICO_API_KEY,
secretKey: process.env.IYZICO_SECRET,
uri: "https://sandbox-api.iyzipay.com",
});
iyzico.threedsInitialize.create({
locale: "tr", price: "100",
paidPrice: "100", currency: "TRY",
paymentCard: { ... }, buyer: { ... },
// 18 more required fields...
}, (err, res) => { /* callback hell */ });// Form-encoded POST. No SDK.
const merchantId = process.env.PAYTR_ID;
const merchantKey = process.env.PAYTR_KEY;
const merchantSalt = process.env.PAYTR_SALT;
const hashStr = merchantId + userIp + orderId
+ email + amount + basket + noInstall
+ maxInstall + currency + testMode
+ merchantSalt;
const token = crypto.createHmac("sha256",
merchantKey).update(hashStr).digest("base64");
await axios.post("/get-token", qs.stringify({
merchant_id: merchantId, paytr_token: token, ...
}));import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SK!, {
apiVersion: "2024-06-20",
});
const intent = await stripe.paymentIntents.create({
amount: 4999, // CENTS, not dollars
currency: "usd", // lowercase
payment_method_types: ["card"],
confirmation_method: "manual",
capture_method: "automatic",
// 3DS via next_action.use_stripe_sdk on client
});
// Webhook signature verification needed.// OAuth2 + HMAC-SHA512 hash
const tokenRes = await axios.post(`${BASE}/auth`, {
client_id: MERCHANT_ID,
client_secret: STORE_KEY,
grant_type: "client_credentials",
});
const accessToken = tokenRes.data.access_token;
const payload = { ...txn, terminal: TERMINAL_ID };
const hashStr = JSON.stringify(payload) + STORE_KEY;
const hash = crypto.createHmac("sha512", STORE_KEY)
.update(hashStr).digest("hex");
await axios.post(`${BASE}/transaction/process`,
{ ...payload, hash },
{ headers: { Authorization: `Bearer ${accessToken}` } });| Concern | Iyzico | PayTR | Stripe | Akbank |
|---|---|---|---|---|
| Auth method | API key + secret | ID + salt + HMAC | Bearer secret | OAuth2 token |
| Signature | none (REST) | HMAC-SHA256 b64 | webhook only | HMAC-SHA512 hex |
| Amount format | "100.00" string | kuruş integer | cents integer | "100.00" string |
| Currency | "TRY" | "TL" | "usd" lowercase | "949" ISO numeric |
| 3DS callback | redirect + POST | iframe + POST | client SDK | redirect + POST |
| Error format | { status, errorCode } | "FAILED" string | { type, code } | { responseCode } |
import { Payfyio } from "payfyio";
const payment = new Payfyio({
defaultProvider: "iyzico",
providers: {
iyzico: { enabled: true, config: { ... } },
paytr: { enabled: true, config: { ... } },
stripe: { enabled: true, config: { ... } },
akbank: { enabled: true, config: { ... } },
},
});
// Same shape. Every provider. Always.
await payment.use("iyzico").initThreeDSPayment(opts);
await payment.use("paytr").initThreeDSPayment(opts);
await payment.use("stripe").initThreeDSPayment(opts);
await payment.use("akbank").initThreeDSPayment(opts);
// Switch providers without changing call sites.Quick Start
$ npm install payfyioimport { Payfyio, ProviderType } from "payfyio";
const payment = new Payfyio({
defaultProvider: ProviderType.IYZICO,
providers: {
iyzico: {
enabled: true,
config: {
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
baseUrl: process.env.IYZICO_BASE_URL!,
},
},
},
});
export default payment;import payment from "@/lib/payment";
// Unified API — works identically for every provider
const result = await payment.createPayment({
price: "100.00",
currency: "TRY",
buyer: { id: "usr-123", ... },
basketItems: [ ... ],
});
// Or switch to a different provider at runtime
const checkout = await payment.use("paytr").initThreeDSPayment({ ... });Global & Regional Gateways
Example usage
// Stripe PaymentIntent + 3DS
const result = await payment.use("stripe")
.createPayment({
price: "49.99", currency: "USD",
paymentCard: { ... },
buyer: { ... }
});
// Same shape across every providerGlobal · PaymentIntents API · 135+ currencies
Stripe PaymentIntents with 3D Secure (SCA) flow. Cards, wallets, and 135+ currencies — same payfyio interface, no Stripe SDK lock-in.
Capabilities
Regional Bank Rails · Turkey
Native Virtual POS rails — no third-party gateway, full control over settlement and hash signing. Turkey live below; EU · UK · MENA · LATAM banks shipping next.
Sanal POS · Direct Integration
Direct integration with Akbank's Virtual POS API. OAuth2 token authentication, HMAC-signed requests, and full support for both 2D and 3D Secure payment flows — no intermediary gateway.
OAuth2 Auth
Token-based authentication
2D & 3D Secure
Both flows supported
Hash Verified
HMAC request signing
Direct API
No third-party middleware
Integration example
import { Payfyio } from "payfyio";
const payment = new Payfyio({
providers: {
akbank: {
enabled: true,
config: {
merchantId: process.env.AKBANK_MERCHANT_ID!,
terminalId: process.env.AKBANK_TERMINAL_ID!,
storeKey: process.env.AKBANK_STORE_KEY!,
baseUrl: "https://apiprod.akbank.com",
},
},
},
});
// 3D Secure initialization
const init = await payment.akbank.initThreeDSPayment({
price: "250.00",
currency: "TRY",
callbackUrl: "https://yoursite.com/akbank/callback",
paymentCard: { ... },
buyer: { ... },
});Hand-crafted primitives. No SaaS. No telemetry. No lock-in. One dependency tree, audited end-to-end. Read the source, ship the code.
One method set across every provider. createPayment, refund, cancel — same shapes everywhere.
Full type definitions out of the box. Catch payment errors at compile time, not in production.
Only axios as a peer dependency. Lean bundle. Clean dependency tree. No bloat.
HMAC-SHA256 signature validation, 3D Secure support, no credential exposure in transport.
PayfyioHandler turns your config into a full REST API — drop-in for Next.js or Express.
payment.use("paytr") at runtime. A/B test gateways without touching call sites.
Card, 3DS, EFT/IBAN, hosted checkout, installments, subscriptions — fully unified.
İyzico subscription APIs — products, pricing plans, card update — through the unified handler.
↳ THE HOSTED EDITION
payfyio cloud hosts the payment plumbing. You bring the GitHub repo and the merchant credentials. We seal them, expose a single embeddable snippet, and route every charge through the same Payfyio instance you already know — server-side, PCI-scoped to us.
OAuth-only auth. Pick a repo to link your project — stable repoId tracked across renames.
Provider keys sealed with AES-256-GCM, per-row IV. Versioned master key, rotatable. Plaintext never logged.
Copy a single <script> tag with your publishable key. Hosted iframe checkout opens — keys never leave our backend.
↳ SNIPPET / EMBED
Drop the loader script on any page. The iframe inherits your active providers, your origin allowlist, and your credential rotation — without re-deploying.
<script
src="https://payfyio.cloud/p/proj_8f2a1c.js"
data-amount="100"
data-currency="TRY"
data-order-id="ORD-2026-0042"
></script>Run two İyzico merchants on one project. Route by label.
Switch which gateways are live without touching code.
Iframe only loads on your registered domains. CSP frame-ancestors enforced.
Amount and currency HMAC-signed. Client cannot tamper.
§00
Compatible runtimes
One package. Global gateways plus regional bank rails — Turkey live, more regions shipping. Self-host the npm SDK or skip the backend entirely with payfyio cloud.