GetAPI.ONE
Generate video with the ONE task API
Submit an OpenAI-shaped video task, preserve its public task ID, poll the exact ONE status route to a terminal state, and fetch content only after completion.
Confirm the protocol before spending
- Choose a current catalog model that explicitly declares the OpenAI video endpoint.
- Review live pricing and the model’s supported input fields; video work may be asynchronous and billable.
- Use a short, low-risk prompt for the first accepted test.
POST https://www.getapi.one/v1/videos
GET https://www.getapi.one/v1/videos/{task_id}
GET https://www.getapi.one/v1/videos/{task_id}/contentSubmit, poll, and fetch
- Submit POST https://www.getapi.one/v1/videos and save the returned task ID exactly.
- Poll GET https://www.getapi.one/v1/videos/{task_id} at a fixed interval with a bounded number of checks; do not create a new task while waiting.
- Continue for queued or in_progress; stop successfully only for completed.
- Stop and surface the error for failed. Treat unknown states as non-success and preserve the response for diagnosis.
- After completed, fetch GET https://www.getapi.one/v1/videos/{task_id}/content.
- Stream the content in fixed-size chunks under a cumulative limit. The example uses a 512 MiB local ceiling and removes its partial file on any read, validation, write, or cancellation failure.
curl --fail-with-body https://www.getapi.one/v1/videos \
-H "Authorization: Bearer $GETAPI_ONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<OPENAI_VIDEO_MODEL_ID_FROM_CURRENT_CATALOG>",
"prompt": "A five-second locked-camera product turntable on a neutral background"
}' > video-submit.jsonimport json
import os
import time
from pathlib import Path
from urllib.parse import quote
from urllib.request import Request, urlopen
base_url = "https://www.getapi.one"
api_key = os.environ["GETAPI_ONE_API_KEY"]
submitted = json.loads(Path("video-submit.json").read_text(encoding="utf-8"))
task_id = submitted.get("id") or submitted.get("task_id")
if not task_id:
raise ValueError("Submit response did not contain id or task_id")
safe_id = quote(task_id, safe="")
headers = {"Authorization": f"Bearer {api_key}"}
for attempt in range(30):
request = Request(f"{base_url}/v1/videos/{safe_id}", headers=headers)
with urlopen(request, timeout=30) as response:
task = json.load(response)
status = task.get("status")
if status == "completed":
break
if status == "failed":
raise RuntimeError(f"video task failed: {task.get('error')}")
if status not in {"queued", "in_progress"}:
raise RuntimeError(f"unknown non-success status: {status}")
if attempt == 29:
raise TimeoutError("video was not complete after 30 status checks")
time.sleep(10)
content_request = Request(
f"{base_url}/v1/videos/{safe_id}/content",
headers=headers,
)
MAX_VIDEO_BYTES = 512 * 1024 * 1024
CHUNK_BYTES = 1024 * 1024
output_path = Path("result.mp4")
created_output = False
with urlopen(content_request, timeout=60) as response:
content_type = response.headers.get_content_type()
if not content_type.startswith("video/"):
raise ValueError(f"unexpected content type: {content_type}")
try:
output = output_path.open("xb")
created_output = True
with output:
total_bytes = 0
while chunk := response.read(CHUNK_BYTES):
total_bytes += len(chunk)
if total_bytes > MAX_VIDEO_BYTES:
raise ValueError("video exceeds the local 512 MiB limit")
output.write(chunk)
except BaseException:
if created_output:
output_path.unlink(missing_ok=True)
raiseImplement the state machine
| Status | Client action |
|---|---|
| queued | Wait for the fixed interval, then query the same task ID within the bounded number of checks. |
| in_progress | Show progress if supplied and keep polling. |
| completed | Stop polling and request the content route. |
| failed | Stop polling, record the safe error details, and require an intentional retry. |
Verify the expected result
- The submit response provides a task ID and the client stores it durably enough for the workflow.
- Every status request uses that same ID and never creates duplicate work.
- The downloaded content has a video content type and opens only after completed.
Recover without duplicating tasks
- On submit timeout, do not blindly submit again: inspect whether a task ID or console record was created.
- On 404 while polling, verify the public task ID, the exact singular/plural route, and the same account key.
- On failed, preserve the model, safe request summary, task ID, and error details before changing inputs.
Protect media tasks and results
- Keep the key and task lookup on your authenticated backend.
- Validate prompts, uploads, duration, dimensions, and counts against the selected model contract before forwarding.
- Store approved results in controlled storage; do not assume a content URL is permanent or public-safe.
- Set a cumulative download limit below your memory and storage budget, stream fixed-size chunks, and clean partial artifacts when the download does not finish.