URL: /code/apps/crm · Id: `page:/code/apps/crm`

# CRM

> Your Contacts, Organizations, leads and deals on one record, with qualify, assign, advance and win as calls every agent and app shares.

Your [Contacts](https://startupbuilder.dev/business/nouns/contact), [Organizations](https://startupbuilder.dev/business/nouns/organization), [leads](https://startupbuilder.dev/business/nouns/lead) and [deals](https://startupbuilder.dev/business/nouns/deal) on one record, with qualify, assign, advance and win as calls every agent and app shares.

- **System:** [CRM](https://startupbuilder.dev/systems/crm)
- **Nouns:** 4
- **Verbs:** 13
- **Events:** 10

```text title="Run it · Ask"
Rosa booked Tuesday’s call: qualify Northgate Rentals for Leaseline and open the Deal.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Lead.qualify({ lead: 'lead_Nr5gT1aV7k', offer: 'offer_Ls1mP4qR8v' })
```

```json title="Run it · Response"
{
  "api": "https://api.sb/leaseline.app",
  "deal": {
    "$type": "Deal",
    "status": "Open",
    "value": {
      "amount": 1788,
      "currency": "USD"
    },
    "nextStep": "Discovery call, Tuesday, November 3, 2:00 p.m. Central"
  },
  "lead": {
    "$id": "https://api.sb/leaseline.app/leads/lead_Nr5gT1aV7k",
    "$type": "Lead",
    "status": "working",
    "fit": "strong",
    "interest": "Can you send times for Tuesday?"
  },
  "action": {
    "operation": "Lead.qualify",
    "mode": "try",
    "status": "done"
  }
}
```

## Nouns
| Noun | What it is |
| --- | --- |
| [Contact](https://startupbuilder.dev/business/nouns/contact) | A Contact is a person or Agent a startup knows by at least one address, where Consent to message them is recorded. |
| [Organization](https://startupbuilder.dev/business/nouns/organization) | An Organization is an outside party as one startup knows it, keyed by its domain, such as an employer or a vendor. |
| [Lead](https://startupbuilder.dev/business/nouns/lead) | A lead is a Contact who raised a hand, by joining a Waitlist, filling a Form, or replying, without accepting an offer. |
| [Deal](https://startupbuilder.dev/business/nouns/deal) | A deal is a startup’s pursuit of one buyer’s acceptance of one or more offers, ending won or lost. |

## Properties
The hub defines each Noun’s core Properties; CRM adds the ones a sale needs.

### Contact
| Property | Type | What it holds | Defined by |
| --- | --- | --- | --- |
| `email` | `email` | The primary email address. | The hub |
| `phone` | `string` | The primary phone number. | The hub |
| `name` | `string` | The name the Contact goes by. | The hub |
| `title` | `string` | Their job title as they state it, refreshed by `Contact.enrich`. | CRM |
| `organization` | `Organization` | Where they work now; a job change moves it and keeps the old one in history. | CRM |
| `acquisition` | `Acquisition` | Where they came from: the Play, the site and the first touch. | CRM |
| `lastTouchAt` | `datetime` | The last Message either way, so no seat writes to someone touched this week. | CRM |

### Organization
| Property | Type | What it holds | Defined by |
| --- | --- | --- | --- |
| `name` | `string` | The name it trades under. | The hub |
| `hostname` | `string` | The web domain that keys it. | The hub |
| `headcount` | `integer` | People on staff, as read by `Organization.enrich`; ranges stay ranges. | CRM |
| `fit` | `'strong' \| 'partial' \| 'none'` | Fit to your ICP, graded from the evidence, never typed in. | CRM |
| `evidence` | `string[]` | The quotes and pages that show the fit, each with its URL. | CRM |

### Lead
| Property | Type | What it holds | Defined by |
| --- | --- | --- | --- |
| `interest` | `text` | What the lead asked for. | The hub |
| `status` | `string` | One of `new`, `working`, `nurture`, `converted`, or `disqualified`. | The hub |
| `owner` | `worker` | The Worker who answers it. | The hub |
| `fit` | `string` | One of `strong`, `partial`, or `none`: fit to the ICP as the lead fit Policy grades it, never set by hand. | The hub |
| `offer` | `Offer` | The offer the hand was raised for. | CRM |
| `respondBy` | `datetime` | When the first answer is owed: 5 minutes after an inbound form in working hours. | CRM |
| `reason` | `string` | Why it was disqualified or nurtured, in the buyer’s words where there are some. | CRM |

### Deal
| Property | Type | What it holds | Defined by |
| --- | --- | --- | --- |
| `status` | `string` | One of `Open`, `Qualified`, `Proposed`, `Won`, or `Lost`. | The hub |
| `value` | `money` | What the deal is worth if won. | The hub |
| `owner` | `worker` | The Worker who runs it. | The hub |
| `closesOn` | `date` | The date the buyer expects to decide. | The hub |
| `statusSince` | `datetime` | When it entered its current status, computed from its Events. | The hub |
| `nextStep` | `text` | The next dated step agreed with the buyer. | The hub |
| `offer` | `Offer` | The offer being bought; a second offer is a second deal. | CRM |
| `meetings` | `Meeting[]` | Every call held, each with its brief and notes. | CRM |
| `lostReason` | `string` | The reason the buyer gave, set by `Deal.lose` and read by the weekly review. | CRM |

## Lifecycle
Every move names the Verb that makes it, or the Event it waits on.

### Lead
| State | What it means | Moves to |
| --- | --- | --- |
| `new` (first) | It raised a hand, and no Worker works it yet. | `working` by [`Lead.assign`](https://startupbuilder.dev/business/nouns/lead/assign); `nurture` by [`Lead.nurture`](https://startupbuilder.dev/business/nouns/lead/nurture); `disqualified` by [`Lead.disqualify`](https://startupbuilder.dev/business/nouns/lead/disqualify); `converted` on `Offer.accepted` |
| `working` | Its owner is in touch and owes the next step. | `converted` by [`Lead.qualify`](/code/apps/crm/qualify); `converted` by [`Lead.convert`](https://startupbuilder.dev/business/nouns/lead/convert); `nurture` by [`Lead.nurture`](https://startupbuilder.dev/business/nouns/lead/nurture); `disqualified` by [`Lead.disqualify`](https://startupbuilder.dev/business/nouns/lead/disqualify) |
| `nurture` | Not ready to buy: it is off its owner’s queue and hears from a Sequence until it raises a hand again. | `working` by [`Lead.assign`](https://startupbuilder.dev/business/nouns/lead/assign); `disqualified` by [`Lead.disqualify`](https://startupbuilder.dev/business/nouns/lead/disqualify) |
| `converted` | It fits an offer: a deal is open for it, or it bought on its own; the customer record carries on. | None: it ends here. |
| `disqualified` | It fits no offer, for the reason recorded; its Contact record stays. | None: it ends here. |

### Deal
| State | What it means | Moves to |
| --- | --- | --- |
| `Open` | A qualified lead became a deal; its owner owes the first call. | `Qualified` by [`Deal.advance`](https://startupbuilder.dev/business/nouns/deal/advance); `Lost` by [`Deal.lose`](https://startupbuilder.dev/business/nouns/deal/lose) |
| `Qualified` | The buyer confirmed the problem, the budget and who decides. | `Proposed` by [`Deal.propose`](https://startupbuilder.dev/business/nouns/deal/propose); `Lost` by [`Deal.lose`](https://startupbuilder.dev/business/nouns/deal/lose) |
| `Proposed` | A Quote is with the buyer, waiting on their yes. | `Won` by [`Deal.win`](https://startupbuilder.dev/business/nouns/deal/win); `Won` on `Offer.accepted`; `Lost` by [`Deal.lose`](https://startupbuilder.dev/business/nouns/deal/lose) |
| `Won` | The Order is placed and the buyer is your customer. | None: it ends here. |
| `Lost` | Closed with the buyer’s reason; the Contact stays. | None: it ends here. |

## Verbs
| Verb | What it does | Approval | On each site |
| --- | --- | --- | --- |
| [`Lead.qualify`](/code/apps/crm/qualify) | Opens a deal for a lead that fits one of your offers, with its value and the reason it fits. | Runs on its own | Facebook, LinkedIn, Instagram |
| [`Lead.assign`](https://startupbuilder.dev/business/nouns/lead/assign) | Gives a lead one owner seat, by round robin, territory or ICP fit, as your routing rule says. | Runs on its own | None. |
| [`Deal.advance`](https://startupbuilder.dev/business/nouns/deal/advance) | Moves a deal to its next stage once every field that stage requires is filled. | Runs on its own | None. |
| [`Deal.win`](https://startupbuilder.dev/business/nouns/deal/win) | Closes a deal as won, places its Order and makes the buyer your customer. | Runs on its own | None. |
| [`Deal.lose`](https://startupbuilder.dev/business/nouns/deal/lose) | Closes a deal as lost, with the reason the buyer gave. | Runs on its own | None. |
| [`Lead.nurture`](https://startupbuilder.dev/business/nouns/lead/nurture) | Takes a lead that is not ready to buy off its owner’s queue and onto a Sequence, until it raises a hand again. | Goes out on its own | None. |
| [`Lead.convert`](https://startupbuilder.dev/business/nouns/lead/convert) | Ends a qualified lead’s run as a lead: it opens a deal, or sends the buyer to self-serve checkout. | Runs on its own | None. |
| [`Lead.disqualify`](https://startupbuilder.dev/business/nouns/lead/disqualify) | Closes a lead that fits none of your offers, with the reason; its Contact and Consent stay. | Runs on its own | None. |
| [`Deal.assign`](https://startupbuilder.dev/business/nouns/deal/assign) | Gives a deal one owner, who carries its next step until it is won or lost. | Runs on its own | None. |
| [`Deal.propose`](https://startupbuilder.dev/business/nouns/deal/propose) | Sends the buyer a Quote they accept to place an Order. | Runs on its own | None. |
| [`Contact.enrich`](/code/data/people/enrich) | Fills a Contact’s missing fields from outside sources, each value marked with where it came from. | Runs on its own | None. |
| [`Contact.merge`](https://startupbuilder.dev/business/nouns/contact/merge) | Joins a duplicate Contact into the one you keep, with every link, Message and Event. | Runs on its own | None. |
| [`Organization.merge`](https://startupbuilder.dev/business/nouns/organization/merge) | Joins a duplicate Organization into the one you keep, with its Contacts, deals and Events. | Runs on its own | None. |

## Events
| Event | Emitted by |
| --- | --- |
| `Lead.qualified` | [`Lead.qualify`](/code/apps/crm/qualify) |
| `Lead.assigned` | [`Lead.assign`](https://startupbuilder.dev/business/nouns/lead/assign) |
| `Lead.converted` | [`Lead.convert`](https://startupbuilder.dev/business/nouns/lead/convert) |
| `Lead.disqualified` | [`Lead.disqualify`](https://startupbuilder.dev/business/nouns/lead/disqualify) |
| `Deal.advanced` | [`Deal.advance`](https://startupbuilder.dev/business/nouns/deal/advance) |
| `Deal.proposed` | [`Deal.propose`](https://startupbuilder.dev/business/nouns/deal/propose) |
| `Deal.won` | [`Deal.win`](https://startupbuilder.dev/business/nouns/deal/win) |
| `Deal.lost` | [`Deal.lose`](https://startupbuilder.dev/business/nouns/deal/lose) |
| `Contact.enriched` | [`Contact.enrich`](/code/data/people/enrich) |
| `Contact.merged` | [`Contact.merge`](https://startupbuilder.dev/business/nouns/contact/merge) |

A [Trigger](https://startupbuilder.dev/business/nouns/trigger) can start a Workflow on any of them, and a Watch delivers each to your endpoint, signed ([Events and webhooks](/code/events)).

## Who operates it
| Part | CRM |
| --- | --- |
| Accountable | [Sales lead](https://startupbuilder.dev/agents/sales/sales-lead) |
| Also calls its Verbs | [Prospector](https://startupbuilder.dev/agents/sales/prospector), [Sales Engineer](https://startupbuilder.dev/agents/sales/sales-engineer), [Success Manager](https://startupbuilder.dev/agents/customer/success-manager) |
| Seat | An agent holds each seat until you seat a person in it. |
| Asks you first | None of its Verbs: each runs within its seat’s Limits |

## Integrations
[The CRM you already use](/code/integrations/your-crm)

## Import and export
| Direction | What | How |
| --- | --- | --- |
| Import | Contacts, Organizations and open deals from the CRM you already use | `Integration.sync` through [the CRM you already use](/code/integrations/your-crm); the declared leader wins each field |
| Import | A spreadsheet of people | `Contact.create` for each row; duplicates join through `Contact.merge` |
| Export | Any Noun, once or on a schedule | `Collection.export` to a file or your warehouse |
| Export | One question, answered | `Collection.query` by SQL or a relationship path |

## Example
**A reply becomes a deal.**

1. Maya Chen at Cedar Hollow Rentals answers the second email: “We still track rent in a spreadsheet.” `Prospect.engage` makes her a lead, with the cold email Play as her source.
2. `Lead.assign` gives the lead to the Sales lead seat; its first answer is owed within the hour.
3. `Lead.qualify` checks her against the Leaseline offer: 64 units, an owner-operator, a spreadsheet today. It opens a deal worth $1,788 a year.
4. She books through the link in the answer. `Meeting.book` holds Thursday at 10:00 Central, and the brief lands on the deal.
5. After the call, `Deal.advance` moves it to Qualified, and `Deal.propose` sends the Quote.