Contents
On this page
Move Opportunity Stage - Plugixa CRM
PUT /plugixa-crm/v1/opportunities/{id}/stage
Move an opportunity to another stage of its pipeline, as dragging it on the board does. PATCH works the same way.
Any user with access to Plugixa CRM. With Plugixa CRM Pro roles, the user’s role must also allow editing this opportunity.
Note. Moving to the stage it is already in still records a history entry and resets
probabilityandlast_stage_change_at.
Request
PUT https://your-site.example/wp-json/plugixa-crm/v1/opportunities/24/stage
Path parameters
| Name | Type | Description |
|---|---|---|
id |
integer |
The opportunity’s id |
Request body
Content type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
stage_id |
integer |
Yes | A stage of the opportunity’s pipeline. |
lost_reason |
string |
No | Stored only when the stage is a lost stage. |
The move sets status to the stage’s type, probability to the stage’s probability and last_stage_change_at to now. A won or lost stage stamps closed_at; an open stage clears it. Each move is added to history with the time spent in the previous stage.
{
"stage_id": 6,
"lost_reason": "Went with a competitor"
}
Responses
200 OK. data is the moved opportunity.
{
"success": true,
"data": {
"id": 24,
"name": "Northwind Traders: platform licence",
"account_id": 12,
"contact_id": 31,
"lead_id": null,
"pipeline_id": 1,
"stage_id": 6,
"amount": 12000,
"currency": "EUR",
"amount_base": 13020,
"probability": 0,
"close_date": "2026-12-15",
"status": "lost",
"lost_reason": "Went with a competitor",
"source": "",
"description": "",
"last_stage_change_at": "2026-11-12 10:15:00",
"closed_at": "2026-11-12 10:15:00",
"assigned_user_id": "3",
"created_by": "1",
"modified_by": "1",
"created_at": "2026-11-12 09:30:00",
"modified_at": "2026-11-12 10:15:00",
"deleted_at": null,
"history": [
{
"id": 31,
"opportunity_id": 24,
"from_stage_id": null,
"to_stage_id": 3,
"from_status": null,
"to_status": "open",
"amount_at_change": 13020,
"seconds_in_from_stage": null,
"changed_by": "1",
"changed_at": "2026-11-12 09:30:00",
"to_stage_name": "Proposal",
"from_stage_name": null
},
{
"id": 37,
"opportunity_id": 24,
"from_stage_id": 3,
"to_stage_id": 6,
"from_status": "open",
"to_status": "lost",
"amount_at_change": 13020,
"seconds_in_from_stage": 2700,
"changed_by": "1",
"changed_at": "2026-11-12 10:15:00",
"to_stage_name": "Closed Lost",
"from_stage_name": "Proposal"
}
],
"stage": {
"id": 6,
"pipeline_id": 1,
"name": "Closed Lost",
"slug": "closed-lost",
"type": "lost",
"probability": 0,
"color": "#dc2626",
"position": 5,
"created_at": "2026-11-12 09:30:00"
},
"stages": [
{
"id": 1,
"pipeline_id": 1,
"name": "Qualification",
"slug": "qualification",
"type": "open",
"probability": 10,
"color": "#64748b",
"position": 0,
"created_at": "2026-11-12 09:30:00"
},
{
"id": 2,
"pipeline_id": 1,
"name": "Needs Analysis",
"slug": "needs-analysis",
"type": "open",
"probability": 25,
"color": "#0ea5e9",
"position": 1,
"created_at": "2026-11-12 09:30:00"
},
{
"id": 3,
"pipeline_id": 1,
"name": "Proposal",
"slug": "proposal",
"type": "open",
"probability": 50,
"color": "#6366f1",
"position": 2,
"created_at": "2026-11-12 09:30:00"
},
{
"id": 4,
"pipeline_id": 1,
"name": "Negotiation",
"slug": "negotiation",
"type": "open",
"probability": 75,
"color": "#a855f7",
"position": 3,
"created_at": "2026-11-12 09:30:00"
},
{
"id": 5,
"pipeline_id": 1,
"name": "Closed Won",
"slug": "closed-won",
"type": "won",
"probability": 100,
"color": "#16a34a",
"position": 4,
"created_at": "2026-11-12 09:30:00"
},
{
"id": 6,
"pipeline_id": 1,
"name": "Closed Lost",
"slug": "closed-lost",
"type": "lost",
"probability": 0,
"color": "#dc2626",
"position": 5,
"created_at": "2026-11-12 09:30:00"
}
]
}
}
| Field | Type | Meaning |
|---|---|---|
data.stage_id |
integer |
The current stage |
data.status |
string |
open, won or lost, taken from the stage’s type |
data.probability |
integer |
0 to 100 |
data.closed_at |
string|null |
UTC datetime it reached a won or lost stage |
data.history |
array |
Every stage move, with from_stage_name, to_stage_name, amount_at_change, changed_at |
Errors
| Status | Code | When |
|---|---|---|
404 |
plugixa_crm_not_found |
No opportunity with that id, or it is in the trash. |
422 |
plugixa_crm_invalid_stage |
stage_id is missing or not an existing stage. |
422 |
plugixa_crm_stage_pipeline_mismatch |
The stage belongs to another pipeline. |
Plus the errors every endpoint can return.
Examples
curl -s -X PUT "https://your-site.example/wp-json/plugixa-crm/v1/opportunities/24/stage" \
-u "admin:$WP_APP_PASSWORD" \
-H "Content-Type: application/json" \
-d '{"stage_id":6,"lost_reason":"Went with a competitor"}'
<?php
$ch = curl_init('https://your-site.example/wp-json/plugixa-crm/v1/opportunities/24/stage');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'admin:' . getenv('WP_APP_PASSWORD'),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'stage_id' => 6,
'lost_reason' => 'Went with a competitor',
]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
const auth = 'Basic ' + btoa(`admin:${process.env.WP_APP_PASSWORD}`);
const response = await fetch('https://your-site.example/wp-json/plugixa-crm/v1/opportunities/24/stage', {
method: 'PUT',
headers: {
'Authorization': auth,
'Content-Type': 'application/json',
},
body: JSON.stringify({ stage_id: 6, lost_reason: 'Went with a competitor' }),
});
const { data } = await response.json();
Quick Links
Share