Daily news brief voiceover: 1,400 characters a day for 30 days
A 1,400-character daily brief costs $0.0665 on Sume TTS, so 30 days is $1.995. Table for 1,000, 1,400 and 2,000 characters, plus a retry-safe daily job.

A daily news brief of 1,400 characters costs $0.0665 to voice on Sume TTS, and a 30-day month of them costs $1.995. Sume bills TTS at $0.0475 per 1,000 characters, so the monthly bill is a straight multiplication of script length by days.
What a month of daily briefs costs
Each row is one TTS request per day at the listed length. The per-day price comes from the Sume price tool (TTS, customer USD), and the month column is that number times 30.
| Characters per brief | Per day | 30 days |
|---|---|---|
| 1,000 | $0.0475 | $1.425 |
| 1,400 | $0.0665 | $1.995 |
| 2,000 | $0.095 | $2.85 |
Submit one job per day with a date key
Use the date as the Idempotency-Key. If your scheduler fires twice, or your process dies after the POST, the second call with the same key and the same body returns the original job with idempotency_hit true instead of creating a second paid job. The fields below (transcript, avatar_handle, language) are the TTS 1.0 request shape from the OpenAPI document; the avatar must have a ready voice, which you can check on GET /v1/avatar-1.0/avatars.
Call speak() with a key like brief-2026-10-09, then audio_url() once the job is terminal. The result lists the audio file under result.artifacts.
import os, time, requests
API = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def speak(text, key):
body = {"transcript": text, "avatar_handle": "@narrator", "language": "en"}
r = requests.post(f"{API}/v1/tts-1.0/generate", json=body,
headers={**H, "Idempotency-Key": key})
r.raise_for_status()
return r.json()["data"]["job"]["id"]
def audio_url(job_id):
while True:
s = requests.get(f"{API}/v1/jobs/{job_id}/status", headers=H).json()["data"]
if s["terminal"]:
break
time.sleep(s["recommended_poll_interval_seconds"])
if s["sume_status"] != "completed":
raise RuntimeError(s["sume_status"])
res = requests.get(f"{API}/v1/jobs/{job_id}/result", headers=H).json()["data"]["result"]
return next(a["url"] for a in res["artifacts"] if a["type"] == "audio")Limits and gotchas
One request takes at most 20,000 characters, so a 1,400-character brief is nowhere near the cap. Spaces and punctuation count toward usage, so count the final string you send, not the word count.
If you edit the script and resend it under the same date key, Sume answers 409 idempotency_conflict instead of re-voicing it. Use a new key such as brief-2026-10-09-v2 for a deliberate retake, and expect to pay for it as a new job.
The default output is mp3 at 44,100 Hz and 128 kbps. Set output_format only if a downstream tool needs wav or a different sample rate.
- Exact price is the job's usage.billable_amount_usd on the submit response.
- A 30-second sync wait is available with mode sync, but poll status_url if the job is not done by then.
Sources
Related posts
More in Use cases
- Do 480p AI video clips pass TikTok's ad minimums? 540x960 and 640x640
TikTok's non-Spark ad minimums are 540x960, 960x540 and 640x640. A 480p AI clip is named for 480 pixels on its short side, which is below all three. Use 720p.
- Dub a 3-minute video into Spanish: a 47.8-cent Sume ledger
Detach, transcribe, translate, speak and re-render a 3-minute video: $0.47825 in Sume jobs at 900 characters a minute. Translation is billed elsewhere.
- 12 Ad Variants From One Body Clip: Hooks, Renders, Queue Limits
Test 12 opening hooks on one product ad: 3-second Omni Flash hooks, one trimmed body, 12 renders and captions, plus how queue limits shape the batch.
- Product Page Video From One Packshot for Under $2.50
One packshot to a 15-second product video on Sume: background removal, three Nano Banana 2.1 scenes, three Omni Flash clips and a timeline render, itemized.
Written by Sume