Refactor: Fully migrated to direct PostgreSQL, implemented Public API v1, fixed Vercel deployment conflicts, and updated documentation
This commit is contained in:
129
app/api/v1/checkout/route.ts
Normal file
129
app/api/v1/checkout/route.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import { validateApiKey } from '@/lib/api-auth';
|
||||
import { CryptoEngine } from '@/lib/crypto-engine';
|
||||
import { PaymentProviderFactory } from '@/lib/payment-providers';
|
||||
|
||||
/**
|
||||
* Public API for Merchants to create a payment session
|
||||
* POST /api/v1/checkout
|
||||
* Header: x-api-key: YOUR_API_KEY
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const apiKey = req.headers.get('x-api-key');
|
||||
const merchant = await validateApiKey(apiKey);
|
||||
|
||||
if (!merchant) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized. Invalid API Key.' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
amount,
|
||||
currency = 'TRY',
|
||||
order_id,
|
||||
callback_url,
|
||||
customer_name,
|
||||
customer_phone,
|
||||
success_url,
|
||||
cancel_url
|
||||
} = await req.json();
|
||||
|
||||
if (!amount) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Amount is required.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 1. Determine provider
|
||||
const provider = merchant.payment_provider || 'stripe';
|
||||
const useMock = process.env.NEXT_PUBLIC_USE_MOCK_PAYMENTS === 'true';
|
||||
|
||||
let clientSecret = '';
|
||||
let providerTxId = '';
|
||||
let nextAction = 'none';
|
||||
let redirectUrl = '';
|
||||
|
||||
// Generate Temporary Wallets for Crypto fallback
|
||||
const evmWallet = await CryptoEngine.createTemporaryWallet('POLYGON');
|
||||
const solWallet = await CryptoEngine.createTemporaryWallet('SOLANA');
|
||||
|
||||
const cryptoWallets = {
|
||||
EVM: { address: evmWallet.address, privateKey: evmWallet.privateKey },
|
||||
SOLANA: { address: solWallet.address, privateKey: solWallet.privateKey }
|
||||
};
|
||||
|
||||
if (useMock) {
|
||||
clientSecret = 'mock_secret_' + Math.random().toString(36).substring(7);
|
||||
providerTxId = clientSecret;
|
||||
} else {
|
||||
// Use Factory to create intent based on provider (Stripe, etc.)
|
||||
const intent = await PaymentProviderFactory.createIntent(provider, {
|
||||
amount,
|
||||
currency,
|
||||
merchantId: merchant.id,
|
||||
refId: order_id,
|
||||
customerName: customer_name,
|
||||
customerPhone: customer_phone,
|
||||
callbackUrl: callback_url || success_url,
|
||||
providerConfig: merchant.provider_config
|
||||
});
|
||||
|
||||
clientSecret = intent.clientSecret;
|
||||
providerTxId = intent.providerTxId;
|
||||
nextAction = intent.nextAction || 'none';
|
||||
redirectUrl = intent.redirectUrl || '';
|
||||
}
|
||||
|
||||
// 2. Insert Transaction into DB
|
||||
const txResult = await db.query(`
|
||||
INSERT INTO transactions (
|
||||
amount, currency, status, stripe_pi_id, source_ref_id,
|
||||
customer_name, customer_phone, callback_url, merchant_id,
|
||||
provider, metadata
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id
|
||||
`, [
|
||||
amount, currency, 'pending', providerTxId, order_id,
|
||||
customer_name, customer_phone, callback_url || success_url, merchant.id,
|
||||
provider, JSON.stringify({
|
||||
nextAction,
|
||||
redirectUrl,
|
||||
wallets: cryptoWallets,
|
||||
success_url,
|
||||
cancel_url
|
||||
})
|
||||
]);
|
||||
|
||||
const txId = txResult.rows[0].id;
|
||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
|
||||
|
||||
// 3. Return response with checkout URL
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
id: txId,
|
||||
amount,
|
||||
currency,
|
||||
order_id,
|
||||
checkout_url: `${baseUrl}/checkout?session_id=${txId}`,
|
||||
status: 'pending',
|
||||
wallets: {
|
||||
EVM: evmWallet.address,
|
||||
SOLANA: solWallet.address
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Public API Error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user