---
title: "Approve a proposed plan revision"
method: POST
path: "/experiments/{experiment_id}/finetune-plans/{plan_id}/approve"
tags: ["finetune-plans"]
---

# Approve a proposed plan revision

`POST /experiments/{experiment_id}/finetune-plans/{plan_id}/approve`

Authorise a revision the caller was shown.

Args:
    experiment_id: Experiment the plan belongs to.
    plan_id: Revision to approve.
    request: Digest of the revision as displayed.
    auth: Authenticated caller.

Returns:
    The approved revision.

## Path parameters

- `experiment_id` string, uuid, required
- `plan_id` string, uuid, required

## Request body

- FinetunePlanApproveRequest — Payload for authorising a proposed revision. ``revision_hash`` is the anti-stale check: the caller echoes the hash of the revision they were shown, so a revision that changed between rendering and clicking cannot be approved on the strength of the older display.
  - `revision_hash` string, required

## Response `200`

Successful Response

- FinetunePlanResponse — One plan revision as returned to a user-authenticated caller.
  - `id` string, uuid, required
  - `experiment_id` string, uuid, required
  - `revision` integer, required
  - `revision_hash` string, required
  - `envelope` FinetunePlanEnvelope, required — The machine-checked half of a plan (EDD section 6.1). Every field here maps to a check on a real route. A field that does not belongs in the intent instead -- that split is what keeps "envelope" an enforceable word rather than a decorative one. Note there is no spend limit: owner-set limits are team- and project-scoped only (ENG-6083).
    - `expires_at` string, date-time, required
    - `allow_synthetic_data` boolean
    - `allow_eval_upload` boolean
    - `allowed_base_models` string[]
    - `baseline_model_ids` string[]
    - `allow_preview_deployment` boolean
    - `allow_deployment` boolean
  - `intent` FinetunePlanIntent, required — The recorded, rendered, never-checked half of a plan (EDD section 6.1). ``estimated_cost_usd`` is server-derived at propose (ENG-6414) and shown beside the work so a user can tell a rounding error from a serious bill. Spend is bounded by team and project limits (ENG-6083), not this row.
    - `objective` string, required
    - `success_criteria` string, nullable
    - `baseline` string, nullable
    - `dataset_reasoning` string, nullable
    - `prose_constraints` string, nullable
    - `extra` object
    - `estimated_cost_usd` string, nullable
  - `quote` FinetunePlanQuoteBasisOutput — Pricing inputs the server quotes from. Assumptions, not constraints. The stored ``estimated_cost_usd`` is derived from these fields via ``quote_cost_usd``. They are not hashed: they are inputs to a value that already is.
    - `quote_model` string, required
    - `estimated_gpu_minutes` string, required
    - `estimated_instance_type` string, required
  - `is_current` boolean, required
  - `proposed_by` string, uuid, required
  - `proposed_at` string, date-time, required
  - `approved_by` string, uuid, nullable, required
  - `approved_at` string, date-time, nullable, required
  - `rejected_by` string, uuid, nullable, required
  - `rejected_at` string, date-time, nullable, required

## Other responses

- `422` — Validation Error

## Changes

- **2026-09-24** `1cffaad2a921` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/pioneer/apis/brain-api/changes/experiments/:experiment_id/finetune-plans/:plan_id/approve/post.md)

---

[API](https://skmtc.dev/pioneer/apis/brain-api.md) · [All operations](https://skmtc.dev/pioneer/apis/brain-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pioneer/apis/brain-api/revisions/1cffaad2a921?raw)
