# Start Editing an Approved Template

> Starts editing a template that is ready for automation, once the person picks what happens after the edit.

- **URL**: https://orshot.com/docs/api-reference/approvals-items-start-edit

---

The Approvals API is available on Enterprise plans, or through first-party apps (the Orshot app and the Orshot MCP server). This endpoint needs [`move` access](/docs/api-reference/approvals-overview#access-levels).
See [Enterprise pricing](https://orshot.com/pricing) to get access.

Starts editing a template that is ready for automation, once the person picks what happens after the edit. Until then, design writes to it (in a locked stage that renders, like Automation approved) are refused with stage_locked, code approval.edit.choice_required. Ask the person which they want. mode keep: edit it where it is and it stays ready for automation (approvers of the stage, owners and admins only). mode review: edit it where it is, then send it to the review before its stage. mode draft: move it to Draft now, where it can be edited. With keep or review, automation keeps rendering the approved design while you edit; finish with [finish editing an approved template](https://orshot.com/docs/api-reference/approvals-items-finish-edit).

Send an `Idempotency-Key` header to retry safely: a repeat within 24 hours returns the first response and changes nothing.

## Endpoint

```markdown tab="Endpoint"
https://api.orshot.com/v1/approval-flows/:flow/items/:item/start-edit
```

## Path Parameters

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `flow` | String | Yes | The approval flow's id or slug. A number is an id, anything else a slug. |
| `item` | Integer | Yes | The approval item's id (one template in one approval flow). |

## Request Body

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `mode` | String | Yes | What happens after the edit: keep (edit it where it is; approvers of the stage, owners and admins), review (edit it where it is, then send it to the review before its stage) or draft (move it to Draft now). |
| `revision` | Integer | No | The item's revision you last saw; refused with state_conflict if it changed. |

## Headers

| Header | Required | Description |
| ------ | -------- | ----------- |
| `Authorization` | Yes | `Bearer <API key or OAuth token>` |
| `x-workspace-id` | No | OAuth tokens with several workspaces: the workspace to act in. API keys ignore it. |
| `X-Orshot-User-Id` | No | API keys only: the user id of the owner, admin or member this call is for. See Acting for a Team Member below. |
| `Idempotency-Key` | No | Up to 255 visible characters, unique per request. A replay within 24 hours returns the stored response with Idempotent-Replayed: true. |
| `X-Session-Id` | No | Groups the calls of one agent or MCP session in the activity history. |

## Acting for a Team Member

With an API key, you can send `X-Orshot-User-Id` with the user id of an owner, admin or member of the workspace to make this call for them. It needs both the key's access level and that person's own access, and it's credited to them: people see "Priya Shah, via API key", and they aren't notified about their own change. See [acting for a team member](https://orshot.com/docs/api-reference/approvals-overview#acting-for-a-team-member).

## Request

**Request**
```js
await fetch("https://api.orshot.com/v1/approval-flows/brand-and-legal/items/1/start-edit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
    "Idempotency-Key": "<unique request id>",
  },
  body: JSON.stringify({
    "mode": "keep"
  }),
});
```

**Response**
```json
{
  "item": {
    "id": 1,
    "flow": {
      "id": 1,
      "slug": "brand-and-legal",
      "name": "Brand and legal"
    },
    "stage": {
      "id": 5,
      "slug": "approved-for-automation",
      "name": "Automation approved",
      "category": "approved",
      "color": null
    },
    "template": {
      "id": 101,
      "name": "Spring sale banner",
      "thumbnailUrl": "https://storage.orshot.com/thumbnails/101.png",
      "currentVersion": "5b8e2f7a-3c1d-4e9b-a6f0-7d2c8e1b4a93",
      "folderId": null,
      "tags": []
    },
    "reviewRound": 1,
    "revision": 6,
    "approvals": null,
    "changesRequested": null,
    "commentCount": 2,
    "canRender": {
      "image": true,
      "pdf": true,
      "video": true
    },
    "heldBack": null,
    "editSession": {
      "mode": "keep",
      "startedAt": "2026-09-28T09:30:00.000Z",
      "by": {
        "id": "7c1e4b2a-5d3f-4a8e-9b61-2f0d8c3e5a17",
        "name": "Sam Rivera",
        "email": "sam@acme.com",
        "role": "owner"
      }
    },
    "dueAt": null,
    "createdAt": "2026-09-28T09:30:00.000Z",
    "updatedAt": "2026-09-28T09:30:00.000Z"
  },
  "warnings": []
}
```

## Response Fields

Responds `200` with:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `item` | Object | One ApprovalItem, fields below. |
| `item.id` | Integer | Numeric id. |
| `item.flow` | Object | `{ id, slug, name }`. |
| `item.stage` | Object | `{ id, slug, name, category, color }`. Color is the stage's color, null when it has none. |
| `item.template` | Object | `{ id, name, thumbnailUrl, currentVersion, folderId, tags }`. With currentVersion to send back as reviewedVersion when approving, folderId the template's folder (null for none) and tags its tags (string[]). |
| `item.reviewRound` | Integer | Goes up each time the template re-enters review. |
| `item.revision` | Integer | Send it back on move (state_conflict if it changed). |
| `item.approvals` | Object | `{ mode, required, approvedBy: Person[], changesRequestedBy: Person[], submitter?: { id } }`. For the current round, in review stages. submitter is who submitted it when the stage keeps them from approving it themselves (the stage doesn't let people approve what they submitted, and they are not an owner or admin). |
| `item.changesRequested` | Object | `{ by: Person[], stage: { id, slug, name } }`. The change request it was sent back with, until it is resubmitted. Can be `null`. |
| `item.commentCount` | Integer | Comments on the template (replies included, deleted ones left out). |
| `item.canRender` | Object | `{ image, pdf, video }`. Booleans. |
| `item.movedWithoutApproval` | Object | `{ by: Person, at: ISO date, reason }`. or absent, present while the template sits where an owner or admin moved it without its approvals. |
| `item.dueAt` | String | ISO 8601 timestamp. Can be `null`. |
| `item.createdAt` | String | ISO 8601 timestamp. |
| `item.updatedAt` | String | ISO 8601 timestamp. |
| `warnings` | Array | Non-blocking notices, each `{ code, message? }`, for example `no_approver`. Always present on writes, empty when there is nothing to say. |

## Error Responses

Every error has the same body: `error`, `code`, `message` and `helpUrl`, plus the fields that apply (`required`, `role`, `context`, `blockers`, `violations`, `issues`, `current`). Branch on `error`; `code` is more specific. See the [error reference](https://orshot.com/docs/error-reference).

| Status Code | Error | Description |
| ----------- | ----- | ----------- |
| 401 | `oauth_token_invalid` | The OAuth token is invalid, expired or revoked. |
| 403 | `api_key_missing` | No `Authorization: Bearer` header. |
| 403 | `permission_denied` | You don't have access to do this. Ask an owner or admin. `code` names the capability, for example `approval.item.decide_denied`; `required` and `role` say what was missing. With `code: insufficient_scope`: the OAuth token lacks `workspace:approvals:write`. With `code: approval.member_header_not_member`: `X-Orshot-User-Id` names someone who isn't an owner, admin or member of the workspace now. With `code: approval.member_header_not_allowed`: an OAuth token sent `X-Orshot-User-Id`. |
| 403 | `plan_required` | The workspace's plan doesn't include Approvals, or doesn't include this part of it. |
| 403 | `enterprise_api_required` | Using approvals with an API key needs an Enterprise plan. Contact hi@orshot.com to turn it on. |
| 404 | `not_found` | This doesn't exist or isn't available to you. Reviewers get this, never 403, for flows and templates outside their access. |
| 409 | `state_conflict` | Someone else moved this template first. Refresh to see where it is now. `current` carries the item's revision and stage now. |
| 409 | `state_conflict` | With `code: approval.request_in_progress`: the same Idempotency-Key is still running. |
| 422 | `validation_failed` | Some fields aren't valid: the fields listed in issues. `issues` lists each field with a path and a reason. |
| 422 | `validation_failed` | With `code: approval.member_header_invalid`: `X-Orshot-User-Id` isn't a user id. |
| 422 | `validation_failed` | With `code: approval.idempotency_key_reused`: the Idempotency-Key was used with a different request. |
| 429 | `rate_limit_exceeded` | More than 120 approvals requests in a minute from one person or key. Wait for Retry-After. |
| 503 | `approvals_unavailable` | Approvals aren't available right now. Try again in a moment. Also returned while approvals are not switched on for the API. |