openapi: 3.2.0 info: title: Magic Hour Video Projects API version: beta description: "\nMagic Hour provides an API (beta) that can be integrated into your own application to generate videos and images using AI. \n\nWebhook documentation can be found [here](https://docs.magichour.ai/webhook-reference).\n\nIf you have any questions, please reach out to us via [discord](https://discord.gg/JX5rgsZaJp).\n\n# Authentication\n\nEvery request requires an API key.\n\nTo get started, first generate your API key [here](https://magichour.ai/developer?tab=api-keys&utm_source=docs&utm_medium=referral&utm_campaign=api-reference).\n\nThen, add the `Authorization` header to the request.\n\n| Key | Value |\n|-|-|\n| Authorization | Bearer mhk_live_apikey |\n\n> **Warning**: any API call that renders a video will utilize credits in your account.\n" termsOfService: https://magichour.ai/terms-of-service servers: - url: https://api.magichour.ai tags: - name: Video Projects description: API related to video projects paths: /v1/video-projects/{id}: get: description: "Check the progress of a video project. The `downloads` field is populated after a successful render.\n \n**Statuses**\n- `queued` — waiting to start\n- `rendering` — in progress\n- `complete` — ready; see `downloads`\n- `error` — a failure occurred (see `error`)\n- `canceled` — user canceled\n- `draft` — not used" summary: Get video details tags: - Video Projects parameters: - name: id in: path required: true schema: type: string example: cuid-example description: Unique ID of the video project. This value is returned by all of the POST APIs that create a video. operationId: videoProjects.getDetails responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. name: type: - string - 'null' description: The name of the video. example: Example Name status: type: string enum: - draft - queued - rendering - complete - error - canceled description: 'The status of the video. - `draft` - the project was created but has not been submitted for rendering - `queued` - the job is waiting for an available server - `rendering` - the job is being processed; the `video.started` webhook event fires when rendering begins - `complete` - the job finished successfully; fires `video.completed` - `error` - the job failed during processing; fires `video.errored` - `canceled` - the job was manually canceled (for example from the Magic Hour web app) **Note:** `rendering`, `complete`, and `error` have matching webhook events; `canceled` does not - a canceled job emits no webhook event, so poll this endpoint to detect cancellation.' example: complete type: type: string description: The type of the video project. Possible values are ANIMATION, AUTO_SUBTITLE, VIDEO_TO_VIDEO, FACE_SWAP, TEXT_TO_VIDEO, IMAGE_TO_VIDEO, LIP_SYNC, TALKING_PHOTO, AVATAR, VIDEO_UPSCALER, VIDEO_EDITOR, CHARACTER_REPLACE, VIDEO_COLORIZER, VIDEO_TRANSLATOR, MUSIC_VIDEO, EXTEND, AUDIO_TO_VIDEO, VIDEO_EXPANDER, UGC_AD example: FACE_SWAP created_at: type: string format: date-time width: type: integer description: The width of the final output video. A value of -1 indicates the width can be ignored. example: 512 height: type: integer description: The height of the final output video. A value of -1 indicates the height can be ignored. example: 960 enabled: type: boolean description: Whether this resource is active. If false, it is deleted. start_seconds: type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 fps: type: number description: Frame rate of the video. If the status is not 'complete', the frame rate is an estimate and will be adjusted when the video completes. example: 30 error: type: - object - 'null' properties: message: type: string description: Details on the reason why a failure happened. example: Please use an image with a detectable face code: type: string example: no_source_face description: An error code to indicate why a failure happened. required: - message - code description: In the case of an error, this object will contain the error encountered during video render example: null downloads: type: array items: type: object properties: url: type: string format: uri example: https://videos.magichour.ai/id/output.mp4 expires_at: type: string format: date-time example: '2024-10-19T05:16:19.027Z' required: - url - expires_at description: The download url and expiration date of the image project required: - id - name - status - type - created_at - width - height - enabled - start_seconds - end_seconds - credits_charged - fps - error - downloads description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found security: - bearerAuth: [] x-codeSamples: - lang: python source: 'from magic_hour import Client from os import getenv client = Client(token=getenv("API_TOKEN")) res = client.v1.video_projects.get(id="cuid-example")' - lang: javascript source: 'import { Client } from "magic-hour"; const client = new Client({ token: process.env["API_TOKEN"]!! }); const res = await client.v1.videoProjects.get({ id: "cuid-example" });' - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tvideo_projects \"github.com/magichourhq/magic-hour-go/resources/v1/video_projects\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.VideoProjects.Get(video_projects.GetRequest{\n\t\tId: \"cuid-example\",\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .video_projects()\n .get(magic_hour::resources::v1::video_projects::GetRequest {\n id: \"cuid-example\".to_string(),\n })\n .await;" - lang: curl source: "curl --request GET \\\n --url https://api.magichour.ai/v1/video-projects/id \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer '" - lang: php source: " \"https://api.magichour.ai/v1/video-projects/id\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"GET\",\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.get(\"https://api.magichour.ai/v1/video-projects/id\")\n .header(\"accept\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .asString();" delete: description: Permanently delete the rendered video. This action is not reversible, please be sure before deleting. summary: Delete video tags: - Video Projects parameters: - name: id in: path required: true schema: type: string example: cuid-example description: Unique ID of the video project. This value is returned by all of the POST APIs that create a video. operationId: videoProjects.delete responses: '204': description: '204' '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string required: - message description: When a request fails validations example: message: video is a template and cannot be deleted. Please reach out to our support team. security: - bearerAuth: [] x-codeSamples: - lang: python source: 'from magic_hour import Client from os import getenv client = Client(token=getenv("API_TOKEN")) res = client.v1.video_projects.delete(id="cuid-example")' - lang: javascript source: 'import { Client } from "magic-hour"; const client = new Client({ token: process.env["API_TOKEN"]!! }); const res = await client.v1.videoProjects.delete({ id: "cuid-example" });' - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tvideo_projects \"github.com/magichourhq/magic-hour-go/resources/v1/video_projects\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\terr := client.V1.VideoProjects.Delete(video_projects.DeleteRequest{\n\t\tId: \"cuid-example\",\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .video_projects()\n .delete(magic_hour::resources::v1::video_projects::DeleteRequest {\n id: \"cuid-example\".to_string(),\n })\n .await;" - lang: curl source: "curl --request DELETE \\\n --url https://api.magichour.ai/v1/video-projects/id \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer '" - lang: php source: " \"https://api.magichour.ai/v1/video-projects/id\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"DELETE\",\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.delete(\"https://api.magichour.ai/v1/video-projects/id\")\n .header(\"accept\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .asString();" /v1/ai-talking-photo: post: description: Create a talking photo from an image and audio or text input. summary: AI Talking Photo tags: - Video Projects parameters: [] operationId: aiTalkingPhoto.createTalkingPhoto requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your image a custom name for easy identification. example: My Talking Photo image default: Talking Photo - dateTime start_seconds: type: number minimum: 0 description: 'The start time of the input audio in seconds. Maximum clip length depends on style.generation_mode: realistic 180s, prompted 45s.' format: float example: 0 end_seconds: type: number minimum: 0.1 description: 'The end time of the input audio in seconds. Maximum clip length depends on style.generation_mode: realistic 180s, prompted 45s.' format: float example: 15 assets: type: object properties: image_file_path: type: string minLength: 1 description: 'The source image to animate. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.png audio_file_path: type: string minLength: 1 description: 'The audio file to sync with the image. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp3 required: - image_file_path - audio_file_path description: Provide the assets for creating a talking photo style: type: object properties: generation_mode: default: realistic type: string enum: - realistic - prompted - pro - standard - stable - expressive description: 'Controls overall motion style. * `realistic` - Maintains likeness well, high quality, and reliable. * `prompted` - Slightly lower likeness; allows option to prompt scene. **Deprecated values (maintained for backward compatibility):** * `pro` - Deprecated: use `realistic` * `standard` - Deprecated: use `prompted` * `stable` - Deprecated: use `realistic` * `expressive` - Deprecated: use `prompted`' example: realistic prompt: type: string description: 'A text prompt to guide the generation. Only applicable when generation_mode is `prompted`. This field is ignored for other modes.' description: Attributes used to dictate the style of the output max_resolution: type: integer description: Constrains the larger dimension (height or width) of the output video. Allows you to set a lower resolution than your plan's maximum if desired. The value is capped by your plan's max resolution. example: 1024 required: - start_seconds - end_seconds - assets description: Provide the assets for creating a talking photo responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create talking photo required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.ai_talking_photo.generate(\n assets={\n \"audio_file_path\": \"/path/to/1234.mp3\",\n \"image_file_path\": \"/path/to/1234.png\",\n },\n end_seconds=15.0,\n start_seconds=0.0,\n name=\"Talking Photo image\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.aiTalkingPhoto.generate(\n {\n assets: {\n audioFilePath: \"/path/to/1234.mp3\",\n imageFilePath: \"/path/to/1234.png\",\n },\n endSeconds: 15.0,\n name: \"Talking Photo image\",\n startSeconds: 0.0,\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tai_talking_photo \"github.com/magichourhq/magic-hour-go/resources/v1/ai_talking_photo\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.AiTalkingPhoto.Create(ai_talking_photo.CreateRequest{\n\t\tAssets: types.V1AiTalkingPhotoCreateBodyAssets{\n\t\t\tAudioFilePath: \"api-assets/id/1234.mp3\",\n\t\t\tImageFilePath: \"api-assets/id/1234.png\",\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tMaxResolution: nullable.NewValue(1024),\n\t\tName: nullable.NewValue(\"My Talking Photo image\"),\n\t\tStartSeconds: 0.0,\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .ai_talking_photo()\n .create(magic_hour::resources::v1::ai_talking_photo::CreateRequest {\n assets: magic_hour::models::V1AiTalkingPhotoCreateBodyAssets {\n audio_file_path: \"api-assets/id/1234.mp3\".to_string(),\n image_file_path: \"api-assets/id/1234.png\".to_string(),\n },\n end_seconds: 15.0,\n max_resolution: Some(1024),\n name: Some(\"My Talking Photo image\".to_string()),\n start_seconds: 0.0,\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/ai-talking-photo \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Talking Photo image\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"assets\": {\n \"image_file_path\": \"api-assets/id/1234.png\",\n \"audio_file_path\": \"api-assets/id/1234.mp3\"\n },\n \"style\": {\n \"generation_mode\": \"realistic\",\n \"prompt\": \"string\"\n },\n \"max_resolution\": 1024\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/ai-talking-photo\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Talking Photo image',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'assets' => [\n 'image_file_path' => 'api-assets/id/1234.png',\n 'audio_file_path' => 'api-assets/id/1234.mp3'\n ],\n 'style' => [\n 'generation_mode' => 'realistic',\n 'prompt' => 'string'\n ],\n 'max_resolution' => 1024\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/ai-talking-photo\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Talking Photo image\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"assets\\\":{\\\"image_file_path\\\":\\\"api-assets/id/1234.png\\\",\\\"audio_file_path\\\":\\\"api-assets/id/1234.mp3\\\"},\\\"style\\\":{\\\"generation_mode\\\":\\\"realistic\\\",\\\"prompt\\\":\\\"string\\\"},\\\"max_resolution\\\":1024}\")\n .asString();" /v1/ai-video-editor: post: description: "**What this API does**\n\nCreate the same Video Editor you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding video editor into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a video editor job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/ai-video-editor)." summary: AI Video Editor tags: - Video Projects parameters: [] operationId: aiVideoEditor.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Video Editor video default: Video Editor - dateTime start_seconds: default: 0 type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: 'End time of your clip in seconds. Must be greater than `start_seconds`. Minimum duration depends on model: `gemini-omni`: 3s, `ltx-2.3`: 0.5s. Maximum duration depends on model: `gemini-omni`: 10s, `ltx-2.3`: 45s.' format: float example: 5 model: type: string enum: - gemini-omni - ltx-2.3 description: Editing model. Defaults to `ltx-2.3` for free tier and `gemini-omni` for paid. Use `ltx-2.3` for LTX video edit. example: gemini-omni resolution: type: string enum: - 480p - 720p - 1080p description: Output resolution. Defaults to `480p` for free tier and `720p` for paid. Google Omni supports 720p only; LTX-2.3 supports 480p, 720p, and 1080p. example: 720p style: type: object properties: prompt: type: string minLength: 1 description: The prompt used to edit the video. example: Change the car color to blue required: - prompt assets: type: object properties: video_file_path: type: string minLength: 1 description: 'The video to edit. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 required: - video_file_path description: Provide the assets for video editing. required: - end_seconds - style - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to edit video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.ai_video_editor.generate(\n assets={\"video_file_path\": \"/path/to/1234.mp4\"},\n end_seconds=5.0,\n style={\"prompt\": \"Change the car color to blue\"},\n name=\"My Video Editor video\",\n start_seconds=0.0,\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\",\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.aiVideoEditor.generate(\n {\n assets: { videoFilePath: \"/path/to/1234.mp4\" },\n endSeconds: 5.0,\n name: \"My Video Editor video\",\n startSeconds: 0.0,\n style: { prompt: \"Change the car color to blue\" },\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tai_video_editor \"github.com/magichourhq/magic-hour-go/resources/v1/ai_video_editor\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.AiVideoEditor.Create(ai_video_editor.CreateRequest{\n\t\tAssets: types.V1AiVideoEditorCreateBodyAssets{\n\t\t\tVideoFilePath: \"api-assets/id/1234.mp4\",\n\t\t},\n\t\tEndSeconds: 5.0,\n\t\tModel: nullable.NewValue(types.V1AiVideoEditorCreateBodyModelEnumGeminiOmni),\n\t\tName: nullable.NewValue(\"My Video Editor video\"),\n\t\tResolution: nullable.NewValue(types.V1AiVideoEditorCreateBodyResolutionEnum720p),\n\t\tStartSeconds: nullable.NewValue(0.0),\n\t\tStyle: types.V1AiVideoEditorCreateBodyStyle{\n\t\t\tPrompt: \"Change the car color to blue\",\n\t\t},\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .ai_video_editor()\n .create(magic_hour::resources::v1::ai_video_editor::CreateRequest {\n assets: magic_hour::models::V1AiVideoEditorCreateBodyAssets {\n video_file_path: \"api-assets/id/1234.mp4\".to_string(),\n },\n end_seconds: 5.0,\n model: Some(\n magic_hour::models::V1AiVideoEditorCreateBodyModelEnum::GeminiOmni,\n ),\n name: Some(\"My Video Editor video\".to_string()),\n resolution: Some(\n magic_hour::models::V1AiVideoEditorCreateBodyResolutionEnum::Enum720p,\n ),\n start_seconds: Some(0.0),\n style: magic_hour::models::V1AiVideoEditorCreateBodyStyle {\n prompt: \"Change the car color to blue\".to_string(),\n },\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/ai-video-editor \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Video Editor video\",\n \"start_seconds\": 0,\n \"end_seconds\": 5,\n \"model\": \"gemini-omni\",\n \"resolution\": \"720p\",\n \"style\": {\n \"prompt\": \"Change the car color to blue\"\n },\n \"assets\": {\n \"video_file_path\": \"api-assets/id/1234.mp4\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/ai-video-editor\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Video Editor video',\n 'start_seconds' => 0,\n 'end_seconds' => 5,\n 'model' => 'gemini-omni',\n 'resolution' => '720p',\n 'style' => [\n 'prompt' => 'Change the car color to blue'\n ],\n 'assets' => [\n 'video_file_path' => 'api-assets/id/1234.mp4'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/ai-video-editor\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Video Editor video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":5,\\\"model\\\":\\\"gemini-omni\\\",\\\"resolution\\\":\\\"720p\\\",\\\"style\\\":{\\\"prompt\\\":\\\"Change the car color to blue\\\"},\\\"assets\\\":{\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\"}}\")\n .asString();" /v1/animation: post: description: Create a Animation video. The estimated frame cost is calculated based on the `fps` and `end_seconds` input. summary: Animation tags: - Video Projects parameters: [] operationId: animation.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Animation video default: Animation - dateTime fps: type: number minimum: 1 description: The desire output video frame rate example: 12 end_seconds: type: number minimum: 0.1 description: This value determines the duration of the output video. format: float example: 15 height: type: integer minimum: 64 description: The height of the final output video. The maximum height depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details example: 960 width: type: integer minimum: 64 description: The width of the final output video. The maximum width depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details example: 512 style: type: object properties: art_style: type: string enum: - Custom - Painterly Illustration - Vibrant Matte Illustration - Traditional Watercolor - Cyberpunk - Ink and Watercolor Portrait - Intricate Abstract Lines Portrait - 3D Render - Old School Comic - Bold Colored Illustration - Synthwave - Minimal Cold Futurism - Futuristic Anime - Cinematic Miyazaki - Studio Ghibli Film Still - Soft Delicate Matte Portrait - Cinematic Landscape - Landscape Painting - Photograph - Jackson Pollock - Cubist - Abstract Minimalist - Impressionism - Van Gogh - Woodcut - Oil Painting - Vintage Japanese Anime - Pixar - Cosmic - Pixel Art - Fantasy - Arcane - Sin City - Double Exposure - Painted Cityscape - 90s Streets - Overgrown - Postapocalyptic - Spooky - Miniatures - Low Poly - Art Deco - Inkpunk - Dark Graphic Illustration - Dark Watercolor - Faded Illustration - Directed by AI description: The art style used to create the output video example: Painterly Illustration art_style_custom: type: string description: Describe custom art style. This field is required if `art_style` is `Custom` camera_effect: type: string enum: - Simple Zoom Out - Simple Zoom In - Bounce Out - Spin Bounce - Rolling Bounces - Rise and Climb - Dramatic Zoom In - Dramatic Zoom Out - Sway Out - Boost Zoom In - Boost Zoom Out - Heartbeat - Bounce in Place - Earthquake Bounce - Slice Bounce - Bounce In And Out - Jump - Road Trip - Traverse - Rubber Band - Rodeo - Accelerate - Speed of Light - Drift Spin - Vertigo - Cog in the Machine - Quadrant - Tron - Pusher - Roll In - Hesitate In - Zoom In - Audio Sync - Pulse - Audio Sync - Aggressive Zoom In - Audio Sync - Roll In - Audio Sync - Zoom Out - Audio Sync - Aggressive Zoom Out - Audio Sync - Sway Out - Audio Sync - Bounce and Spin - Audio Sync - Zoom In and Spin - Audio Sync - Vertigo - Audio Sync - Bounce Out - Audio Sync - Earthquake Bounce - Audio Sync - Pusher - Audio Sync - Evolve - Audio Sync - Devolve - Audio Sync - Slideshow - Pan Left - Pan Right - Tilt Up - Tilt Down - Directed by AI description: The camera effect used to create the output video example: Simple Zoom In prompt_type: type: string enum: - custom - use_lyrics - ai_choose example: custom description: ' * `custom` - Use your own prompt for the video. * `use_lyrics` - Use the lyrics of the audio to create the prompt. If this option is selected, then `assets.audio_source` must be `file` or `youtube`. * `ai_choose` - Let AI write the prompt. If this option is selected, then `assets.audio_source` must be `file` or `youtube`.' prompt: type: string description: The prompt used for the video. Prompt is required if `prompt_type` is `custom`. Otherwise this value is ignored example: Cyberpunk city transition_speed: type: integer minimum: 1 maximum: 10 description: "Change determines how quickly the video's content changes across frames. \n* Higher = more rapid transitions.\n* Lower = more stable visual experience." example: 5 required: - art_style - camera_effect - prompt_type - transition_speed description: Defines the style of the output video assets: type: object properties: audio_source: type: string enum: - none - file - youtube description: Optionally add an audio source if you'd like to incorporate audio into your video example: file audio_file_path: type: string minLength: 1 description: 'The path of the input audio. This field is required if `audio_source` is `file`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp3 youtube_url: type: string format: uri minLength: 1 description: Using a youtube video as the input source. This field is required if `audio_source` is `youtube` image_file_path: type: string minLength: 1 description: 'An initial image to use a the first frame of the video. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.png required: - audio_source description: Provide the assets for animation. required: - fps - end_seconds - height - width - style - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.animation.generate(\n assets={\n \"audio_file_path\": \"/path/to/1234.mp3\",\n \"audio_source\": \"file\",\n \"image_file_path\": \"/path/to/1234.png\",\n },\n end_seconds=15.0,\n fps=12.0,\n height=960,\n style={\n \"art_style\": \"Painterly Illustration\",\n \"camera_effect\": \"Simple Zoom In\",\n \"prompt\": \"Cyberpunk city\",\n \"prompt_type\": \"custom\",\n \"transition_speed\": 5,\n },\n width=512,\n name=\"Animation video\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.animation.generate(\n {\n assets: {\n audioFilePath: \"/path/to/1234.mp3\",\n audioSource: \"file\",\n imageFilePath: \"/path/to/1234.png\",\n },\n endSeconds: 15.0,\n fps: 12.0,\n height: 960,\n name: \"Animation video\",\n style: {\n artStyle: \"Painterly Illustration\",\n cameraEffect: \"Simple Zoom In\",\n prompt: \"Cyberpunk city\",\n promptType: \"custom\",\n transitionSpeed: 5,\n },\n width: 512,\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tanimation \"github.com/magichourhq/magic-hour-go/resources/v1/animation\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.Animation.Create(animation.CreateRequest{\n\t\tAssets: types.V1AnimationCreateBodyAssets{\n\t\t\tAudioFilePath: nullable.NewValue(\"api-assets/id/1234.mp3\"),\n\t\t\tAudioSource: types.V1AnimationCreateBodyAssetsAudioSourceEnumFile,\n\t\t\tImageFilePath: nullable.NewValue(\"api-assets/id/1234.png\"),\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tFps: 12.0,\n\t\tHeight: 960,\n\t\tName: nullable.NewValue(\"My Animation video\"),\n\t\tStyle: types.V1AnimationCreateBodyStyle{\n\t\t\tArtStyle: types.V1AnimationCreateBodyStyleArtStyleEnumPainterlyIllustration,\n\t\t\tCameraEffect: types.V1AnimationCreateBodyStyleCameraEffectEnumSimpleZoomIn,\n\t\t\tPrompt: nullable.NewValue(\"Cyberpunk city\"),\n\t\t\tPromptType: types.V1AnimationCreateBodyStylePromptTypeEnumCustom,\n\t\t\tTransitionSpeed: 5,\n\t\t},\n\t\tWidth: 512,\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .animation()\n .create(magic_hour::resources::v1::animation::CreateRequest {\n assets: magic_hour::models::V1AnimationCreateBodyAssets {\n audio_file_path: Some(\"api-assets/id/1234.mp3\".to_string()),\n audio_source: magic_hour::models::V1AnimationCreateBodyAssetsAudioSourceEnum::File,\n image_file_path: Some(\"api-assets/id/1234.png\".to_string()),\n ..Default::default()\n },\n end_seconds: 15.0,\n fps: 12.0,\n height: 960,\n name: Some(\"My Animation video\".to_string()),\n style: magic_hour::models::V1AnimationCreateBodyStyle {\n art_style: magic_hour::models::V1AnimationCreateBodyStyleArtStyleEnum::PainterlyIllustration,\n camera_effect: magic_hour::models::V1AnimationCreateBodyStyleCameraEffectEnum::SimpleZoomIn,\n prompt: Some(\"Cyberpunk city\".to_string()),\n prompt_type: magic_hour::models::V1AnimationCreateBodyStylePromptTypeEnum::Custom,\n transition_speed: 5,\n ..Default::default()\n },\n width: 512,\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/animation \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Animation video\",\n \"fps\": 12,\n \"end_seconds\": 15,\n \"height\": 960,\n \"width\": 512,\n \"style\": {\n \"art_style\": \"Painterly Illustration\",\n \"art_style_custom\": \"string\",\n \"camera_effect\": \"Simple Zoom In\",\n \"prompt_type\": \"custom\",\n \"prompt\": \"Cyberpunk city\",\n \"transition_speed\": 5\n },\n \"assets\": {\n \"audio_source\": \"file\",\n \"audio_file_path\": \"api-assets/id/1234.mp3\",\n \"youtube_url\": \"string\",\n \"image_file_path\": \"api-assets/id/1234.png\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/animation\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Animation video',\n 'fps' => 12,\n 'end_seconds' => 15,\n 'height' => 960,\n 'width' => 512,\n 'style' => [\n 'art_style' => 'Painterly Illustration',\n 'art_style_custom' => 'string',\n 'camera_effect' => 'Simple Zoom In',\n 'prompt_type' => 'custom',\n 'prompt' => 'Cyberpunk city',\n 'transition_speed' => 5\n ],\n 'assets' => [\n 'audio_source' => 'file',\n 'audio_file_path' => 'api-assets/id/1234.mp3',\n 'youtube_url' => 'string',\n 'image_file_path' => 'api-assets/id/1234.png'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/animation\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Animation video\\\",\\\"fps\\\":12,\\\"end_seconds\\\":15,\\\"height\\\":960,\\\"width\\\":512,\\\"style\\\":{\\\"art_style\\\":\\\"Painterly Illustration\\\",\\\"art_style_custom\\\":\\\"string\\\",\\\"camera_effect\\\":\\\"Simple Zoom In\\\",\\\"prompt_type\\\":\\\"custom\\\",\\\"prompt\\\":\\\"Cyberpunk city\\\",\\\"transition_speed\\\":5},\\\"assets\\\":{\\\"audio_source\\\":\\\"file\\\",\\\"audio_file_path\\\":\\\"api-assets/id/1234.mp3\\\",\\\"youtube_url\\\":\\\"string\\\",\\\"image_file_path\\\":\\\"api-assets/id/1234.png\\\"}}\")\n .asString();" /v1/audio-to-video: post: description: "**What this API does**\n\nCreate the same Audio To Video you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding audio to video into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a audio to video job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/audio-to-video)." summary: Audio-to-Video tags: - Video Projects parameters: [] operationId: audioToVideo.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Audio To Video video default: Audio To Video - dateTime start_seconds: default: 0 type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 resolution: type: string enum: - 480p - 720p - 1080p description: Output video resolution. Defaults to `720p` on paid tiers and `480p` on free tiers. example: 720p assets: type: object properties: audio_file_path: type: string minLength: 1 description: 'The path of the audio file. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp3 image_file_path: type: string minLength: 1 description: 'Reference image for the initial frame of the video. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.png required: - audio_file_path description: Provide the audio file and an optional reference image. style: type: object properties: prompt: type: string example: Car driving through a city description: Prompt to guide the visual style of the video. description: Attributes used to dictate the style of the output required: - end_seconds - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.audio_to_video.generate(\n assets={\n \"audio_file_path\": \"/path/to/1234.mp3\",\n \"image_file_path\": \"/path/to/1234.png\",\n },\n end_seconds=15.0,\n name=\"My Audio To Video video\",\n resolution=\"720p\",\n start_seconds=0.0,\n style={\"prompt\": \"Car driving through a city\"},\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.audioToVideo.generate(\n {\n assets: {\n audioFilePath: \"/path/to/1234.mp3\",\n imageFilePath: \"/path/to/1234.png\",\n },\n endSeconds: 15.0,\n name: \"Audio To Video video\",\n resolution: \"720p\",\n startSeconds: 0.0,\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\taudio_to_video \"github.com/magichourhq/magic-hour-go/resources/v1/audio_to_video\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.AudioToVideo.Create(audio_to_video.CreateRequest{\n\t\tAssets: types.V1AudioToVideoCreateBodyAssets{\n\t\t\tAudioFilePath: \"api-assets/id/1234.mp3\",\n\t\t\tImageFilePath: nullable.NewValue(\"api-assets/id/1234.png\"),\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tName: nullable.NewValue(\"My Audio To Video video\"),\n\t\tResolution: nullable.NewValue(types.V1AudioToVideoCreateBodyResolutionEnum720p),\n\t\tStartSeconds: nullable.NewValue(0.0),\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .audio_to_video()\n .create(magic_hour::resources::v1::audio_to_video::CreateRequest {\n assets: magic_hour::models::V1AudioToVideoCreateBodyAssets {\n audio_file_path: \"api-assets/id/1234.mp3\".to_string(),\n image_file_path: Some(\"api-assets/id/1234.png\".to_string()),\n },\n end_seconds: 15.0,\n name: Some(\"My Audio To Video video\".to_string()),\n resolution: Some(\n magic_hour::models::V1AudioToVideoCreateBodyResolutionEnum::Enum720p,\n ),\n start_seconds: Some(0.0),\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/audio-to-video \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Audio To Video video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"resolution\": \"720p\",\n \"assets\": {\n \"audio_file_path\": \"api-assets/id/1234.mp3\",\n \"image_file_path\": \"api-assets/id/1234.png\"\n },\n \"style\": {\n \"prompt\": \"Car driving through a city\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/audio-to-video\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Audio To Video video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'resolution' => '720p',\n 'assets' => [\n 'audio_file_path' => 'api-assets/id/1234.mp3',\n 'image_file_path' => 'api-assets/id/1234.png'\n ],\n 'style' => [\n 'prompt' => 'Car driving through a city'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/audio-to-video\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Audio To Video video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"resolution\\\":\\\"720p\\\",\\\"assets\\\":{\\\"audio_file_path\\\":\\\"api-assets/id/1234.mp3\\\",\\\"image_file_path\\\":\\\"api-assets/id/1234.png\\\"},\\\"style\\\":{\\\"prompt\\\":\\\"Car driving through a city\\\"}}\")\n .asString();" /v1/auto-subtitle-generator: post: description: Automatically generate subtitles for your video in multiple languages. summary: Auto Subtitle Generator tags: - Video Projects parameters: [] operationId: autoSubtitleGenerator.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Auto Subtitle video default: Auto Subtitle - dateTime start_seconds: type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 assets: type: object properties: video_file_path: type: string minLength: 1 description: 'This is the video used to add subtitles. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 required: - video_file_path description: Provide the assets for auto subtitle generator style: type: object properties: template: type: string enum: - karaoke - cinematic - minimalist - highlight description: Preset subtitle templates. Please visit https://magichour.ai/create/auto-subtitle-generator to see the style of the existing templates. custom_config: type: object properties: font: type: string description: "Font name from Google Fonts. Not all fonts support all languages or character sets. \nWe recommend verifying language support and appearance directly on https://fonts.google.com before use." example: Noto Sans font_size: type: number description: Font size in pixels. If not provided, the font size is automatically calculated based on the video resolution. example: 24 font_style: type: string description: Font style (e.g., normal, italic, bold) example: normal text_color: type: string description: Primary text color in hex format example: '#FFFFFF' highlighted_text_color: type: string description: Color used to highlight the current spoken text example: '#FFD700' stroke_color: type: string description: Stroke (outline) color of the text example: '#000000' stroke_width: type: number description: Width of the text stroke in pixels. If `stroke_color` is provided, but `stroke_width` is not, the `stroke_width` will be calculated automatically based on the font size. example: 1 vertical_position: type: string description: Vertical alignment of the text (e.g., top, center, bottom) example: bottom horizontal_position: type: string description: Horizontal alignment of the text (e.g., left, center, right) example: center description: Custom subtitle configuration. description: "Style of the subtitle. At least one of `.style.template` or `.style.custom_config` must be provided. \n* If only `.style.template` is provided, default values for the template will be used.\n* If both are provided, the fields in `.style.custom_config` will be used to overwrite the fields in `.style.template`.\n* If only `.style.custom_config` is provided, then all fields in `.style.custom_config` will be used.\n\nTo use custom config only, the following `custom_config` params are required:\n* `.style.custom_config.font`\n* `.style.custom_config.text_color`\n* `.style.custom_config.vertical_position`\n* `.style.custom_config.horizontal_position`\n" required: - start_seconds - end_seconds - assets - style responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.auto_subtitle_generator.generate(\n assets={\"video_file_path\": \"/path/to/1234.mp4\"},\n end_seconds=15.0,\n start_seconds=0.0,\n style={},\n name=\"Auto Subtitle video\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.autoSubtitleGenerator.generate(\n {\n assets: { videoFilePath: \"/path/to/1234.mp4\" },\n endSeconds: 15.0,\n name: \"Auto Subtitle video\",\n startSeconds: 0.0,\n style: {},\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tauto_subtitle_generator \"github.com/magichourhq/magic-hour-go/resources/v1/auto_subtitle_generator\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.AutoSubtitleGenerator.Create(auto_subtitle_generator.CreateRequest{\n\t\tAssets: types.V1AutoSubtitleGeneratorCreateBodyAssets{\n\t\t\tVideoFilePath: \"api-assets/id/1234.mp4\",\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tName: nullable.NewValue(\"My Auto Subtitle video\"),\n\t\tStartSeconds: 0.0,\n\t\tStyle: types.V1AutoSubtitleGeneratorCreateBodyStyle{},\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .auto_subtitle_generator()\n .create(magic_hour::resources::v1::auto_subtitle_generator::CreateRequest {\n assets: magic_hour::models::V1AutoSubtitleGeneratorCreateBodyAssets {\n video_file_path: \"api-assets/id/1234.mp4\".to_string(),\n },\n end_seconds: 15.0,\n name: Some(\"My Auto Subtitle video\".to_string()),\n start_seconds: 0.0,\n style: magic_hour::models::V1AutoSubtitleGeneratorCreateBodyStyle {\n ..Default::default()\n },\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/auto-subtitle-generator \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Auto Subtitle video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"assets\": {\n \"video_file_path\": \"api-assets/id/1234.mp4\"\n },\n \"style\": {\n \"template\": \"karaoke\",\n \"custom_config\": {\n \"font\": \"Noto Sans\",\n \"font_size\": 24,\n \"font_style\": \"normal\",\n \"text_color\": \"#FFFFFF\",\n \"highlighted_text_color\": \"#FFD700\",\n \"stroke_color\": \"#000000\",\n \"stroke_width\": 1,\n \"vertical_position\": \"bottom\",\n \"horizontal_position\": \"center\"\n }\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/auto-subtitle-generator\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Auto Subtitle video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'assets' => [\n 'video_file_path' => 'api-assets/id/1234.mp4'\n ],\n 'style' => [\n 'template' => 'karaoke',\n 'custom_config' => [\n 'font' => 'Noto Sans',\n 'font_size' => 24,\n 'font_style' => 'normal',\n 'text_color' => '#FFFFFF',\n 'highlighted_text_color' => '#FFD700',\n 'stroke_color' => '#000000',\n 'stroke_width' => 1,\n 'vertical_position' => 'bottom',\n 'horizontal_position' => 'center'\n ]\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/auto-subtitle-generator\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Auto Subtitle video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"assets\\\":{\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\"},\\\"style\\\":{\\\"template\\\":\\\"karaoke\\\",\\\"custom_config\\\":{\\\"font\\\":\\\"Noto Sans\\\",\\\"font_size\\\":24,\\\"font_style\\\":\\\"normal\\\",\\\"text_color\\\":\\\"#FFFFFF\\\",\\\"highlighted_text_color\\\":\\\"#FFD700\\\",\\\"stroke_color\\\":\\\"#000000\\\",\\\"stroke_width\\\":1,\\\"vertical_position\\\":\\\"bottom\\\",\\\"horizontal_position\\\":\\\"center\\\"}}}\")\n .asString();" /v1/character-replace: post: description: "**What this API does**\n\nCreate the same Character Replace you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding character replace into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a character replace job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/character-replace)." summary: Character Replace tags: - Video Projects parameters: [] operationId: characterReplace.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Character Replace video default: Character Replace - dateTime start_seconds: default: 0 type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 resolution: type: string enum: - 480p - 720p description: Output video resolution. Defaults to 480p, the lowest resolution available on your plan. example: 720p assets: type: object properties: video_file_path: type: string minLength: 1 description: 'Source video containing the subject to replace or animate. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 image_file_path: type: string minLength: 1 description: 'Reference character image used as the replacement or animation target. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/5678.png required: - video_file_path - image_file_path description: Source video and reference character image for the job. style: type: object properties: mode: type: string enum: - replace - animate description: Processing mode. `replace` swaps the detected subject with your reference character. `animate` transfers motion from the video onto your character image. example: replace selection_mode: type: string enum: - auto - point description: How to locate the subject in the source video. `auto` detects a person automatically. `point` uses your `points` to mark the subject. Defaults to `auto`. example: auto points: type: array items: type: object properties: position_x: type: integer minimum: 0 description: Horizontal pixel coordinate in the source video frame at `time_seconds`, measured from the left edge. example: 320 position_y: type: integer minimum: 0 description: Vertical pixel coordinate in the source video frame at `time_seconds`, measured from the top edge. example: 180 time_seconds: type: number minimum: 0 description: Timestamp on the source video timeline in seconds. Uses the same clock as `start_seconds` and `end_seconds`. format: float example: 2.5 required: - position_x - position_y - time_seconds description: On-frame markers for manual subject selection. Required when `selection_mode` is `point`. Ignored when `selection_mode` is `auto` or omitted. description: Optional style controls for replace vs animate mode and subject selection. example: mode: replace selection_mode: auto required: - end_seconds - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.character_replace.generate(\n data={\n \"assets\": {\n \"image_file_path\": \"/path/to/5678.png\",\n \"video_file_path\": \"/path/to/1234.mp4\",\n },\n \"end_seconds\": 15.0,\n \"name\": \"My Character Replace video\",\n \"resolution\": \"720p\",\n \"start_seconds\": 0.0,\n \"style\": {\"mode\": \"replace\", \"selection_mode\": \"auto\"},\n },\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\",\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.characterReplace.generate(\n {\n assets: {\n imageFilePath: \"/path/to/5678.png\",\n videoFilePath: \"/path/to/1234.mp4\",\n },\n endSeconds: 15.0,\n name: \"My Character Replace video\",\n resolution: \"720p\",\n startSeconds: 0.0,\n style: { mode: \"replace\", selectionMode: \"auto\" },\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tcharacter_replace \"github.com/magichourhq/magic-hour-go/resources/v1/character_replace\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.CharacterReplace.Create(character_replace.CreateRequest{\n\t\tAssets: types.V1CharacterReplaceCreateBodyAssets{\n\t\t\tImageFilePath: \"api-assets/id/5678.png\",\n\t\t\tVideoFilePath: \"api-assets/id/1234.mp4\",\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tName: nullable.NewValue(\"My Character Replace video\"),\n\t\tResolution: nullable.NewValue(types.V1CharacterReplaceCreateBodyResolutionEnum720p),\n\t\tStartSeconds: nullable.NewValue(0.0),\n\t\tStyle: nullable.NewValue(types.V1CharacterReplaceCreateBodyStyle{\n\t\t\tMode: nullable.NewValue(types.V1CharacterReplaceCreateBodyStyleModeEnumReplace),\n\t\t\tSelectionMode: nullable.NewValue(types.V1CharacterReplaceCreateBodyStyleSelectionModeEnumAuto),\n\t\t}),\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .character_replace()\n .create(magic_hour::resources::v1::character_replace::CreateRequest {\n assets: magic_hour::models::V1CharacterReplaceCreateBodyAssets {\n image_file_path: \"api-assets/id/5678.png\".to_string(),\n video_file_path: \"api-assets/id/1234.mp4\".to_string(),\n },\n end_seconds: 15.0,\n name: Some(\"My Character Replace video\".to_string()),\n resolution: Some(\n magic_hour::models::V1CharacterReplaceCreateBodyResolutionEnum::Enum720p,\n ),\n start_seconds: Some(0.0),\n style: Some(magic_hour::models::V1CharacterReplaceCreateBodyStyle {\n mode: Some(\n magic_hour::models::V1CharacterReplaceCreateBodyStyleModeEnum::Replace,\n ),\n selection_mode: Some(\n magic_hour::models::V1CharacterReplaceCreateBodyStyleSelectionModeEnum::Auto,\n ),\n ..Default::default()\n }),\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/character-replace \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Character Replace video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"resolution\": \"720p\",\n \"assets\": {\n \"video_file_path\": \"api-assets/id/1234.mp4\",\n \"image_file_path\": \"api-assets/id/5678.png\"\n },\n \"style\": {\n \"mode\": \"replace\",\n \"selection_mode\": \"auto\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/character-replace\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Character Replace video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'resolution' => '720p',\n 'assets' => [\n 'video_file_path' => 'api-assets/id/1234.mp4',\n 'image_file_path' => 'api-assets/id/5678.png'\n ],\n 'style' => [\n 'mode' => 'replace',\n 'selection_mode' => 'auto'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/character-replace\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Character Replace video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"resolution\\\":\\\"720p\\\",\\\"assets\\\":{\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\",\\\"image_file_path\\\":\\\"api-assets/id/5678.png\\\"},\\\"style\\\":{\\\"mode\\\":\\\"replace\\\",\\\"selection_mode\\\":\\\"auto\\\"}}\")\n .asString();" /v1/face-swap: post: description: "**What this API does**\n\nCreate the same Face Swap you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding face swap into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a face swap job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/face-swap)." summary: Face Swap Video tags: - Video Projects parameters: [] operationId: faceSwap.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Face Swap video default: Face Swap - dateTime start_seconds: type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 style: type: object properties: version: type: string enum: - v1 - v2 - default example: default description: '* `v1` - May preserve skin detail and texture better, but weaker identity preservation. * `v2` - Faster, sharper, better handling of hair and glasses. stronger identity preservation. * `default` - Use the version we recommend, which will change over time. This is recommended unless you need a specific earlier version. This is the default behavior.' description: Style of the face swap video. example: version: default assets: type: object properties: face_swap_mode: default: all-faces type: string enum: - all-faces - individual-faces description: 'Choose how to swap faces: **all-faces** (recommended) — swap all detected faces using one source image (`source_file_path` required) +- **individual-faces** — specify exact mappings using `face_mappings`' example: all-faces image_file_path: type: string description: 'The path of the input image with the face to be swapped. The value is required if `face_swap_mode` is `all-faces`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: image/id/1234.png face_mappings: type: array items: type: object properties: original_face: type: string description: 'The face detected from the image in `target_file_path`. The file name is in the format of `-.png`. This value is corresponds to the response in the [face detection API](https://docs.magichour.ai/api-reference/files/get-face-detection-details). * The face_frame is the frame number of the face in the target image. For images, the frame number is always 0. * The face_index is the index of the face in the target image, starting from 0 going left to right.' example: api-assets/id/0-0.png new_face: type: string description: 'The face image that will be used to replace the face in the `original_face`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.png required: - original_face - new_face maxItems: 5 description: This is the array of face mappings used for multiple face swap. The value is required if `face_swap_mode` is `individual-faces`. example: - original_face: api-assets/id/0-0.png new_face: api-assets/id/1234.png video_source: type: string enum: - file - youtube description: Choose your video source. example: file video_file_path: type: string description: 'Your video file. Required if `video_source` is `file`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 youtube_url: type: string format: uri description: YouTube URL (required if `video_source` is `youtube`). required: - video_source description: Provide the assets for face swap. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used required: - start_seconds - end_seconds - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.face_swap.generate(\n assets={\n \"face_mappings\": [\n {\n \"new_face\": \"/path/to/1234.png\",\n \"original_face\": \"api-assets/id/0-0.png\",\n }\n ],\n \"face_swap_mode\": \"all-faces\",\n \"image_file_path\": \"image/id/1234.png\",\n \"video_file_path\": \"/path/to/1234.mp4\",\n \"video_source\": \"file\",\n },\n end_seconds=15.0,\n start_seconds=0.0,\n name=\"Face Swap video\",\n style={\"version\": \"default\"},\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.faceSwap.generate(\n {\n assets: {\n faceMappings: [\n {\n newFace: \"api-assets/id/1234.png\",\n originalFace: \"api-assets/id/0-0.png\",\n },\n ],\n faceSwapMode: \"all-faces\",\n imageFilePath: \"image/id/1234.png\",\n videoFilePath: \"/path/to/1234.mp4\",\n videoSource: \"file\",\n },\n endSeconds: 15.0,\n name: \"Face Swap video\",\n startSeconds: 0.0,\n style: { version: \"default\" },\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tface_swap \"github.com/magichourhq/magic-hour-go/resources/v1/face_swap\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.FaceSwap.Create(face_swap.CreateRequest{\n\t\tAssets: types.V1FaceSwapCreateBodyAssets{\n\t\t\tFaceMappings: nullable.NewValue([]types.V1FaceSwapCreateBodyAssetsFaceMappingsItem{\n\t\t\t\ttypes.V1FaceSwapCreateBodyAssetsFaceMappingsItem{\n\t\t\t\t\tNewFace: \"api-assets/id/1234.png\",\n\t\t\t\t\tOriginalFace: \"api-assets/id/0-0.png\",\n\t\t\t\t},\n\t\t\t}),\n\t\t\tFaceSwapMode: nullable.NewValue(types.V1FaceSwapCreateBodyAssetsFaceSwapModeEnumAllFaces),\n\t\t\tImageFilePath: nullable.NewValue(\"image/id/1234.png\"),\n\t\t\tVideoFilePath: nullable.NewValue(\"api-assets/id/1234.mp4\"),\n\t\t\tVideoSource: types.V1FaceSwapCreateBodyAssetsVideoSourceEnumFile,\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tName: nullable.NewValue(\"My Face Swap video\"),\n\t\tStartSeconds: 0.0,\n\t\tStyle: nullable.NewValue(types.V1FaceSwapCreateBodyStyle{\n\t\t\tVersion: nullable.NewValue(types.V1FaceSwapCreateBodyStyleVersionEnumDefault),\n\t\t}),\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .face_swap()\n .create(magic_hour::resources::v1::face_swap::CreateRequest {\n assets: magic_hour::models::V1FaceSwapCreateBodyAssets {\n face_mappings: Some(\n vec![\n magic_hour::models::V1FaceSwapCreateBodyAssetsFaceMappingsItem {\n new_face : \"api-assets/id/1234.png\".to_string(), original_face :\n \"api-assets/id/0-0.png\".to_string() }\n ],\n ),\n face_swap_mode: Some(\n magic_hour::models::V1FaceSwapCreateBodyAssetsFaceSwapModeEnum::AllFaces,\n ),\n image_file_path: Some(\"image/id/1234.png\".to_string()),\n video_file_path: Some(\"api-assets/id/1234.mp4\".to_string()),\n video_source: magic_hour::models::V1FaceSwapCreateBodyAssetsVideoSourceEnum::File,\n ..Default::default()\n },\n end_seconds: 15.0,\n name: Some(\"My Face Swap video\".to_string()),\n start_seconds: 0.0,\n style: Some(magic_hour::models::V1FaceSwapCreateBodyStyle {\n version: Some(\n magic_hour::models::V1FaceSwapCreateBodyStyleVersionEnum::Default,\n ),\n }),\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/face-swap \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Face Swap video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"style\": {\n \"version\": \"default\"\n },\n \"assets\": {\n \"face_swap_mode\": \"all-faces\",\n \"image_file_path\": \"image/id/1234.png\",\n \"face_mappings\": [\n {\n \"original_face\": \"api-assets/id/0-0.png\",\n \"new_face\": \"api-assets/id/1234.png\"\n }\n ],\n \"video_source\": \"file\",\n \"video_file_path\": \"api-assets/id/1234.mp4\",\n \"youtube_url\": \"string\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/face-swap\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Face Swap video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'style' => [\n 'version' => 'default'\n ],\n 'assets' => [\n 'face_swap_mode' => 'all-faces',\n 'image_file_path' => 'image/id/1234.png',\n 'face_mappings' => [\n [\n 'original_face' => 'api-assets/id/0-0.png',\n 'new_face' => 'api-assets/id/1234.png'\n ]\n ],\n 'video_source' => 'file',\n 'video_file_path' => 'api-assets/id/1234.mp4',\n 'youtube_url' => 'string'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/face-swap\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Face Swap video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"style\\\":{\\\"version\\\":\\\"default\\\"},\\\"assets\\\":{\\\"face_swap_mode\\\":\\\"all-faces\\\",\\\"image_file_path\\\":\\\"image/id/1234.png\\\",\\\"face_mappings\\\":[{\\\"original_face\\\":\\\"api-assets/id/0-0.png\\\",\\\"new_face\\\":\\\"api-assets/id/1234.png\\\"}],\\\"video_source\\\":\\\"file\\\",\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\",\\\"youtube_url\\\":\\\"string\\\"}}\")\n .asString();" /v1/image-to-video: post: description: "**What this API does**\n\nCreate the same Image To Video you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding image to video into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a image to video job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/image-to-video)." summary: Image-to-Video tags: - Video Projects parameters: [] operationId: imageToVideo.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Image To Video video default: Image To Video - dateTime end_seconds: type: number minimum: 1 maximum: 60 description: 'The total duration of the output video in seconds. Supported durations depend on the chosen model: * **`kling-2.6`**: 5, 10 * **`kling-3.0`**: 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`ltx-2.3`**: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30 * **`minimax-h3`**: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30 * **`seedance-1.5`**: 4, 5, 6, 7, 8, 9, 10, 11, 12 * **`seedance-2.0`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`seedance-2.0-mini`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`seedance-2.5`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 * **`sora-2`**: 4, 8, 12, 24, 36, 48, 60 * **`veo3.1`**: 4, 6, 8, 16, 24, 32, 40, 48, 56 * **`veo3.1-lite`**: 4, 6, 8, 16, 24, 32, 40, 48, 56 * **`wan-2.2`**: 3, 4, 5, 6, 7, 8, 9, 10, 15 ' format: float example: 5 model: default: default type: string enum: - default - ltx-2 - ltx-2.3 - minimax-h3 - wan-2.2 - seedance-1.5 - seedance-2.0 - seedance-2.0-mini - seedance-2.5 - kling-2.5 - kling-2.6 - kling-3.0 - veo3.1 - veo3.1-lite - sora-2 - kling-1.6 - seedance - kling-2.5-audio - veo3.1-audio description: 'The AI model to use for video generation. * `default`: uses our currently recommended model for general use. For paid tiers, defaults to `kling-3.0`. For free tiers, it defaults to `ltx-2.3`. * `kling-2.6`: Great for action, motion blur, and camera moves. * `kling-3.0`: Best overall quality for cinematic storytelling. * `ltx-2.3`: Fastest output. Best for rapid iteration. * `minimax-h3`: Reference-driven video with native audio. * `seedance-1.5`: Smooth, consistent motion with precision. * `seedance-2.0`: Top quality with reference-to-video control. * `seedance-2.0-mini`: Fast, consistent video with strong motion quality * `seedance-2.5`: Highest quality with superior realism, detail, and motion * `sora-2`: Open AI''s model. Great for creativity and viral clips. * `veo3.1`: Google''s model. Highest realism and detail. * `veo3.1-lite`: Veo quality at a more accessible cost. * `wan-2.2`: Strong physics, camera moves, and motion. If you specify the deprecated model value that includes the `-audio` suffix, this will be the same as included `audio` as `true`.' example: kling-3.0 resolution: type: string enum: - 480p - 720p - 1080p - 4k example: 720p description: 'Controls the output video resolution. Defaults to `720p` on paid tiers and `480p` on free tiers. * **`kling-2.6`**: Supports 720p, 1080p. * **`kling-3.0`**: Supports 720p, 1080p, 4k. * **`ltx-2.3`**: Supports 480p, 720p, 1080p. * **`minimax-h3`**: Supports 480p, 720p, 1080p. * **`seedance-1.5`**: Supports 480p, 720p, 1080p. * **`seedance-2.0`**: Supports 480p, 720p. * **`seedance-2.0-mini`**: Supports 480p, 720p. * **`seedance-2.5`**: Supports 480p, 720p. * **`sora-2`**: Supports 720p. * **`veo3.1`**: Supports 720p, 1080p. * **`veo3.1-lite`**: Supports 720p, 1080p. * **`wan-2.2`**: Supports 480p, 720p, 1080p. ' audio: type: boolean description: 'Whether to include audio in the video. Defaults to `false` if not specified. Audio support varies by model: * **`kling-2.6`**: Not supported * **`kling-3.0`**: Toggle-able: audio adds extra credits when enabled * **`ltx-2.3`**: Toggle-able: no additional credits for audio * **`minimax-h3`**: Toggle-able: no additional credits for audio * **`seedance-1.5`**: Toggle-able: audio adds extra credits when enabled * **`seedance-2.0`**: Toggle-able: no additional credits for audio * **`seedance-2.0-mini`**: Toggle-able: no additional credits for audio * **`seedance-2.5`**: Toggle-able: no additional credits for audio * **`sora-2`**: Toggle-able: no additional credits for audio * **`veo3.1`**: Toggle-able: audio adds extra credits when enabled * **`veo3.1-lite`**: Toggle-able: audio adds extra credits when enabled * **`wan-2.2`**: Not supported ' example: true style: type: object properties: prompt: type: string example: a dog running description: The prompt used for the video. description: Attributed used to dictate the style of the output assets: type: object properties: image_file_path: type: string minLength: 1 description: 'The path of the image file. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.png end_image_file_path: type: string minLength: 1 description: 'The image to use as the last frame of the video. * **`kling-2.6`**: Supports 1080p. * **`kling-3.0`**: Supports 720p, 1080p, 4k. * **`ltx-2.3`**: Supports 480p, 720p, 1080p. * **`minimax-h3`**: Not supported * **`seedance-1.5`**: Supports 480p, 720p, 1080p. * **`seedance-2.0`**: Supports 480p, 720p. * **`seedance-2.0-mini`**: Supports 480p, 720p. * **`seedance-2.5`**: Supports 480p, 720p. * **`sora-2`**: Not supported * **`veo3.1`**: Supports 720p, 1080p. Requires a duration of 8 seconds or less. * **`veo3.1-lite`**: Supports 720p, 1080p. Requires a duration of 8 seconds or less. * **`wan-2.2`**: Not supported ' example: api-assets/id/1234.png required: - image_file_path description: Provide the assets for image-to-video. Sora 2 only supports images with an aspect ratio of `9:16` or `16:9`. required: - end_seconds - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.image_to_video.generate(\n assets={\"image_file_path\": \"/path/to/1234.png\"},\n end_seconds=5.0,\n name=\"Image To Video video\",\n resolution=\"720p\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.imageToVideo.generate(\n {\n assets: { imageFilePath: \"/path/to/1234.png\" },\n endSeconds: 5.0,\n name: \"Image To Video video\",\n resolution: \"720p\",\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\timage_to_video \"github.com/magichourhq/magic-hour-go/resources/v1/image_to_video\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.ImageToVideo.Create(image_to_video.CreateRequest{\n\t\tAssets: types.V1ImageToVideoCreateBodyAssets{\n\t\t\tEndImageFilePath: nullable.NewValue(\"api-assets/id/1234.png\"),\n\t\t\tImageFilePath: \"api-assets/id/1234.png\",\n\t\t},\n\t\tAudio: nullable.NewValue(true),\n\t\tEndSeconds: 5.0,\n\t\tModel: nullable.NewValue(types.V1ImageToVideoCreateBodyModelEnumKling30),\n\t\tName: nullable.NewValue(\"My Image To Video video\"),\n\t\tResolution: nullable.NewValue(types.V1ImageToVideoCreateBodyResolutionEnum720p),\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .image_to_video()\n .create(magic_hour::resources::v1::image_to_video::CreateRequest {\n assets: magic_hour::models::V1ImageToVideoCreateBodyAssets {\n end_image_file_path: Some(\"api-assets/id/1234.png\".to_string()),\n image_file_path: \"api-assets/id/1234.png\".to_string(),\n },\n audio: Some(true),\n end_seconds: 5.0,\n model: Some(magic_hour::models::V1ImageToVideoCreateBodyModelEnum::Kling30),\n name: Some(\"My Image To Video video\".to_string()),\n resolution: Some(\n magic_hour::models::V1ImageToVideoCreateBodyResolutionEnum::Enum720p,\n ),\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/image-to-video \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Image To Video video\",\n \"end_seconds\": 5,\n \"model\": \"kling-3.0\",\n \"resolution\": \"720p\",\n \"audio\": true,\n \"style\": {\n \"prompt\": \"a dog running\"\n },\n \"assets\": {\n \"image_file_path\": \"api-assets/id/1234.png\",\n \"end_image_file_path\": \"api-assets/id/1234.png\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/image-to-video\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Image To Video video',\n 'end_seconds' => 5,\n 'model' => 'kling-3.0',\n 'resolution' => '720p',\n 'audio' => true,\n 'style' => [\n 'prompt' => 'a dog running'\n ],\n 'assets' => [\n 'image_file_path' => 'api-assets/id/1234.png',\n 'end_image_file_path' => 'api-assets/id/1234.png'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/image-to-video\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Image To Video video\\\",\\\"end_seconds\\\":5,\\\"model\\\":\\\"kling-3.0\\\",\\\"resolution\\\":\\\"720p\\\",\\\"audio\\\":true,\\\"style\\\":{\\\"prompt\\\":\\\"a dog running\\\"},\\\"assets\\\":{\\\"image_file_path\\\":\\\"api-assets/id/1234.png\\\",\\\"end_image_file_path\\\":\\\"api-assets/id/1234.png\\\"}}\")\n .asString();" /v1/lip-sync: post: description: "**What this API does**\n\nCreate the same Lip Sync you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding lip sync into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a lip sync job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/lip-sync)." summary: Lip Sync tags: - Video Projects parameters: [] operationId: lipSync.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Lip Sync video default: Lip Sync - dateTime start_seconds: type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 max_fps_limit: type: number minimum: 1 description: Defines the maximum FPS (frames per second) for the output video. If the input video's FPS is lower than this limit, the output video will retain the input FPS. This is useful for reducing unnecessary frame usage in scenarios where high FPS is not required. example: 12 assets: type: object properties: audio_file_path: type: string minLength: 1 description: 'The path of the audio file. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp3 video_source: type: string enum: - file - youtube description: Choose your video source. example: file video_file_path: type: string description: 'Your video file. Required if `video_source` is `file`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 youtube_url: type: string format: uri description: YouTube URL (required if `video_source` is `youtube`). required: - audio_file_path - video_source description: Provide the assets for lip-sync. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used style: type: object properties: generation_mode: default: lite type: string enum: - lite - standard - pro description: "A specific version of our lip sync system, optimized for different needs.\n* `lite` - Fast and affordable lip sync - best for simple videos. Costs 1 credit per frame of video.\n* `standard` - Natural, accurate lip sync - best for most creators. Costs 1 credit per frame of video.\n* `pro` - Premium fidelity with enhanced detail - best for professionals. Costs 2 credits per frame of video.\n\nNote: `standard` and `pro` are only available for users on Creator, Pro, and Business tiers.\n " example: lite description: Attributes used to dictate the style of the output required: - start_seconds - end_seconds - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.lip_sync.generate(\n assets={\n \"audio_file_path\": \"/path/to/1234.mp3\",\n \"video_file_path\": \"/path/to/1234.mp4\",\n \"video_source\": \"file\",\n },\n style={\n \"generation_mode\": \"lite\",\n },\n end_seconds=15.0,\n start_seconds=0.0,\n max_fps_limit=12.0,\n name=\"Lip Sync video\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.lipSync.generate(\n {\n assets: {\n audioFilePath: \"/path/to/1234.mp3\",\n videoFilePath: \"/path/to/1234.mp4\",\n videoSource: \"file\",\n },\n endSeconds: 15.0,\n maxFpsLimit: 12.0,\n name: \"Lip Sync video\",\n startSeconds: 0.0,\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tlip_sync \"github.com/magichourhq/magic-hour-go/resources/v1/lip_sync\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.LipSync.Create(lip_sync.CreateRequest{\n\t\tAssets: types.V1LipSyncCreateBodyAssets{\n\t\t\tAudioFilePath: \"api-assets/id/1234.mp3\",\n\t\t\tVideoFilePath: nullable.NewValue(\"api-assets/id/1234.mp4\"),\n\t\t\tVideoSource: types.V1LipSyncCreateBodyAssetsVideoSourceEnumFile,\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tMaxFpsLimit: nullable.NewValue(12.0),\n\t\tName: nullable.NewValue(\"My Lip Sync video\"),\n\t\tStartSeconds: 0.0,\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .lip_sync()\n .create(magic_hour::resources::v1::lip_sync::CreateRequest {\n assets: magic_hour::models::V1LipSyncCreateBodyAssets {\n audio_file_path: \"api-assets/id/1234.mp3\".to_string(),\n video_file_path: Some(\"api-assets/id/1234.mp4\".to_string()),\n video_source: magic_hour::models::V1LipSyncCreateBodyAssetsVideoSourceEnum::File,\n ..Default::default()\n },\n end_seconds: 15.0,\n max_fps_limit: Some(12.0),\n name: Some(\"My Lip Sync video\".to_string()),\n start_seconds: 0.0,\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/lip-sync \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Lip Sync video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"max_fps_limit\": 12,\n \"assets\": {\n \"audio_file_path\": \"api-assets/id/1234.mp3\",\n \"video_source\": \"file\",\n \"video_file_path\": \"api-assets/id/1234.mp4\",\n \"youtube_url\": \"string\"\n },\n \"style\": {\n \"generation_mode\": \"lite\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/lip-sync\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Lip Sync video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'max_fps_limit' => 12,\n 'assets' => [\n 'audio_file_path' => 'api-assets/id/1234.mp3',\n 'video_source' => 'file',\n 'video_file_path' => 'api-assets/id/1234.mp4',\n 'youtube_url' => 'string'\n ],\n 'style' => [\n 'generation_mode' => 'lite'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/lip-sync\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Lip Sync video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"max_fps_limit\\\":12,\\\"assets\\\":{\\\"audio_file_path\\\":\\\"api-assets/id/1234.mp3\\\",\\\"video_source\\\":\\\"file\\\",\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\",\\\"youtube_url\\\":\\\"string\\\"},\\\"style\\\":{\\\"generation_mode\\\":\\\"lite\\\"}}\")\n .asString();" /v1/text-to-video: post: description: "**What this API does**\n\nCreate the same Text To Video you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding text to video into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a text to video job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/text-to-video)." summary: Text-to-Video tags: - Video Projects parameters: [] operationId: textToVideo.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Text To Video video default: Text To Video - dateTime end_seconds: type: number minimum: 1 maximum: 60 description: 'The total duration of the output video in seconds. Supported durations depend on the chosen model: * **`kling-2.6`**: 5, 10 * **`kling-3.0`**: 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`ltx-2.3`**: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30 * **`minimax-h3`**: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30 * **`seedance-1.5`**: 4, 5, 6, 7, 8, 9, 10, 11, 12 * **`seedance-2.0`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`seedance-2.0-mini`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 * **`seedance-2.5`**: 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 * **`sora-2`**: 4, 8, 12, 24, 36, 48, 60 * **`veo3.1`**: 4, 6, 8, 16, 24, 32, 40, 48, 56 * **`veo3.1-lite`**: 4, 6, 8, 16, 24, 32, 40, 48, 56 * **`wan-2.2`**: 3, 4, 5, 6, 7, 8, 9, 10, 15 ' format: float example: 5 aspect_ratio: type: string enum: - '16:9' - '9:16' - '1:1' description: 'Determines the aspect ratio of the output video. * **`kling-2.6`**: Supports 9:16, 16:9, 1:1. * **`kling-3.0`**: Supports 9:16, 16:9, 1:1. * **`ltx-2.3`**: Supports 9:16, 16:9, 1:1. * **`minimax-h3`**: Supports 16:9, 9:16, 1:1. * **`seedance-1.5`**: Supports 9:16, 16:9, 1:1. * **`seedance-2.0`**: Supports 9:16, 16:9, 1:1. * **`seedance-2.0-mini`**: Supports 9:16, 16:9, 1:1. * **`seedance-2.5`**: Supports 9:16, 16:9, 1:1. * **`sora-2`**: Supports 9:16, 16:9. * **`veo3.1`**: Supports 9:16, 16:9. * **`veo3.1-lite`**: Supports 9:16, 16:9. * **`wan-2.2`**: Supports 9:16, 16:9, 1:1. ' example: '16:9' resolution: type: string enum: - 480p - 720p - 1080p - 4k example: 720p description: 'Controls the output video resolution. Defaults to `720p` on paid tiers and `480p` on free tiers. * **`kling-2.6`**: Supports 720p, 1080p. * **`kling-3.0`**: Supports 720p, 1080p, 4k. * **`ltx-2.3`**: Supports 480p, 720p, 1080p. * **`minimax-h3`**: Supports 480p, 720p, 1080p. * **`seedance-1.5`**: Supports 480p, 720p, 1080p. * **`seedance-2.0`**: Supports 480p, 720p. * **`seedance-2.0-mini`**: Supports 480p, 720p. * **`seedance-2.5`**: Supports 480p, 720p. * **`sora-2`**: Supports 720p. * **`veo3.1`**: Supports 720p, 1080p. * **`veo3.1-lite`**: Supports 720p, 1080p. * **`wan-2.2`**: Supports 480p, 720p, 1080p. ' model: default: default type: string enum: - default - ltx-2 - ltx-2.3 - minimax-h3 - wan-2.2 - seedance-1.5 - seedance-2.0 - seedance-2.0-mini - seedance-2.5 - kling-2.5 - kling-2.6 - kling-3.0 - veo3.1 - veo3.1-lite - sora-2 - kling-1.6 - seedance - kling-2.5-audio - veo3.1-audio description: 'The AI model to use for video generation. * `default`: uses our currently recommended model for general use. For paid tiers, defaults to `kling-3.0`. For free tiers, it defaults to `ltx-2.3`. * `kling-2.6`: Great for action, motion blur, and camera moves. * `kling-3.0`: Best overall quality for cinematic storytelling. * `ltx-2.3`: Fastest output. Best for rapid iteration. * `minimax-h3`: Reference-driven video with native audio. * `seedance-1.5`: Smooth, consistent motion with precision. * `seedance-2.0`: Top quality with reference-to-video control. * `seedance-2.0-mini`: Fast, consistent video with strong motion quality * `seedance-2.5`: Highest quality with superior realism, detail, and motion * `sora-2`: Open AI''s model. Great for creativity and viral clips. * `veo3.1`: Google''s model. Highest realism and detail. * `veo3.1-lite`: Veo quality at a more accessible cost. * `wan-2.2`: Strong physics, camera moves, and motion. If you specify the deprecated model value that includes the `-audio` suffix, this will be the same as included `audio` as `true`.' example: kling-3.0 audio: type: boolean description: 'Whether to include audio in the video. Defaults to `false` if not specified. Audio support varies by model: * **`kling-2.6`**: Not supported * **`kling-3.0`**: Toggle-able: audio adds extra credits when enabled * **`ltx-2.3`**: Toggle-able: no additional credits for audio * **`minimax-h3`**: Toggle-able: no additional credits for audio * **`seedance-1.5`**: Toggle-able: audio adds extra credits when enabled * **`seedance-2.0`**: Toggle-able: no additional credits for audio * **`seedance-2.0-mini`**: Toggle-able: no additional credits for audio * **`seedance-2.5`**: Toggle-able: no additional credits for audio * **`sora-2`**: Toggle-able: no additional credits for audio * **`veo3.1`**: Toggle-able: audio adds extra credits when enabled * **`veo3.1-lite`**: Toggle-able: audio adds extra credits when enabled * **`wan-2.2`**: Not supported ' example: true style: type: object properties: prompt: type: string minLength: 1 maxLength: 2000 example: a dog running description: The prompt used for the video. required: - prompt required: - end_seconds - style responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.text_to_video.generate(\n end_seconds=5.0,\n aspect_ratio=\"16:9\",\n style={\"prompt\": \"a dog running\"},\n name=\"Text To Video video\",\n resolution=\"720p\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.textToVideo.generate(\n {\n endSeconds: 5.0,\n name: \"Text To Video video\",\n resolution: \"720p\",\n style: { prompt: \"a dog running\" },\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\ttext_to_video \"github.com/magichourhq/magic-hour-go/resources/v1/text_to_video\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.TextToVideo.Create(text_to_video.CreateRequest{\n\t\tAspectRatio: nullable.NewValue(types.V1TextToVideoCreateBodyAspectRatioEnum169),\n\t\tAudio: nullable.NewValue(true),\n\t\tEndSeconds: 5.0,\n\t\tModel: nullable.NewValue(types.V1TextToVideoCreateBodyModelEnumKling30),\n\t\tName: nullable.NewValue(\"My Text To Video video\"),\n\t\tResolution: nullable.NewValue(types.V1TextToVideoCreateBodyResolutionEnum720p),\n\t\tStyle: types.V1TextToVideoCreateBodyStyle{\n\t\t\tPrompt: \"a dog running\",\n\t\t},\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .text_to_video()\n .create(magic_hour::resources::v1::text_to_video::CreateRequest {\n aspect_ratio: Some(\n magic_hour::models::V1TextToVideoCreateBodyAspectRatioEnum::Enum169,\n ),\n audio: Some(true),\n end_seconds: 5.0,\n model: Some(magic_hour::models::V1TextToVideoCreateBodyModelEnum::Kling30),\n name: Some(\"My Text To Video video\".to_string()),\n resolution: Some(\n magic_hour::models::V1TextToVideoCreateBodyResolutionEnum::Enum720p,\n ),\n style: magic_hour::models::V1TextToVideoCreateBodyStyle {\n prompt: \"a dog running\".to_string(),\n ..Default::default()\n },\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/text-to-video \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Text To Video video\",\n \"end_seconds\": 5,\n \"aspect_ratio\": \"16:9\",\n \"resolution\": \"720p\",\n \"model\": \"kling-3.0\",\n \"audio\": true,\n \"style\": {\n \"prompt\": \"a dog running\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/text-to-video\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Text To Video video',\n 'end_seconds' => 5,\n 'aspect_ratio' => '16:9',\n 'resolution' => '720p',\n 'model' => 'kling-3.0',\n 'audio' => true,\n 'style' => [\n 'prompt' => 'a dog running'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/text-to-video\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Text To Video video\\\",\\\"end_seconds\\\":5,\\\"aspect_ratio\\\":\\\"16:9\\\",\\\"resolution\\\":\\\"720p\\\",\\\"model\\\":\\\"kling-3.0\\\",\\\"audio\\\":true,\\\"style\\\":{\\\"prompt\\\":\\\"a dog running\\\"}}\")\n .asString();" /v1/video-to-video: post: description: "**What this API does**\n\nCreate the same Video To Video you can make in the browser, but programmatically, so you can automate it, run it at scale, or connect it to your own app or workflow.\n \n**Good for**\n- Automation and batch processing \n- Adding video to video into apps, pipelines, or tools \n\n**How it works (3 steps)**\n1) Upload your inputs (video, image, or audio) with [Generate Upload URLs](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls) and copy the `file_path`. \n2) Send a request to create a video to video job with the basic fields. \n3) Check the job status until it's `complete`, then download the result from `downloads`.\n\n**Key options**\n- Inputs: see the request schema for endpoint-specific assets \n- Resolution: free users default to 480p; higher plans unlock HD and larger sizes \n- Extra fields: see the request schema for endpoint-specific options \n\n**Cost** \nCredits are only charged for the frames that actually render. You'll see an estimate when the job is queued, and the final total after it's done.\n\nFor detailed examples, see the [product page](https://magichour.ai/products/video-to-video)." summary: Video-to-Video tags: - Video Projects parameters: [] operationId: videoToVideo.createVideo requestBody: required: true description: Body content: application/json: schema: type: object properties: name: type: string description: Give your video a custom name for easy identification. example: My Video To Video video default: Video To Video - dateTime start_seconds: type: number minimum: 0 description: Start time of your clip (seconds). Must be ≥ 0. format: float example: 0 end_seconds: type: number minimum: 0.1 description: End time of your clip (seconds). Must be greater than start_seconds. format: float example: 15 fps_resolution: default: HALF type: string enum: - FULL - HALF description: 'Determines whether the resulting video will have the same frame per second as the original video, or half. * `FULL` - the result video will have the same FPS as the input video * `HALF` - the result video will have half the FPS as the input video' example: HALF style: type: object properties: art_style: type: string enum: - Minecraft - Watercolor - Pixel - Retro Sci-Fi - Lego - Origami - Ghost - Sub-Zero - Studio Ghibli - Comic - Impressionism - Master Chief - Solid Snake - Street Fighter - Hologram - GTA - Clay - Mystique - Dragonball Z - Mario - Samurai - Spartan - Boba Fett - 3D Render - Airbender - Android - Anime Warrior - Armored Knight - Assassin's Creed - Avatar - Black Spiderman - Bold Anime - Celestial Skin - Chinese Swordsmen - Cyberpunk - Cypher - Dark Fantasy - Future Bot - Futuristic Fantasy - Ghibli Anime - Gundam - Illustration - Ink - Ink Poster - Jinx - Knight - Link - Marble - Mech - Naruto - Neon Dream - No Art Style - Oil Painting - On Fire - Painterly Anime - Pixar - Power Armor - Power Ranger - Radiant Anime - Realistic Anime - Realistic Pixar - Retro Anime - Samurai Bot - Sharp Anime - Soft Anime - Starfield - The Void - Tomb Raider - Underwater - Van Gogh - Viking - Western Anime - Wu Kong - Wuxia Anime - Zelda version: default: default type: string enum: - v1 - v2 - default example: default description: '* `v1` - more detail, closer prompt adherence, and frame-by-frame previews. * `v2` - faster, more consistent, and less noisy. * `default` - use the default version for the selected art style.' prompt_type: default: default type: string enum: - default - custom - append_default example: default description: '* `default` - Use the default recommended prompt for the art style. * `custom` - Only use the prompt passed in the API. Note: for v1, lora prompt will still be auto added to apply the art style properly. * `append_default` - Add the default recommended prompt to the end of the prompt passed in the API.' prompt: type: - string - 'null' description: The prompt used for the video. Prompt is required if `prompt_type` is `custom` or `append_default`. If `prompt_type` is `default`, then the `prompt` value passed will be ignored. model: default: default type: string enum: - Dreamshaper - Absolute Reality - Flat 2D Anime - Soft Anime - Kaywaii - Western Anime - 3D Anime - default example: default description: '* `Dreamshaper` - a good all-around model that works for both animations as well as realism. * `Absolute Reality` - better at realism, but you''ll often get similar results with Dreamshaper as well. * `Flat 2D Anime` - best for a flat illustration style that''s common in most anime. * `default` - use the default recommended model for the selected art style.' required: - art_style assets: type: object properties: video_source: type: string enum: - file - youtube description: Choose your video source. example: file video_file_path: type: string description: 'Your video file. Required if `video_source` is `file`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). See the [file upload guide](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) for details. ' example: api-assets/id/1234.mp4 youtube_url: type: string format: uri description: YouTube URL (required if `video_source` is `youtube`). required: - video_source description: Provide the assets for video-to-video. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used required: - start_seconds - end_seconds - style - assets responses: '200': description: Success content: application/json: schema: type: object properties: id: type: string example: cuid-example description: Unique ID of the video. Use it with the [Get video Project API](https://docs.magichour.ai/api-reference/video-projects/get-video-details) to fetch status and downloads. credits_charged: type: integer description: "The amount of credits deducted from your account to generate the video. If the status is not 'complete', this value is an estimate and may be adjusted upon completion based on the actual FPS of the output video. \n\nIf video generation fails, credits will be refunded, and this field will be updated to include the refund." example: 450 required: - id - credits_charged description: Success '400': description: Invalid Request content: application/json: schema: type: object properties: message: type: string required: - message description: The request is invalid example: message: Missing request body '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string enum: - Unauthorized required: - message description: The request is not properly authenticated example: message: Unauthorized '402': description: Payment Required content: application/json: schema: type: object properties: message: type: string required: - message description: The request requires payment example: message: Payment required '404': description: Not Found content: application/json: schema: type: object properties: message: type: string enum: - Not Found required: - message description: Requested resource is not found example: message: Not Found '422': description: Unprocessable Entity content: application/json: schema: type: object properties: message: type: string example: Unable to create video required: - message description: Unprocessable Entity security: - bearerAuth: [] x-codeSamples: - lang: python source: "from magic_hour import Client\nfrom os import getenv\n\nclient = Client(token=getenv(\"API_TOKEN\"))\nres = client.v1.video_to_video.generate(\n assets={\"video_file_path\": \"/path/to/1234.mp4\", \"video_source\": \"file\"},\n end_seconds=15.0,\n start_seconds=0.0,\n style={\n \"art_style\": \"3D Render\",\n \"model\": \"default\",\n \"prompt\": \"string\",\n \"prompt_type\": \"default\",\n \"version\": \"default\",\n },\n fps_resolution=\"HALF\",\n name=\"Video To Video video\",\n wait_for_completion=True,\n download_outputs=True,\n download_directory=\".\"\n)" - lang: javascript source: "import { Client } from \"magic-hour\";\n\nconst client = new Client({ token: process.env[\"API_TOKEN\"]!! });\nconst res = await client.v1.videoToVideo.generate(\n {\n assets: { videoFilePath: \"/path/to/1234.mp4\", videoSource: \"file\" },\n endSeconds: 15.0,\n fpsResolution: \"HALF\",\n name: \"Video To Video video\",\n startSeconds: 0.0,\n style: {\n artStyle: \"3D Render\",\n model: \"default\",\n prompt: \"string\",\n promptType: \"default\",\n version: \"default\",\n },\n },\n {\n waitForCompletion: true,\n downloadOutputs: true,\n downloadDirectory: \".\",\n },\n);" - lang: go source: "package main\n\nimport (\n\tos \"os\"\n\n\tsdk \"github.com/magichourhq/magic-hour-go/client\"\n\tnullable \"github.com/magichourhq/magic-hour-go/nullable\"\n\tvideo_to_video \"github.com/magichourhq/magic-hour-go/resources/v1/video_to_video\"\n\ttypes \"github.com/magichourhq/magic-hour-go/types\"\n)\n\nfunc main() {\n\tclient := sdk.NewClient(\n\t\tsdk.WithBearerAuth(os.Getenv(\"API_TOKEN\")),\n\t)\n\tres, err := client.V1.VideoToVideo.Create(video_to_video.CreateRequest{\n\t\tAssets: types.V1VideoToVideoCreateBodyAssets{\n\t\t\tVideoFilePath: nullable.NewValue(\"api-assets/id/1234.mp4\"),\n\t\t\tVideoSource: types.V1VideoToVideoCreateBodyAssetsVideoSourceEnumFile,\n\t\t},\n\t\tEndSeconds: 15.0,\n\t\tFpsResolution: nullable.NewValue(types.V1VideoToVideoCreateBodyFpsResolutionEnumHalf),\n\t\tName: nullable.NewValue(\"My Video To Video video\"),\n\t\tStartSeconds: 0.0,\n\t\tStyle: types.V1VideoToVideoCreateBodyStyle{\n\t\t\tArtStyle: types.V1VideoToVideoCreateBodyStyleArtStyleEnum3dRender,\n\t\t\tModel: nullable.NewValue(types.V1VideoToVideoCreateBodyStyleModelEnumDefault),\n\t\t\tPromptType: nullable.NewValue(types.V1VideoToVideoCreateBodyStylePromptTypeEnumDefault),\n\t\t\tVersion: nullable.NewValue(types.V1VideoToVideoCreateBodyStyleVersionEnumDefault),\n\t\t},\n\t})\n}" - lang: rust source: "let client = magic_hour::Client::default()\n .with_bearer_auth(&std::env::var(\"API_TOKEN\").unwrap());\nlet res = client\n .v1()\n .video_to_video()\n .create(magic_hour::resources::v1::video_to_video::CreateRequest {\n assets: magic_hour::models::V1VideoToVideoCreateBodyAssets {\n video_file_path: Some(\"api-assets/id/1234.mp4\".to_string()),\n video_source: magic_hour::models::V1VideoToVideoCreateBodyAssetsVideoSourceEnum::File,\n ..Default::default()\n },\n end_seconds: 15.0,\n fps_resolution: Some(\n magic_hour::models::V1VideoToVideoCreateBodyFpsResolutionEnum::Half,\n ),\n name: Some(\"My Video To Video video\".to_string()),\n start_seconds: 0.0,\n style: magic_hour::models::V1VideoToVideoCreateBodyStyle {\n art_style: magic_hour::models::V1VideoToVideoCreateBodyStyleArtStyleEnum::Enum3dRender,\n model: Some(\n magic_hour::models::V1VideoToVideoCreateBodyStyleModelEnum::Default,\n ),\n prompt_type: Some(\n magic_hour::models::V1VideoToVideoCreateBodyStylePromptTypeEnum::Default,\n ),\n version: Some(\n magic_hour::models::V1VideoToVideoCreateBodyStyleVersionEnum::Default,\n ),\n ..Default::default()\n },\n ..Default::default()\n })\n .await;" - lang: curl source: "curl --request POST \\\n --url https://api.magichour.ai/v1/video-to-video \\\n --header 'accept: application/json' \\\n --header 'authorization: Bearer ' \\\n --header 'content-type: application/json' \\\n --data '\n{\n \"name\": \"My Video To Video video\",\n \"start_seconds\": 0,\n \"end_seconds\": 15,\n \"fps_resolution\": \"HALF\",\n \"style\": {\n \"art_style\": \"Minecraft\",\n \"version\": \"default\",\n \"prompt_type\": \"default\",\n \"prompt\": \"string\",\n \"model\": \"default\"\n },\n \"assets\": {\n \"video_source\": \"file\",\n \"video_file_path\": \"api-assets/id/1234.mp4\",\n \"youtube_url\": \"string\"\n }\n}\n'" - lang: php source: " \"https://api.magichour.ai/v1/video-to-video\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode([\n 'name' => 'My Video To Video video',\n 'start_seconds' => 0,\n 'end_seconds' => 15,\n 'fps_resolution' => 'HALF',\n 'style' => [\n 'art_style' => 'Minecraft',\n 'version' => 'default',\n 'prompt_type' => 'default',\n 'prompt' => 'string',\n 'model' => 'default'\n ],\n 'assets' => [\n 'video_source' => 'file',\n 'video_file_path' => 'api-assets/id/1234.mp4',\n 'youtube_url' => 'string'\n ]\n ]),\n CURLOPT_HTTPHEADER => [\n \"accept: application/json\",\n \"authorization: Bearer \",\n \"content-type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}" - lang: java source: "HttpResponse response = Unirest.post(\"https://api.magichour.ai/v1/video-to-video\")\n .header(\"accept\", \"application/json\")\n .header(\"content-type\", \"application/json\")\n .header(\"authorization\", \"Bearer \")\n .body(\"{\\\"name\\\":\\\"My Video To Video video\\\",\\\"start_seconds\\\":0,\\\"end_seconds\\\":15,\\\"fps_resolution\\\":\\\"HALF\\\",\\\"style\\\":{\\\"art_style\\\":\\\"Minecraft\\\",\\\"version\\\":\\\"default\\\",\\\"prompt_type\\\":\\\"default\\\",\\\"prompt\\\":\\\"string\\\",\\\"model\\\":\\\"default\\\"},\\\"assets\\\":{\\\"video_source\\\":\\\"file\\\",\\\"video_file_path\\\":\\\"api-assets/id/1234.mp4\\\",\\\"youtube_url\\\":\\\"string\\\"}}\")\n .asString();" components: securitySchemes: bearerAuth: type: http scheme: bearer description: Bearer authentication header of the form `Bearer `, where `` is your API key. To get your API key, go to [Developer Hub](https://magichour.ai/developer?tab=api-keys&utm_source=docs&utm_medium=referral&utm_campaign=api-reference) and click "Create new API Key".