Conversions

The unified API for all audio generation. Submit a changelog or any text document and get back polished audio.

Create a Conversion

POST/v1/conversions

Submit content for audio generation. Returns immediately with a conversion ID (202 Accepted). Set wait: true to block until completion (200 OK).

Request Body

ParameterTypeRequiredDescription
source_typestring
changelogdocument
RequiredType of content. Use "changelog" for release notes, "document" for any other text.
titlestringRequiredTitle for this conversion. Maximum 500 characters.
contentstringRequiredContent to convert to audio. Maximum 50KB.
additional_contextstringOptionalAdditional context to guide the AI script generator (e.g., target audience, key emphasis). Maximum 10KB.
settingsobjectOptionalScript generation and audio settings. See Settings Object below.
voiceobjectOptionalTTS voice configuration. See Voice Config below.
product_idstring (UUID)OptionalAssociate this conversion with a specific product.
public_urlbooleanOptional(default: false)If true, creates publicly shareable listen and embed URLs.
webhook_urlstringOptionalHTTPS URL to receive a webhook when the conversion completes or fails.
waitbooleanOptional(default: false)Block until completion (max 90 seconds). Returns 200 with full conversion details instead of 202.

Settings Object

Settings Object Reference

FieldTypeDefaultDescription
product_namestring-Product or company name to use in the script.
versionstring-Version number to emphasize (e.g., "2.0.0").
tonestring
casualprofessionalenthusiastictechnical
casualScript tone.
audiencestring-Target audience (e.g., "developers", "general").
verbositystring
briefnormaldetailed
normalScript length preference.
speakersinteger11 = single narrator, 2 = two-host dialogue.
use_historybooleantrueInclude previous changelogs as context for the script generator.
history_limitinteger10Number of previous changelogs to include as context (1-100).
ctastring-Optional call-to-action to include at the end.
severity_aware_toneboolean-Adjust tone based on severity of changes (e.g., more serious for breaking changes).

Voice Config

ParameterTypeRequiredDescription
providerstring
geminielevenlabs
Optional(default: gemini)TTS provider.
delivery_presetstring
measureddynamictheatrical
OptionalControls the pacing and energy of the narration.
pronunciation_notesstringOptionalPronunciation guidance for product names, acronyms, etc. Maximum 500 characters.
expression_settingsobjectOptionalFine-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_idstringOptionalElevenLabs voice ID for single-speaker mode. Only used when provider is "elevenlabs".
modelstring
v3flash_v2
OptionalElevenLabs model. Only used when provider is "elevenlabs".
host_voice_ids.host1stringOptionalElevenLabs voice ID for host 1 (dialogue mode).
host_voice_ids.host2stringOptionalElevenLabs 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

GET/v1/conversions

Returns a paginated list of conversions for your organization, sorted newest first.

Query Parameters

ParameterTypeRequiredDescription
source_typestring
changelogdocument
OptionalFilter by source type.
statusstring
pendingprocessinggeneratingcompletedfailed
OptionalFilter by status.
limitintegerOptional(default: 20)Maximum results per page (1-100).
cursorstringOptionalPagination cursor from previous response.
200 OK
{
"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

GET/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

PATCH/v1/conversions/{id}

Update metadata on a conversion after creation. Only a limited set of fields can be modified.

Request Body

ParameterTypeRequiredDescription
public_urlbooleanOptionalEnable or disable public listen/embed URLs for this conversion.
titlestringOptionalUpdate the conversion title.
additional_contextstringOptionalUpdate the additional context.

Body

{
"public_url": true
}

Retry a Failed Conversion

POST/v1/conversions/{id}/retry

Re-queues a failed conversion. Only conversions with status 'failed' can be retried. Quota is consumed on retry.

200 OK
// 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

GET/v1/conversions/{id}/audio

Returns 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.

200 OK
// 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

DELETE/v1/conversions/{id}

Permanently deletes a conversion and all associated media files from storage. This action cannot be undone.

200 OK
{
"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.

POST/v1/conversions/{id}/embed-token

Create a new embed token for a conversion.

200 OK
// 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"
}
GET/v1/conversions/{id}/embed-token

List all active embed tokens for a conversion.

DELETE/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:

Poll for completion
const API_KEY = process.env.LOGTALK_API_KEY;
const BASE = 'https://logtalk.io/api/v1';
// 1. Create conversion
const { 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:

FieldDescription
listen_urlFull public page with audio player, show notes, and share buttons.
embed_urlCompact player for iframe embedding on external sites.
Embed player
<iframe
src="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