> ## Documentation Index
> Fetch the complete documentation index at: https://help.reevo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Stages

> Change contact, account, and opportunity stages through normal record patch requests.

<Warning>
  **Restricted access.** Public API v2 is currently available only to allowlisted
  organizations. Requests from workspaces that have not been enabled are rejected.
  Contact your Reevo representative to have your organization added to the allowlist.
</Warning>

# Manage Stages

This is the authoritative guide for changing stages in Public API v2. There is no dedicated stage-shift endpoint. Change stages by patching the `stage` attribute on the record.

This applies uniformly to contact, account, and opportunity: each exposes a writable `stage` attribute. Account stage is backed internally by a different column, but the public write key is `stage` — there is no `current_stage_id` field on the public API.

For the read, write, and filter shape of stage values themselves, see [Selects and Stages](/Public-API-v2/Value-Types/Selects-and-Stages).

## Contact stages

```bash theme={null}
curl -X PATCH "https://api.reevo.ai/api/v2/public/contact/<contact_id>" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": {
      "stage": { "value_type": "select", "value": { "api_name": "working" } }
    }
  }'
```

Stage changes can be blocked by entrance criteria. This applies to contact, opportunity, and account stage moves: when a move is blocked, the API returns `422 stage_entrance_criteria_not_met`.

## Opportunity stages

Opportunity `stage` is required when creating an opportunity.

```json theme={null}
{
  "attributes": {
    "display_name": "Acme - Enterprise Deal",
    "stage": { "value_type": "select", "value": { "api_name": "proposal" } },
    "account_id": "<account_id>",
    "amount": 150000
  }
}
```

Patch the `stage` attribute to move an opportunity:

```bash theme={null}
curl -X PATCH "https://api.reevo.ai/api/v2/public/opportunity/<opportunity_id>" \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": {
      "stage": { "value_type": "select", "value": { "api_name": "closed_won" } }
    }
  }'
```

Opportunity stage writes accept the option `id`, `api_name`, or `display_name` (a bare string is matched as a display name). When the same stage name exists in more than one pipeline, add `select_list_id` to the option reference to pin the pipeline whose stage you mean — for example `{ "select_list_id": "<pipeline stage list id>", "api_name": "closed_won" }`. Referencing by `id` is unambiguous on its own.

### Closing an opportunity

Moving an opportunity into a closing stage requires a close reason in the same request:

* A move to a **closed-won** stage requires `primary_closed_won_reason`.
* A move to a **closed-lost** stage requires `primary_closed_lost_reason`.

These reasons are required only on the closing transition, not on create, so they are not flagged as required-on-create in `GET /api/v2/public/_schema/opportunity`. Discover the valid reasons there: each pipeline's stage list in the schema carries `closed_won_reasons` and `closed_lost_reasons` — the reason options for that specific pipeline. Send the matching reason (by option `id`) in the same patch that moves the opportunity to the closing stage; omitting it rejects the stage change.

### Moving between pipelines

An opportunity belongs to one pipeline at a time. Patching `stage` to a stage that lives in a **different** pipeline migrates the opportunity into that pipeline.

A pipeline move has two rules:

* **Only the target pipeline's initial stage may be set in the move.** Set `stage` to the first (initial) stage of the destination pipeline; setting any later stage returns `400 field_value_invalid` ("Only the initial stage of the target pipeline may be set…"). Advance the opportunity further with a follow-up patch once it is in the new pipeline.
* **Close reasons resolve against the target pipeline.** If the move is also a close, send `primary_closed_won_reason` / `primary_closed_lost_reason` using option `id`s from the destination pipeline's reason lists (see above).

A destination pipeline with no active stage, or a move the pipeline rejects, also returns `400 field_value_invalid` with the reason in `details`.

## Read-only opportunity fields

Do not write these fields directly:

* `closed_at`
* `stage_last_shifted_at`

They are rendered on reads where available, but direct writes are rejected as `unknown_field` (the API does not expose them as writable attributes).

`closed_at` is stamped when the opportunity first enters a closing stage and is not re-stamped if it later moves to a different closing stage. `stage_last_shifted_at`, by contrast, advances on every stage change.

An opportunity's won/lost outcome is not a writable top-level field. It is exposed through the `stage` value's `outcome_state` (`OPEN`, `CLOSED_WON`, or `CLOSED_LOST`) and changes only as a side effect of moving the opportunity to a closing stage. There is no top-level `outcome` or `status` attribute to write; sending one is rejected as `unknown_field`.

## Common errors

| Error code                        | Usually means                                                                                                                                                                                                                                                               | How to recover                                                                                        |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `request_validation_failed`       | A required standard field (`display_name`, `stage`, `account_id`) was omitted on opportunity create (`422`), or a required standard field's value failed type validation — for example an explicit `stage: null` (`400`). `details.loc`/`type`/`all_errors` name the field. | Include every required standard field in the create request, and send a real value rather than `null` |
| `field_required_missing`          | A required custom field was omitted on opportunity create. Returns `400`.                                                                                                                                                                                                   | Include the required custom field                                                                     |
| `field_value_invalid`             | A stage value could not be resolved (for example an unknown stage `id`), or a pipeline move was invalid — a non-initial target stage, a destination pipeline with no active stage, or a move the pipeline rejected (returns `400`); `details` carries the reason            | Set the target pipeline's initial stage (then shift in a follow-up patch), or use a valid stage `id`  |
| `unknown_field`                   | Request tried to write a read-only or system-managed stage-related field (such as `closed_at`, `stage_last_shifted_at`, or a top-level `outcome`/`status`) — these are not exposed as writable attributes                                                                   | Remove read-only fields from the request                                                              |
| `stage_entrance_criteria_not_met` | A contact, opportunity, or account stage move is blocked by criteria                                                                                                                                                                                                        | Fix the missing prerequisites before retrying                                                         |
