Unified API surface
createPayment, initThreeDSPayment, refund, cancel and getPayment take the same request types on every provider and return the same result shape.
Better Payment gives iyzico, PayTR, Parampos and Akbank one type-safe interface, with signature-verified callbacks and a secure-by-default HTTP handler.
Different request shapes, signatures, error formats and callback rules. Better Payment implements each one against the provider's specification and gives you one set of types to work with.
Payment gateway
IYZWSv2-signed JSON API with non-3D and 3D Secure payments, a hosted checkout form, pay with IBAN (PWI), subscriptions, and BIN and installment queries.
Capabilities
// JSON body + IYZWSv2 signature on every request
const rnd = Date.now() + "123456789";
const uri = "/payment/iyzipos/checkoutform/initialize/auth/ecom";
const signature = createHmac("sha256", secretKey)
.update(rnd + uri + JSON.stringify(body))
.digest("hex");
const auth = btoa(
`apiKey:${apiKey}&randomKey:${rnd}&signature:${signature}`,
);
const res = await fetch(baseUrl + uri, {
method: "POST",
headers: {
Authorization: "IYZWSv2 " + auth,
"x-iyzi-rnd": rnd,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
// Map iyzico's status and error codes yourself// Hosted checkout form
const result = await payment.iyzico.initCheckoutForm({
price: "100.00",
paidPrice: "100.00",
currency: "TRY",
basketId: "B1",
callbackUrl: "https://yoursite.com/checkout/callback",
buyer: { ... },
basketItems: [ ... ],
});
// Render result.checkoutFormContent on your page
result.status; // "success" | "failure" | "pending"createPayment, initThreeDSPayment, refund, cancel and getPayment take the same request types on every provider and return the same result shape.
No runtime dependencies, ESM and CJS builds, and a browser-safe client. Runs on Node.js, Vercel Edge, Cloudflare Workers, Deno and Bun.
3D Secure callbacks and PayTR notifications are checked against your own credentials, in constant time, before anything counts as paid.
The HTTP handler exposes only callbacks and card queries by default. Refunds, cancels and lookups require an authorize hook.
A timeout returns pending with NETWORK_ERROR instead of guessing. Payment, refund and cancel requests are never retried automatically.
Talk to a bank's virtual POS directly, without a payment institution in between, using the same request and result types.
Sanal POS · direct integration
Akbank's Sanal POS JSON API with HMAC-SHA512 signed requests, signature-verified 3D Secure (3D_PAY) callbacks, refunds, voids and order status queries.
View Akbank docsScroll to explore what's next
A new provider, a clearer guide, a test that catches a bug. Every contribution makes Better Payment better for everyone.
Built in the open. Improved together.
All contributors on GitHub$ npm install better-paymentimport { betterPayment, iyzico } from "better-payment";
export const payment = betterPayment({
mode: "sandbox", // test URLs and provider test modes
providers: {
iyzico: iyzico({
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
}),
},
});import { payment } from "@/lib/payment";
const result = await payment.iyzico.initThreeDSPayment({
price: "100.00",
paidPrice: "100.00",
currency: "TRY",
basketId: "B1",
callbackUrl: "https://yoursite.com/api/pay/iyzico/payment/complete-3ds",
paymentCard: { ... },
buyer: { ... },
shippingAddress: { ... },
billingAddress: { ... },
basketItems: [ ... ],
});
// Render result.threeDSHtmlContent. The bank posts back to callbackUrl,
// where the handler verifies the result before you mark the order paid.
One package for iyzico, PayTR, Parampos and Akbank, with full TypeScript support. Upgrading from 3.x? Read what's new since the reset.