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

# Poll edit status

> Track an in-flight edit and read the final result

## Overview

After [submitting an edit](/api-reference/create-edit), use the returned `edit_id` to poll for progress. The endpoint accepts the same `X-API-Key` you used to create the edit, and only the original submitter (or an active member of the submitter's organization) may read the edit.

```
GET {API_BASE}/v1/edits/{edit_id}
```

<Note>
  Your `API_BASE` is shown in the Developer tab of your dashboard. The default production base is `https://api.knowlify.com`.
</Note>

## Authentication

Send your key in the `X-API-Key` header — the same key (personal or organization) that submitted the edit.

```bash theme={null}
X-API-Key: kn_<64 hex chars>
```

See [Authentication](/api-reference/authentication) for details on key issuance, rotation, and JWT alternatives.

## Path parameters

<ParamField path="edit_id" type="string" required>
  The edit ID returned by `POST /v1/edits`.
</ParamField>

## Code examples

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.knowlify.com/v1/edits/e942890a-7776-4029-82d6-ce733d0a2cb2" \
    -H "X-API-Key: kn_YOUR_KEY_HERE"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `https://api.knowlify.com/v1/edits/${editId}`,
    { headers: { "X-API-Key": "kn_YOUR_KEY_HERE" } },
  );
  const edit = await res.json();
  if (edit.is_complete) {
    console.log("New video link:", edit.result.link);
  }
  ```

  ```python Python theme={null}
  import requests

  resp = requests.get(
      f"https://api.knowlify.com/v1/edits/{edit_id}",
      headers={"X-API-Key": "kn_YOUR_KEY_HERE"},
      timeout=15,
  )
  resp.raise_for_status()
  edit = resp.json()
  if edit["is_complete"]:
      print("New video link:", edit["result"]["link"])
  ```
</CodeGroup>

## Response

<ResponseField name="edit_id" type="string">
  The edit ID (echoes the path parameter).
</ResponseField>

<ResponseField name="video_uuid" type="string">
  The video this edit was submitted against.
</ResponseField>

<ResponseField name="status" type="string">
  Current state. One of:

  * `queued` — another edit on the same video is in flight; this one will run after it finishes.
  * `processing` — phase 1 (Claude edit) is running.
  * `applying` — phase 3 (video sync) is running.
  * `complete` — all three phases finished successfully.
  * `error` — a phase failed. See `error_message`.
  * `reverted` — this edit was undone by [`POST /v1/edits/{edit_id}/revert`](/api-reference/revert-edit).
</ResponseField>

<ResponseField name="is_complete" type="boolean">
  `true` when `status` is `complete` or `reverted`.
</ResponseField>

<ResponseField name="is_failed" type="boolean">
  `true` when `status` is `error`. Inspect `error_message`.
</ResponseField>

<ResponseField name="progress" type="object">
  <Expandable title="progress fields">
    <ResponseField name="stage" type="string">
      One of `queued`, `editing`, `regenerating_frames`, `applying_edits`, `done`.
    </ResponseField>

    <ResponseField name="percent" type="integer">
      Coarse 0–100 progress estimate. Updates at phase boundaries (5 → 40 → 75 → 100); it does not advance continuously inside a phase.
    </ResponseField>

    <ResponseField name="scene_numbers" type="integer[]">
      Present during `regenerating_frames` — the scene numbers being regenerated.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="result" type="object">
  Present once `status` is `complete` or `reverted`.

  <Expandable title="result fields">
    <ResponseField name="link" type="string">
      The new video URL, or `null` when phase 3 was skipped because the target video had never been rendered. See `video_synced`.
    </ResponseField>

    <ResponseField name="changed_scene_numbers" type="integer[]">
      Scenes whose content was modified by the edit.
    </ResponseField>

    <ResponseField name="added_scene_numbers" type="integer[]">
      New scenes inserted by the edit.
    </ResponseField>

    <ResponseField name="deleted_scene_numbers" type="integer[]">
      Scenes removed by the edit.
    </ResponseField>

    <ResponseField name="regenerated_scenes" type="integer[]">
      Scenes whose video clips were regenerated during phase 3.
    </ResponseField>

    <ResponseField name="kept_scenes" type="integer[]">
      Scenes whose clips were carried forward unchanged.
    </ResponseField>

    <ResponseField name="video_synced" type="boolean">
      `false` when the target video had no rendered timestamps and phase 3 was skipped — the planner reflects the edit but no new video was produced.
    </ResponseField>

    <ResponseField name="revert_diff" type="object">
      Present only on `status: "reverted"` responses. Contains `changed_scene_numbers`, `added_scene_numbers`, `deleted_scene_numbers` describing what the revert restored.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="error_message" type="string">
  Human-readable failure reason. `null` on healthy edits.

  When a phase fails because the account ran out of credits mid-flight, this field is prefixed with `INSUFFICIENT_CREDITS:`. Top up the account and resubmit the edit. See [Credit cost](/api-reference/create-edit#credit-cost) for the per-scene rates and the pre-flight check that normally catches this at submission time.
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO-8601 timestamp when the edit was accepted.
</ResponseField>

<ResponseField name="updated_at" type="string">
  ISO-8601 timestamp of the last status change. Use this to detect stalled edits.
</ResponseField>

#### Example response (mid-flight)

```json theme={null}
{
  "edit_id": "e942890a-7776-4029-82d6-ce733d0a2cb2",
  "video_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "is_complete": false,
  "is_failed": false,
  "progress": {
    "stage": "regenerating_frames",
    "percent": 40,
    "scene_numbers": [2]
  },
  "result": null,
  "error_message": null,
  "created_at": "2026-05-25T15:30:01.000000+00:00",
  "updated_at": "2026-05-25T15:30:42.123000+00:00"
}
```

#### Example response (complete)

```json theme={null}
{
  "edit_id": "e942890a-7776-4029-82d6-ce733d0a2cb2",
  "video_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "complete",
  "is_complete": true,
  "is_failed": false,
  "progress": { "stage": "done", "percent": 100 },
  "result": {
    "link": "https://animation-encoder-videos.s3.us-west-2.amazonaws.com/<uuid>.mp4",
    "changed_scene_numbers": [2],
    "added_scene_numbers": [],
    "deleted_scene_numbers": [],
    "regenerated_scenes": [2],
    "kept_scenes": [1, 3, 4, 5],
    "video_synced": true
  },
  "error_message": null,
  "created_at": "2026-05-25T15:30:01.000000+00:00",
  "updated_at": "2026-05-25T15:32:18.500000+00:00"
}
```

<Tip>
  Poll at most once every 5 seconds — `progress.percent` advances at phase boundaries, not per-scene. Production integrations should subscribe to Supabase realtime updates on the `external_edits` table instead. Reach out for a Supabase anon key scoped to your account.
</Tip>

## Limits & errors

* The polling endpoint shares the 10 requests / 60 seconds rate limit with `POST /v1/edits`. See [Rate Limits](/api-reference/rate-limits).
* Full status code reference: [Errors](/api-reference/errors).
