better-payment
A unified, type-safe payment gateway library for Node.js applications. Integrate multiple Turkish payment providers with a single consistent API.
Introduction
better-payment is an open-source Node.js library that provides a unified API for integrating multiple Turkish payment gateways. Instead of learning and maintaining separate integrations for each provider, you configure them all once and use the same method calls regardless of the provider.
Supported providers:
- İyzico — V2 Authorization, Checkout Form, Subscriptions, Installments
- PayTR — Card Payments, 3D Secure, Hosted Checkout, IBAN Transfer
- Parampos — SOAP API, 3D Secure, Installments, Refund & Cancellation
Installation
Requires Node.js 20+.
npm install better-paymentOr using other package managers:
yarn add better-payment
pnpm add better-paymentQuick Start
Here's everything you need to process your first payment:
import { BetterPayment } from "better-payment";
const payment = new BetterPayment({
defaultProvider: "iyzico",
providers: {
iyzico: {
enabled: true,
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
baseUrl: "https://sandbox-api.iyzipay.com", // or production URL
},
},
});
export default payment;import payment from "@/lib/payment";
export async function POST(req: Request) {
const { amount, buyerInfo } = await req.json();
const result = await payment.createPayment({
price: amount,
currency: "TRY",
buyer: buyerInfo,
basketItems: [
{ id: "item-1", name: "Product", price: amount, category: "General" },
],
billingAddress: {
contactName: buyerInfo.name,
city: "Istanbul",
country: "Turkey",
address: "Billing address here",
},
});
return Response.json(result);
}Configuration
The BetterPayment constructor accepts a configuration object with the following structure:
const payment = new BetterPayment({
defaultProvider: "iyzico", // optional: sets the default provider
providers: {
iyzico: { ... },
paytr: { ... },
parampos: { ... },
},
});| Property | Type | Required | Description |
|---|---|---|---|
| defaultProvider | "iyzico" | "paytr" | "parampos" | No | The provider used when no explicit provider is selected via use(). |
| providers | ProvidersConfig | Yes | An object containing the configuration for each provider. |
İyzico Configuration
| Property | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | Enable or disable this provider. |
| apiKey | string | Yes | Your İyzico API key. |
| secretKey | string | Yes | Your İyzico secret key. |
| baseUrl | string | Yes | API base URL. Use sandbox for testing. |
iyzico: {
enabled: true,
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
baseUrl: "https://sandbox-api.iyzipay.com",
// Production: "https://api.iyzipay.com"
}PayTR Configuration
| Property | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | Enable or disable this provider. |
| merchantId | string | Yes | Your PayTR merchant ID. |
| merchantKey | string | Yes | Your PayTR merchant key. |
| merchantSalt | string | Yes | Your PayTR merchant salt. |
paytr: {
enabled: true,
merchantId: process.env.PAYTR_MERCHANT_ID!,
merchantKey: process.env.PAYTR_MERCHANT_KEY!,
merchantSalt: process.env.PAYTR_MERCHANT_SALT!,
}Parampos Configuration
| Property | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | Enable or disable this provider. |
| clientCode | string | Yes | Your Parampos client code. |
| clientUsername | string | Yes | Your Parampos client username. |
| clientPassword | string | Yes | Your Parampos client password. |
Environment Variables
Store all credentials in environment variables. Never hardcode them.
# İyzico
IYZICO_API_KEY=your_api_key_here
IYZICO_SECRET_KEY=your_secret_key_here
# PayTR
PAYTR_MERCHANT_ID=your_merchant_id
PAYTR_MERCHANT_KEY=your_merchant_key
PAYTR_MERCHANT_SALT=your_merchant_salt
# Parampos
PARAMPOS_CLIENT_CODE=your_client_code
PARAMPOS_USERNAME=your_username
PARAMPOS_PASSWORD=your_password.env files to version control. Add them to .gitignore.API Reference
use(provider)
Switches to a specific provider for the next call. Returns the payment instance for method chaining.
// Use a specific provider for this call
const result = await payment.use("paytr").createPayment({ ... });
// Chain multiple calls
const iyzico = payment.use("iyzico");
const checkout = await iyzico.createCheckoutForm({ ... });createPayment(options)
Creates a standard (non-3D) payment request.
const result = await payment.createPayment({
price: "150.00", // total amount as string
currency: "TRY", // ISO 4217 currency code
buyer: {
id: "user-123",
name: "John",
surname: "Doe",
email: "john@example.com",
identityNumber: "11111111111",
ip: "85.34.78.112",
city: "Istanbul",
country: "Turkey",
address: "Billing address",
zipCode: "34000",
},
basketItems: [
{
id: "item-1",
name: "Product Name",
price: "150.00",
category: "Electronics",
itemType: "PHYSICAL", // or "VIRTUAL"
},
],
billingAddress: {
contactName: "John Doe",
city: "Istanbul",
country: "Turkey",
address: "Nispetiye Cd. No:1",
zipCode: "34000",
},
shippingAddress: { ... }, // optional
});create3DPayment(options)
Creates a 3D Secure payment. Redirects the user to the bank's verification page.
const result = await payment.create3DPayment({
...sameOptionsAsCreatePayment,
callbackUrl: "https://yoursite.com/payment/callback",
});
// result.redirectUrl — redirect the user herecallbackUrl will receive a POST request with the payment result.createCheckoutForm(options)
Creates a hosted checkout form (iframe or redirect). Available for İyzico and PayTR.
const result = await payment.createCheckoutForm({
...sameOptionsAsCreatePayment,
callbackUrl: "https://yoursite.com/payment/callback",
});
// result.checkoutFormContent — inject into your page (İyzico)
// result.redirectUrl — redirect user (PayTR)createSubscription(options)
Creates a recurring/subscription payment. Available for İyzico.
const result = await payment.use("iyzico").createSubscription({
pricingPlanReferenceCode: "your-plan-code",
subscriptionInitialStatus: "ACTIVE",
buyer: { ... },
billingAddress: { ... },
shippingAddress: { ... },
});inquireInstallments(options)
Retrieves available installment options for a card BIN number.
const result = await payment.inquireInstallments({
binNumber: "454671", // first 6 digits of the card
price: "500.00",
currency: "TRY",
});
// result.installmentDetails — array of available installment plansGuides
3D Secure Payments
3D Secure adds an extra layer of authentication. The flow is:
- Call
create3DPayment()with acallbackUrl - Redirect the user to
result.redirectUrl - The bank authenticates the user and POSTs the result to your callback URL
- Verify the result and complete the order
export async function POST(req: Request) {
const body = await req.json();
const result = await payment.create3DPayment({
...body,
callbackUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/api/payment/callback`,
});
return Response.json({ redirectUrl: result.redirectUrl });
}
// app/api/payment/callback/route.ts
export async function POST(req: Request) {
const formData = await req.formData();
const status = formData.get("status");
if (status === "success") {
// Update order in database
}
return Response.redirect("/payment/result");
}Subscription Billing
Use İyzico's subscription API for recurring charges.
// 1. First create a subscription plan in İyzico dashboard
// 2. Then subscribe a customer to that plan
const result = await payment.use("iyzico").createSubscription({
pricingPlanReferenceCode: "MONTHLY_PREMIUM",
subscriptionInitialStatus: "ACTIVE",
buyer: {
gsmNumber: "+905350000000",
name: "John",
surname: "Doe",
identityNumber: "11111111111",
email: "john@example.com",
id: "user-123",
},
billingAddress: { ... },
shippingAddress: { ... },
customer: {
name: "John",
surname: "Doe",
email: "john@example.com",
gsmNumber: "+905350000000",
identityNumber: "11111111111",
billingAddress: { ... },
shippingAddress: { ... },
},
});EFT / IBAN Transfer
PayTR supports EFT and IBAN-based transfers (PWI — Payment With IBAN).
const result = await payment.use("paytr").createPayment({
paymentMethod: "eft",
price: "500.00",
currency: "TRY",
buyer: { ... },
basketItems: [ ... ],
billingAddress: { ... },
});Error Handling
All methods return a result object with a status field. Wrap calls in try/catch for unexpected errors.
try {
const result = await payment.createPayment({ ... });
if (result.status === "success") {
// Payment succeeded
console.log("Payment ID:", result.paymentId);
} else {
// Payment failed — check error message
console.error("Payment failed:", result.errorMessage);
}
} catch (error) {
// Network error, invalid configuration, etc.
console.error("Unexpected error:", error);
}result.status — a resolved promise does not necessarily mean a successful payment.