Format audio chapters for podcast apps
Three chapters starting at 0, 120 and 1800 seconds become one file that podcast apps read to show a table of contents and jump through the episode. Times must go strictly forward, or nothing is exported. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
Producers already know the section titles and when each section starts; what they need is a correct, app-readable export with camelCase startTime fields, optional artwork and deep links, and a guarantee that timestamps never go backwards.
What a chapters file does for listeners
Podcast apps that support chapters do not read them from the audio file itself. They fetch a small separate file linked from the episode in your feed, and use it to show a table of contents, jump to each section and swap the artwork as the episode plays. Each chapter needs a start time in seconds from the beginning of the audio; a title is strongly recommended so listeners see readable names. You can also add an image and a web link to any chapter, mark a chapter as silent so it does not appear in the list, and set an explicit end time if you want one. Because apps fetch the file at playback time, you can correct a title or add an image after publishing without re-encoding the episode.
How to prepare the chapters and avoid mistakes
Write your sections in order, each with its title and the second where it starts, for example an intro at 0, the main topic at 120 and the outro at 1800. The tool converts them into the standard layout and returns the text ready to host at a stable web address. The most common mistake is a start time that repeats or goes backwards. The tool never reorders chapters for you, because a silent reorder could hide an error and attach the wrong artwork to the wrong segment; it stops and tells you which row is out of order instead.
What a podcast chapters file looks like
The Podcasting 2.0 namespace points each episode at an external chapters file with a mime type of application/json+chapters. Each chapter needs at least startTime as a float in seconds from the beginning of the audio; title is strongly recommended so listeners see a readable table of contents. Optional chapter fields include img for per-section artwork, url for a related web page or show notes link, toc set to false for silent metadata-only markers, and endTime when you want an explicit end.
Optional file-level fields such as author, title, podcastName, and description help web players and archives without changing how apps jump through audio. Chapter order is validated, not guessed: the capability never re-sorts out-of-order times, because a silent reorder could hide producer mistakes and put the wrong artwork on the wrong segment. Instead it requires strictly increasing start times and fails clearly when a later row is equal to or earlier than the previous one.
Apps fetch the file at playback time, so you can fix titles or add images after publish without re-encoding the episode.
FAQ
What happens if start times are not strictly increasing?
Equal or decreasing times are rejected so podcast apps never receive out-of-order markers.
Can I include chapter images and links?
Yes. Optional img and url strings on each chapter become the Podcasting 2.0 img and url fields. Empty strings are omitted from the export.
How do I add the chapters to my podcast feed?
Host the file the tool gives you at a stable web address, then link it from the episode in your feed as its chapters file. Apps that support chapters fetch it when the episode plays.
Can I change a chapter title after the episode is published?
Yes. Apps fetch the chapters file at playback time, so you can fix titles or add images later and host the new file at the same address, without re-encoding the audio.
Can a chapter stay out of the table of contents?
Yes. Mark it as silent and it works as a marker that apps keep without listing it for listeners. Chapters are listed by default, so you only change the ones you want hidden.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/audio/audio-chapter-export-format \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"chapters":[{"title":"Intro","start_time":0},{"title":"Main topic","start_time":120,"img":"https://example.com/art/main.jpg","url":"https://example.com/notes/main"},{"title":"Outro","start_time":1800}]}'const res = await fetch("https://api.kit.forhosting.com/audio/audio-chapter-export-format", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"chapters": [
{
"title": "Intro",
"start_time": 0
},
{
"title": "Main topic",
"start_time": 120,
"img": "https://example.com/art/main.jpg",
"url": "https://example.com/notes/main"
},
{
"title": "Outro",
"start_time": 1800
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/audio/audio-chapter-export-format",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"chapters": [
{
"title": "Intro",
"start_time": 0
},
{
"title": "Main topic",
"start_time": 120,
"img": "https://example.com/art/main.jpg",
"url": "https://example.com/notes/main"
},
{
"title": "Outro",
"start_time": 1800
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/audio/audio-chapter-export-format", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"chapters":[{"title":"Intro","start_time":0},{"title":"Main topic","start_time":120,"img":"https://example.com/art/main.jpg","url":"https://example.com/notes/main"},{"title":"Outro","start_time":1800}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"chapters":[{"title":"Intro","start_time":0},{"title":"Main topic","start_time":120,"img":"https://example.com/art/main.jpg","url":"https://example.com/notes/main"},{"title":"Outro","start_time":1800}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/audio/audio-chapter-export-format", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"chapters": [
{
"title": "Intro",
"start_time": 0
},
{
"title": "Main topic",
"start_time": 120,
"img": "https://example.com/art/main.jpg",
"url": "https://example.com/notes/main"
},
{
"title": "Outro",
"start_time": 1800
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "audio.audio_chapter_export_format",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 200 |
max_minutes | 180 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Podcast apps that support Podcasting 2.0 chapters expect a small JSON file linked from the episode RSS item, not chapter tags baked into the MP3. This capability takes your ordered chapter rows—title plus start time in seconds, with optional image and URL per chapter—and emits the standard versioned chapters object plus a pretty-printed json_text string you can host and reference with the podcast:chapters tag. If start times are not strictly increasing, the task fails with invalid_input so bad markers never reach the feed.
What Podcasting 2.0 chapter JSON looks like
That file is a JSON object whose required keys are version (commonly 1.2.0) and chapters, an array of markers ordered by ascending startTime. This exporter maps your row-oriented input—start_time and title on each chapter, optional img and url—into that camelCase shape so you do not hand-edit braces or forget the version string. Host the resulting json_text at a stable HTTPS URL, then add podcast:chapters with type application/json+chapters in the item.
Input contract, response shape, and validation rules
Optional output keys are omitted entirely rather than set to null. POST a JSON body with a required chapters array of at least one object. Every object must include title as a non-empty string and start_time as a non-negative finite number of seconds (aliases such as startTime are accepted on each row). Optional per-chapter fields are img and url as non-empty strings, toc as a boolean (false marks a silent chapter; true is the default and is omitted from the export), and end_time as a non-negative number not less than that chapter's start. Optional file-level strings—version (default 1.2.0), episode_title, author, podcast_name, and description—are copied into the chapters object when present. On success the body returns version, chapter_count, chapters as the Podcasting 2.0 array with startTime keys, json_text as the pretty-printed file ready to upload, mime_type set to application/json+chapters, and any provided episode metadata under author, title, podcast_name, and description. Validation failures throw invalid_input and are not billed: missing chapters, empty title, negative or non-finite times, end before start, more than five hundred rows, or start times that are not strictly increasing. Example: three rows at zero, one hundred twenty, and eighteen hundred seconds with an image and link on the middle chapter produce a three-entry chapters array and a json_text string that matches the public Podcasting 2.0 examples in structure.
Where a deterministic chapter exporter earns its keep
Transcript or chapter-suggestion tools that output plain title and second pairs can pipe their result here to obtain the app-facing format without embedding Podcasting 2.0 knowledge in every client. Failed validation does not consume balance. Pair this exporter with separate ASR chapter-generation products when you need timestamps invented from audio; use this path when you already know the markers and only need a standards-compliant export. Independent producers finishing an episode in a DAW already have timestamps in a spreadsheet or show notes; they need a correct JSON file without learning the namespace by trial and error in each app. Keep chapter titles short enough for mobile TOC UIs, prefer absolute HTTPS URLs for img and url, and re-run the formatter after every edit so strictly increasing order stays enforced.
Integration use cases
Publish-ready chapters from a show-notes table
Paste title and start-time rows from your episode outline, add optional artwork links, and download Podcasting 2.0 json_text to host beside the MP3.
CMS and hosting pipeline checks
Call the API from your publish job so every episode’s chapter list is validated for strictly increasing times before the podcast:chapters RSS tag is written.
Bridge from plain markers to app JSON
Convert title-plus-seconds output from editors or transcript tools into camelCase startTime chapters without hand-editing JSON braces.
Technical questions
What format does the audio chapter export produce?
Podcasting 2.0 JSON chapters: a version string (default 1.2.0), a chapters array with startTime and title (plus optional img, url, toc, endTime), and a pretty-printed json_text file with mime type application/json+chapters.
How do I attach the file to my RSS feed?
Host json_text at a public HTTPS URL, then add <podcast:chapters url="…" type="application/json+chapters" /> on the episode item. Apps fetch the file at playback.
What does formatting audio chapters cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.