TikTok upload_url is valid for one hour: finish the Sume job first
TikTok says the Direct Post upload_url is valid for one hour after issuance. Wait for the Sume job to complete before you initialize so the upload fits.

TikTok's Direct Post reference says the upload_url is valid for one hour after issuance, and the upload must finish in that range. Order the work so the clip already exists: wait for the Sume job to be completed, then call init, then upload straight away.
If you init first and render second, a slow or queued render can burn the window.
What is the safe order?
The sequence below keeps the one-hour window for the upload only.
| Step | Action | Why |
|---|---|---|
| 1 | Submit the render on Sume with an Idempotency-Key | The job id exists at once; the video does not |
| 2 | Wait for job.completed or poll status_url | A queued job is normal, not a failure |
| 3 | Fetch the result from GET /v1/jobs/{id}/result | The result is only available after completion |
| 4 | Call init and receive upload_url and publish_id | The one-hour window starts here |
| 5 | Upload the file before the hour ends | TikTok requires it |
How do I block init until the job is ready?
Poll the status endpoint and honor next_poll_after_seconds when it is present. The sample returns only when the job is terminal.
import os
import time
import requests
def wait_terminal(job_id: str) -> dict:
headers = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
while True:
r = requests.get(f"https://api.sume.com/v1/jobs/{job_id}/status", headers=headers, timeout=30)
r.raise_for_status()
body = r.json()
if body.get("terminal"):
return body
time.sleep(body.get("next_poll_after_seconds") or 10)
if __name__ == "__main__":
print(wait_terminal("job_123").get("sume_status"))What if the upload still expires?
Initialize again and upload again with the same stored file; do not re-render. The post on TikTok upload errors covers the failure codes.
Sources
Related posts
More in Developers
- Time a 360p Omni draft vs 720p: separate queue wait from run time
Google says the 360p draft is up to 60% faster. Measure it on Sume with a Python script that splits pending time from in_progress time.
- Timeline refuses a 180-second Short: clips end more than 0.5 s early
Timeline 1.0 allows video coverage to stop at most 0.5 seconds before the end of the audio spine. Check slot ends in Python before you plan a 180-second Short.
- Timeline plan first: the unbilled estimate for a 30-second Short
POST /v1/timeline-1.0/plan compiles your cut without a job or a charge and returns duration, segments and estimated cost. A 30-second render bills one minute.
- Timeline plan for a 40-second Omni stitch: four segments, one minute
Run Sume's unbilled timeline plan on four 10-second Omni clips to see segment_count, billable_minutes and the cost before you render. Request body included.
Written by Sume