Opportunities API
https://<your-host>/api/opportunities/
This page covers the parts most integrations need. The full reference is Opportunities in the CRM docs.
List
GET /api/opportunities/?pipeline=<pipeline-id>&open=true
Authorization: Bearer <token>
The response carries the page of deals under opportunities, plus totals computed over the whole
filtered set rather than the current page: count, amount_sum, weighted_sum (the amount times
the probability, summed), a by_currency breakdown, and stalled_count. Deals in different
currencies are never added together; with more than one currency in the set the two sums are null
and by_currency carries the figures. A non-admin only sees deals they created or are assigned to.
Each deal in the list also carries next_activity: { "id", "title", "due_date" } for its earliest
open task that the caller can open (soonest due date first, undated tasks last), or null when
there is none. It is sent for won and lost deals too; both clients show it, and flag its absence,
only on open deals, reading stage_kind. The deal detail does not include it.
Filters: name, search, account, stage and lead_source (both substring matches, and
case-sensitive), tags, assigned_to, created_at__gte/lte, closed_on__gte/lte,
amount__gte/lte, cf_<key>, pipeline (a pipeline id), open=true (excludes won and lost
stages) and rotten=true (stalled deals only).
GET /api/opportunities/export/ takes the same query string and returns the same rows as a CSV.
See CSV import and export.
Create
POST /api/opportunities/
{
"name": "Acme, Annual 2026",
"account": "a001-…",
"pipeline": "91be-…",
"stage": "PROPOSAL",
"amount": "24000",
"currency": "USD",
"closed_on": "2026-06-30"
}
name is required and unique per org, case-insensitive. pipeline defaults to your org's default
pipeline and stage to that pipeline's first open stage. A won or lost stage needs closed_on, and a
won stage also needs amount. probability is auto-filled when it is 0 or unset. contacts,
tags, teams and assigned_to are lists of ids from your org.
Detail, update, delete
GET /api/opportunities/<id>/
PATCH /api/opportunities/<id>/
PUT /api/opportunities/<id>/
DELETE /api/opportunities/<id>/
Reading or editing a deal needs an admin, its creator or one of its assignees. Deleting needs an
admin or its creator. Changing pipeline requires a stage of the new pipeline in the same request.
Moving a deal
PATCH /api/opportunities/<id>/move/
{ "column_id": "NEGOTIATION" }
column_id is a stage code of the deal's own pipeline; anything else is a 400, since the board
never moves a deal between pipelines. Moving into a won or lost stage records who closed it (and the
close date, if the deal had none); moving a closed deal back to an open stage clears that. Moving
into a won stage without an amount is a 400.
GET /api/opportunities/kanban/?pipeline=<id> returns one column per stage of that pipeline, or of
the default pipeline when pipeline is absent, with at most 100 cards per column and the column's
full count in item_count. From django-crm 1.13.0 it takes every filter the deal list takes (name
and search, account, stage, lead source, tags, assignees, the created, closed and amount ranges,
custom fields, open=true and rotten=true), so a filter narrows the board and the list the same
way. Each card carries tags, line_items, stage_changed_at, updated_at and can_move (whether
you may move it) beside its name, stage, amount, account, assignees, aging and next step.
Pipelines and stages
Reads are open to every member of the org; every write is admin-only (403 otherwise). An id from
another org is a 404.
| Endpoint | Method | Does |
|---|---|---|
/api/opportunities/pipelines/ |
GET | every pipeline with its stages, default first |
/api/opportunities/pipelines/ |
POST | {"name"}; creates a pipeline seeded with the six default stages |
/api/opportunities/pipelines/<id>/ |
GET, PATCH, DELETE | rename or delete; the default pipeline, or one holding deals, cannot be deleted |
/api/opportunities/pipelines/<id>/stages/ |
POST | {"label", "kind", "expected_days"?, "warning_days"?}; appends a stage |
/api/opportunities/pipelines/<id>/stages/reorder/ |
POST | {"stage_ids": [...]}, every stage of the pipeline exactly once |
/api/opportunities/stages/<id>/ |
PATCH, DELETE | edit or remove one stage |
A stage has a code (derived from the label when it is created and never changed afterwards), a
label, an order, a kind (open, won or lost) and optional expected_days and
warning_days between 1 and 3650. Every pipeline keeps at least one stage of each kind, and a stage
cannot be deleted or change kind while deals are in it.
A deal is flagged past expected at warning_days (or expected_days) in an open stage, and stalled
at one and a half times expected_days.