Payment welcome cutover
Prepared for code deployment. The welcome remains inactive until the live cutover below. No workflow publication, customer send, or survey submission was performed during the October 2, 2026 review.Verified existing configuration
- Agency Location:
HUjFTz0AbjoNOcWuS1h7. - Published FM Closers Signed Agreement Workflows:
cdc89371-97e7-4a7f-a7c3-f05d1e781485. Annual/monthly document-completed triggers currently send the welcome email and its companion SMS. Other actions include pipeline updates, Slack notification, contact copying, and a member tag. Leave those actions in place. The copy destination was not established by the UI. - Existing template:
69bc798be2e963a9d5a3e2dd. Its button targets the public onboarding root. Its click condition adds agency tag onboarding link clicked. The user approved retiring that click tag on October 2, 2026. The cloud welcome records opens without propagating the agency tag. Existing tag history is retained; Operations contact IDs must never be used as agency IDs. - Operations Location:
ReoQmuh4ooNuHeE5stlj. - Published Create Onboarding Opp on New Subscription Payment:
aa7de117-009f-43f6-80fd-013bc8bbbceb. Both triggers require Payment status Success. Products are Funding Machine SaaS - V2 + Setup and MFM SaaS - V2 + Leads + Setup. Find Opportunity matches the Onboarding pipeline and contact full name. It does not establish contact identity; the app separately verifies the returned card’s contact ID. - Z - Onboarding Funnel, page
mAfOovWqrNep7g3bdGAt, publisheshttps://onboarding.myfundingmachine.com/pre-onboarding-step-1-page. It embeds General | Pre Onboarding Form - V2, surveyCzZVhTZnyHwIuT4nNcDo. The funnel overrides the survey’s thank-you message with a redirect to{{custom_values.schedule_tech_call_url}}and existing first/last name, phone, email, agency name, agency owner email, and relationship ID parameters. Sticky Contact and partial-submission contact creation were off. Preserve the survey and this redirect. No contact-ID binding contract was verified. A browser visit with only synthetic first/last-name query values confirmed those fields prefill in this exact published page. No contact details or survey answers were submitted; full submission-to-contact matching still needs a designated test.
Implementation
POST /api/webhooks/ghl-workflow/onboarding-payment authenticates a dedicated
ONBOARDING_PAYMENT_WEBHOOK_TOKEN bearer before reading its bounded JSON body:
items[].product._id. No customer payload was saved.
The existing cloud cron processes at most five welcome records per pass. It rechecks
provider state, current contact DND, hold status, and CRM form-submitted date. The
first pass sends E1; a later pass sends W1-welcome-sms. Existing durable claims,
receipts, pause fencing and uncertain-send reconciliation remain authoritative.
The app controls sending; Operations CRM conversations remain the delivery provider.
The email/SMS use a 30-day HMAC link. The redirect validates the enrollment,
generation, expiry and pause state, reads the scoped contact, records its first open,
and redirects to the existing funnel with encoded prefill plus UTM attribution.
It does not send a raw contact-ID override or forward the bearer token to the funnel.
Email/phone matching remains with the CRM. It never treats a click as a submission;
link scanners may also generate opens. Prefill appears in the destination URL/history.
Slack before product provisioning
Enrollment now durably queuesonboardingSlackPaid.refresh. The existing Slack
reconciliation cron processes at most five due payment enrollments per pass. The
payment worker rereads transaction/order/contact/opportunity evidence and hold status
before claiming and immediately before each provider write. It requires send mode,
enabled persisted live state, ONBOARDING_ENGINE_LIVE_ENABLED=true, workspace mode,
provisioning and CRM writes. A configured Location pilot list denies pre-product writes.
Compute mode can prepare the welcome for review without an existing channel or provider writes. No new production flag is enabled by deployment.
For the new-paid-only rollout, keep ONBOARDING_SLACK_PROVISION_ENABLED=false and
set ONBOARDING_SLACK_PAID_PROVISION_ENABLED=true only at the authorized cutover.
The paid switch requires an exact Operations payment enrollment on or after the
policy cutoff, including after a product Location adopts the job. It does not grant
provisioning to older accounts without an eligible enrollment. Turn the paid switch
off to stop new writes while retaining channels and receipts.
FM Bot posts the personalized welcome only after channel membership is confirmed.
Its account link uses the verified product Location. If the member joins before
account linking, welcomePendingAccountLink records that the same welcomeTs needs
a link update. Updates retry against that message; uncertain initial sends are never
automatically reposted. Legacy messages without the pending flag are preserved.
The onboarding owner specified the customer destination as
https://app.myfundingmachine.com/v2/location/{locationId}/custom-menu-link/fundingmachine.
On October 7, 2026, a read-only authenticated browser inspection of an existing customer
tab at this route confirmed the Funding Machine dashboard iframe for the same Location,
including its Onboarding & Setup link. The older app.leadbuilt.com/.../ugflmc links
elsewhere are not the requested customer-agency destination. No live send was performed
for this verification.
The existing onboardingSlackProvisioning reservation can initially have a welcomeId
without locationId. That welcome is scoped to Operations; Operations is never stored
as a synthetic customer Location. A unique opportunity reservation and lease serialize
both entry points. Later verified product linking atomically adopts it, preserving
channel ID, recovery name, Operator ID and invitation/welcome receipts. Active leases,
conflicting identities/channels and paused enrollment prevent adoption. Product pauses,
Labs and agency checks remain in force. Pre-product channels never enter account-scoped
support ingestion; humans can still respond in Slack.
With workspace mode enabled, E1 and its SMS wait for confirmed channel/staff setup and
a usable current invitation. They include a signed /api/onboarding/welcome link with
destination=slack. The redirect uses the same enrollment, generation, expiry and pause
checks, and reads the current approved invitation. It never takes a redirect URL from
the caller, records an intake-form open for a Slack click, or forwards the signed token
to Slack. Pausing or rotating an invitation takes effect on the next click.
For recovery, inspect onboardingSlackProvisioning.health, message, nextCheckAt
and the write-attempt receipts for the exact opportunity. Pre-reservation failures log
the welcome ID, error class and provider HTTP status without response bodies or secrets.
The enrollment’s slackNextCheckAt retries those failures independently of email timing.
The sweep also initializes at most five older welcome records per pass without changing
send receipts. Once a verified Location job owns retries, the welcome leaves the Slack
queue. Failures before reservation use the same bounded backoff as saved jobs: three
five-minute retries, then 30 minutes, then six hours. Stale failures cannot overwrite
newer progress, active leases, paused enrollments or changed account mappings. Reissue/resume requeues the
welcome’s Slack check; neither clears write receipts. Expired enrollments require staff
review/reissue. Already linked jobs continue through the normal product checker.
Activation prerequisites and exact live changes
- Click-tag retirement is approved: the replacement welcome does not add the agency onboarding link clicked tag. Disable the old welcome sends at cutover as below; do not delete historical tags or add cross-Location propagation.
- Deploy the reviewed app and Convex changes while the welcome remains unconfigured. This requires explicit production deployment authorization under AGENTS.md.
- Configure
ONBOARDING_PAYMENT_WEBHOOK_TOKENin the app and its matching bearer header in the Operations workflow; configure a separate high-entropyONBOARDING_WELCOME_LINK_SECRET(at least 32 characters) in Convex. Use the existing Operations-scopedONBOARDING_ENGINE_LIVE_PIT; verify payment read scopes and conversation send permission. Never print or commit credentials. - Pause the existing engine and finish its lease. Preserve its reviewed config,
imported history and cohort. Call
onboardingWelcomeStore.configurewith an admin actor, review reason and policy JSON containing:mode: "compute", a future UTC millisecondstartsAt,liveMode: true, exact approved OperationsproductIds,nativeOwnershipEvidence, verified OperationssenderName/senderEmail, andintakeOriginset to the HTTPS app origin. Product IDs and sender address must be read from the actual Operations configuration; display names are not IDs. The cutoff is immutable once configured and avoids historical backfill. - Add the authenticated webhook after finding/creating the card in both branches of the exact Operations payment workflow above. Keep the success/product filters. Confirm the synthetic/test execution supplies the correct IDs and receives 202.
- Disable only Email and SMS in the exact agency signed-agreement workflow. Keep the workflow and its other actions. Preserve the linked template as a rollback reference. Confirm no enrolled contact remains queued for those sends.
- Before send mode, confirm workspace settings, the current Never expires invitation, bot/staff configuration, provisioning and CRM-write gates. A Location-only pilot cannot create a pre-product channel: obtain broader-rollout approval before removing that restriction. Rehearse payment → channel with no sub-account → workspace join → account linking, confirming one channel and one welcome. Pause/resume, rejected or refunded payments, uncertain writes and invitation rotation must also be checked.
- After compute evidence and an explicitly authorized test send to a designated
test contact confirm sender, SMS destination, prefill and calendar handoff, pause,
configure the same policy as
mode: "send", and resume the engine. Do not enable sending while the old welcome actions can still fire.
manage: pause before enabling send mode. A historical agency
receipt must never be inferred merely from matching an email address.
Staff inspection and recovery
onboardingWelcomeStore.find({ locationId, contactId })returns the enrollment ID, paid/open/expiry timestamps, pause state and opportunity ID. It excludes form data.onboardingEngineLiveStore.inspectandevidenceexpose run reports and accepted or uncertain communication claims. Existingresolverequires a paused engine, exact attempt and evidence. Do not turn an uncertain result into a resend without confirming the provider did not accept it.onboardingWelcomeStore.manageacceptspause,resume, orreissueplus admin actor and reason. Reissue requires a paused engine with no active lease, invalidates the old link and returns the replacement link for controlled delivery. It never clears receipts or automatically resends an accepted message. Treat that returned link as a bearer credential, not something to put in logs or tickets.- Rollback: pause the cloud engine and disable both general and paid Slack provisioning first, preserve all enrollment and dispatch history, then review affected contacts before restoring native sends. Never run both welcome senders simultaneously or bulk-reenroll existing customers.

