Project: One-Time Purchase and License Key Delivery
In this project, we will build a one-time purchase billing workflow. When a user buys our software application, we will verify the purchase webhook, generate a license key, save it to PostgreSQL, and email it using the Resend API.
1. Lifecycle Event Ingestion
graph TD
A[Customer pays once on checkout] --> B[Paddle triggers transaction.completed]
B --> C[Server generates a License Key]
C --> D[Save Key in Database]
D --> E[Email Key to Customer via Resend]2. Webhook Event Processing Action
In your Webhook route, monitor the transaction.completed event:
// app/api/webhooks/paddle/route.ts (One-time transaction snippet)
import { prisma } from "../../../lib/prisma";
import { resend } from "../../../lib/resend";
import crypto from "crypto";
export async function handleTransactionComplete(event: any) {
const data = event.data;
// 1. Double check the transaction is fully paid and billed
if (data.status !== "completed") return;
const email = data.customer?.email || data.billingDetails?.email;
const transactionId = data.id;
if (!email) {
console.error("Missing customer email details in transaction:", transactionId);
return;
}
// 2. Prevent duplicate code processing by checking if this transaction already generated keys
const existingKey = await prisma.licenseKey.findUnique({
where: { transactionId },
});
if (existingKey) {
console.log("Transaction already processed keys:", transactionId);
return;
}
// 3. Generate a secure custom license key
const licenseToken = `LIC-${crypto.randomBytes(16).toString("hex").toUpperCase()}`;
// 4. Save license state in database
await prisma.licenseKey.create({
data: {
email,
keyString: licenseToken,
transactionId,
activated: false,
},
});
// 5. Deliver registration key to recipient inbox via Resend
try {
await resend.emails.send({
from: "Licensing Desk <desk@mycompany.com>",
to: [email],
subject: "Your Software License Activation Key",
html: `
<h2>Purchase Confirmation</h2>
<p>Thank you for buying our application! Here is your private activation code:</p>
<pre style="background:#f3f4f6; padding:15px; border-radius:8px; font-weight:bold;">${licenseToken}</pre>
<p>Enter this registration key in the application settings page to unlock all pro features.</p>
`,
});
console.log("License email successfully sent to:", email);
} catch (err: any) {
console.error("Failed to email licensing code:", err.message);
}
}3. Database Model Requirement
Create this database model to store your app registration keys:
// schema.prisma snippet
model LicenseKey {
id String @id @default(cuid())
email String
keyString String @unique
transactionId String @unique
activated Boolean @default(false)
activatedAt DateTime?
createdAt DateTime @default(now())
}Published on Last updated: