A pipeline that fills itself from real usage.
HAL's CRM is deliberately small: companies, contacts, deals, stages. Its edge is what flows in — every identify call, chat, and product event is already attached.
The records
- Company — the account. Domain, industry, notes, health signals, and its deals. Its stage and deal value mirror its main deal, so anything that reads a company's stage keeps working.
- Deal — one sale with a company: new business, an expansion, or a renewal. Each has a stage, amount, owner, expected close date, next step, the people involved with their role, and a lost reason when it is lost.
- Contact — a person. Emails, tags, notes, and links to one or many companies.
- Visitor — a browsing session. Anonymous until identified, then attached to a contact.
The full ownership rules — which record holds which field, and what happens on identify — are in CRM data model.
How data enters
There are four inlets, and they all converge on the same records:
- Widget identify —
HalWidget.identify()from your site. The most common path: signed-in users appear in CRM automatically. - Server-side identify —
POST /api/widget/identifyfrom your backend. - Public API —
/api/v1/contacts,/api/v1/companiesand/api/v1/dealswith an API key. For billing webhooks, data warehouse sync, and integrations. - Dashboard — manual entry and CSV import with duplicate merging.
Stages
Stages are fully custom per project: name, color, order, and probability. A stage at 100% marks a deal won and one at 0% marks it lost. The board shows deals as cards with column totals — one-time, MRR, or ARR semantics per your sales currency setting — and flags deals past their close date, with an overdue next step, or untouched for two weeks.
Product signals respect stage precedence: writes from the widget advance deals forward in your stage order but never backward, unless the write explicitly requests exact mode. Manual moves from the dashboard always win. Details in CRM data model.
Deals and deal values
Create deals from the board, a company, the API (/api/v1/deals), or MCP. Widget and company writes — HalWidget.setStage(), HalWidget.setDeal({ deal_value: 1800 }), deal_value / stage_id on companies — move the company's main deal, and a company entering the pipeline gets one. A customer who comes back after a lost deal gets a new deal, so each sale keeps its own record. Amounts roll up into board totals, win rate, sales cycle and revenue reporting. Interpretation (one-time vs MRR vs ARR) is a project setting so totals mean one thing.
Health signals
Define rules — "no conversation in 14 days", "usage dropped below X", "open ticket + trial ending" — and HAL surfaces a "needs attention" state on the company.
Attribution
Because visitors, contacts, and companies are linked, HAL can trace a revenue line: anonymous visit → identified user → company → stage changes → won. The marketing view reports qualified pipeline and won revenue attributed back to the original touchpoints.