Opportunities & Pipeline
An opportunity is a potential deal tracked through your configurable sales pipeline — carrying a customer, value, probability, expected close date, and a full stage-change history.
An opportunity is a potential deal you are pursuing with a customer. It lives in a pipeline — an ordered sequence of stages that reflects how your sales process works, from first contact through to a win or loss. Each opportunity carries the customer it belongs to, a monetary value, a probability percentage, an expected close date, and a complete record of every stage change so the deal's history is always auditable.
Opportunities are part of the CRM, but their pipeline is shared with quoting and the customer directory. Winning an opportunity doesn't automatically create a quote — but the Convert to Quote action turns one into a draft quote in a click (see below). Invoices remain a separate step in their own module.
The sales pipeline #
Your account comes with six default pipeline stages — Prospecting, Qualification, Proposal, Negotiation, Closed Won, and Closed Lost — ready to use out of the box. Each stage has a name, a color for its badge, and a sort order that controls its position left-to-right in the pipeline view.
Two flags make a stage special:
- Marks as Won — the stage is the conventional "won" stage. Use the
Mark as Won button on the opportunity to set
won_at. The flag is mutually exclusive with "Marks as Lost." - Marks as Lost — the stage is the conventional "lost" stage. Use the
Mark as Lost button (which also prompts for a lost reason) to set
lost_at.
Add, rename, reorder, or delete stages from CRM → Pipeline Stages → New Stage. Deleting a stage soft-deletes it; any opportunities still in that stage retain the reference but the stage no longer appears in the pipeline.
Creating an opportunity #
New opportunities are created from CRM → Opportunities → New Opportunity (or from a customer's page). The form has two sections.
Opportunity Details:
- Title — a short description of the deal. Required.
- Customer — the customer this deal belongs to. Required. Selecting a customer filters the Contact dropdown to that account's contacts.
- Contact — the specific contact at the customer who is your main point of call. Optional.
- Stage — which pipeline stage the opportunity starts in. Optional; can be left unstageed and placed later.
- Assigned To — the team member responsible for closing it. Optional; defaults to unassigned.
Deal Info:
- Value ($) — the expected deal size, entered in dollars in the UI.
Internally the value is stored as an integer in cents, so
$2,500is stored as250000. The API reflects this — send250000, not2500.00. - Probability (%) — your confidence that the deal will close, 0–100. Combined with value, this drives the weighted-value forecasting in reports.
- Expected Close — the date you expect to close the deal.
- Source — where the lead came from: Website, Referral, Cold Outreach, Trade Show, Partner, or Other.
- Notes — free-form context about the deal.
Moving through stages #
There are two ways to advance a deal:
- Edit form — update the Stage field on the opportunity's edit form.
- Pipeline Board — open CRM → Pipeline Board for a drag-and-drop kanban view with one column per stage; drag a card to a new column to move it.
Either way, every stage change is recorded as a stage history entry,
capturing the from stage (from_stage_uuid), to stage
(to_stage_uuid), who moved it (moved_by_uuid), and when
(moved_at), and it fires the opportunity stage-change
automation trigger and opportunity.stage_changed
webhook.
To close a deal, use the Mark as Won or Mark as Lost button on the
opportunity's view page — these set won_at or lost_at respectively. For
lost deals the button also prompts for a Lost Reason to feed
retrospectives.
Converting to a quote #
The Convert to Quote button on an opportunity creates a draft
quote for the same customer (and contact), seeded with a
single line item priced at the opportunity's deal value so the quote total starts
where the deal did. You then refine it into real line items before sending. The
quote keeps a link back to the originating opportunity. Available over the API as
POST /api/v1/crm/opportunities/{id}/convert-to-quote.
Pipeline Board #
CRM → Pipeline Board is a kanban view of your open pipeline: one column per pipeline stage (in configured order, tinted with each stage's color), with every opportunity shown as a draggable card carrying its title, customer, value, and assigned owner. Each column header totals the count and summed value of the deals in it, so the board doubles as a live pipeline-value readout.
Drag a card to another column to move that deal to the new stage. Because the
board changes the same pipeline_stage_uuid, it records stage history and fires
the same automation and webhook as the edit form. Two columns are special:
- Dropping a card into a won stage marks the deal won (sets
won_atand bumps probability to 100%). - Dropping a card into a lost stage opens a prompt for the Lost Reason,
then marks it lost (
lost_at).
Dragging a closed deal back to an open stage clears its won/lost outcome.
The opportunity list #
CRM → Opportunities shows every deal with its title, customer, stage badge (colored by the stage's configured color), value, probability, assigned team member, and expected close date. Click any row to open the detail view.
Filter the list by stage (multi-select) to focus on a part of the funnel. The Trashed filter surfaces soft-deleted records. Sort by value, probability, or close date to prioritize.
Pipeline stages as their own resource #
Pipeline stages have their own management page at CRM → Pipeline Stages. The
form fields are: Name (required), Color (hex color picker, defaults to
#6b7280), Sort Order (integer, lower = further left), Marks as Won,
and Marks as Lost. The two "marks" toggles are wired so turning one on
automatically turns the other off, keeping the win/loss flags mutually
exclusive.
At most one stage should be flagged Marks as Won and one Marks as Lost. The API does not enforce uniqueness, but reports and
won_at/lost_attimestamps rely on the convention that each flag belongs to exactly one stage.
Stage history #
Every time an opportunity moves to a new stage, an OpportunityStageHistory
record is written with from_stage_uuid, to_stage_uuid, moved_by_uuid,
and moved_at. These records are not soft-deleted and accumulate permanently
so the deal's journey through the pipeline is never lost, even if the
opportunity itself is archived.
The opportunity's view page has a read-only Stage History tab listing each
move (from stage, to stage, who moved it, and when), newest first. The same
history is available over the API at
GET /api/v1/crm/opportunities/{id}/stage-history. Note the initial stage set
when the opportunity is created is not itself a move, so history begins at the
first stage change.
Relationship to other modules #
- Customers — every opportunity belongs to a customer. The customer page lists all opportunities associated with that account.
- Contacts — optionally tied to a specific customer contact.
- Quotes — once an opportunity reaches proposal stage you will typically create a quote linked to the same customer.
- Customer Invoices — won deals progress to invoices manually; there is no automatic conversion.
- Automation Rules — the opportunity stage change event can trigger automation rules, for example to send a notification or create a task when a deal is won.
Doing it from the API #
# List open opportunities assigned to a specific customer
curl "https://your-domain.com/api/v1/crm/opportunities?status=open&customer_id=<id>" \
-H "Authorization: Bearer $TOKEN"
# Create an opportunity (value in cents: 250000 = $2,500.00)
curl -X POST "https://your-domain.com/api/v1/crm/opportunities" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "<customer-id>",
"pipeline_stage_id": "<stage-id>",
"title": "New ERP rollout - Acme Corp",
"value": 250000,
"probability": 60,
"expected_close_date": "2026-09-30",
"source": "referral"
}'
# Mark an opportunity as won
curl -X PUT "https://your-domain.com/api/v1/crm/opportunities/<id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"won_at": "2026-06-02"}'
# Read an opportunity's stage-change history (newest first)
curl "https://your-domain.com/api/v1/crm/opportunities/<id>/stage-history" \
-H "Authorization: Bearer $TOKEN"
valueis sent and returned in cents over the API —250000equals $2,500.00. Thestatusfilter acceptsopen,won, orlost.pipeline_stage_idis optional — omit it to create an unstaged opportunity, matching the form, which also allows "No stage". Pipeline stages are managed separately at/api/v1/crm/pipeline-stages.