Conversions
The unified API for all audio generation. Submit a changelog or any text document and get back polished audio.
Create a Conversion
/v1/conversionsSubmit content for audio generation. Returns immediately with a conversion ID (202 Accepted). Set wait: true to block until completion (200 OK).
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
source_type | string changelogdocument | Required | Type of content. Use "changelog" for release notes, "document" for any other text. |
title | string | Required | Title for this conversion. Maximum 500 characters. |
content | string | Required | Content to convert to audio. Maximum 50KB. |
additional_context | string | Optional | Additional context to guide the AI script generator (e.g., target audience, key emphasis). Maximum 10KB. |
settings | object | Optional | Script generation and audio settings. See Settings Object below. |
voice | object | Optional | TTS voice configuration. See Voice Config below. |
product_id | string (UUID) | Optional | Associate this conversion with a specific product. |
public_url | boolean | Optional(default: false) | If true, creates publicly shareable listen and embed URLs. |
webhook_url | string | Optional | HTTPS URL to receive a webhook when the conversion completes or fails. |
wait | boolean | Optional(default: false) | Block until completion (max 90 seconds). Returns 200 with full conversion details instead of 202. |
Settings Object
Settings Object Reference
| Field | Type | Default | Description |
|---|---|---|---|
product_name | string | - | Product or company name to use in the script. |
version | string | - | Version number to emphasize (e.g., "2.0.0"). |
tone | string casualprofessionalenthusiastictechnical | casual | Script tone. |
audience | string | - | Target audience (e.g., "developers", "general"). |
verbosity | string briefnormaldetailed | normal | Script length preference. |
speakers | integer | 1 | 1 = single narrator, 2 = two-host dialogue. |
use_history | boolean | true | Include previous changelogs as context for the script generator. |
history_limit | integer | 10 | Number of previous changelogs to include as context (1-100). |
cta | string | - | Optional call-to-action to include at the end. |
severity_aware_tone | boolean | - | Adjust tone based on severity of changes (e.g., more serious for breaking changes). |
Voice Config
| Parameter | Type | Required | Description |
|---|---|---|---|
provider | string geminielevenlabs | Optional(default: gemini) | TTS provider. |
delivery_preset | string measureddynamictheatrical | Optional | Controls the pacing and energy of the narration. |
pronunciation_notes | string | Optional | Pronunciation guidance for product names, acronyms, etc. Maximum 500 characters. |
expression_settings | object | Optional | Fine-grained vocal expression controls (ElevenLabs only). Fields: emotional_range ("subtle"|"moderate"|"full"), allow_whispering (boolean), allow_laughter (boolean), emphasis_style ("pauses"|"both"), emotional_arc (boolean). |
voice_id | string | Optional | ElevenLabs voice ID for single-speaker mode. Only used when provider is "elevenlabs". |
model | string v3flash_v2 | Optional | ElevenLabs model. Only used when provider is "elevenlabs". |
host_voice_ids.host1 | string | Optional | ElevenLabs voice ID for host 1 (dialogue mode). |
host_voice_ids.host2 | string | Optional | ElevenLabs voice ID for host 2 (dialogue mode). |
Body
{"source_type": "changelog","title": "MyApp v2.0.0 Release","content": "## v2.0.0 - 2026-01-15\n\n### Added\n- Dark mode support\n- Real-time collaboration\n\n### Fixed\n- Login timeout issue","additional_context": "This release focuses on user experience improvements after customer feedback.","settings": {"product_name": "MyApp","version": "2.0.0","tone": "casual","use_history": true,"history_limit": 5},"public_url": true}
Synchronous mode: Add "wait": true to block until the conversion is complete (up to 90 seconds). The response returns 200 with the full conversion result including audio_url.
List Conversions
/v1/conversionsReturns a paginated list of conversions for your organization, sorted newest first.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
source_type | string changelogdocument | Optional | Filter by source type. |
status | string pendingprocessinggeneratingcompletedfailed | Optional | Filter by status. |
limit | integer | Optional(default: 20) | Maximum results per page (1-100). |
cursor | string | Optional | Pagination cursor from previous response. |
{"success": true,"data": [{"id": "550e8400-e29b-41d4-a716-446655440000","source_type": "changelog","title": "MyApp v2.0.0 Release","status": "completed","has_audio": true,"duration_seconds": 45,"product_id": null,"public_url": true,"created_at": "2026-01-18T14:30:00.000Z","completed_at": "2026-01-18T14:30:30.000Z"}],"meta": {"total_count": 42,"has_more": true,"next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wMS0xN1QxMjowMDowMC4wMDBaIn0="},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:30:00.000Z"}
Get Conversion
/v1/conversions/{id}Retrieves the current status and details of a conversion. Use this to poll for completion.
Response by Status
Processing
{"success": true,"data": {"id": "550e8400-e29b-41d4-a716-446655440000","source_type": "changelog","title": "MyApp v2.0.0 Release","status": "processing","has_audio": false,"poll_url": "https://logtalk.io/api/v1/conversions/550e8400-e29b-41d4-a716-446655440000","estimated_completion_seconds": 20,"public_url": false,"created_at": "2026-01-18T14:30:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:30:10.000Z"}
Completed
Note: listen_url and embed_url only appear when public_url: true was set.
{"success": true,"data": {"id": "550e8400-e29b-41d4-a716-446655440000","source_type": "changelog","title": "MyApp v2.0.0 Release","status": "completed","has_audio": true,"audio_url": "https://logtalk.io/api/v1/conversions/550e8400.../audio","generated_script": "[NARRATOR]: Welcome to MyApp version 2.0...","duration_seconds": 45,"listen_url": "https://logtalk.io/listen/550e8400-e29b-41d4-a716-446655440000","embed_url": "https://logtalk.io/embed/550e8400-e29b-41d4-a716-446655440000","public_url": true,"completed_at": "2026-01-18T14:30:30.000Z","created_at": "2026-01-18T14:30:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:30:30.000Z"}
Failed
{"success": true,"data": {"id": "550e8400-e29b-41d4-a716-446655440000","status": "failed","error": {"code": "GENERATION_FAILED","message": "Script generation failed"},"failed_at": "2026-01-18T14:30:30.000Z","created_at": "2026-01-18T14:30:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:30:30.000Z"}
Update Conversion
/v1/conversions/{id}Update metadata on a conversion after creation. Only a limited set of fields can be modified.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
public_url | boolean | Optional | Enable or disable public listen/embed URLs for this conversion. |
title | string | Optional | Update the conversion title. |
additional_context | string | Optional | Update the additional context. |
Body
{"public_url": true}
Retry a Failed Conversion
/v1/conversions/{id}/retryRe-queues a failed conversion. Only conversions with status 'failed' can be retried. Quota is consumed on retry.
// 202 Accepted{"success": true,"data": {"id": "550e8400-e29b-41d4-a716-446655440000","status": "processing","poll_url": "https://logtalk.io/api/v1/conversions/550e8400-e29b-41d4-a716-446655440000","estimated_completion_seconds": 30,"created_at": "2026-01-18T14:35:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:35:00.000Z"}
Get Audio URL
/v1/conversions/{id}/audioReturns a signed URL for the conversion audio file.
By default, responds with a 302 redirect to the signed URL. Set Accept: application/json to receive JSON instead.
The signed URL expires after approximately 50 minutes. No quota is consumed — credits are used when the conversion is created.
// With Accept: application/json{"success": true,"data": {"audio_url": "https://r2.logtalk.io/audio/550e8400...?X-Amz-Expires=3000...","content_type": "audio/mpeg","duration_seconds": 45,"expires_at": "2026-01-18T15:20:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T14:30:30.000Z"}
Delete Conversion
/v1/conversions/{id}Permanently deletes a conversion and all associated media files from storage. This action cannot be undone.
{"success": true,"data": {"id": "550e8400-e29b-41d4-a716-446655440000","deleted": true,"deleted_at": "2026-01-18T15:00:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T15:00:00.000Z"}
Embed Tokens
Embed tokens allow you to embed an audio player on external sites without making the conversion fully public. Each token is scoped to a single conversion and does not expire.
Rate limit: 100 tokens per organization per day. Requires paid tier.
/v1/conversions/{id}/embed-tokenCreate a new embed token for a conversion.
// 201 Created{"success": true,"data": {"token": "emb_a1b2c3d4e5f6...","conversion_id": "550e8400-e29b-41d4-a716-446655440000","embed_url": "https://logtalk.io/embed/550e8400-e29b-41d4-a716-446655440000?token=emb_a1b2c3d4e5f6","created_at": "2026-01-18T15:00:00.000Z"},"request_id": "req_1kn5f2a_a3b4c5d6e7f8","timestamp": "2026-01-18T15:00:00.000Z"}
/v1/conversions/{id}/embed-tokenList all active embed tokens for a conversion.
/v1/conversions/{id}/embed-token/{token}Revoke an embed token. The token will immediately stop working for playback.
Polling for Completion
After creating a conversion, poll GET /v1/conversions/{id} until status is completed or failed:
const API_KEY = process.env.LOGTALK_API_KEY;const BASE = 'https://logtalk.io/api/v1';// 1. Create conversionconst { data } = await fetch(`${BASE}/conversions`, {method: 'POST',headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },body: JSON.stringify({source_type: 'changelog',title: 'MyApp v2.0.0',content: changelogMarkdown,settings: { product_name: 'MyApp' }})}).then(r => r.json());// 2. Poll until complete (max 2 minutes)let conversion;const maxAttempts = 40;for (let i = 0; i < maxAttempts; i++) {await new Promise(r => setTimeout(r, 3000));const res = await fetch(`${BASE}/conversions/${data.id}`, {headers: { Authorization: `Bearer ${API_KEY}` }}).then(r => r.json());conversion = res.data;if (conversion.status === 'completed') break;if (conversion.status === 'failed') throw new Error('Conversion failed');}if (conversion.status !== 'completed') throw new Error('Polling timed out');console.log('Audio URL:', conversion.audio_url);
Tip: Use "wait": true on the create request to skip polling entirely — the API blocks until completion and returns the full result.
Public Sharing & Embedding
Set public_url: true when creating a conversion (or via PATCH) to generate public share and embed URLs:
| Field | Description |
|---|---|
listen_url | Full public page with audio player, show notes, and share buttons. |
embed_url | Compact player for iframe embedding on external sites. |
<iframesrc="https://logtalk.io/embed/550e8400-e29b-41d4-a716-446655440000"width="100%"height="180"frameborder="0"allow="autoplay"></iframe>
Idempotency
Include the Idempotency-Key header on POST requests to prevent duplicate conversions on retries:
curl -X POST https://logtalk.io/api/v1/conversions \-H "Authorization: Bearer lt_live_your_key" \-H "Content-Type: application/json" \-H "Idempotency-Key: release-v2.0.0-20260118" \-d '{"source_type": "changelog", "title": "...", "content": "..."}'
- Keys must be 1-256 printable ASCII characters
- Keys are valid for 24 hours
- Same key + same body returns the cached response
- Same key + different body returns
409 Conflict