Images and video
Images and video
POST /v1/images for image generation; POST /v1/videos with polling for video jobs.
Both endpoints take a model and a prompt and return generated images or video. List the models with GET /v1/images/models and GET /v1/videos/models; both lists are free and not rate-limited and include a predev price object per row.
Images
POST /v1/images returns generated images synchronously and is charged when the response is returned.
curl --fail-with-body https://api.pre.dev/v1/images \
-H "Authorization: Bearer $PREDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1"}'Pick another model from GET /v1/images/models; each row lists the parameters it accepts in supported_parameters, and some models edit an input image rather than start from a prompt.
To edit an image or draw from one, pass it in input_references. Each item is a URL or data: URL string, or {"type": "image_url", "image_url": {"url": "..."}}.
curl --fail-with-body https://api.pre.dev/v1/images \
-H "Authorization: Bearer $PREDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "google/gemini-3.1-flash-lite-image", "prompt": "The same lighthouse at night, under a sky full of stars", "input_references": ["https://example.com/lighthouse.png"]}'Use credits_per_image or the other predev prices in the model row to estimate cost; the actual charge follows the call’s metered usage, like every other call.
Video
Video generation is asynchronous:
POST /v1/videossubmits the job and returns it with itsidand apolling_url.GET /v1/videos/{id}reports status.polling_urlis this same URL, ending with the job’sid, so polling either one works.GET /v1/videos/{id}/contentreturns the finished video.
ID=$(curl --fail-with-body -s https://api.pre.dev/v1/videos \
-H "Authorization: Bearer $PREDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "bytedance/seedance-2.0-mini", "prompt": "A paper boat drifting down a rain gutter", "duration": 4, "resolution": "480p"}' | jq -r '.id')
# poll until the status is terminal
while :; do
STATUS=$(curl --fail-with-body -s "https://api.pre.dev/v1/videos/$ID" -H "Authorization: Bearer $PREDEV_API_KEY" | jq -r '.status')
case "$STATUS" in completed|failed|cancelled|expired) break ;; esac
sleep 5
done
# then download
curl --fail-with-body "https://api.pre.dev/v1/videos/$ID/content" \
-H "Authorization: Bearer $PREDEV_API_KEY" -o video.mp4Submitting a job needs at least 10 credits available. The job is charged once it finishes, not at submission: on the first status poll that reports completion, on the /content download if you never polled, or by pre.dev afterwards if you stopped polling. Poll until the status is terminal (completed, failed, cancelled or expired) before reading /content. Poll and download with the job’s id from the submit response.
Jobs belong to the workspace that created them; another workspace’s job id returns 404.
curl -X POST "https://api.pre.dev/v1/images" \ -H "Content-Type: application/json" \ -d '{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1" }'const body = JSON.stringify({ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1"})fetch("https://api.pre.dev/v1/images", { method: "POST", headers: { "Content-Type": "application/json" }, body})package mainimport ( "fmt" "net/http" "io/ioutil" "strings")func main() { url := "https://api.pre.dev/v1/images" body := strings.NewReader(`{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1" }`) req, _ := http.NewRequest("POST", url, body) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}import requestsurl = "https://api.pre.dev/v1/images"body = """{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1"}"""response = requests.request("POST", url, data = body, headers = { "Content-Type": "application/json"})print(response.text)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.net.http.HttpResponse.BodyHandlers;import java.time.Duration;import java.net.http.HttpRequest.BodyPublishers;var body = BodyPublishers.ofString("""{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1"}""");HttpClient client = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .build();HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() .uri(URI.create("https://api.pre.dev/v1/images")) .header("Content-Type", "application/json") .POST(body) .build();try { HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString()); System.out.println("Status code: " + response.statusCode()); System.out.println("Response body: " + response.body());} catch (Exception e) { e.printStackTrace();}using System;using System.Net.Http;using System.Text;var body = new StringContent("""{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1"}""", Encoding.UTF8, "application/json");var client = new HttpClient();var response = await client.PostAsync("https://api.pre.dev/v1/images", body);var responseBody = await response.Content.ReadAsStringAsync();use reqwest::{Result, Client};async fn main() -> Result<()> { let client = Client::new(); let url = "https://api.pre.dev/v1/images"; let body = r#"{ "model": "recraft/recraft-v4.1-flash", "prompt": "A lighthouse at dawn, watercolor", "n": 1, "aspect_ratio": "1:1" }"#; let res = client .post(url) .header("Content-Type", "application/json") .body(body) .send() .await? .text() .await?; println!("{}", res); Ok(())}{ "created": 1790500000, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…", "media_type": "image/png" } ]}The workspace API key (pdk_…) from Integrations → Built-in in the pre.dev dashboard.
In: header
Header Parameters
Attribute this call to one of the workspace's projects. An id the workspace does not own is ignored.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
Generated images as base64. With stream: true on a model that supports it, partial images arrive as server-sent events.
TypeScript Definitions
Use the response body type in TypeScript.
application/json
The body is not valid JSON (checked before authentication), or the model rejected the request, for example an unknown model id. Errors from the model keep their status and use the ModelError shape.
TypeScript Definitions
Use the response body type in TypeScript.
The request body is not valid JSON. Checked before authentication.
application/json
Missing or invalid API key.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
The workspace cannot pay for this request. Nothing was sent to the model and nothing was charged.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
The request refers to a file, response or video job that is not this workspace's (not_found from pre.dev; nothing ran and nothing was charged), or the model could not serve the request (its own status and message, in the ModelError shape).
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
Too many requests. Wait Retry-After seconds when it is present. A rate_limit_exceeded refusal is per workspace per minute (600, or 30 on the free trial). An error from the model keeps the ModelError shape.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
Unexpected error.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
The model did not answer. Retry with backoff, or send models fallbacks.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.
application/json
The credit balance could not be read, so nothing ran. Retry after Retry-After seconds.
TypeScript Definitions
Use the response body type in TypeScript.
An error raised by pre.dev, in the OpenAI error shape with an extra predev object (absent on catalog_unavailable from the catalog listings). Branch on error.code.