Pipelines
List pipelines, inspect their steps, and move records between stages.
Pipelines define the stages a record moves through in your workflow. Any object with a PIPELINE field can have one or more pipelines associated with it -- not just opportunities.
List all pipelines
GET /api/v1/pipelinesReturns every pipeline in your organization, including their ordered steps.
Response
{
"pipelines": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Sales Pipeline",
"objectName": "opportunities",
"steps": [
{
"id": "step-001",
"name": "Qualification",
"order_index": 0
},
{
"id": "step-002",
"name": "Discovery",
"order_index": 1
},
{
"id": "step-003",
"name": "Proposal",
"order_index": 2
},
{
"id": "step-004",
"name": "Negotiation",
"order_index": 3
},
{
"id": "step-005",
"name": "Closed Won",
"order_index": 4
}
]
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"name": "Recruitment Pipeline",
"objectName": "candidates",
"steps": [
{
"id": "step-010",
"name": "Applied",
"order_index": 0
},
{
"id": "step-011",
"name": "Screening",
"order_index": 1
},
{
"id": "step-012",
"name": "Interview",
"order_index": 2
},
{
"id": "step-013",
"name": "Offer",
"order_index": 3
}
]
}
]
}Example
curl -X GET "https://kasar.app/api/v1/pipelines" \
-H "Authorization: Bearer YOUR_API_TOKEN"Move a record to a different step
PUT /api/v1/pipelines/{object}/{id}/moveMoves a record to a different pipeline step. Works with any object that has a PIPELINE field.
Path parameters
| Parameter | Type | Description |
|---|---|---|
object | string | The object name (e.g., opportunities, candidates) |
id | string | The record ID to move |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
pipeline_step_id | string | Yes | The target step ID |
pipeline_id | string | No | The pipeline ID. Auto-inferred from the step if not provided. |
{
"pipeline_step_id": "step-003"
}Behavior
- The endpoint validates that the target step belongs to the specified (or inferred) pipeline.
- If
pipeline_idis omitted, Kasar looks up which pipeline owns the given step and uses it automatically. - If the step does not belong to the pipeline, the request is rejected with a validation error.
- The endpoint runs the canonical pipeline transition flow (same code path as kanban drag-drop and the in-app table step picker):
- Required-field validation. If the source step has
required_for_next_stagequestions (forward transition) or the source/target steps haverequired_for_closurequestions (closure towon/lost), the endpoint refuses the move when those linked fields are empty on the record. The response isMISSING_REQUIRED_FIELDSwith the list of missing field names. Forced-value questions are exempt (the server fills them automatically). - The step column on the record is updated.
pipeline_step_entered_atis stamped (drivespipeline_step_duration).- Forced and default values configured on the target step are applied to the record server-side. Forced values overwrite any existing value; default values fill empty fields.
- A witness row is recorded in
pipeline_step_historyso the step is tagged as visited. For a transition from the last ongoing step into a final (won/lost) step, two witness rows are recorded — one for the step left, one for the final step entered. Backward transitions (target step before current in the order) do not record a witness row and skip required-field validation.
- Required-field validation. If the source step has
GET /api/v1/pipelinesreturns each pipeline's ordered steps (id,name,order_index) but not the per-step required-field rules. If a move is rejected withMISSING_REQUIRED_FIELDS, thefield_errorsarray names exactly which fields to fill before retrying.- A forward step change can also be done via
PUT /api/v1/{object}/{id}by setting the step column directly — the same validation, side effects and witness-row recording apply.
Response
On success the endpoint returns a flat object (no data wrapper) confirming the move:
{
"deal_id": "record-uuid",
"pipeline_step_id": "step-003",
"action": "moved"
}deal_id echoes the path {id}. The endpoint does not return the full record — clients refetch it (e.g. GET /api/v1/{object}/{id}) if they need the post-move state.
Errors
Every handler error is returned with HTTP status 400 (the route does not vary the status by error code). A 401 is returned by the auth layer for a missing or invalid token. The error body is a flat object — { "code", "message" }, plus field_errors for MISSING_REQUIRED_FIELDS — with no error wrapper.
| Status | Code | Description |
|---|---|---|
| 400 | MISSING_REQUIRED_FIELD | pipeline_step_id is missing from the request body (the path {id} supplies deal_id) |
| 400 | MISSING_REQUIRED_FIELDS | The transition is blocked because required_for_next_stage or required_for_closure fields are empty. The body includes field_errors: [{ field, message }] listing the fields to fill before retrying. |
| 400 | INVALID_OBJECT | The object name in the path is unknown |
| 400 | INVALID_OPERATION | The object has no PIPELINE field, or the step belongs to a different pipeline than the one passed in pipeline_id |
| 400 | PERMISSION_DENIED | The caller cannot edit this record |
| 400 | RECORD_NOT_FOUND | The pipeline step does not exist for this object, or the record does not exist / is not visible to the caller |
| 400 | INTERNAL_ERROR | The transition flow failed (server-side; see message) |
| 401 | UNAUTHORIZED | Missing or invalid API token |
Example: handling MISSING_REQUIRED_FIELDS
{
"code": "MISSING_REQUIRED_FIELDS",
"message": "MISSING_REQUIRED_FIELDS: cannot transition step — fill these fields first: budget, decision_maker",
"field_errors": [
{ "field": "budget", "message": "Budget is required (required_for_next_stage)" },
{ "field": "decision_maker", "message": "Decision maker is required (required_for_next_stage)" }
]
}Fill the listed fields on the record (PUT /api/v1/{object}/{id}) and retry the move.
Example
Move an opportunity to the "Proposal" step:
curl -X PUT "https://kasar.app/api/v1/pipelines/opportunities/record-uuid/move" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"pipeline_step_id": "step-003"
}'Move a record and explicitly specify the pipeline:
curl -X PUT "https://kasar.app/api/v1/pipelines/candidates/record-uuid/move" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"pipeline_step_id": "step-011",
"pipeline_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}'