Render smoother video from your app.
Generate an API key from your dashboard, upload a clip, estimate the charged xeconds, start a render, poll until it finishes, and download the output. The examples default to curl because it is the most reliable format for humans and coding agents; switch tabs for JavaScript or Python.
Get an API key
API users authenticate with a dashboard-generated key. Use this key on protected endpoints. Keep it server-side in production; these examples show the key inline so the replaceable value is obvious.
API key
Not generated yetAPI tokens use the same balance as studio renders. A new token replaces the old one.
Send it on every protected request as Authorization: Bearer <your_api_key>.
curl -s "https://reframefx-production.up.railway.app/me" \
-H "Authorization: Bearer <your_api_key>"Render workflow
This is the canonical flow for external users. Use curl as the source of truth; the other tabs mirror the same steps for app code.
#!/usr/bin/env bash
set -euo pipefail
API=https://reframefx-production.up.railway.app
FILE=clip.mp4
# 1. Create an upload URL.
PRESIGN=$(curl -s -X POST "$API/upload/presign" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"filename":"clip.mp4","content_type":"video/mp4"}')
UPLOAD_URL=$(echo "$PRESIGN" | jq -r .upload_url)
UPLOAD_KEY=$(echo "$PRESIGN" | jq -r .key)
PROJECT_ID=$(echo "$PRESIGN" | jq -r .project_id)
# 2. Upload directly to storage.
curl -s -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary @"$FILE"
# 3. Estimate cost from the uploaded video.
curl -s -X POST "$API/pricing/estimate-video" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d "{\"r2_key\":\"$UPLOAD_KEY\",\"target_fps_options\":[60,120,240]}"
# 4. Start the render.
JOB=$(curl -s -X POST "$API/jobs" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d "{\"r2_key\":\"$UPLOAD_KEY\",\"project_id\":\"$PROJECT_ID\",\"target_fps\":60}")
JOB_ID=$(echo "$JOB" | jq -r .job_id)
# 5. Poll until done.
while true; do
RESULT=$(curl -s "$API/jobs/$JOB_ID" \
-H "Authorization: Bearer <your_api_key>")
STATUS=$(echo "$RESULT" | jq -r .live_status)
echo "status=$STATUS"
if [ "$STATUS" = "done" ] || [ "$STATUS" = "failed" ]; then
echo "$RESULT"
break
fi
sleep 3
doneEndpoint reference
GET/meRead your profile, balance, and API key state.GET/pricing/configRead public pricing bands, packs, and upload limits.POST/pricing/estimateEstimate charged xeconds from known duration/FPS metadata.POST/upload/presignCreate a direct upload URL for your video file.POST/pricing/estimate-videoProbe an uploaded file and estimate one or more output FPS choices.POST/jobsStart a render. Credits are deducted when the job is accepted.GET/jobs/{id}Poll render status until done or failed.GET/jobsList recent jobs for the account.GET/projectsList project history with inputs, outputs, and jobs.GET/projects/{id}/files/{file_id}/downloadCreate a fresh download URL for an input or output.POST/projects/{id}/shareCreate a public review link for a project.GET/share/{token}Read a shared project without an API key.Protected endpoints require Authorization: Bearer <your_api_key>. Public endpoints are /pricing/config, /pricing/estimate, and /share/{token}.
Job status
Poll GET /jobs/{id} every 3-5 seconds. The frontend owns the user-facing wording; the API returns stable status values.
pendingJob created and waiting for render status.queuedAccepted and waiting to start.no_workersQueued while render capacity is full.cold_startRender environment is preparing.processingVideo is being processed.doneRender succeeded. Use output_url or output_file_id for download.failedRender failed. Deducted xeconds should be refunded automatically.Limits and pricing
Video size250MB maximum during launch. Larger files return 413.Video length120 seconds maximum during launch. Longer clips are coming.Output FPS24-240fps, and target_fps must be greater than the source FPS.Smooth bandUp to 60fps: charged_xeconds = ceil(duration_sec) x 1.Slo-mo band61-120fps: charged_xeconds = ceil(duration_sec) x 2.Ultra band (cinematic slo-mo)121-240fps: charged_xeconds = ceil(duration_sec) x 4.Free creditsFree renders are watermarked. Paid-credit renders are clean by default.Errors
Errors return a status code and JSON with a readable detail field.
{
"detail": "Launch limit is 120s per video. Longer video chunking is coming."
}400Invalid request body or unsupported params.401Missing or invalid API key.402Insufficient xeconds balance.403The resource belongs to another account.404Project, job, file, or share token was not found.413Upload exceeds launch size or duration limits.500Unexpected server error. Retry reads; contact support if a write is unclear.OpenAPI schema
The machine-readable schema is available at /openapi.json. Use it with Postman, Cursor, Claude Code, or any OpenAPI-aware client generator.