curl -d to Sume /v1/videos gives 415: add the JSON Content-Type
A POST /v1/videos with a body that is not application/json gets 415 unsupported_media_type, with the content type you sent in details. The curl fix.

A POST /v1/videos whose body is not application/json is answered with 415 unsupported_media_type, and details.received_content_type shows what the server saw. The usual cause is curl -d '{...}' with no -H "Content-Type: application/json": curl sends application/x-www-form-urlencoded by default for -d.
Reading the 415
The error uses the standard Sume envelope with a request id. It is a client error and a retry with the same headers will give the same answer, so fix the header rather than adding a backoff.
Validation happens before any cost estimate or reservation, so the 415 bills nothing.
| Status | Code | Usual cause |
|---|---|---|
| 401 | unauthorized | missing or wrong Authorization: Bearer key |
| 415 | unsupported_media_type | body is not application/json |
| 400 | invalid_request | a required field is missing, such as prompt |
| 400 | unsupported_parameter | size, seed or provider.options sent |
| 404 | model_not_found | org-prefixed or unknown model id |
The working command
The command below sends both headers and a body that matches the docs. It prints the id and polling_url from the 202 response. A bare object comes back, so jq reads the keys without .data.
curl -s -X POST https://api.sume.com/v1/videos \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"model":"wan-3.0","prompt":"A paper boat on a rainy street","duration":5,"resolution":"720p","aspect_ratio":"9:16"}' \
| jq '{id, polling_url, status}'
Why this is worth a header check
A 415 is cheap to fix, but it hides behind the same symptom as other client mistakes: the call fails, no job exists, and no polling_url comes back. Many wrappers swallow the body and show only the status, so an engineer sees 415 and has to guess. Print the envelope, which names the received content type and carries a request id, and the cause is on the screen.
Another detail: a failing POST has no job, so there is nothing to poll or cancel. Do not start a poll loop on a response that has no polling_url; check for the 202 first. In a script, test the HTTP status before you read the body, and stop on anything that is not 202.
Other clients
The same cause shows up elsewhere: an HTTP client that is given a string body may set a text content type, a form helper may send multipart, and a shell variable that holds the JSON may be passed through a wrapper that drops headers. If the 415 persists, print the headers your client sends and compare them with details.received_content_type.
Multipart is a related case on the image-edit route; see the multipart 415 post. For a script that checks the whole flow, see the curl and jq video step.
- Use
--fail-with-bodyin scripts so a 415 prints the envelope. - Generate a fresh
Idempotency-Keyfor each new clip, not for each retry. - Keep the key out of shell history by reading it from the environment.
Sources
Related posts
More in Developers
- Dart: submit a 30-second Wan 3.0 clip with package:http
Server-side Dart with package:http: POST wan-3.0 for 30 seconds, poll until completed and write the MP4. Keep the key out of the Flutter app.
- Deno 2.9.7: scope permissions to a Sume key check on GET /v1/me
Run a Sume API key check in Deno 2.9.7 with allow-net limited to api.sume.com and allow-env limited to the key, and see what the permission error looks like.
- Deno 2.9.7 traceparent fix: tag a Sume job id in a Deno.serve log
Deno 2.9.7 extracts traceparent from Deno.serve regardless of header case. In a Sume webhook handler, log the job_id with the trace so a render is traceable.
- Deno: a 30-second Wan 3.0 video with fetch and top-level await
A short Deno script that submits a 30-second wan-3.0 job, polls to completion and writes clip.mp4, using only fetch and no npm packages.
Written by Sume