{"openapi":"3.1.0","info":{"title":"Render API","version":"1.0.0","description":"Turn a brief into a finished ad video.\n\nGeneration spends plan credits first — 25 credits per generated\nsecond — and meters the overflow at $0.25 per second once the pool\nis empty.\n\nEvery response is wrapped: `{ success: true, data }` or\n`{ success: false, error: { code, message, isRetriable, retryAfter } }`.\n\nAd creation is asynchronous. `POST /v1/ads` returns 202 with an id;\npoll `GET /v1/ads/{id}` or register a webhook.\n\nSend `Idempotency-Key` on every POST — generations take minutes and\ncost money, so retries are expected and deduplicated.\n\nRequest bodies are strict: an unknown field is a 400 that names it,\nso a misspelt parameter cannot silently fall back to a default.\n\nCreative controls on POST /ads — `product_id`, `references` (with\nroles), `language`, `voice_id`, `script`, `style`, `captions`,\n`music`, `presenter` — are hard constraints the agent must honour,\nnot hints. `metadata` is yours and comes back on the ad and in\nevery webhook."},"servers":[{"url":"https://tryrender.ai/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Ads","description":"Create, track and revise ads."},{"name":"Brands","description":"Who the ad is for."},{"name":"Products","description":"What the ad is selling."},{"name":"Uploads","description":"Your own images and footage."},{"name":"Webhooks","description":"Be told, instead of polling."},{"name":"Account","description":"Credits and usage."}],"paths":{"/ads":{"post":{"summary":"Create an ad","description":"Returns immediately with `status: \"planning\"`. In `review` mode the ad reaches `awaiting_approval` with a plan and costs nothing until approved; in `auto` mode it is approved and billed as soon as the plan exists (`queued` while it waits for a generation slot behind the account's concurrency cap).","operationId":"createAd","tags":["Ads"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"brief":{"type":"string","minLength":1,"maxLength":8000,"description":"What the ad should be."},"brand_id":{"description":"From POST /brands.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"product_id":{"description":"From POST /products. The ad sells this; its images are used.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"format":{"default":"9:16","type":"string","enum":["16:9","9:16","1:1","4:5","4:3","3:4"]},"duration_seconds":{"default":30,"description":"How long the ad runs. The plan's shots must add up to it and the delivered file is exactly this long — a plan that does not fit is sent back to the planner before it is shown or approved. `output.duration_seconds` confirms it on the finished ad; billing is on the plan.","type":"integer","minimum":5,"maximum":120},"mode":{"default":"auto","description":"auto: plan and generate in one call. review: stop at the plan.","type":"string","enum":["review","auto"]},"name":{"type":"string","maxLength":120},"reference_media_ids":{"description":"Upload ids with no stated role. Prefer `references`.","maxItems":10,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"references":{"description":"Uploads with a role: product | person | style | scene | motion.","maxItems":10,"type":"array","items":{"type":"object","properties":{"upload_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"role":{"type":"string","enum":["product","person","style","scene","motion"]},"note":{"type":"string","maxLength":200}},"required":["upload_id","role"],"additionalProperties":false}},"language":{"description":"BCP-47 code for all speech and on-screen text, e.g. \"es\", \"pt-BR\".","type":"string","pattern":"^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$"},"voice_id":{"description":"From GET /voices.","type":"string","minLength":1,"maxLength":64},"script":{"description":"Exact spoken words, used verbatim and in order.","type":"string","minLength":1,"maxLength":2000},"style":{"description":"ugc | cinematic | product_demo | motion_graphics.","type":"string","enum":["ugc","cinematic","product_demo","motion_graphics"]},"captions":{"description":"Burn word-timed captions into the finished file.","type":"boolean"},"music":{"description":"false for none, or direction such as \"warm acoustic, 80bpm\".","anyOf":[{"type":"boolean","const":false},{"type":"string","minLength":1,"maxLength":200}]},"presenter":{"description":"\"me\": the account owner appears on camera from their enrolled photo.","type":"string","enum":["me"]},"metadata":{"description":"Up to 16 string key/values, echoed on the ad and in webhooks.","type":"object","propertyNames":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$"},"additionalProperties":{"type":"string","maxLength":500}}},"required":["brief"]}}}},"responses":{"202":{"description":"Ad accepted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List ads","operationId":"listAds","tags":["Ads"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Filter to one status. Status is derived per ad after the page is read, so a filtered page can be short or empty while has_more is still true — keep following next_cursor.","schema":{"type":"string","enum":["planning","needs_input","awaiting_approval","queued","generating","ready","failed","canceled"]}},{"name":"brand_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"created_after","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"created_before","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"A page of ads","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/AdList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/estimate":{"post":{"summary":"Estimate what an ad will cost","description":"Prices a batch against your current balance: how much comes out of credits and how much lands on the invoice. Nothing is created and nothing is charged.","operationId":"estimateAd","tags":["Ads"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"duration_seconds":{"type":"integer","minimum":5,"maximum":120},"quantity":{"default":1,"type":"integer","minimum":1,"maximum":500}},"required":["duration_seconds"]}}}},"responses":{"200":{"description":"Estimate","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/AdEstimate"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/{id}":{"get":{"summary":"Fetch an ad","description":"The polling endpoint. Carries the plan, the progress counter, the question if it is stuck, and a signed download URL once ready.","operationId":"getAd","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The ad","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Cancel an ad","description":"Before approval this stops the ad and costs nothing. After approval the generation jobs are already running and their credits are already spent.","operationId":"cancelAd","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The canceled ad","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/{id}/approve":{"post":{"summary":"Approve a plan and start generating","description":"Synchronous, so you learn here whether the account can afford it (402) or too much is already running (429).","operationId":"approveAd","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The ad, now generating","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/{id}/messages":{"post":{"summary":"Answer a question, or ask for a revision","description":"Free before approval. Revising a generated ad produces a new plan that must be approved like any other.","operationId":"sendAdMessage","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":4000}},"required":["content"]}}}},"responses":{"202":{"description":"The ad, replanning","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/{id}/revise":{"post":{"summary":"Same as /messages","description":"An alias of POST /ads/{id}/messages under the name the MCP tool uses (revise_ad).","operationId":"reviseAd","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":4000}},"required":["content"]}}}},"responses":{"202":{"description":"The ad, replanning","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Ad"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ads/{id}/variants":{"post":{"summary":"Make variants of an ad that worked","description":"Each variant is a full independent ad inheriting this one's brand, format, length and structure, varying the hook (or CTA, or angle).","operationId":"createAdVariants","tags":["Ads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"count":{"default":3,"type":"integer","minimum":1,"maximum":10},"vary":{"default":"hook","type":"string","enum":["hook","cta","angle"]},"direction":{"type":"string","maxLength":1000},"mode":{"default":"auto","type":"string","enum":["review","auto"]},"metadata":{"type":"object","propertyNames":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$"},"additionalProperties":{"type":"string","maxLength":500}}}}}}},"responses":{"202":{"description":"The variant ads","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/AdList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brands":{"post":{"summary":"Create a brand","description":"From a website URL, or from explicit fields.","operationId":"createBrand","tags":["Brands"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"type":"object","properties":{"url":{"type":"string","format":"uri"},"name":{"type":"string","maxLength":200}},"required":["url"]},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","minLength":1,"maxLength":4000},"tagline":{"type":"string","maxLength":500},"industry":{"type":"string","maxLength":200},"tone_of_voice":{"type":"string","maxLength":500},"target_audience":{"type":"string","maxLength":1000},"value_proposition":{"type":"string","maxLength":1000},"brand_colors":{"maxItems":12,"type":"array","items":{"type":"string","maxLength":32}},"key_messaging":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":500}}},"required":["name","description"]}]}}}},"responses":{"201":{"description":"The brand","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Brand"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List brands","operationId":"listBrands","tags":["Brands"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A page of brands","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BrandList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brands/{id}":{"get":{"summary":"Fetch a brand","operationId":"getBrand","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The brand","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Brand"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a brand","operationId":"deleteBrand","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Deleted"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products":{"post":{"summary":"Create a product","operationId":"createProduct","tags":["Products"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"default":"","type":"string","maxLength":4000},"image_ids":{"maxItems":10,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"required":["name"]}}}},"responses":{"201":{"description":"The product","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Product"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List products","operationId":"listProducts","tags":["Products"],"responses":{"200":{"description":"Products","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ProductList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/uploads":{"post":{"summary":"Start an upload","description":"Returns a presigned URL. PUT the bytes to it with the exact `content_type`, then call the complete endpoint.","operationId":"createUpload","tags":["Uploads"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"type":"object","properties":{"file_name":{"type":"string","minLength":1,"maxLength":200},"content_type":{"type":"string","pattern":"^(image|video|audio)\\/[\\w.+-]+$"}},"required":["file_name","content_type"],"description":"Reserve an id and get a URL to PUT the bytes to."},{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"},"file_name":{"type":"string","minLength":1,"maxLength":200}},"required":["url"],"description":"Import a public image, video or audio file by URL (up to 50MB). Returns a ready upload."}]}}}},"responses":{"201":{"description":"Where to send the bytes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Upload"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/uploads/{id}/complete":{"post":{"summary":"Finish an upload","description":"Verifies the bytes arrived and marks the upload usable. An upload that is never completed cannot be used in an ad.","operationId":"completeUpload","tags":["Uploads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Ready to use","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/UploadComplete"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"post":{"summary":"Register a webhook endpoint","description":"The signing secret is returned once. Every delivery carries `Render-Signature: t=<unix seconds>,v1=<hex>`; verify it as HMAC-SHA256, keyed by the secret, over the timestamp followed by a dot followed by the raw request body.","operationId":"createWebhook","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["ad.plan_ready","ad.needs_input","ad.generating","ad.ready","ad.failed"]}},"description":{"type":"string","maxLength":200}},"required":["url"]}}}},"responses":{"201":{"description":"The endpoint, with its secret","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookCreated"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List webhook endpoints","operationId":"listWebhooks","tags":["Webhooks"],"responses":{"200":{"description":"Endpoints","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/WebhookList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"get":{"summary":"Fetch an endpoint and its recent deliveries","operationId":"getWebhook","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The endpoint","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Webhook"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a webhook endpoint","operationId":"deleteWebhook","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Deleted"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/voices":{"get":{"summary":"Narration voices","description":"The preset roster plus your own cloned voice when you have one. Pass an id as `voice_id` on POST /ads.","operationId":"listVoices","tags":["Account"],"responses":{"200":{"description":"Voices","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/VoiceList"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/credits":{"get":{"summary":"Credit balance","operationId":"getCredits","tags":["Account"],"responses":{"200":{"description":"Balance","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/CreditBalance"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/usage":{"get":{"summary":"What the API has spent","operationId":"getUsage","tags":["Account"],"parameters":[{"name":"start","in":"query","required":false,"schema":{"type":"string"}},{"name":"end","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage over the window","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/Usage"}},"required":["success","data"]}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key from the API & MCP page of your Render account (`rk_live_…`). It spends the account's credits, so treat it like a password."}},"schemas":{"Error":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable code, e.g. INSUFFICIENT_CREDITS, CREDIT_LIMIT_EXCEEDED, CONCURRENCY_LIMIT, CONFLICT, VALIDATION_FAILED."},"message":{"type":"string"},"details":{},"isRetriable":{"type":"boolean"},"retryAfter":{"type":"number","description":"Seconds to wait, when the error is retriable."}},"required":["code","message","isRetriable"]}},"required":["success","error"]},"Deleted":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string"},"deleted":{"type":"boolean","const":true}}},"AdPlan":{"type":"object","properties":{"object":{"type":"string","const":"ad_plan"},"angle":{"type":"string"},"premise":{"type":"string"},"rationale":{"type":"string"},"opening_line":{"type":"string"},"cta":{"type":"string"},"generation_format":{"type":"string","description":"The aspect the video model shoots at; the ad's own `format` is what is delivered."},"total_duration_seconds":{"type":"number"},"shots":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"duration_seconds":{"type":"number"},"description":{"type":"string"},"spoken_line":{"type":"string"},"delivery":{"type":"string","enum":["dialogue","voiceover"]},"on_screen_text":{"type":"string"}}}},"characters":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"description":{"type":"string"}}}},"music_prompt":{"type":"string"},"billable_seconds":{"type":"integer","description":"Seconds of video this plan generates."},"estimated_credits":{"type":"integer","description":"Credits if the pool covers all of it (25/second). What it actually splits into is settled at approval — see POST /ads/estimate."},"estimated_usd_if_no_credits":{"type":"number","description":"Cost if the pool is empty and every second meters."}}},"Ad":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"ad"},"status":{"type":"string","enum":["planning","needs_input","awaiting_approval","queued","generating","ready","failed","canceled"]},"mode":{"type":"string","enum":["review","auto"]},"test_mode":{"type":"boolean"},"brief":{"type":"string"},"format":{"type":"string"},"duration_seconds":{"type":"integer"},"brand_id":{"type":"string"},"credits_charged":{"type":"integer","description":"Credits this ad took out of the plan pool."},"billable_seconds":{"type":"integer"},"usd":{"type":"number","description":"What the metered overflow added to the invoice, if any."},"variant_of_ad_id":{"type":"string"},"reference_media_ids":{"type":"array","items":{"type":"string"},"description":"Upload ids attached to this ad, as accepted."},"product_id":{"type":"string"},"references":{"type":"array","items":{"type":"object","properties":{"upload_id":{"type":"string"},"role":{"type":"string","enum":["product","person","style","scene","motion"]},"note":{"type":"string"}}}},"controls":{"type":"object","description":"language / voice_id / script / style / captions / music / presenter, as accepted.","additionalProperties":true},"metadata":{"type":"object","additionalProperties":{"type":"string"},"description":"Your own key/values, echoed untouched — also in every webhook."},"plan":{"$ref":"#/components/schemas/AdPlan"},"question":{"type":"string","description":"Present when status is needs_input. Answer via /messages."},"progress":{"type":"object","properties":{"completed":{"type":"integer"},"total":{"type":"integer"}}},"output":{"type":"object","properties":{"url":{"type":"string","description":"Signed; expires. GET the ad again for a fresh one."},"format":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"width":{"type":"integer"},"height":{"type":"integer"},"duration_seconds":{"type":"number"},"size_bytes":{"type":"integer"}}},"failure_reason":{"type":"string","description":"Why status is `failed`. Planning: `dispatch_failed` (queue unavailable; nothing billed), `planning_timeout`, `planning_failed` (the model crashed twice, or could not plan the requested length after two corrections), `needs_input_unattended` (auto mode; the agent could not proceed without an answer — use review mode or a fuller brief). Auto-approval refusals: `credit_limit_exceeded`, `forbidden` (no way to bill), `concurrency_limit` (only after waiting an hour for a slot — an auto ad queues behind the plan's concurrency cap rather than failing). Generation: `generation_timeout`, `generation_failed`. Export: `export_unavailable`, `export_failed`, `export_timeout`. Credits already spent on generation are not refunded by a later export failure; open `project_id` in the editor to export by hand."},"project_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"finished_at":{"type":"string","format":"date-time"}},"required":["id","object","status"]},"AdEstimate":{"type":"object","properties":{"object":{"type":"string","const":"ad_estimate"},"duration_seconds":{"type":"integer"},"quantity":{"type":"integer"},"credits_per_second":{"type":"integer"},"usd_per_second":{"type":"number"},"billable_seconds_per_ad":{"type":"integer"},"credits_per_ad":{"type":"integer"},"billable_seconds_total":{"type":"integer"},"credits_covered_seconds":{"type":"integer","description":"Seconds your current balance covers."},"credits_charged":{"type":"integer"},"metered_seconds":{"type":"integer"},"usd_total":{"type":"number"},"credits_available":{"type":"integer"},"covered_by_credits":{"type":"boolean"},"month_to_date_usd":{"type":"number"},"monthly_limit_usd":{"type":"number"},"within_monthly_limit":{"type":"boolean"}}},"Brand":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"brand"},"name":{"type":"string"},"description":{"type":"string"},"tagline":{"type":"string"},"industry":{"type":"string"},"tone_of_voice":{"type":"string"},"target_audience":{"type":"string"},"value_proposition":{"type":"string"},"logo_url":{"type":"string"},"brand_colors":{"type":"array","items":{"type":"string"}},"products":{"type":"array","items":{"type":"object"}},"key_messaging":{"type":"array","items":{"type":"string"}},"source_url":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Product":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"product"},"name":{"type":"string"},"description":{"type":"string"},"image_ids":{"type":"array","items":{"type":"string"}}}},"Upload":{"type":"object","description":"Reserve-then-PUT returns upload_url + expires_at; a URL import returns status: ready with size_bytes.","properties":{"id":{"type":"string"},"object":{"type":"string","const":"upload"},"upload_url":{"type":"string"},"content_type":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["uploading","ready"]},"size_bytes":{"type":"integer"},"source_url":{"type":"string"}}},"Voice":{"type":"object","properties":{"object":{"type":"string","const":"voice"},"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["preset","cloned"]},"gender":{"type":"string"},"age":{"type":"string"},"accent":{"type":"string"},"descriptor":{"type":"string"},"preview_url":{"type":"string"}}},"UploadComplete":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"upload"},"status":{"type":"string","const":"ready"},"size_bytes":{"type":"integer"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"webhook"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["ad.plan_ready","ad.needs_input","ad.generating","ad.ready","ad.failed"]}},"active":{"type":"boolean"},"disabled_reason":{"type":"string"},"consecutive_failures":{"type":"integer"},"last_success_at":{"type":"string","format":"date-time"}}},"WebhookCreated":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"Returned once. Cannot be retrieved later."}}}]},"CreditBalance":{"type":"object","properties":{"object":{"type":"string","const":"credit_balance"},"credits":{"type":"integer"},"plan":{"type":"string"},"overage_credits":{"type":"integer"},"usage_based_pricing_enabled":{"type":"boolean"},"usd_per_credit":{"type":"number"}}},"Usage":{"type":"object","properties":{"object":{"type":"string","const":"usage"},"period_start":{"type":"string","format":"date-time"},"period_end":{"type":"string","format":"date-time"},"billable_seconds":{"type":"integer"},"credit_seconds":{"type":"integer"},"credits_charged":{"type":"integer"},"metered_seconds":{"type":"integer"},"usd":{"type":"number"},"credits_per_second":{"type":"integer"},"usd_per_second":{"type":"number"},"ads_created":{"type":"integer"},"ads_delivered":{"type":"integer"},"monthly_limit_usd":{"type":"number"}}},"AdList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Ad"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"VoiceList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Voice"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"BrandList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Brand"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"ProductList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"WebhookList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}}}}}