Skip to content
Bahman Shadmehr Independent AI Systems & Automation Engineer

Revenue operations · Reference design

Reliable lead intake

The form said thank you. The CRM never heard of them.

Separate accepting a submission from delivering it, so a CRM outage or a lost response can delay a lead but never lose or duplicate it.

Company Northwind is a hypothetical company. Every figure is illustrative.

Index cards for inbound leads, one marked with a pencilled question about where it went.

About Company Northwind

Company Northwind is a hypothetical company, written for this reference design; the details below are its constraints. Every figure is illustrative, computed from stated assumptions. No client work or measured result is claimed.

Industry
B2B software: fleet-telematics add-ons for mid-market logistics firms
Size
About 120 people; a revenue team of 22
Systems
Website demo form, partner-referral form, trade-fair badge scans, a SaaS CRM, an enrichment API, a no-code automation tool
Team
One RevOps manager, a part-time marketing-ops contractor, six SDRs across three territories
Volume
About 900 submissions a month, a few hundred more after trade fairs
Constraints
GDPR consent before outreach; the CRM stays the system of record; a few hundred euros a month for new infrastructure

In brief

ProblemOne automation chain runs enrichment, classification, routing and the CRM write in sequence, so a single failed call silently drops a submission the visitor was already thanked for.
SystemTransactional intake (submission and job in one commit), a worker with timeouts and fallbacks, CRM writes keyed by event ID with read-back, and a review queue with owners and deadlines.
People decideAmbiguous identity, conflicting territory rules, CRM rejections that need correction, and holds past their deadline.

How the work ran before

Company Northwind is a 120-person software company that sells fleet-telematics add-ons to logistics firms. Demand arrives through three doors: the demo form on the website, a partner-referral form, and spreadsheets of badge scans after each trade fair. Around 900 submissions a month, with a spike of a few hundred in the week after an event.

A no-code automation connects everything. When someone submits the form, one automation run does all of it in sequence: look the company up in an enrichment service, ask a model what the person wants, pick an owner from a territory spreadsheet, create the lead in the CRM, and post a message to the sales channel. Six sales development reps work the leads from a CRM view called "New today". A marketing-ops contractor built the chain two years ago and now looks after it a few hours a week.

On a normal day this works, which is why nobody questions it.

Where it broke

The failure that starts Company Northwind's project is quiet. A prospect from a large carrier fills in the demo form, hears nothing, and two weeks later writes to the CEO. The RevOps manager goes looking and finds the submission in the automation tool's list of failed runs. The CRM had returned a rate-limit error during a busy hour. The run stopped. Nothing else happened, because a failed run in that tool is a line in a list that nobody is paid to read.

The same week, another prospect appears twice in the CRM. The CRM had created the lead, the response timed out, and the tool's automatic retry created it again.

Both problems have one cause. The form, the enrichment call, the model call, the CRM write and the notification are one chain, so the moment the visitor sees "Thanks, we'll be in touch" means nothing. The system has promised something it has no record of keeping.

What I would build

The core change is to separate accepting a submission from delivering it.

  1. Accept. The form handler checks the source, checks consent, validates the few fields that must exist, and writes one row to a database: the submission, a stable event key, and a job to process it. Both rows commit in the same transaction. Only then does the visitor see the thank-you page.
  2. Process. A worker picks up the job. Enrichment, intent classification and owner routing run here, each with a timeout and a fallback. None of them can make the visitor's submission disappear.
  3. Deliver. The worker writes to the CRM using the event key, then reads the record back. The submission is delivered only when the CRM confirms it.
  4. Hold what code can't decide. An unclear identity ("is this the parent company or the subsidiary we already sell to?"), two territory rules that both match, or a withdrawn consent becomes an item in a review queue with a named owner and a deadline.

The model has one job: read the free-text message and propose an intent category, quoting the words it based that on. It does not decide who owns the lead, whether to contact the person, or whether two records are the same company.

Following one submission through

Here is the lost-response case from above, run through the new design at Company Northwind. All identifiers are sample data.

A visitor submits the demo form at 10:14. The handler writes submission lead_evt_28491 and its job in one transaction and returns the thank-you page. At 10:14:03 the worker enriches the domain, the model tags the message "fleet pilot, 40 vehicles", and the territory rules pick the DACH team. The worker sends a CRM create request carrying the event key. The CRM creates the record, but the response is lost in a network timeout.

The old chain would retry blindly and create a duplicate. The worker does not know whether the write happened, so it records the attempt as unknown and does the one safe thing: it searches the CRM for a record carrying lead_evt_28491. It finds one, links it, and marks the submission delivered. The rep sees one lead.

Submission Intake CRM result State Next action
lead_evt_28491 Accepted Response lost Reconciling, then delivered Read back by event key before any retry
lead_evt_28492 Accepted No record found Retry scheduled Retry from the CRM step only
lead_evt_28493 Accepted Record confirmed Delivered Owner assigned
lead_evt_28494 Accepted Not attempted Rejected: consent withdrawn Delivery cancelled, no retries

Sample data. Four submissions from one simulated morning.

Company Northwind · CRM delivery reconciliation

Lead

lead_evt_28491 · sample lead

Lead owner
Waiting for read-back
Accepted
10:14 · submission and job committed
Source
Demo form · event key lead_evt_28491
Status
Reconciling
CRM response lost · outcome unknown

Search the CRM for the event key before any second create. Unknown is not the same as failed.

Attempts Event key · lead_evt_28491

  • Create lead Timeout after send Unknown

    10:14:03 · no response body

  • Read back by event key One record found Linked

    submission marked delivered · no retry needed

Worked example · sample data. A CRM record view for Company Northwind, a hypothetical company.

When things go wrong

The CRM is down for an hour. Submissions keep being accepted, because acceptance only needs the local database. Jobs wait with backoff. When the CRM returns, they drain in order. The team sees a queue with an age instead of silence.

Enrichment times out. The worker routes with what it has. If the territory can't be decided from the submitted country alone, the lead goes to the review queue with the reason "no enrichment, territory ambiguous" instead of a guessed owner.

The model returns nonsense or nothing. The intent field stays empty and the lead is delivered without it. Intent helps prioritize; it is never required for delivery.

A person withdraws consent before delivery. The pending job is cancelled and the reason is recorded. Retrying a delivery the law no longer allows is not a recovery.

What changes for the team

Northwind's reps keep their workflow: they still work from the CRM. What changes is what the RevOps manager can see and trust.

Question Before After
Did every submission reach the CRM? Unknown without checking the failed-runs list One query: accepted minus delivered minus held
Why is this lead not assigned? Ask in chat Hold reason and owner on the item
Why are there two records? Guess Attempt log with the event key
Who fixes a stuck lead? Whoever notices The queue owner, within a deadline

Illustrative figures for one month, computed from assumptions I state in the technical design (900 submissions, 3% of CRM calls rate-limited, 1% of responses lost). They are not measurements.

Illustrative outcome (per month) Chained automation Durable intake
Submissions lost after acceptance about 27 0 by design, if the database commit succeeds
Duplicate CRM records from blind retries about 9 about 0, if read-back by event key works
Leads waiting for a person not tracked about 40, each with a reason and owner

The third row is the honest cost: durable intake turns ambiguity into work someone has to do.

What this does not solve

It does not make the CRM faster or more reliable. It does not fix a territory spreadsheet that contradicts itself; it only makes the contradiction visible. And if the CRM offers neither idempotency keys nor a searchable field for the event key, the duplicate protection weakens to "search by email and company and ask a person when unsure".

How I would prove it

A two-week shadow run is enough. The new intake writes to its own database while the old chain keeps running. Every day, compare three lists: submissions the form received, leads the old chain delivered, and leads the new pipeline would have delivered. The differences are the evidence, and every one should have a reason.

The technical design

The same system for engineers: architecture, records, failure handling, evaluation, the options I rejected, and the stack. About 5 minutes.

  1. Scope and assumptions
  2. Architecture
  3. Data model
  4. States
  5. Failure handling
  6. Where the model fits
  7. Evaluation
  8. Trade-offs I considered
  9. Stack
  10. Security and operations

Read the technical design

Losing leads between tools?

Bring a week of form submissions.

A submission log and the matching CRM records are enough to find where delivery breaks. Please don't send personal data; counts and IDs will do.