Skip to content

Opportunities & Pipelines

An opportunity tracks a deal as it moves through a pipeline, from first contact to won or lost. Each opportunity sits in one pipeline stage, can link back to a contact, and carries a monetary value you can report on.

Base URL: https://services.smbcrm.com · Version header: v3 · Scopes: opportunities.readonly (read), opportunities.write (create/update/delete opportunities). Pipeline management uses pipelines.readonly (get one pipeline), pipelines.create (create), and pipelines.write (update/delete). Listing pipelines only needs opportunities.readonly. See Scopes.

A pipeline is an ordered list of stages that deals move through. You can build pipelines and stages in the SMBcrm UI, or create and manage them with the endpoints in this section.

GET/opportunities/pipelines

List every pipeline in your account, with its stages in order.

scope opportunities.readonlyauth Location token or PIT

locationId is required as a query parameter. Use this endpoint to look up the pipeline and stage IDs you need when you create or move an opportunity. Each pipeline’s position is a string sort key (such as a0V), not a number, and it orders pipelines in your account.

Terminal window
curl "https://services.smbcrm.com/opportunities/pipelines?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"pipelines": [
{
"id": "<pipeline_id>",
"name": "Sales Pipeline",
"locationId": "<location_id>",
"showInFunnel": true,
"showInPieChart": true,
"useOpportunityProbability": false,
"colorRenderMode": "dot",
"position": "a0V",
"stages": [
{ "id": "<pipeline_stage_id>", "name": "New Lead", "position": 1, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Contacted", "position": 2, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Proposal Sent", "position": 3, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Won", "position": 4, "showInFunnel": true }
]
}
]
}
POST/opportunities/pipelines

Create a pipeline with at least one stage.

scope pipelines.createauth Location token or PIT

name, stages, and locationId are required. Pipeline names must be unique within a location (case-insensitive), and stage names must be unique within the pipeline. A successful call returns HTTP 200 with the new pipeline.

Body field Description
name Pipeline name. Required.
locationId Your account/location ID. Required.
stages Array of stage objects, at least one. Required. Each stage takes a name, a position, showInFunnel, and an optional stageWinProbability.
showInFunnel Whether the pipeline appears in the funnel view.
showInPieChart Whether the pipeline appears in the pie chart view.
useOpportunityProbability Turns on stage-level win probability.
colorRenderMode How colors render: dot, bg-tint, or none.

To use manual win probabilities, set useOpportunityProbability to true and give every stage a stageWinProbability from 0 to 100. If any stage has no value, SMBcrm calculates probabilities from each stage’s position instead.

Terminal window
curl -X POST https://services.smbcrm.com/opportunities/pipelines \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"locationId": "<location_id>",
"name": "Sales Pipeline",
"stages": [
{ "name": "New Lead", "position": 1, "showInFunnel": true },
{ "name": "Contacted", "position": 2, "showInFunnel": true },
{ "name": "Proposal Sent", "position": 3, "showInFunnel": true },
{ "name": "Won", "position": 4, "showInFunnel": true }
],
"showInFunnel": true,
"showInPieChart": true,
"useOpportunityProbability": false,
"colorRenderMode": "dot"
}'
200 OK
{
"id": "<pipeline_id>",
"name": "Sales Pipeline",
"locationId": "<location_id>",
"showInFunnel": true,
"showInPieChart": true,
"useOpportunityProbability": false,
"colorRenderMode": "dot",
"position": "a0V",
"stages": [
{ "id": "<pipeline_stage_id>", "name": "New Lead", "position": 1, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Contacted", "position": 2, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Proposal Sent", "position": 3, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Won", "position": 4, "showInFunnel": true }
]
}
GET/opportunities/pipelines/{pipelineId}

Fetch a single pipeline by ID, with its stages and settings.

scope pipelines.readonlyauth Location token or PIT

This endpoint uses the pipelines.readonly scope. A token with only opportunities.readonly can list pipelines but can’t fetch one by ID.

Terminal window
curl https://services.smbcrm.com/opportunities/pipelines/<pipeline_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"id": "<pipeline_id>",
"name": "Sales Pipeline",
"locationId": "<location_id>",
"showInFunnel": true,
"showInPieChart": true,
"useOpportunityProbability": false,
"colorRenderMode": "dot",
"position": "a0V",
"stages": [
{ "id": "<pipeline_stage_id>", "name": "New Lead", "position": 1, "showInFunnel": true },
{ "id": "<pipeline_stage_id>", "name": "Won", "position": 2, "showInFunnel": true }
]
}
PUT/opportunities/pipelines/{pipelineId}

Rename a pipeline, change its settings, or replace its stages.

scope pipelines.writeauth Location token or PIT

Every body field is optional: name, stages, showInFunnel, showInPieChart, useOpportunityProbability, and colorRenderMode. The body takes no locationId. Pipeline and stage names must stay unique (case-insensitive) within the location.

stages replaces the whole list:

  • Send an existing stage’s id to keep it. A stage without an id is created.
  • You can’t remove every stage in one call.
  • Opportunities in a removed stage move to the remaining stage with the lowest position.
Terminal window
curl -X PUT https://services.smbcrm.com/opportunities/pipelines/<pipeline_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"name": "Sales Pipeline",
"stages": [
{ "id": "<pipeline_stage_id>", "name": "New Lead", "position": 1 },
{ "id": "<pipeline_stage_id>", "name": "Contacted", "position": 2 },
{ "name": "Demo Scheduled", "position": 3 },
{ "id": "<pipeline_stage_id>", "name": "Won", "position": 4 }
]
}'

The response is HTTP 200 with the updated pipeline, in the same shape as Retrieve a pipeline.

DELETE/opportunities/pipelines/{pipelineId}

Permanently delete a pipeline and every opportunity in it.

scope pipelines.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/opportunities/pipelines/<pipeline_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "success": true }

success is true when the pipeline was deleted. If the deletion fails, message explains why.

POST/opportunities/

Create an opportunity in a pipeline stage.

scope opportunities.writeauth Location token or PIT

pipelineId, locationId, name, status, and contactId are required. pipelineStageId is optional and places the deal in a specific stage; use the IDs from Pipelines above. monetaryValue is the deal size in your account’s currency. status accepts open, won, lost, or abandoned.

These optional fields are also accepted:

Body field Description
assignedTo ID of the user who owns the deal. See Users.
forecastExpectedCloseDate Expected close date: YYYY-MM-DD, YYYY/MM/DD, MM/DD/YYYY, MM-DD-YYYY, YYYY.MM.DD, MM.DD.YYYY, or an ISO 8601 timestamp.
forecastProbability Forecast win probability, as a number from 0 to 100.
customFields Array of custom field values. Each entry names the field by id (key also works for string values) and carries a fieldValue, which can be a string, an array of strings, or an object.

For field definitions, see Custom Fields, Values & Tags.

Terminal window
curl -X POST https://services.smbcrm.com/opportunities/ \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"pipelineId": "<pipeline_id>",
"locationId": "<location_id>",
"pipelineStageId": "<pipeline_stage_id>",
"name": "Website redesign - Acme Co.",
"status": "open",
"contactId": "<contact_id>",
"monetaryValue": 4200,
"assignedTo": "<user_id>",
"forecastExpectedCloseDate": "2026-11-15",
"customFields": [{ "id": "<custom_field_id>", "fieldValue": "Referral" }]
}'
201 Created
{
"opportunity": {
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co.",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"locationId": "<location_id>",
"status": "open",
"contactId": "<contact_id>",
"assignedTo": "<user_id>",
"monetaryValue": 4200,
"forecastExpectedCloseDate": "2026-11-15",
"customFields": [{ "id": "<custom_field_id>", "fieldValue": "Referral" }],
"createdAt": "2026-07-08T15:04:00.000Z"
}
}
POST/opportunities/upsert

Create or update an opportunity in a single call.

scope opportunities.writeauth Location token or PIT

Pass the id of an existing opportunity to update it. The response’s new field is true when the call created an opportunity and false when it updated one.

Body field Description
pipelineId Pipeline ID. Required.
locationId Your account/location ID. Required.
followers Array of user IDs to add or remove as followers. Required.
followersActionType add or remove: what to do with the users in followers. Required.
isRemoveAllFollowers Set to true to remove every follower. Required.
id ID of the opportunity to update.
name Opportunity name.
status open, won, lost, or abandoned.
lostReasonId Lost reason ID, for deals you set to lost. See Lost reasons.
pipelineStageId Stage to place the deal in.
monetaryValue Deal size in your account’s currency.
assignedTo ID of the user who owns the deal.
forecastExpectedCloseDate Expected close date, in the same formats as Create an opportunity.
forecastProbability Forecast win probability, as a number from 0 to 100.
Terminal window
curl -X POST https://services.smbcrm.com/opportunities/upsert \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"id": "<opportunity_id>",
"pipelineId": "<pipeline_id>",
"locationId": "<location_id>",
"pipelineStageId": "<pipeline_stage_id>",
"status": "open",
"monetaryValue": 6800,
"followers": [],
"followersActionType": "add",
"isRemoveAllFollowers": false
}'
200 OK
{
"opportunity": {
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co.",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"locationId": "<location_id>",
"status": "open",
"contactId": "<contact_id>",
"monetaryValue": 6800
},
"new": false
}
GET/opportunities/{id}

Fetch a single opportunity by ID.

scope opportunities.readonlyauth Location token or PIT

The response includes the deal’s forecast fields, custom fields, followers, and a contact summary. Unlike the create, update, and search responses, it doesn’t include notes, tasks, calendarEvents, or effectiveProbability.

Terminal window
curl https://services.smbcrm.com/opportunities/<opportunity_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"opportunity": {
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co.",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"locationId": "<location_id>",
"status": "open",
"contactId": "<contact_id>",
"assignedTo": "<user_id>",
"source": "public api",
"monetaryValue": 4200,
"forecastExpectedCloseDate": "2026-11-15",
"forecastProbability": 40,
"customFields": [{ "id": "<custom_field_id>", "fieldValue": "Referral" }],
"followers": ["<user_id>"],
"contact": {
"id": "<contact_id>",
"name": "Jordan Lee",
"companyName": "Acme Co.",
"email": "jordan@example.com",
"phone": "+15125550142",
"tags": ["website-lead"]
},
"createdAt": "2026-07-08T15:04:00.000Z",
"updatedAt": "2026-07-09T09:30:00.000Z",
"lastStatusChangeAt": "2026-07-08T15:04:00.000Z",
"lastStageChangeAt": "2026-07-08T15:04:00.000Z",
"lastActionDate": "2026-07-09T09:30:00.000Z"
}
}
GET/opportunities/search

Search opportunities by pipeline, stage, status, contact, or free text.

scope opportunities.readonlyauth Location token or PIT
Query parameter Description
locationId Your account/location ID. Required.
pipelineId Limit results to one pipeline.
pipelineStageId Limit results to one stage.
status Filter by status: open, won, lost, abandoned, or all.
contactId Limit results to opportunities linked to one contact.
assignedTo Limit results to opportunities assigned to one user.
campaignId Limit results to one campaign.
id Return only the opportunity with this ID.
country Filter by country, as an ISO 3166-1 alpha-2 code such as US.
q Free-text search query, up to 75 characters.
date Start of a date range, as mm-dd-yyyy.
endDate End of the date range, as mm-dd-yyyy.
order Sort order, such as added_asc, added_desc, name_asc, or name_desc.
limit Results per page. Default 20, maximum 100.
page Page number. Default 1.
startAfter Cursor timestamp in epoch milliseconds, taken from meta.startAfter in the previous response.
startAfterId Cursor ID, taken from meta.startAfterId in the previous response. Send it with startAfter.
getTasks, getNotes, getCalendarEvents Set to true to include each result’s tasks, notes, or calendar events.

You can page through results in two ways. Raise page while keeping limit fixed, or send the startAfter and startAfterId values from the previous response’s meta to continue from where it ended. Each result includes assignedTo and a nested contact summary with the contact’s id, name, companyName, email, phone, and tags.

Terminal window
curl "https://services.smbcrm.com/opportunities/search?locationId=<location_id>&pipelineId=<pipeline_id>&status=open&limit=20&page=2" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"opportunities": [
{
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co.",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"status": "open",
"contactId": "<contact_id>",
"assignedTo": "<user_id>",
"monetaryValue": 4200,
"contact": {
"id": "<contact_id>",
"name": "Jordan Lee",
"companyName": "Acme Co.",
"email": "jordan@example.com",
"phone": "+15125550142",
"tags": ["website-lead"]
},
"createdAt": "2026-07-08T15:04:00.000Z"
}
],
"meta": {
"total": 120,
"currentPage": 2,
"nextPage": 3,
"prevPage": 1,
"startAfter": 1625203104328,
"startAfterId": "<opportunity_id>"
}
}
POST/opportunities/search

Search opportunities with a JSON body and get per-stage totals back.

scope opportunities.readonlyauth Location token or PIT

Send every field in the body.

Body field Description
locationId Your account/location ID.
query Full-text search string, up to 75 characters.
limit Results per page.
page Page number, starting at 0.
searchAfter Cursor values for deep pagination, in the form [<timestamp>, "<opportunity_id>"].
additionalDetails Object with four booleans, all required: notes, tasks, calendarEvents, and unReadConversations. Each one chooses whether to include that detail in the response.
Terminal window
curl -X POST https://services.smbcrm.com/opportunities/search \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"locationId": "<location_id>",
"query": "Acme",
"limit": 20,
"page": 0,
"searchAfter": [],
"additionalDetails": {
"notes": false,
"tasks": false,
"calendarEvents": false,
"unReadConversations": false
}
}'

The response lists the matching opportunities and a total. When a pipeline filter applies, stageAggregations adds one object per stage with totalCount, totalValue, weightedValue, openValue, openWeightedValue, and wonValue. The weighted values multiply each deal by its win probability. Use them for pipeline value reports.

200 OK
{
"opportunities": [
{
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co.",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"status": "open",
"contactId": "<contact_id>",
"monetaryValue": 4200,
"createdAt": "2026-07-08T15:04:00.000Z"
}
],
"total": 120,
"stageAggregations": [
{
"pipelineStageId": "<pipeline_stage_id>",
"totalCount": 12,
"totalValue": 24500,
"weightedValue": 14700,
"openValue": 18000,
"openWeightedValue": 10800,
"wonValue": 6500
}
],
"aggregations": {}
}
PUT/opportunities/{id}

Update fields on an existing opportunity, including moving it to a different stage or pipeline.

scope opportunities.writeauth Location token or PIT

Every body field is optional: name, pipelineId, pipelineStageId, status, monetaryValue, assignedTo, forecastExpectedCloseDate, forecastProbability, and customFields. You can’t change the linked contact here. To record a lost reason, use the status endpoint below. The response is HTTP 200 with the updated opportunity.

Terminal window
curl -X PUT https://services.smbcrm.com/opportunities/<opportunity_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"name": "Website redesign - Acme Co. (Phase 2)",
"pipelineStageId": "<pipeline_stage_id>",
"monetaryValue": 6800
}'
200 OK
{
"opportunity": {
"id": "<opportunity_id>",
"name": "Website redesign - Acme Co. (Phase 2)",
"pipelineId": "<pipeline_id>",
"pipelineStageId": "<pipeline_stage_id>",
"locationId": "<location_id>",
"status": "open",
"contactId": "<contact_id>",
"monetaryValue": 6800,
"updatedAt": "2026-07-09T09:30:00.000Z"
}
}
PUT/opportunities/{id}/status

Update only an opportunity's status, for example to mark a deal won, lost, or abandoned.

scope opportunities.writeauth Location token or PIT

status is required: open, won, lost, or abandoned. When you set it to lost, pass lostReasonId too so the deal records why it was lost. See Lost reasons below for valid IDs.

Terminal window
curl -X PUT https://services.smbcrm.com/opportunities/<opportunity_id>/status \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{ "status": "won" }'
200 OK
{ "success": true }

Check success to confirm the change.

DELETE/opportunities/{id}

Permanently delete an opportunity.

scope opportunities.writeauth Location token or PIT
Terminal window
curl -X DELETE https://services.smbcrm.com/opportunities/<opportunity_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "success": true }

Followers are the users who get updates on a deal. Both endpoints take a followers array of user IDs, up to 10 per call. See Users for how to look up user IDs.

POST/opportunities/{id}/followers

Add followers to an opportunity.

scope opportunities.writeauth Location token or PIT
Terminal window
curl -X POST https://services.smbcrm.com/opportunities/<opportunity_id>/followers \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{ "followers": ["<user_id>"] }'

The response lists every follower after the change in followers and the users this call added in followersAdded.

201 Created
{
"followers": ["<user_id>", "<user_id>"],
"followersAdded": ["<user_id>"]
}
DELETE/opportunities/{id}/followers

Remove followers from an opportunity.

scope opportunities.writeauth Location token or PIT

The followers array in the body is required. To remove all followers from the opportunity, also set the query parameter isRemoveAllFollowers=true.

Terminal window
curl -X DELETE https://services.smbcrm.com/opportunities/<opportunity_id>/followers \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{ "followers": ["<user_id>"] }'

The response lists every remaining follower in followers and the users this call removed in followersRemoved.

200 OK
{
"followers": ["<user_id>"],
"followersRemoved": ["<user_id>"]
}
GET/opportunities/lost-reason

List the lost reasons configured for your account.

scope opportunities.readonlyauth Location token or PIT

The id of each reason is what you pass as lostReasonId when you set an opportunity’s status to lost.

Query parameter Description
locationId Your account/location ID. Required.
limit Maximum number of reasons to return. Default 100.
skip Number of reasons to skip, for paging. Default 0.
query Search text.
name Filter by lost reason name.
deleted Set to true to list deleted reasons. Default false.
getCount Set to true to return the total count.
Terminal window
curl "https://services.smbcrm.com/opportunities/lost-reason?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"lostReasons": [
{
"id": "<lost_reason_id>",
"name": "Went with a competitor",
"locationId": "<location_id>",
"createdAt": "2026-01-04T10:00:00.000Z",
"updatedAt": "2026-01-04T10:00:00.000Z"
}
],
"total": 1
}
  • Contacts. The contactId on an opportunity points to a contact record.
  • Conversations & Messages. Follow up with the contact tied to a deal.
  • Users. The assignedTo and followers values are user IDs.
  • Custom Fields, Values & Tags. Define the custom fields you set on a deal.
  • Scopes. The permissions your token needs for each endpoint, including opportunities.readonly, opportunities.write, and the pipelines.* scopes.