feat: implement GHL webhook endpoint for auto account + license key creation

POST /api/v1/automations/create/account accepts JSON with email,
name, and subscription_level. Creates a Better Auth user via signUpEmail
with a temporary password, sends a password reset email so the user
can set their own password, generates and persists a license key,
and emails the key to the user. Returns success/error as JSON.
This commit is contained in:
NeilClack
2026-07-08 14:16:31 -05:00
parent 4d21288511
commit e6ef7d3b36
@@ -1,21 +1,91 @@
import type { RequestHandler } from './$types';
import { json, error } from '@sveltejs/kit';
import { auth } from '$lib/auth';
import { prisma } from '$lib/db';
import { sendMail } from '$lib/server/resend';
export const POST: RequestHandler = async () => {
// Request validation (400)
// 1. Validate and extract information
function generateLicenseKey(): string {
const hex = crypto.randomUUID().replace(/-/g, '').slice(0, 16).toUpperCase();
return `${hex.slice(0, 4)}-${hex.slice(4, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}`;
}
// Business rule validation (409)
// 2. Check for existing entries
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
const { email, name, subscription_level } = body;
// Resource creation (500 on unexpected failures)
// 3. Create new entries
// 5. Create license key
if (!email || typeof email !== 'string') {
error(400, 'email is required');
}
if (!subscription_level || typeof subscription_level !== 'string') {
error(400, 'subscription_level is required');
}
// External operations (502/503/504 or 500, depending on your API)
// 4. Send profile setup email
// 6. Send license key email
const level = await prisma.subscriptionLevel.findFirst({
where: { name: subscription_level }
});
if (!level) {
error(400, `subscription_level "${subscription_level}" not found`);
}
// Success (200/201)
// 7. Send response
return new Response(JSON.stringify({ msg: 'success' }));
let user = await prisma.user.findUnique({ where: { email } });
if (!user) {
const tempPassword = crypto.randomUUID().replace(/-/g, '').slice(0, 20);
try {
await auth.api.signUpEmail({
body: {
email,
password: tempPassword,
name: name ?? email.split('@')[0]
}
});
user = await prisma.user.findUnique({ where: { email } });
await auth.api.requestPasswordReset({
body: {
email,
redirectTo: '/reset-password'
}
});
} catch (err) {
console.error('Failed to create user:', err);
error(500, 'Failed to create account');
}
}
if (!user) {
error(500, 'Failed to find or create user');
}
const key = generateLicenseKey();
await prisma.licenseKey.create({
data: {
key,
active: true,
level: subscription_level,
userId: user.id
}
});
try {
await sendMail({
to: email,
subject: 'Your License Key',
data: {
firstName: name ?? 'Valued Customer',
licenseKey: key
}
});
} catch (e) {
console.error('Failed to send license key email:', e);
}
return json({
success: true,
message: 'Account and license key created',
user_id: user.id
});
};