Skip to content

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.