{"openapi":"3.1.0","info":{"title":"FrameSurfer API","version":"1.0.0","description":"Make AI images, short video clips and music tracks. Needs a paid FrameSurfer plan and an API key from https://framesurfer.com/api-keys. Send it as Authorization: Bearer fs_... Guide: https://framesurfer.com/docs/api"},"servers":[{"url":"https://framesurfer.com/api"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"A FrameSurfer API key (fs_...), made at https://framesurfer.com/api-keys."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}},"paths":{"/v1/images":{"post":{"summary":"Create an image","description":"Makes one AI picture from a prompt, or changes an existing picture. The request is charged when it is accepted. It answers at once with an id; get the finished picture with GET /v1/images/{id}.","operationId":"createImage","security":[{"apiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. The same key with the same body returns the same job and charges once.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"What the picture shows."},"model":{"type":"string","default":"gpt-image-2.5","description":"An image model id from GET /v1/models."},"aspectRatio":{"type":"string","enum":["9:16","16:9","1:1"],"default":"9:16","description":"9:16 vertical, 16:9 wide or 1:1 square."},"imageUrl":{"type":"string","format":"uri","description":"A picture to change instead of starting from nothing. The model must edit pictures (editsPictures in GET /v1/models)."}}}}}},"responses":{"202":{"description":"Create an image","content":{"application/json":{"schema":{"type":"object","example":{"id":"project-image-7c1e0a9b4d2f","kind":"image","status":"processing","credits":1,"model":"gpt-image-2.5"}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/images/{id}":{"get":{"summary":"Retrieve an image","description":"Where a picture stands. Ask every few seconds until status is completed or failed; most pictures take 10 to 30 seconds.","operationId":"getImage","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The id POST /v1/images answered with.","schema":{"type":"string"}}],"responses":{"200":{"description":"Retrieve an image","content":{"application/json":{"schema":{"type":"object","example":{"id":"project-image-7c1e0a9b4d2f","kind":"image","status":"completed","url":"https://media.framesurfer.com/media/ai-images/lighthouse.png"}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/videos":{"post":{"summary":"Create a video clip","description":"Makes one short AI video clip: a single continuous shot, from a prompt or starting from a picture. The request is charged when it is accepted. It answers at once with an id; get the finished clip with GET /v1/videos/{id}.","operationId":"createVideo","security":[{"apiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. The same key with the same body returns the same job and charges once.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"The one shot: what is seen, what moves, and any sound or line."},"model":{"type":"string","default":"p-video-2-pro","description":"A video model id from GET /v1/models."},"durationSec":{"type":"integer","default":5,"description":"Length in seconds. It is rounded to a length the model can make (allowedDurations in GET /v1/models), and the response gives the real length."},"aspectRatio":{"type":"string","enum":["9:16","16:9","1:1"],"default":"9:16","description":"9:16 vertical, 16:9 wide or 1:1 square."},"resolution":{"type":"string","description":"One of the model's resolutions, for example 480p or 768p. Defaults to the model's own (480p on p-video-2-pro)."},"sound":{"type":"boolean","default":true,"description":"Generate sound with the picture."},"startImageUrl":{"type":"string","format":"uri","description":"A picture the clip starts from."},"endImageUrl":{"type":"string","format":"uri","description":"A picture the clip ends on, when the model takes one (endsOnPicture in GET /v1/models)."}}}}}},"responses":{"202":{"description":"Create a video clip","content":{"application/json":{"schema":{"type":"object","example":{"id":"tool-video-credit-4b8d2e61f0aa","kind":"video","status":"processing","credits":5,"durationSec":5,"resolution":"480p","aspectRatio":"9:16","withAudio":true,"model":"p-video-2-pro"}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/videos/{id}":{"get":{"summary":"Retrieve a video clip","description":"Where a clip stands. Ask every 5 to 10 seconds until status is completed or failed; most clips take 30 seconds to 3 minutes.","operationId":"getVideo","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The id POST /v1/videos answered with.","schema":{"type":"string"}}],"responses":{"200":{"description":"Retrieve a video clip","content":{"application/json":{"schema":{"type":"object","example":{"id":"tool-video-credit-4b8d2e61f0aa","kind":"video","status":"completed","url":"https://media.framesurfer.com/media/videos/waves.mp4"}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/music":{"post":{"summary":"Create a music track","description":"Makes one instrumental music track and answers with its link in the same request, usually within a minute. If the same request is still being made it answers 202; send it again with the same Idempotency-Key to collect the track.","operationId":"createMusic","security":[{"apiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string. The same key with the same body returns the same job and charges once.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"What the music sounds like: genre, mood, instruments, tempo."},"durationSec":{"type":"integer","default":30,"minimum":1,"maximum":180,"description":"Length in seconds, 1 to 180."}}}}}},"responses":{"200":{"description":"Create a music track","content":{"application/json":{"schema":{"type":"object","example":{"kind":"music","status":"completed","url":"https://media.framesurfer.com/media/music/calm-piano.mp3","credits":10,"durationSec":30}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/quote":{"post":{"summary":"Get a price","description":"The price of a request, without making anything or charging. Send kind plus the same fields you would send to create it; prompt is optional here.","operationId":"quote","security":[{"apiKey":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["kind"],"properties":{"kind":{"const":"image"},"model":{"type":"string","default":"gpt-image-2.5","description":"An image model id from GET /v1/models."},"aspectRatio":{"type":"string","enum":["9:16","16:9","1:1"],"default":"9:16","description":"9:16 vertical, 16:9 wide or 1:1 square."},"imageUrl":{"type":"string","format":"uri","description":"A picture to change instead of starting from nothing. The model must edit pictures (editsPictures in GET /v1/models)."}}},{"type":"object","required":["kind"],"properties":{"kind":{"const":"video"},"model":{"type":"string","default":"p-video-2-pro","description":"A video model id from GET /v1/models."},"durationSec":{"type":"integer","default":5,"description":"Length in seconds. It is rounded to a length the model can make (allowedDurations in GET /v1/models), and the response gives the real length."},"aspectRatio":{"type":"string","enum":["9:16","16:9","1:1"],"default":"9:16","description":"9:16 vertical, 16:9 wide or 1:1 square."},"resolution":{"type":"string","description":"One of the model's resolutions, for example 480p or 768p. Defaults to the model's own (480p on p-video-2-pro)."},"sound":{"type":"boolean","default":true,"description":"Generate sound with the picture."},"startImageUrl":{"type":"string","format":"uri","description":"A picture the clip starts from."},"endImageUrl":{"type":"string","format":"uri","description":"A picture the clip ends on, when the model takes one (endsOnPicture in GET /v1/models)."}}},{"type":"object","required":["kind"],"properties":{"kind":{"const":"music"},"durationSec":{"type":"integer","default":30,"minimum":1,"maximum":180,"description":"Length in seconds, 1 to 180."}}}]}}}},"responses":{"200":{"description":"Get a price","content":{"application/json":{"schema":{"type":"object","example":{"kind":"video","credits":20,"durationSec":10,"resolution":"768p","aspectRatio":"9:16","withAudio":true,"model":"p-video-2-pro","availableCredits":1240,"canAfford":true}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models":{"get":{"summary":"List models","description":"Every image, video and music option with its credits and the defaults. Video models list the lengths they make, their resolutions and credits per second, and whether they start or end on a picture.","operationId":"listModels","security":[{"apiKey":[]}],"parameters":[],"responses":{"200":{"description":"List models","content":{"application/json":{"schema":{"type":"object","example":{"image":{"defaultModel":"gpt-image-2.5","models":[{"id":"gpt-image-2.5","label":"GPT Image 2.5","credits":1,"editsPictures":true}]},"video":{"defaultModel":"p-video-2-pro","models":[{"id":"p-video-2-pro","label":"Pruna P-Video-2 Pro","allowedDurations":[5,6,7,8,9,10,11,12,13,14,15],"defaultDuration":5,"startsFromPicture":true,"endsOnPicture":true,"creditsPerSecond":[{"resolution":"480p","silent":1,"withSound":1},{"resolution":"768p","silent":2,"withSound":2}]}]},"music":{"creditsPerTrack":10,"maxDurationSec":180,"defaultDurationSec":30}}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/account":{"get":{"summary":"Get the account","description":"Credits left and the plan.","operationId":"getAccount","security":[{"apiKey":[]}],"parameters":[],"responses":{"200":{"description":"Get the account","content":{"application/json":{"schema":{"type":"object","example":{"credits":1240,"plan":"Standard"}}}}},"400":{"description":"invalid_request, invalid_json, bad_request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"missing_api_key, invalid_api_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"paid_plan_required, insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/health":{"get":{"summary":"Health check","operationId":"getHealth","responses":{"200":{"description":"Service health","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"service":{"type":"string"}}}}}}}}},"/free-tools/generate-hooks":{"post":{"summary":"Generate short-form video hooks","operationId":"generateHooks","responses":{"200":{"description":"Generated hook ideas"}}}},"/free-tools/script-to-video":{"post":{"summary":"Turn a script into video scene guidance","operationId":"scriptToVideo","responses":{"200":{"description":"Scene guidance"}}}}}}