Quick Start
Make your first payment in under 5 minutes.
1. Create the payment object
import { betterPayment, iyzico } from 'better-payment';
export const payment = betterPayment({
mode: 'sandbox', // sandbox URLs and provider test modes; default is 'production'
providers: {
iyzico: iyzico({
apiKey: process.env.IYZICO_API_KEY!,
secretKey: process.env.IYZICO_SECRET_KEY!,
}),
},
});2. Build a Payment Request
Build the request on the server from your own order data. Never take amounts from the browser.
import { Currency, BasketItemType } from 'better-payment';
const request = {
price: '100.00',
paidPrice: '100.00',
currency: Currency.TRY,
installment: 1,
basketId: 'B67832',
conversationId: 'ORDER123', // your order id (letters and digits only for PayTR)
paymentCard: {
cardHolderName: 'John Doe',
cardNumber: '5528790000000008',
expireMonth: '12',
expireYear: '2030',
cvc: '123',
},
buyer: {
id: 'BY789',
name: 'John',
surname: 'Doe',
gsmNumber: '+905350000000',
email: 'johndoe@example.com',
identityNumber: '74300864791',
registrationAddress: 'Nidakule Göztepe, Merdivenköy Mah.',
city: 'Istanbul',
country: 'Turkey',
ip: '85.34.78.112',
},
shippingAddress: {
contactName: 'Jane Doe',
city: 'Istanbul',
country: 'Turkey',
address: 'Nidakule Göztepe, Merdivenköy Mah.',
},
billingAddress: {
contactName: 'Jane Doe',
city: 'Istanbul',
country: 'Turkey',
address: 'Nidakule Göztepe, Merdivenköy Mah.',
},
basketItems: [
{
id: 'BI101',
name: 'Binocular',
category1: 'Collectibles',
itemType: BasketItemType.PHYSICAL,
price: '100.00',
},
],
};3. Start 3D Secure
const init = await payment.initThreeDSPayment({
...request,
callbackUrl: 'https://yoursite.com/api/pay/iyzico/payment/complete-3ds',
});
if (init.status === 'pending') {
// Render init.threeDSHtmlContent in the browser
// (or redirect to init.redirectUrl when the provider returns one)
}4. Complete 3D Secure
The bank POSTs the result to callbackUrl. Pass that POST body as it is:
const result = await payment.completeThreeDSPayment(callbackBody);
if (result.status === 'success') {
// mark the order as paid
}The library checks the callback with your credentials and, when the provider
requires it, finalizes the payment. A forged or failed callback always returns
failure. The HTTP handler does this for you.
5. Handle results
| status | meaning |
|---|---|
success | Confirmed by the provider |
failure | Rejected; see errorCode / errorMessage |
pending | Waiting for the customer, or the outcome is unknown (errorCode: 'NETWORK_ERROR') |
cancelled | Voided or fully refunded (status queries) |
On NETWORK_ERROR the payment may still have gone through. Check it with getPayment(paymentId) before trying again. Payment, refund and cancel requests are never retried automatically.
Using Multiple Providers
const payment = betterPayment({
providers: {
iyzico: iyzico({ /* ... */ }),
paytr: paytr({ /* ... */ }),
},
defaultProvider: 'iyzico',
});
await payment.createPayment(request); // default provider
await payment.paytr.initThreeDSPayment(paytrRequest); // specific provider
await payment.use('paytr').getPayment('ORDER123');Update orders with events
Instead of checking every result, listen to payment events. They are emitted for every provider and flow, after the provider verified the result:
payment.on('payment.succeeded', async (event) => {
await orders.markPaid(event.conversationId, event.paymentId);
});
payment.on('payment.failed', async (event) => {
await orders.markFailed(event.conversationId, event.code);
});