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

# Fix Video

> Execute the fix the readiness check prescribed, and verify it worked

Takes a video, runs the readiness check, executes the fix that check prescribes, and then **re-runs the check on the result** before handing it back.

A file is only returned as fixed if the original failure is confirmed gone and the output still matches the source in duration, audio and orientation. If it does not pass, you get the reason and are charged nothing.

**You do not need to call [Check Readiness](/api-reference/check-readiness) first.** This runs the same check itself and does not bill for it separately. Call readiness when you want the verdict without committing to the fix.

<Tip>
  **Try it on our footage first.** `GET /api/v1/samples` lists two videos that are
  broken on purpose, and checking or fixing them costs no credits. No API key
  needed to list them.
</Tip>

### What it can fix today

| Check | What it does |
| - | - |
| `vfr` | Conforms variable frame rate footage to a constant rate |
| `rotation_metadata` | Bakes a rotation flag into the pixels, so every tool agrees which way up the video is |

Anything else is refused explicitly rather than attempted. A verdict can prescribe fixes we do not execute yet — `422 fix_not_executable` names which.

<ParamField body="video_url" type="string" required>
  Public HTTP/HTTPS URL of the video.
</ParamField>

<ParamField body="context" type="string" required>
  What the footage is for. The fix executed is the one this context's verdict prescribes, and the same clip can need different work for different destinations — a rotation flag is a defect for `motion_analysis` and a non-event for `nle_editing`.

  Accepts the same values as [Check Readiness](/api-reference/check-readiness): `motion_analysis`, `nle_editing`, `social_playback`, `archival`.
</ParamField>

<ParamField body="reason_id" type="string">
  Which failing check to fix, e.g. `vfr`. Optional — with one executable failure, which is the common case, it is inferred.

  When a clip fails several checks, the fix that runs is the one for the most severe of them. Name a `reason_id` to choose differently.
</ParamField>

<ParamField body="overrides" type="object">
  Threshold overrides, exactly as on [Check Readiness](/api-reference/check-readiness). They shape the verdict, and therefore what gets fixed.
</ParamField>

<ParamField header="Idempotency-Key" type="string">
  Send one to make retries safe. Replaying a request with the same key returns the original job instead of charging and transcoding again — it does not even re-read the video.

  Scoped to your API key, so you are free to choose any value.
</ParamField>

### Response

```json theme={null}
{
  "fix_job_id": "9c2f1e40-5f6d-4a1e-9a2b-3f8c7d1e0b42",
  "status": "queued",
  "reason_id": "vfr",
  "context": "motion_analysis@v1",
  "quote": {
    "credits": 2,
    "resolution_tier": "hd",
    "billed_minutes": 1,
    "credits_per_minute": 2,
    "output": { "width": 1280, "height": 720 }
  },
  "credits_charged": 2
}
```

The quote carries its working, not just the total, so you can see which band and how many minutes produced the number without reimplementing the rate table.

Poll `GET /api/v1/fix/{fix_job_id}` for the result.

### Statuses

| `status` | Meaning |
| - | - |
| `queued` | Accepted, not yet handed to the transcoder |
| `transcoding` | In progress |
| `verifying` | The file came back; we are checking it |
| `succeeded` | Verified. `result_url` carries the file |
| `failed_provider` | The transcode could not be completed for this file |
| `failed_timeout` | It did not finish in the time we allow, or we lost track of it |
| `verification_failed` | A file came back and it was not what was prescribed |

`terminal` tells you whether the status is final, so you do not need to keep the list above in your client to know when to stop polling.

**All three failures charge nothing.** That is not a refund you have to ask for — it is the state of the job.

### Why three failure states and not one

They mean different things to a decision you are about to make. `failed_provider` says this file could not be transcoded; retrying is unlikely to help. `failed_timeout` says nothing is known about the outcome; retrying is reasonable. `verification_failed` says a file came back and we would not stand behind it — the `verification` report says which check failed and what was measured.

### The verification report

Present on `succeeded` and on `verification_failed` alike, because the checks that passed are as informative as the one that did not:

```json theme={null}
{
  "passed": false,
  "failed_checks": ["duration_preserved"],
  "checks": [
    { "name": "measurement_ran", "passed": true, "detail": "Sampled via spread_3x50." },
    { "name": "original_failure_cleared", "passed": true, "detail": "'vfr' no longer fails for motion_analysis@v1." },
    { "name": "duration_preserved", "passed": false, "detail": "20.000s -> 12.004s (delta 7.996s, tolerance 0.033s = one frame)" },
    { "name": "audio_preserved", "passed": true, "detail": "Audio present (aac)." },
    { "name": "dimensions_as_prescribed", "passed": true, "detail": "asked 1280x720, got 1280x720" },
    { "name": "rotation_resolved", "passed": true, "detail": "No rotation metadata on the output." }
  ]
}
```

Two of these are worth understanding.

**`measurement_ran`** is checked separately, and first. Our frame-rate detector reports "no variable frame rate" when it could not read the file — which is honest about the file and useless as evidence. Without asking this question on its own, a failed measurement would look exactly like a clean result, and we would hand you a file stamped verified having proved nothing. If this check fails, it is not a claim that the fix failed; it is a statement that we could not confirm it, and you were not charged either way.

**`duration_preserved`** tolerates one frame, not a fixed number of seconds. Conforming to a constant rate moves the final frame onto a new boundary, which costs up to `1/fps` — 0.033s at 30fps, 0.042s at 24. A flat tolerance would either pass a truncated encode or fail a correct one, depending on the rate.

Frame *count* is deliberately not checked. Forcing a constant rate changes it — that is the fix working.

### Result URLs

`result_url` is signed when you read the job, with a fresh one-hour expiry. Re-poll to get a new one; there is no stale-link failure mode.

### Cost

Credits by output duration and resolution. See [Pricing](/pricing) for the table.

The quote is returned before anything runs, and computed from measurements we have already taken — so it is the price, not an estimate.

<Warning>
  **A fix is one video in, one video out.** There is no batch form and no output ladder. If you need several renditions, that is a transcoding service, and this is not one — it executes a prescription and proves it worked.
</Warning>

### Errors

| Status | Code | Meaning |
| - | - | - |
| 402 | `insufficient_credits` | The error carries the price and your balance |
| 422 | `nothing_to_fix` | This file has no recoverable failure matching the request. The verdict is attached |
| 422 | `fix_not_executable` | The verdict prescribes a fix we do not execute yet |
| 422 | `not_measurable` | The video could not be inspected closely enough to fix safely |
| 422 | `unreadable_source` | The URL could not be read |
| 503 | `fix_unavailable` | Fix execution is not enabled on this deployment |

`nothing_to_fix` is worth expecting rather than treating as an error: it is what you get when the file is already fine for the context you named. Nothing is charged, and the attached verdict tells you why we thought so.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.