Skip to content
// Accept from the page's form (POST, so link scanners in email can't accept by visiting a URL).
const b = $('Accept API').first().json.body ?? {};
const q = $('Accept API').first().json.query ?? {};
const p = ($getWorkflowStaticData('global').proposals ?? {})[String(b.id ?? '')];
const today = String(q.now || new Date().toISOString()).slice(0, 10);
const fail = (code, title, msg) => [{ json: { accepted: false, code, title, msg } }];
if (!p) return fail(404, 'Proposal not found', 'Check the link in your email.');
if (b.t !== p.token) return fail(403, 'Link not valid', 'Please use the link from your email.');
if (p.status === 'accepted') return fail(409, 'Already accepted', `Accepted by ${p.accepted_by} on ${p.accepted_at.slice(0, 10)}.`);
if (today > p.valid_until) return fail(410, 'Proposal expired', `It expired on ${p.valid_until}. Reply to the email and we'll refresh it.`);
const name = String(b.name ?? '').trim();
if (name.length < 2 || b.agree !== 'yes') return fail(400, 'Almost there', 'Type your full name and tick the box to accept.');
p.status = 'accepted'; p.accepted_by = name; p.accepted_at = new Date().toISOString();
p.accepted_from = $('Accept API').first().json.headers?.['x-forwarded-for'] ?? null;
const s = $('Settings (edit me)').first().json;
const money = (n) => new Intl.NumberFormat('en-US', { style: 'currency', currency: p.quote.currency.toUpperCase(), maximumFractionDigits: 0 }).format(n);
return [{ json: { accepted: true, code: 200, id: p.id, title: 'Thank you!', msg: `Proposal accepted. We'll send the deposit invoice (${money(p.quote.deposit)}) and a kickoff invite shortly.`,
  notify: { to: s.owner_email, subject: `✅ ${p.lead.company || p.lead.client} accepted ${p.id} (${money(p.quote.total)})`,
    body: `${name} accepted proposal ${p.id} for ${p.quote.items.map((i) => i.name).join(', ')}.\nTotal ${money(p.quote.total)}, deposit ${money(p.quote.deposit)}.\nClient: ${p.lead.client} <${p.lead.email}>\nViewed ${p.views} time(s).` } } }];