payfyio
Integrations

Next.js Integration

Complete guide for integrating payfyio with Next.js App Router.

Setup

1. Create the singleton

// lib/payment.ts
import { Payfyio, ProviderType } from 'payfyio';

let _instance: Payfyio | null = null;

export function getPayfyio(): Payfyio {
  if (!_instance) {
    _instance = 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 ?? 'https://sandbox-api.iyzipay.com',
          },
        },
      },
    });
  }
  return _instance;
}

Use lazy initialization (a function, not a module-level new Payfyio(...)) to avoid crashes during Next.js static page generation when env vars are not available.

2. Create the catch-all route handler

// app/api/pay/[...path]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getPayfyio } from '@/lib/payment';
import type { PayfyioRequest } from 'payfyio';

async function handler(req: NextRequest): Promise<NextResponse> {
  const contentType = req.headers.get('content-type') ?? '';
  let body: unknown;

  if (req.method !== 'GET' && req.method !== 'HEAD') {
    if (contentType.includes('application/json')) {
      body = await req.json().catch(() => undefined);
    } else if (contentType.includes('application/x-www-form-urlencoded')) {
      const fd = await req.formData();
      const obj: Record<string, string> = {};
      fd.forEach((v, k) => { obj[k] = v as string; });
      body = obj;
    }
  }

  const payfyioReq: PayfyioRequest = {
    method: req.method,
    url: req.url,
    headers: Object.fromEntries(req.headers.entries()),
    body,
  };

  const res = await getPayfyio().handler.handle(payfyioReq);

  return NextResponse.json(res.body, {
    status: res.status,
    headers: res.headers,
  });
}

export const GET = handler;
export const POST = handler;

3. Configure environment variables

# .env.local
IYZICO_API_KEY=your-api-key
IYZICO_SECRET_KEY=your-secret-key
IYZICO_BASE_URL=https://sandbox-api.iyzipay.com

Making Payments from the Frontend

// Client-side payment initiation
const response = await fetch('/api/pay/iyzico/create', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    price: '100.00',
    paidPrice: '100.00',
    currency: 'TRY',
    // ...
  }),
});

const result = await response.json();

3D Secure Flow

// 1. Initialize from Server Action or API Route
const init = await fetch('/api/pay/iyzico/3ds/init', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ...paymentData, callbackUrl: `${origin}/payment/callback` }),
});

const { htmlContent } = await init.json();

// 2. Display htmlContent in an iframe or dangerouslySetInnerHTML
// 3. Handle callback in a separate route

Callback Route

// app/payment/callback/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getPayfyio } from '@/lib/payment';

export async function POST(req: NextRequest) {
  const body = await req.formData();
  const paymentId = body.get('paymentId') as string;
  const conversationId = body.get('conversationId') as string;

  const result = await getPayfyio().iyzico.completeThreeDSPayment({
    paymentId,
    conversationId,
  });

  if (result.status === 'success') {
    return NextResponse.redirect(new URL('/payment/success', req.url));
  }

  return NextResponse.redirect(new URL('/payment/failure', req.url));
}

On this page