# How to Track Podcast Generation Job Status via the Commands API in Open Notebook

> Learn to track podcast generation job status using Open Notebooks Commands API. Discover how to poll endpoints for real-time progress and results from SurrealDB.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-07-05

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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:

```json
{
  "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:

```python
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:

```python
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`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/commands.py) (lines 88-95):

```bash
curl -s "http://localhost:5055/commands/jobs?command=generate_podcast&status=running" | jq .

```

Or use the podcast-specific shortcut for individual job lookups:

```bash
curl -s http://localhost:5055/podcasts/jobs/command:podcast:abcd1234 | jq .

```

## Summary

- Open Notebook creates podcast generation jobs via `PodcastService.submit_generation_job` in [`api/podcast_service.py`](https://github.com/lfnovo/open-notebook/blob/main/api/podcast_service.py), which registers them as SurrealDB command records.
- Track individual jobs using either `GET /commands/jobs/{job_id}` (generic) or `GET /podcasts/jobs/{job_id}` (podcast-specific), both delegating to `CommandService.get_command_status`.
- The status response includes `job_id`, `status`, `progress` metrics, `result` data, 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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.