A developer building a Claude Code agent needs to ingest audio transcripts, including interview recordings, meeting notes, and support call logs, before passing them into an agent’s context or retrieval layer. Audio transcripts arrive as flat text with no heading structure, so naive token-based splitting cuts across speaker turns and topic boundaries and strips provenance entirely. EnConvert’s Ingest endpoint accepts an audio transcript upload and returns JSONL chunks split at H1, H2, and H3 heading boundaries, with a 512 word soft cap and tables and code blocks kept whole. Each chunk carries headings_path, section, chunk_index, word_count, and source_url metadata, ready to pass into a Claude Code agent or vector store.
How to Ingest Audio Transcripts with Claude Code
How to ingest audio transcripts inside a Claude Code pipeline with EnConvert, returning heading-aware JSONL chunks with section metadata for retrieval
Get API keyExample
python
import json
import os
import time
import requests
import anthropic
# Step 1: Upload the audio transcript file to the Ingest endpoint
with open("meeting-transcript.txt", "rb") as f:
upload_response = requests.post(
"https://api.enconvert.com/v2/ingest/files",
headers={"X-API-Key": os.environ["ENCONVERT_API_KEY"]},
files={"files": f},
)
if upload_response.status_code == 402:
raise RuntimeError("Ingest is not on your plan, or the monthly ops allowance is exhausted")
upload_response.raise_for_status()
job_id = upload_response.json()["job_id"]
# Step 2: Poll until the job reaches a terminal state
while True:
status_response = requests.get(
f"https://api.enconvert.com/v2/ingest/{job_id}",
headers={"X-API-Key": os.environ["ENCONVERT_API_KEY"]},
)
status_response.raise_for_status()
job = status_response.json()
if job["status"] == "completed":
break
if job["status"] in {"failed", "canceled"}:
raise RuntimeError(
job.get("error_message") or f"Ingest job {job_id} ended with status {job['status']}"
)
time.sleep(5)
# Step 3: Download JSONL output from signed output_url (expires after 15 minutes)
jsonl_response = requests.get(job["output_url"])
jsonl_response.raise_for_status()
chunks = [json.loads(line) for line in jsonl_response.text.splitlines() if line.strip()]
# Step 4: Build context block from chunks, preserving section and position metadata
context = "\n\n".join(
f"[section: {c['metadata']['section']} | chunk: {c['metadata']['chunk_index']} | source: {c['metadata']['source_url']}]\n"
f"{c.get('content')}"
for c in chunks[:6]
)
# Step 5: Pass context into a Claude Code agent using the Anthropic SDK messages API
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
message = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
system=(
"Answer questions about the transcript using only the context provided. "
"Cite the section and chunk index for every claim you make."
),
messages=[
{
"role": "user",
"content": f"Context:\n\n{context}\n\nWhat were the main decisions made in this meeting?"
}
],
)
for block in message.content:
if block.type == "text":
print(block.text)
What you get back
The Ingest endpoint returns JSONL chunks split at H1, H2, and H3 heading boundaries with a 512 word soft cap, tables and code blocks kept whole, and each chunk carrying headings_path, section, chunk_index, word_count, and source_url. Splitting a transcript by token count instead cuts across speaker turns and topic shifts without section context or metadata, and passing the raw transcript into an agent context inflates token usage without provenance.