> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnifence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Real-time progress

> Stream job progress updates with Server-Sent Events

Use Server-Sent Events (SSE) to receive real-time progress updates for moderation jobs. This is more efficient than polling the job status endpoint.

## Connecting

Open an SSE connection to the progress endpoint:

```
GET /api/v1/job/{id}/progress
Authorization: Bearer YOUR_API_KEY
```

The server responds with `Content-Type: text/event-stream`.

## Event types

### `connected`

Sent immediately when the connection opens. Contains the current job state.

```
event: connected
data: {"job_id":"a1b2c3d4","status":"queued","progress":0}
```

If the job has already completed, the `connected` event includes `progress: 100` and the stream closes immediately.

### `progress`

Sent as the job progresses through the moderation pipeline.

```
event: progress
data: {"job_id":"a1b2c3d4","status":"processing","progress":50}
```

For video moderation jobs, progress events include frame counts:

```
event: progress
data: {"job_id":"a1b2c3d4","status":"processing","progress":60,"frames_completed":27,"frame_count":45}
```

### Event data fields

| Field              | Type    | Description                                       |
| ------------------ | ------- | ------------------------------------------------- |
| `job_id`           | string  | The job identifier.                               |
| `status`           | string  | `queued`, `processing`, `completed`, or `failed`. |
| `progress`         | number  | Completion percentage (0–100).                    |
| `detail`           | string  | Human-readable step description. Optional.        |
| `frames_completed` | integer | Frames processed so far. Post-moderation only.    |
| `frame_count`      | integer | Total frames to process. Post-moderation only.    |

## Stream lifecycle

* The stream closes automatically when `progress` reaches 100 or `status` is `completed` or `failed`.
* A keepalive comment (`: keepalive`) is sent every 15 seconds to prevent connection timeouts.
* If the client disconnects, the server cleans up the subscription.

## Code examples

### JavaScript

```javascript theme={null}
const source = new EventSource('https://api.omnifence.ai/api/v1/job/a1b2c3d4/progress', {
  headers: { Authorization: 'Bearer YOUR_API_KEY' },
});

source.addEventListener('connected', (e) => {
  console.log('Initial state:', JSON.parse(e.data));
});

source.addEventListener('progress', (e) => {
  const { progress, status } = JSON.parse(e.data);
  console.log(`${progress}% — ${status}`);

  if (progress >= 100) source.close();
});

source.onerror = () => source.close();
```

### cURL

```bash theme={null}
curl -N https://api.omnifence.ai/api/v1/job/a1b2c3d4/progress \
  -H "Authorization: Bearer YOUR_API_KEY"
```
