How to Track Podcast Generation Job Status via the Commands API in Open Notebook
You can track podcast generation job status in Open Notebook by polling the generic GET /commands/jobs/{job_id} endpoint or the shortcut GET /podcasts/jobs/{job_id}, both of which return real-time status, progress metrics, and results from the SurrealDB command registry.
Open Notebook handles podcast creation as asynchronous background jobs managed through the Surreal-Commands registry. When you submit a generation request via the API, the system returns a unique SurrealDB RecordID that you can query to monitor execution progress, check completion status, and retrieve the final audio file path. This article explains how to use the commands API endpoints to track podcast generation jobs from submission through completion.
How Podcast Generation Jobs Are Created
When you call POST /podcasts/generate, the request flows through PodcastService.submit_generation_job in api/podcast_service.py (lines 36-45). This service validates the provided episode and speaker profiles, prepares the notebook context if a notebook_id is supplied, and then submits the job to the command registry.
The critical submission happens at lines 87-96 in api/podcast_service.py, where the service imports the commands.podcast_commands module to ensure the command is registered, then calls submit_command("open_notebook", "generate_podcast", args). This creates a persistent command record in SurrealDB and returns a job identifier (e.g., command:podcast:123) that you can use for status tracking.
Tracking Job Status via the Commands API
Open Notebook provides two equivalent methods for checking job status. Both expose the same underlying data but serve different architectural purposes.
Generic Command Status Endpoint
The primary method uses the commands router at GET /commands/jobs/{job_id}. This endpoint is implemented in api/routers/commands.py (lines 74-81) and delegates to CommandService.get_command_status, which wraps the surreal_commands.get_command_status library function.
This generic endpoint supports monitoring any background job type (podcasts, transcriptions, embeddings) through a unified interface, making it ideal for building centralized job dashboards.
Podcast-Specific Shortcut Endpoint
For convenience, the podcasts router exposes GET /podcasts/jobs/{job_id} at lines 72-78 in api/routers/podcasts.py. This endpoint simply forwards the request to PodcastService.get_job_status, which internally calls the same get_command_status function.
Use this shortcut when you want cleaner URL semantics for podcast-specific client applications while maintaining the same underlying command infrastructure.
Job Status Response Structure
Both endpoints return a JSON payload containing comprehensive job metadata:
{
"job_id": "command:podcast:123",
"status": "running|completed|failed",
"result": { "audio_path": "/path/to/file.mp3" },
"error_message": null,
"created": "2026-07-05T12:34:56Z",
"updated": "2026-07-05T12:35:10Z",
"progress": { "step": "embedding", "percent": 57 }
}
The status field indicates the current execution state, while progress provides granular updates for long-running operations like voice synthesis. When status is completed, the result object contains the generated audio file path.
End-to-End Implementation Examples
Submitting a Generation Job
Use httpx or any HTTP client to submit a podcast generation request and capture the job ID:
import httpx
api = "http://localhost:5055"
payload = {
"episode_profile": "default_episode",
"speaker_profile": "default_speaker",
"episode_name": "AI Trends July 2026",
"notebook_id": "notebook:12345"
}
resp = httpx.post(f"{api}/podcasts/generate", json=payload)
resp.raise_for_status()
data = resp.json()
job_id = data["job_id"] # e.g., "command:podcast:abcd1234"
print("Job submitted:", job_id)
Polling for Status Updates
Poll the generic commands endpoint until the job reaches a terminal state:
import time
import httpx
api = "http://localhost:5055"
job_id = "command:podcast:abcd1234"
while True:
r = httpx.get(f"{api}/commands/jobs/{job_id}")
r.raise_for_status()
status = r.json()
print(f"Status: {status['status']}, Progress: {status.get('progress', {}).get('percent', 0)}%")
if status["status"] in ("completed", "failed"):
if status["status"] == "completed":
print(f"Audio file ready: {status['result']['audio_path']}")
else:
print(f"Error: {status['error_message']}")
break
time.sleep(5)
Listing Active Jobs with Filters
Query all running podcast generation jobs using the list endpoint with query parameters. This functionality is implemented in api/routers/commands.py (lines 88-95):
curl -s "http://localhost:5055/commands/jobs?command=generate_podcast&status=running" | jq .
Or use the podcast-specific shortcut for individual job lookups:
curl -s http://localhost:5055/podcasts/jobs/command:podcast:abcd1234 | jq .
Summary
- Open Notebook creates podcast generation jobs via
PodcastService.submit_generation_jobinapi/podcast_service.py, which registers them as SurrealDB command records. - Track individual jobs using either
GET /commands/jobs/{job_id}(generic) orGET /podcasts/jobs/{job_id}(podcast-specific), both delegating toCommandService.get_command_status. - The status response includes
job_id,status,progressmetrics,resultdata, and timestamps for comprehensive monitoring. - Filter multiple jobs by type and status using
GET /commands/jobs?command=generate_podcast&status={status}to build monitoring dashboards. - All background operations use the Surreal-Commands registry, providing a consistent API for tracking long-running tasks across the Open Notebook platform.
Frequently Asked Questions
How do I get the job ID after submitting a podcast generation request?
When you successfully submit a POST request to /podcasts/generate, the API returns a JSON object containing a job_id field. This identifier is a SurrealDB RecordID (e.g., command:podcast:uuid) that uniquely identifies your background job in the Surreal-Commands registry. Store this ID immediately if you need to poll for status later.
What is the difference between the /commands/jobs and /podcasts/jobs endpoints?
The /commands/jobs/{job_id} endpoint in api/routers/commands.py is generic and handles status queries for any command type (podcasts, transcriptions, embeddings). The /podcasts/jobs/{job_id} endpoint in api/routers/podcasts.py is a convenience shortcut that provides podcast-specific URL semantics while internally calling the same get_command_status function. Both return identical response structures.
How can I list all running podcast generation jobs?
Query the list endpoint at /commands/jobs with query parameters to filter by command type and status. As implemented in api/routers/commands.py (lines 88-95), you can use ?command=generate_podcast&status=running to retrieve only active podcast generation jobs. This supports building monitoring dashboards that track multiple concurrent operations.
What status values can a podcast generation job have?
According to the Surreal-Commands registry implementation, jobs typically cycle through states including pending, running, completed, and failed. The progress field may contain additional metadata like the current processing step (embedding, synthesis, etc.) and completion percentage. When status is failed, the error_message field contains diagnostic information about the failure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →