Appearance
Update an opportunity
Partial update — send only the fields you want to change. Existing values for omitted fields are preserved.
Just like Retrieve, the URL accepts either the numeric id or a contact phone number (digits only, country code prefix, no + — e.g. 201062691152).
Narrow the phone lookup with pipeline_id
The same contact phone can be linked to opportunities in more than one pipeline. When you update by phone, pass an optional pipeline_id query parameter to make sure you hit the opportunity in the pipeline you care about. Ignored when the identifier is a numeric id.
PUT/api/user/opportunities/{identifier}
Required scope:
opportunities:writePath parameters
integer | string
Query parameters
integer
Request body (JSON)
curl -X PUT "https://loopx-console.test/api/user/opportunities/98314" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"stage_id":189,"notes":"notes","status":"active","context":{"source_campaign":"summer-2026"},"tags":["vip"],"deleted_tags":[],"contact":{"name":"Ali","priority":"high"}}'Example response
{
"status": true,
"code": 200,
"validation": [],
"message": "Success",
"data": {
"id": 98314,
"status": "active",
"contact_id": 44016,
"stage_id": 189,
"pipeline_id": 17,
"name": null,
"notes": "notes",
"created_at": "2026-07-06T12:28:57.000000Z",
"updated_at": "2026-07-06T13:36:27.000000Z",
"source": "facebook",
"source_id": "120248819452900116",
"contact_name": "Ali",
"contact_custom_name": null,
"contact_priority": null,
"contact_identifier": "36537370685479@lid",
"contact_email": null,
"contact_custom_email": null,
"contact_phone": "201062691152",
"contact_custom_phone": null,
"stage_nature": "neutral",
"stage_name": "New Lead",
"tags": [],
"conversations": [
{
"id": 89328,
"is_test": false,
"last_message_at": "2026-07-06T13:10:21.000000Z",
"messages_count": 2,
"cost_for_user": 0.014633325,
"status": "active",
"last_message_content": "…last AI reply preview…",
"avg_response_time": 0,
"pivot": {
"opportunity_id": 98314,
"conversation_id": 89328
}
}
]
}
}The response mirrors the Retrieve response — you get the fully updated opportunity back so you don't need a follow-up request.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
identifier | integer | string | yes | Opportunity id or contact phone number |
Query parameters
| Name | Type | Description |
|---|---|---|
pipeline_id | integer | Optional. When updating by phone, restricts the match to a single pipeline. Ignored when the identifier is a numeric id. |
Request body
All fields optional — send only what you want to change.
| Field | Type | Description |
|---|---|---|
stage_id | integer | Move the opportunity to this stage (must belong to the same pipeline) |
name | string | Max 255 chars |
notes | string | null | Free-form notes |
status | enum | active, won, lost (see OpportunityStatus) |
context | object | null | Arbitrary key-value metadata attached to the opportunity (merged on the AI side) |
tags | string[] | Tag names to add to this opportunity (created if they don't exist yet) |
deleted_tags | integer[] | Tag ids to remove from this opportunity |
contact.name | string | null | Contact display name override |
contact.email | string | null | Valid email override |
contact.phone | string | null | Phone number override |
contact.priority | enum | low, medium, high (see ContactPriority) |
Errors
| Code | When |
|---|---|
403 | Token missing opportunities:write scope |
404 | Opportunity not found in your workspace |
422 | stage_id doesn't exist, invalid enum value, or bad contact.email |