Build with Satsun Voice.
Quick Start · Authentication · Text to Speech · Voices · Generations · Credits · Usage · API Keys · Idempotency · Errors · Rate Limits
Developer guide
Generate speech with the published Satsun voice using your account’s test API key.
Quick Start
Accept a beta invitation, sign in to Studio, and create a test key if API access is enabled for your plan. Store it in your server environment, then follow an example below. Studio and API use the same account credits.
Authentication
Authorization: Bearer sat_test_...Keep keys on your server or in a secret manager. Your key determines the application; no application ID is required. Keys cannot administer accounts, projects or other keys. Live keys appear only when a live environment is enabled for your assigned account.
API base: https://api.voice.satsuntech.com. This developer endpoint uses HTTPS and the existing Satsun Voice API. Use only your own API key in server-side integrations.
Endpoints
| Operation | Endpoint |
|---|---|
| Generate speech | POST /v1/text-to-speech |
| Check generation | GET /v1/generations/{id} |
| Download completed WAV | GET /v1/generations/{id}/audio |
| Generation history | GET /v1/generations |
| Published voices | GET /v1/voices |
| Credit balance | GET /v1/account/credits |
| Daily usage | GET /v1/account/usage?from=YYYY-MM-DD&to=YYYY-MM-DD |
Generation and credits
Submission returns 202 while queued or processing, and 200 when complete. Poll with the returned generation ID. Use the same Idempotency-Key and identical body when retrying an interrupted submission. Changing the body with the same key returns 409 IDEMPOTENCY_CONFLICT. Intentional regeneration requires a new key and uses new credits.
Original Unicode character units are reserved, then settled once on success or released on failure. Audio playback and downloads, project saves and reopening, and key administration use no additional TTS credits. Your plan sets request size, concurrency and audio retention. Use the credits response’s creditUnitSize for displayed credits.
Usage date ranges are inclusive. Usage and history are paginated: follow nextCursor until null. Each usage page’s daily values cover only that page; sum them across pages for full totals. API request totals in Studio begin with Phase 5C; earlier request counts are unavailable.
Idempotency
Choose one unique Idempotency-Key per intended narration. Retries with the same key and identical request return the original generation and do not charge twice. A new key creates new work.
Rate Limits
Limits are enforced per account and authenticated caller, including API keys. Text size, character throughput, concurrent jobs and remaining credits are enforced on the server. A 429 response includes Retry-After. Poll at least six seconds apart, back off when asked, and avoid tight retry loops.
Errors
401 INVALID_API_KEY or API_KEY_REVOKED means access is denied. 402 means insufficient credits. 429 means the account is rate-limited; honor Retry-After and keep the same idempotency key. A 503 QUEUE_UNAVAILABLE can follow a saved request: retry the same request. Failed generations release reservations. Revoke or rotate a compromised key immediately.
curl
export SATSUN_API_BASE="https://api.voice.satsuntech.com"
# Set SATSUN_API_KEY securely in your shell; never put it in source control.
curl -X POST "$SATSUN_API_BASE/v1/text-to-speech" \
-H "Authorization: Bearer $SATSUN_API_KEY" \
-H "Idempotency-Key: my-first-narration-001" \
-H "Content-Type: application/json" \
-d '{"text":"Welcome to Satsun Voice.","voice":"teacher_male_01","language":"en-IN","pace":1,"format":"wav"}'
curl "$SATSUN_API_BASE/v1/generations/GENERATION_ID" -H "Authorization: Bearer $SATSUN_API_KEY"
curl "$SATSUN_API_BASE/v1/voices" -H "Authorization: Bearer $SATSUN_API_KEY"
curl "$SATSUN_API_BASE/v1/account/credits" -H "Authorization: Bearer $SATSUN_API_KEY"
curl "$SATSUN_API_BASE/v1/account/usage?from=2026-09-01&to=2026-09-30" -H "Authorization: Bearer $SATSUN_API_KEY"
# After completion, download the WAV:
curl "$SATSUN_API_BASE/v1/generations/GENERATION_ID/audio" -H "Authorization: Bearer $SATSUN_API_KEY" -o narration.wavJavaScript
// Server-side JavaScript (Node.js). Keep the key out of browser bundles.
const base = process.env.SATSUN_API_BASE;
const authorization = 'Bearer ' + process.env.SATSUN_API_KEY;
const response = await fetch(base + '/v1/text-to-speech', {
method: 'POST',
headers: { Authorization: authorization, 'Content-Type': 'application/json',
'Idempotency-Key': 'my-first-narration-001' },
body: JSON.stringify({ text: 'Welcome to Satsun Voice.', voice: 'teacher_male_01',
language: 'en-IN', pace: 1, format: 'wav' })
});
const generation = await response.json();
if (!response.ok) throw new Error(generation.error?.code || 'REQUEST_FAILED');
// Poll every 6 seconds until completed or failed. Log IDs/status only, never headers.
const status = await fetch(base + '/v1/generations/' + generation.generationId,
{ headers: { Authorization: authorization } }).then(r => r.json());
console.log({ generationId: status.generationId, status: status.status });Python
# Server-side Python; install requests in your application environment.
import os, requests
base = os.environ['SATSUN_API_BASE']
headers = {'Authorization': 'Bearer ' + os.environ['SATSUN_API_KEY']}
response = requests.post(base + '/v1/text-to-speech', timeout=45,
headers={**headers, 'Idempotency-Key': 'my-first-narration-001'},
json={'text': 'Welcome to Satsun Voice.', 'voice': 'teacher_male_01',
'language': 'en-IN', 'pace': 1, 'format': 'wav'})
response.raise_for_status()
generation = response.json()
# Poll every 6 seconds until completed or failed.
result = requests.get(base + '/v1/generations/' + generation['generationId'],
headers=headers, timeout=45)
result.raise_for_status()
print({'generationId': generation['generationId'], 'status': result.json()['status']})API Keys
Copy new keys once and store them securely. The key list exposes only metadata and prefixes. Rotating revokes the old key atomically; revocation does not delete existing audio. A console that silently reuses a listed key is deferred because plaintext keys are not retained. Use these server-side examples with your securely stored key.