> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Edit a Music Video storyboard shot

POST https://api.beatapi.io/v1/music-video/tasks/{task_id}/shots/{shot_id}/edit
Content-Type: application/json

Edit one storyboard shot using its BeatAPI `shot_id`. This operation
charges the customer USD balance using the applicable task tier and shot
duration. Standard edits accept only `prompt`. Premium edits accept
`prompt` plus up to 6 optional replacement `images`. Generation quality,
resolution, and shot duration are inherited from the original task and
are not editable request fields.
When the edit finishes, BeatAPI stores the edited shot media and exposes
it on that shot. The existing final Music Video is not replaced until
you call compose with the selected shot ids.


Reference: https://docs.beatapi.io/api-reference/core/music-video/edit-music-video-shot

## Authentication

- `Authorization` header (bearer token, required) — Send your API key as `Authorization: Bearer <BEATAPI_API_KEY>`.

## Request

### Path parameters

- `task_id` (string, required)
- `shot_id` (string, required)

### Headers

- `Idempotency-Key` (string, optional) — Optional retry key. Reusing the same key for this task, shot, and request body returns the accepted task without charging the USD amount again; changing any of them returns `409 idempotency_conflict`.

### Body (application/json)

This endpoint expects an EditMusicVideoShotRequest.

- `prompt` (string, required)
- `images` (list of string, optional) — Premium tasks only. Optional replacement scene images; an empty array is treated as omitted. Standard tasks reject this field.

## Response

### 202

Shot edit accepted

- `data` (Task, required) — Accepted or current BeatAPI task state.

## Errors

### 400 Bad Request Error

Malformed JSON or a field, value or combination this endpoint does not accept (`bad_request`; the message names the field), or input refused by moderation (`content_policy_violation`). Not retryable unchanged.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 401 Unauthorized Error

No API key (`missing_api_key`), or a key that is wrong, expired, disabled or exhausted (`invalid_api_key`; the message says which). Send it as `Authorization: Bearer <key>`; the key works with or without the `sk-` prefix. Not retryable.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 402 Payment Required Error

Insufficient balance (`insufficient_credits`). The account balance is zero or below the price of this request. Top up, then send it again; not retryable before that.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 404 Not Found Error

Task or shot not found.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 409 Conflict Error

The Idempotency-Key was reused for a different task, shot, or request body, or the same request is still being processed.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 429 Too Many Requests Error

Too many requests (`rate_limit_exceeded`, including the free-model limits) or too many tasks processing at once (`user_concurrency_exceeded`). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 500 Internal Server Error

Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

### 503 Service Unavailable Error

The request could not be completed (`processing_unavailable`, `processing_timeout`, `processing_failed` or `result_transfer_failed`). Nothing was charged. Retryable with backoff; `Retry-After` is sent when the wait is known. BeatAPI does not answer 502 or 504.

- `error` (ErrorError, required) — Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

## Types

### Task

- `id` (string, required) — Stable BeatAPI task ID used for polling and support.
- `object` (enum, required) — Object discriminator; always `task`.
  - Allowed values: `task`
- `task_kind` (enum, required) — Public task family that determines which capability fields are present. `data` is a data capability run as a task (`data:web.research`), polled through `POST /v1/capabilities/run`.
  - Allowed values: `workflow`, `effect`, `image`, `video`, `data`
- `capability_id` (string, required) — Stable BeatAPI workflow, Effect, generation model, or data capability ID (such as `web.research`) selected when the task was accepted.
- `capability_version` (integer, required, nullable) — Immutable capability version used by this task. Legacy workflow rows are returned as version 1.
- `status` (enum, required) — Current task lifecycle status. Stop polling at `succeeded` or `failed`; Music Video can also require manual action.
  - Allowed values: `queued`, `processing`, `storyboard_ready`, `requires_action`, `editing`, `composing`, `succeeded`, `failed`
- `stage` (enum, required) — Current processing stage, exposed separately so workflow progress can be tracked.
  - Allowed values: `queued`, `processing`, `storyboard_ready`, `requires_action`, `editing`, `composing`, `succeeded`, `failed`
- `created_at` (integer, required) — Unix timestamp when BeatAPI accepted the task.
- `updated_at` (integer, required) — Unix timestamp of the latest task update.
- `completed_at` (integer, required, nullable) — Terminal Unix timestamp, or null while work is in progress.
- `output` (TaskOutput, required, nullable) — Output is null until the task succeeds.
- `usage` (TaskUsage, required) — USD reservation, settlement, refund, and optional billable duration for this task.
- `request_id` (string, required) — Correlation ID to retain for logs and BeatAPI support.
- `error_code` (string, required, nullable) — Machine-readable terminal failure code, or null when no task failure is recorded.
- `error_message` (string, required, nullable) — Human-readable terminal failure detail, or null when no task failure is recorded.
- `workflow` (enum, optional) — Present for workflow tasks; identifies the selected BeatAPI workflow.
  - Allowed values: `music-video`, `ecommerce-video`, `video-analysis`
- `effect_id` (string, optional) — Present for Effect tasks; stable selected Effect ID.
- `effect_version` (integer, optional) — Present for Effect tasks; immutable Effect version used for processing.
- `media_type` (enum, optional) — Present when task_kind is image or video.
  - Allowed values: `image`, `video`
- `model` (string, optional) — Stable BeatAPI model alias. It is independent from internal execution routing.
- `storyboard` (Storyboard, optional) — Music Video storyboard metadata when available.
- `poll_after_seconds` (integer, optional) — Present while the task is running: how long to wait before the next status call (5 for images, 8 for video and Effects, 10 for workflows and data tasks). Absent on a terminal task.
- `typical_seconds` (TaskTypicalSeconds, optional) — Present while the task is running, when enough recent finishes exist: how long this task's model recently took from accepted to succeeded, measured on this gateway. Past `p90` with no change the task is running long; there is no ETA beyond that.
- `retryable` (boolean, optional) — Present on a failed task: whether resubmitting could succeed. True when the task failed on our side or timed out (a failed task is not charged); false when it was refused for content or bad input. Same code-to-retryable rule as the error envelope.

### ErrorError

Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.

- `code` (enum, required) — Stable machine-readable error code. `unauthorized` is the deprecated name for a 401; since 2026-09-29 a 401 is `missing_api_key` or `invalid_api_key`. Treat a legacy `unauthorized` like `invalid_api_key`.
  - Allowed values: `bad_request`, `missing_api_key`, `invalid_api_key`, `unauthorized`, `forbidden`, `not_found`, `insufficient_credits`, `idempotency_conflict`, `user_concurrency_exceeded`, `rate_limit_exceeded`, `content_policy_violation`, `processing_unavailable`, `processing_failed`, `processing_timeout`, `result_transfer_failed`, `invalid_signature`, `realtime_disabled`, `realtime_capacity_unavailable`, `realtime_session_expired`, `origin_not_allowed`, `invalid_client_secret`, `transport_not_allowed`, `internal_error`
- `message` (string, required) — English sentence that states the cause; for `bad_request` it names the field. Written for people and logs, not for parsing.
- `retryable` (boolean, required) — Whether making the same call again could succeed. Present on every error; branch on it instead of the status code. True for 429, 500 and 503 (rate_limit_exceeded, user_concurrency_exceeded, internal_error, processing_unavailable, processing_timeout, processing_failed, result_transfer_failed, realtime_capacity_unavailable). False for a request, key or balance that must change first (bad_request, content_policy_violation, missing_api_key, invalid_api_key, insufficient_credits, forbidden, not_found, idempotency_conflict, realtime_disabled and the other realtime credential codes).
- `request_id` (string, required) — Correlation ID to retain for BeatAPI support.
- `retry_after_seconds` (integer, optional) — Seconds to wait before retrying. Present on every 429, and on a 503 when the wait is known; the same value is sent in the `Retry-After` header.
- `docs` (string, optional) — The public Skill page that says what to do about an error. Present on errors answered by the capability endpoints (`/v1/capabilities/search`, `/v1/capabilities/inspect`, `/v1/capabilities/run`); absent on every other endpoint.

### TaskOutput

Output is null until the task succeeds.

### TaskUsage

- `credits_reserved` (double, required) — USD amount reserved for this task. The compatibility field name is retained; 1 Credit equals $1 USD.
- `credits_charged` (double, required) — USD amount charged when the task or operation is accepted.
- `credits_settled` (double, required) — USD amount settled after successful work.
- `credits_refunded` (double, required) — USD amount refunded after failed eligible work.
- `billable_duration_seconds` (integer, optional) — Server-detected or request-declared billable duration used for USD calculation.

### Storyboard

- `shots` (list of StoryboardShot, required) — Ordered Music Video storyboard shots. The array may be empty before storyboard generation completes.

### TaskTypicalSeconds

Present while the task is running, when enough recent finishes exist: how long this task's model recently took from accepted to succeeded, measured on this gateway. Past `p90` with no change the task is running long; there is no ETA beyond that.

- `p50` (integer, required) — Median seconds.
- `p90` (integer, required) — Ninetieth-percentile seconds.
- `samples` (integer, required) — Finished tasks the figures rest on.
- `window` (string, required) — The window measured, such as `7d`.

### TaskOutput0

- `media` (list of TaskOutputOneOf0MediaItems, required) — BeatAPI-hosted result assets.
- `r2_url` (string, required, deprecated) — Deprecated — read media[0].url. The primary asset's URL again (the video, else the first image), the same value as that media[].url, kept only for clients that read one URL.

### TaskOutput1

- `text` (string, required) — Completed video analysis text.
- `usage` (TaskOutputOneOf1Usage, required) — Measured token usage used for final USD settlement.
- `finish_reason` (string, required, nullable) — Why the model stopped generating.

### TaskOutput2

A data task's result: the capability's own result object, such as `web.research` with `research_notes` and `sources` (in a view: `items`).

- `object` (string, required) — The result type, such as `web.research`.

### StoryboardShot

- `id` (string, required) — BeatAPI shot id. Use this id for media retrieval, edit, and compose operations.
- `index` (integer, required) — Zero-based shot order in the storyboard.
- `status` (enum, required) — Current lifecycle state for this storyboard shot.
  - Allowed values: `queued`, `processing`, `storyboard_ready`, `requires_action`, `editing`, `composing`, `succeeded`, `failed`
- `created_at` (integer, required) — Unix timestamp when the shot record was created.
- `updated_at` (integer, required) — Unix timestamp when the shot record last changed.
- `duration_seconds` (integer, optional) — Planned or generated shot duration in seconds.
- `prompt` (string, optional) — Creative instruction used to generate this shot.
- `lyric_text` (string, optional) — Lyric segment aligned with this shot when available.
- `media` (StoryboardShotMedia, optional) — Present only after the shot media has been materialized or after a shot edit finishes.

### TaskOutputOneOf0MediaItems

- `type` (enum, required) — Result asset type.
  - Allowed values: `image`, `video`
- `url` (string, required) — BeatAPI-hosted HTTPS result URL.
- `mime_type` (string, required) — Result asset MIME type.

### TaskOutputOneOf1Usage

Measured token usage used for final USD settlement.

- `input_tokens` (integer, required) — Tokens consumed by the prompt and video input.
- `output_tokens` (integer, required) — Tokens consumed by visible output and model reasoning.
- `total_tokens` (integer, required) — Total measured input and output tokens.

### StoryboardShotMedia

Present only after the shot media has been materialized or after a shot edit finishes.

- `type` (string, optional) — Hosted media type for the materialized shot.
- `url` (string, optional) — BeatAPI-hosted HTTPS URL for the materialized shot.
- `mime_type` (string, optional) — MIME type of the hosted shot media.

## Examples

**Request**

```json
{
  "prompt": "Night city chorus with brighter face lighting.",
  "images": [
    "https://media.beatapi.io/samples/stage.png"
  ]
}
```

**Response**

```json
{
  "data": {
    "id": "task_8K2qA",
    "object": "task",
    "task_kind": "workflow",
    "capability_id": "string",
    "capability_version": 1,
    "status": "queued",
    "stage": "queued",
    "created_at": 1,
    "updated_at": 1,
    "completed_at": 1,
    "output": null,
    "usage": {
      "credits_reserved": 1.1,
      "credits_charged": 1.1,
      "credits_settled": 1.1,
      "credits_refunded": 1.1,
      "billable_duration_seconds": 1
    },
    "request_id": "req_abc123",
    "error_code": "processing_timeout",
    "error_message": "string",
    "workflow": "music-video",
    "effect_id": "video-muscle-max",
    "effect_version": 1,
    "media_type": "image",
    "model": "string",
    "storyboard": {
      "shots": [
        {
          "id": "shot_xxx",
          "index": 0,
          "status": "queued",
          "created_at": 1782210000,
          "updated_at": 1782210300,
          "duration_seconds": 5,
          "prompt": "Opening lyric shot.",
          "lyric_text": "Intro",
          "media": {
            "type": "video",
            "url": "https://media.beatapi.io/outputs/task_8K2qA/shots/0.mp4",
            "mime_type": "video/mp4"
          }
        }
      ]
    },
    "poll_after_seconds": 8,
    "typical_seconds": {
      "p50": 1,
      "p90": 1,
      "samples": 1,
      "window": "string"
    },
    "retryable": true
  }
}
```

**SDK Code**

```python Music Video_editMusicVideoShot_example
import requests

url = "https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit"

payload = {
    "prompt": "Night city chorus with brighter face lighting.",
    "images": ["https://media.beatapi.io/samples/stage.png"]
}
headers = {
    "Idempotency-Key": "music-edit-task_8K2qA-shot_xxx-01",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Music Video_editMusicVideoShot_example
const url = 'https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit';
const options = {
  method: 'POST',
  headers: {
    'Idempotency-Key': 'music-edit-task_8K2qA-shot_xxx-01',
    Authorization: 'Bearer <token>',
    'Content-Type': 'application/json'
  },
  body: '{"prompt":"Night city chorus with brighter face lighting.","images":["https://media.beatapi.io/samples/stage.png"]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Music Video_editMusicVideoShot_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit"

	payload := strings.NewReader("{\n  \"prompt\": \"Night city chorus with brighter face lighting.\",\n  \"images\": [\n    \"https://media.beatapi.io/samples/stage.png\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Idempotency-Key", "music-edit-task_8K2qA-shot_xxx-01")
	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Music Video_editMusicVideoShot_example
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = 'music-edit-task_8K2qA-shot_xxx-01'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"prompt\": \"Night city chorus with brighter face lighting.\",\n  \"images\": [\n    \"https://media.beatapi.io/samples/stage.png\"\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Music Video_editMusicVideoShot_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit")
  .header("Idempotency-Key", "music-edit-task_8K2qA-shot_xxx-01")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"prompt\": \"Night city chorus with brighter face lighting.\",\n  \"images\": [\n    \"https://media.beatapi.io/samples/stage.png\"\n  ]\n}")
  .asString();
```

```php Music Video_editMusicVideoShot_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit', [
  'body' => '{
  "prompt": "Night city chorus with brighter face lighting.",
  "images": [
    "https://media.beatapi.io/samples/stage.png"
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
    'Idempotency-Key' => 'music-edit-task_8K2qA-shot_xxx-01',
  ],
]);

echo $response->getBody();
```

```csharp Music Video_editMusicVideoShot_example
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit");
var request = new RestRequest(Method.POST);
request.AddHeader("Idempotency-Key", "music-edit-task_8K2qA-shot_xxx-01");
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"prompt\": \"Night city chorus with brighter face lighting.\",\n  \"images\": [\n    \"https://media.beatapi.io/samples/stage.png\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Music Video_editMusicVideoShot_example
import Foundation

let headers = [
  "Idempotency-Key": "music-edit-task_8K2qA-shot_xxx-01",
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "prompt": "Night city chorus with brighter face lighting.",
  "images": ["https://media.beatapi.io/samples/stage.png"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/music-video/tasks/task_8K2qA/shots/shot_xxx/edit")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```