53 lines
1.9 KiB
TypeScript
53 lines
1.9 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { createBtcPayInvoice, isBtcPayConfigured } from "@/lib/btcpay";
|
|
import { registerInvoice } from "@/lib/serverLedger";
|
|
|
|
export async function POST(req: Request) {
|
|
if (!isBtcPayConfigured()) {
|
|
return NextResponse.json(
|
|
{ ok: false, error: "BTCPay not configured — set BTCPAY_URL, BTCPAY_API_KEY, BTCPAY_STORE_ID in .env.local" },
|
|
{ status: 503 },
|
|
);
|
|
}
|
|
|
|
let body: unknown;
|
|
try { body = await req.json(); } catch {
|
|
return NextResponse.json({ ok: false, error: "Invalid JSON" }, { status: 400 });
|
|
}
|
|
|
|
const { usdAmount, handle } = (body as Record<string, unknown>) ?? {};
|
|
|
|
if (typeof usdAmount !== "number" || usdAmount <= 0 || !Number.isFinite(usdAmount)) {
|
|
return NextResponse.json({ ok: false, error: "usdAmount must be a positive number" }, { status: 400 });
|
|
}
|
|
if (typeof handle !== "string" || !handle.trim()) {
|
|
return NextResponse.json({ ok: false, error: "handle is required" }, { status: 400 });
|
|
}
|
|
if (usdAmount < 0.5) {
|
|
return NextResponse.json({ ok: false, error: "Minimum deposit is $0.50" }, { status: 400 });
|
|
}
|
|
if (usdAmount > 50000) {
|
|
return NextResponse.json({ ok: false, error: "Maximum single deposit is $50,000" }, { status: 400 });
|
|
}
|
|
|
|
const result = await createBtcPayInvoice(usdAmount, handle.trim());
|
|
if (!result.ok) {
|
|
return NextResponse.json({ ok: false, error: result.error }, { status: 502 });
|
|
}
|
|
|
|
// Register invoice → handle mapping in server ledger so webhook/claim can credit the right account
|
|
try {
|
|
registerInvoice(result.invoice.id, handle.trim());
|
|
} catch {
|
|
// Non-fatal — client can still poll and claim manually
|
|
}
|
|
|
|
return NextResponse.json({
|
|
ok: true,
|
|
invoiceId: result.invoice.id,
|
|
checkoutLink: result.invoice.checkoutLink,
|
|
status: result.invoice.status,
|
|
expiresAt: result.invoice.expirationTime,
|
|
});
|
|
}
|