Sales / CRM, construction chemicals
Researching missing address data in CRM leads automatically
Without a postcode and town, an enquiry cannot be assigned to a sales territory. The system reads the address from the company website's legal notice — and deliberately writes nothing back to the CRM.
- Year
- 2026
- Services
- Artificial intelligence · Automation
- Area
- Sales
- Role
- In-house, employed
Delivered in an employed role for an internal department, not under an external consulting contract. The organisation is not named.
The situation
Documented in the project: CRM leads regularly arrive without postcode and town. As a result the leads “cannot be processed and cannot be routed to the responsible contact”. The trigger named is a specific case — the form said “Germany”, but the company is actually in Switzerland.
What is notable is what already existed: the routing logic was there, it was only missing its input. A deduplication tool was installed too, but it can only check and normalise addresses that exist — it cannot find missing ones.
What staff actually did before — researched manually, went back to the enquirer, or left the leads sitting — is documented nowhere in the project, and is not invented here.
The approach
A Python program reads the incomplete leads: no postcode, or a placeholder instead of a company name, not converted, with a selectable time window. The domain is derived from the website or email field. Known competitor domains and free-mail addresses are filtered out beforehand — so they cost not a single API call.
For the rest, three sources are consulted in fixed order: first the CRM itself (does an account, contact or lead with an address already exist for this domain?), second the company’s legal-notice page, which the program fetches itself and has a language model read, and third — only if that page is blocked or unreachable — a web search. The fetching is deliberately restrained: its own user agent, at most three pages per company, a pause between requests.
Afterwards ordinary code verifies everything: postcode format against each country’s rule, postcode-to-town against free reference data, VAT ID against the country format. Where the research contradicts the form — the “Germany vs. Switzerland” case — the row is flagged and lands on a separate sheet, rather than being silently corrected.
Where it could have gone the other way
Phase 1 deliberately writes nothing back.
The system could have written the addresses it found straight into the leads. Instead it produces an Excel list for manual approval. The reasoning is spelled out in the project: prove the hit rate first, automate second.
The price is real — no immediate time saving, one extra manual step. So is the return: no risk to the CRM data and, more practically, no change needed in the CRM. Read access is enough. The project could start without an approval loop instead of waiting on administration.
The same posture is mirrored technically in the rule no evidence, no value: the model may only reproduce what appears verbatim on the page; every value needs a source URL and a quotation, or it is discarded. A gap is preferable to a plausible invention.
The result
Nine modules, around 1,780 lines, three runnable programs — field analysis, data profile, enrichment. The Excel report has three sheets with roughly 30 columns. Every source file carries the same date: one working day from idea to three test runs against a real organisation.
In parallel, the enquiry text already attached to the lead is sorted into the system’s picklists and marked as a non-lead where it is a job application, an agency pitch or spam. The permitted values are read from the CRM at runtime rather than held in code — if someone changes a picklist, the classification follows automatically.
Deliberately bounded: contradictions are not resolved, they are presented. Free-mail addresses and leads without a website cannot be enriched and are reported as such, not guessed at. Postcode-to-town is cross-checked for four countries only, as far as the reference data reaches; the VAT ID for format only, not against the EU register.
And one sentence that is in the project itself: the actual root cause remains — that the postcode is not a required field on the web form. The tool handles the backlog, not the trigger.
Stack
- Python
- Salesforce API
- Claude API
- httpx / BeautifulSoup
- OpenPLZ API
More projects
Sales & inside sales, construction chemicals
2026One orchestrator, three specialist agents for product questions
Instead of one agent with three knowledge sources, a parent agent routes to three specialists — one each for ERP article data, product content and SharePoint documents.
- Microsoft Copilot Studio
- Azure AI Search
- Azure Functions
- SharePoint
Supply chain, construction chemicals
2026Stock, replenishment and documents per article on one page
Around 334,000 article documents from the data warehouse and the product information system, rebuilt daily. Stock is derived from the movement log rather than the ready-made inventory view — which never reports a zero balance.
- Python
- Azure AI Search
- Azure Functions
- Databricks SQL
Cloud governance, building materials
2026Cloud costs by owner, not by resource ID
A portal shows what cloud usage actually costs, broken down by the people and projects responsible. Shared resources are deliberately not charged to one project, even though that makes the savings look smaller.
- Python / Flask
- Azure Cost Management API
- Azure Resource Graph
- Azure SQL
A similar process at your company?
30 minutes, free, no sales pitch. You describe what is costing you time — I tell you honestly whether automation is worth it.