Follow-up sequence: 7 emails over 14 days in Marty's voice, paid-aware branches

Drafted through the Branded Voice engine (gain, logic, PAS, logic, honest
fear of loss, AIDA, gain + newsletter hand-off), checked against the contract
facts. {{paid:a|b}} resolves per reader from on-chain credits. Defaults now
live in drip-defaults.json; admin overrides still in the volume.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-09 06:37:39 -05:00
parent ce49dbbe4d
commit 15a29af104
3 changed files with 56 additions and 35 deletions
+18 -34
View File
@@ -8,38 +8,13 @@ const path = require('path');
const crypto = require('crypto');
const db = require('./db');
let DATA_DIR = null, mailer = null, accounts = null, SITE = 'https://instantadpay.com';
let DATA_DIR = null, mailer = null, accounts = null, chain = null, SITE = 'https://instantadpay.com';
// hours = time after the account was created
const DEFAULT_SEQUENCE = [
{ hours: 24, subject: 'Your first five minutes on InstantAdPay',
body: 'Yesterday you created a free InstantAdPay account. Here is the shortest useful thing you can do with it today.\n\n'
+ '1. Pick a username. It becomes your invite link, and it is how your sponsor and your line see you.\n'
+ '2. Take the welcome tour. It is three short stops on your upline\'s pages, and it unlocks your welcome credits. Those credits spend on real ads.\n'
+ '3. Copy your invite link and put it somewhere: a bio, a group, a text to one person.\n\n'
+ 'Your link right now: {{link}}\n\n'
+ 'That is the whole first day. Nothing to buy, nothing to connect.\n\n'
+ 'Sign in: {{site}}/my\n\n{{footer}}' },
{ hours: 48, subject: 'Where the money actually goes',
body: 'Most programs ask you to trust a back office. Here is what happens instead, in plain terms.\n\n'
+ 'When anyone buys an ad package, a verified smart contract on Polygon splits that payment in the same transaction: 50 percent to their direct sponsor, 20 percent to level two, 10 percent to level three, 20 percent to the platform. It lands in real wallets in seconds. Nothing is held, so there is nothing to withdraw.\n\n'
+ 'Every one of those payments is public. Open the live ledger and read it yourself:\n{{site}}/ledger\n\n'
+ 'You do not need a wallet to look. You only need one when you buy a package or switch on payouts, and the site walks you through it.\n\n'
+ 'Your invite link: {{link}}\n\n{{footer}}' },
{ hours: 96, subject: 'The five dollar test',
body: 'If you want to see the whole machine work without much at stake, the $5 package is the test.\n\n'
+ 'It mints 500 ad credits. One credit is one cent of delivery, and you spend them on seven formats: banners, text ads, login ads, solo ads into member inboxes, video ads, featured links and verified visits. Every view is dwell-timed on the server, so a real person saw it.\n\n'
+ 'The packages: $5 = 500 credits, $20 = 2,000, $50 = 5,500, $100 = 12,000, $250 = 32,500.\n\n'
+ 'Prefer to spend nothing? Keep viewing ads in Earn credits and run your first campaign on those. Both paths are real.\n\n'
+ 'Buy packages: {{site}}/my#buy\n\n{{footer}}' },
{ hours: 168, subject: 'Two buyers open level two',
body: 'One week in. Here is the referral side, with the numbers exactly as the contract has them.\n\n'
+ 'Every person who joins through your link and buys a package pays you 50 percent of that package, from their very first purchase, in the same transaction.\n\n'
+ 'Two qualifying buyers ($20 or more) open level two: 20 percent of everything their people buy. Five open level three: 10 percent of the level after that.\n\n'
+ 'Promo tools in your dashboard has posts, texts, email swipes and banners already carrying your link, plus honest answers to the objections you will hear. Your sponsor {{sponsor}} can be messaged from the dashboard any time.\n\n'
+ 'Your invite link: {{link}}\n\n'
+ 'No income is promised. Results depend on your effort, and crypto carries risk of loss.\n\n{{footer}}' }
];
// hours = time after the account was created. Copy drafted through Marty's
// Branded Voice engine (one framework per email: gain, logic, PAS, logic,
// honest fear of loss, AIDA, gain + hand-off to the newsletter), then checked
// line by line against the contract facts. Admin overrides live in drip.json.
const DEFAULT_SEQUENCE = require('./drip-defaults.json');
// ---- storage ----
const J = {
@@ -136,18 +111,27 @@ async function vars(email) {
const sp = accounts && await accounts.sponsorOf(email);
if (sp) sponsor = sp.username ? '@' + sp.username : (sp.memberId ? 'member #' + sp.memberId : 'your sponsor');
} catch (e) {}
// paid = has bought at least one package (on-chain credits minted); used by {{paid:a|b}}
let paid = false;
try { if (a && a.memberId && chain) paid = (await chain.creditBalance(a.memberId, 0)) > 0; } catch (e) {}
return {
link: tok ? SITE + '/join/' + tok : SITE + '/my',
sponsor, site: SITE, email,
sponsor, site: SITE, email, paid,
footer: 'You are getting these follow-ups because you created a free InstantAdPay account. Stop them here: ' + unsubUrl(email)
+ '\n\nInstantAdPay · Advertising, not investing. No income is guaranteed; results depend on your effort. Crypto carries risk of loss.'
};
}
function render(text, v) { return String(text).replace(/\{\{(\w+)\}\}/g, (m, k) => (k in v ? v[k] : m)); }
// simple {{key}} placeholders resolve first (they may sit inside a branch),
// then {{paid:words if they bought|words if not}} picks the branch
function render(text, v) {
return String(text)
.replace(/\{\{(\w+)\}\}/g, (m, k) => (k in v && typeof v[k] !== 'boolean' ? v[k] : m))
.replace(/\{\{paid:([\s\S]*?)\|([\s\S]*?)\}\}/g, (m, yes, no) => (v.paid ? yes : no));
}
// ---- lifecycle ----
function init(opts) {
DATA_DIR = opts.dataDir; mailer = opts.mailer; accounts = opts.accounts;
DATA_DIR = opts.dataDir; mailer = opts.mailer; accounts = opts.accounts; chain = opts.chain || null;
if (opts.site) SITE = opts.site;
}
// queue a fresh account; step 0 of the sequence is due `hours` after creation