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

# Generated Content

> Access and manage AI-generated content (images, videos, audio, 3D models)

## Overview

The Generated Content API provides access to content generated through Junis AI agents using [Replicate](https://replicate.com) models. This includes images, videos, audio files, and 3D models (GLB format).

<Info>
  **Content Generation**: Content is generated through AI agents that use the `gen_content` tool. This API provides read-only access to view and retry generated content.
</Info>

***

## Authentication

All endpoints require API key authentication with specific scopes:

| Endpoint                   | Required Scope  |
| -------------------------- | --------------- |
| `GET /content`             | `content:read`  |
| `GET /content/{id}`        | `content:read`  |
| `POST /content/{id}/retry` | `content:retry` |

<Warning>
  **Default Scopes**: The `content:read` and `content:retry` scopes are **not** enabled by default when creating API keys. You must explicitly enable these scopes during key creation.
</Warning>

Include your API key in the `X-API-Key` header:

```bash theme={null}
X-API-Key: jns_live_YOUR_API_KEY_HERE
```

See [Authentication](/api-reference/authentication) for details.

***

## Content Types

Generated content is categorized into the following types:

| Type    | Description                    | Example Models               |
| ------- | ------------------------------ | ---------------------------- |
| `image` | Static images (PNG, JPG, WebP) | SDXL, Flux, Stable Diffusion |
| `video` | Video files (MP4, WebM)        | Runway Gen-3, AnimateDiff    |
| `audio` | Audio files (MP3, WAV)         | MusicGen, Bark               |
| `glb`   | 3D models (GLB format)         | Point-E, Shap-E              |
| `other` | Other content types            | Various                      |

***

## Content Status

Content goes through the following status lifecycle:

| Status       | Description                                          |
| ------------ | ---------------------------------------------------- |
| `pending`    | Generation request received, waiting to be processed |
| `processing` | Content is being generated by Replicate              |
| `completed`  | Generation successful, content available             |
| `failed`     | Generation failed (can be retried)                   |

***

## List Content

Retrieve a paginated list of generated content for your organization.

### Endpoint

```
GET https://api.junis.ai/api/external/content
```

### Query Parameters

| Parameter      | Type    | Required | Description                                                      |
| -------------- | ------- | -------- | ---------------------------------------------------------------- |
| `page`         | integer | No       | Page number (default: `1`, min: `1`)                             |
| `page_size`    | integer | No       | Items per page (default: `20`, max: `100`)                       |
| `content_type` | string  | No       | Filter by type: `image`, `video`, `audio`, `glb`, `other`        |
| `status`       | string  | No       | Filter by status: `pending`, `processing`, `completed`, `failed` |

### Request Example

```bash cURL theme={null}
curl -X GET "https://api.junis.ai/api/external/content?page=1&page_size=10&status=completed" \
  -H "X-API-Key: jns_live_YOUR_API_KEY_HERE"
```

```python Python theme={null}
import requests

response = requests.get(
    "https://api.junis.ai/api/external/content",
    headers={"X-API-Key": "jns_live_YOUR_API_KEY_HERE"},
    params={
        "page": 1,
        "page_size": 10,
        "status": "completed"
    }
)
print(response.json())
```

### Response

**Status Code:** `200 OK`

```json theme={null}
{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "content_type": "image",
      "status": "completed",
      "prompt": "A serene mountain landscape at sunset",
      "replicate_version": "stability-ai/sdxl",
      "output_url": "https://replicate.delivery/...",
      "storage_url": "https://objectstorage.kr-central-2.kakaocloud.com/...",
      "error_message": null,
      "processing_time_ms": 12500,
      "credit_cost": 0.05,
      "created_at": "2026-01-01T10:30:00Z",
      "completed_at": "2026-01-01T10:30:12Z"
    }
  ],
  "total": 42,
  "page": 1,
  "page_size": 10,
  "has_more": true
}
```

### Response Fields

| Field       | Type    | Description                               |
| ----------- | ------- | ----------------------------------------- |
| `items`     | array   | List of content items                     |
| `total`     | integer | Total number of items matching the filter |
| `page`      | integer | Current page number                       |
| `page_size` | integer | Number of items per page                  |
| `has_more`  | boolean | Whether more pages are available          |

### Content Item Fields

| Field                | Type    | Description                                                                                     |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `id`                 | string  | Unique content ID (UUID)                                                                        |
| `content_type`       | string  | Type of content (`image`, `video`, `audio`, `glb`, `other`). `null` until generation completes. |
| `status`             | string  | Current status                                                                                  |
| `prompt`             | string  | Generation prompt (may be truncated in list view)                                               |
| `replicate_version`  | string  | Replicate model version used                                                                    |
| `output_url`         | string  | Direct URL to generated content (Replicate CDN)                                                 |
| `storage_url`        | string  | Permanent URL (Kakao Cloud storage)                                                             |
| `error_message`      | string  | Error description if failed                                                                     |
| `processing_time_ms` | integer | Generation time in milliseconds                                                                 |
| `credit_cost`        | number  | Credit cost for this generation (6 decimal places)                                              |
| `created_at`         | string  | Creation timestamp (ISO 8601)                                                                   |
| `completed_at`       | string  | Completion timestamp (ISO 8601)                                                                 |

***

## Get Content Detail

Retrieve detailed information about a specific content item.

### Endpoint

```
GET https://api.junis.ai/api/external/content/{content_id}
```

### Path Parameters

| Parameter    | Type   | Required | Description              |
| ------------ | ------ | -------- | ------------------------ |
| `content_id` | string | **Yes**  | Content ID (UUID format) |

### Request Example

```bash cURL theme={null}
curl -X GET "https://api.junis.ai/api/external/content/550e8400-e29b-41d4-a716-446655440000" \
  -H "X-API-Key: jns_live_YOUR_API_KEY_HERE"
```

### Response

**Status Code:** `200 OK`

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "organization_id": "org-abc123",
  "user_id": "user-xyz789",
  "content_type": "image",
  "status": "completed",
  "prompt": "A serene mountain landscape at sunset with dramatic clouds and golden light reflecting off a calm lake in the foreground",
  "replicate_version": "stability-ai/sdxl",
  "replicate_prediction_id": "xyz123abc456",
  "replicate_input": {
    "prompt": "A serene mountain landscape at sunset...",
    "negative_prompt": "blurry, low quality",
    "width": 1024,
    "height": 1024,
    "num_inference_steps": 50
  },
  "output_url": "https://replicate.delivery/...",
  "storage_path": "generation/image/550e8400_20260101_103000.png",
  "storage_url": "https://objectstorage.kr-central-2.kakaocloud.com/...",
  "error_message": null,
  "retry_count": 0,
  "max_retries": 3,
  "credit_cost": 0.05,
  "processing_time_ms": 12500,
  "created_at": "2026-01-01T10:30:00Z",
  "started_at": "2026-01-01T10:30:01Z",
  "completed_at": "2026-01-01T10:30:12Z"
}
```

### Additional Detail Fields

| Field                     | Type    | Description                             |
| ------------------------- | ------- | --------------------------------------- |
| `organization_id`         | string  | Organization that owns this content     |
| `user_id`                 | string  | User who initiated the generation       |
| `replicate_prediction_id` | string  | Replicate's internal prediction ID      |
| `replicate_input`         | object  | Full input parameters sent to Replicate |
| `storage_path`            | string  | Path in cloud storage bucket            |
| `retry_count`             | integer | Number of retry attempts made           |
| `max_retries`             | integer | Maximum allowed retries (default: 3)    |
| `started_at`              | string  | Processing start timestamp              |

***

## Retry Failed Content

Retry a failed content generation. This re-queues the generation with the original parameters.

### Endpoint

```
POST https://api.junis.ai/api/external/content/{content_id}/retry
```

### Path Parameters

| Parameter    | Type   | Required | Description                                   |
| ------------ | ------ | -------- | --------------------------------------------- |
| `content_id` | string | **Yes**  | Content ID of failed generation (UUID format) |

### Prerequisites

* Content must have status `failed`
* `retry_count` must be less than `max_retries` (default: 3)

### Request Example

```bash cURL theme={null}
curl -X POST "https://api.junis.ai/api/external/content/550e8400-e29b-41d4-a716-446655440000/retry" \
  -H "X-API-Key: jns_live_YOUR_API_KEY_HERE"
```

```python Python theme={null}
import requests

response = requests.post(
    "https://api.junis.ai/api/external/content/550e8400-e29b-41d4-a716-446655440000/retry",
    headers={"X-API-Key": "jns_live_YOUR_API_KEY_HERE"}
)
print(response.json())
```

### Response

**Status Code:** `200 OK`

```json theme={null}
{
  "success": true,
  "message": "Content generation retry queued (attempt 1/3)",
  "generation_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Response Fields

| Field           | Type    | Description                           |
| --------------- | ------- | ------------------------------------- |
| `success`       | boolean | Whether retry was queued successfully |
| `message`       | string  | Human-readable status message         |
| `generation_id` | string  | Content ID being retried              |

***

## Error Responses

### Common Errors

```json 400 Bad Request - Invalid Filter theme={null}
{
  "detail": "Invalid content_type 'unknown'. Must be one of: ['image', 'video', 'audio', 'glb', 'other']"
}
```

```json 400 Bad Request - Cannot Retry theme={null}
{
  "detail": "Cannot retry content with status 'completed'. Only failed content can be retried."
}
```

```json 400 Bad Request - Max Retries Reached theme={null}
{
  "detail": "Maximum retry attempts (3) reached for this content."
}
```

```json 403 Forbidden - Insufficient Scopes theme={null}
{
  "error": "insufficient_scopes",
  "message": "API key does not have required permissions",
  "required_scopes": ["content:read"],
  "missing_scopes": ["content:read"],
  "available_scopes": ["orchestrator:invoke", "sessions:read"]
}
```

```json 404 Not Found theme={null}
{
  "detail": "Content not found: 550e8400-e29b-41d4-a716-446655440000"
}
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Polling for Content Completion" icon="clock">
    When content is in `pending` or `processing` status, poll the detail endpoint to check for completion:

    ```python theme={null}
    import time
    import requests

    def wait_for_content(content_id, api_key, timeout=300, interval=5):
        """Poll until content is completed or failed."""
        start = time.time()
        while time.time() - start < timeout:
            response = requests.get(
                f"https://api.junis.ai/api/external/content/{content_id}",
                headers={"X-API-Key": api_key}
            )
            data = response.json()

            if data["status"] == "completed":
                return data
            elif data["status"] == "failed":
                raise Exception(f"Generation failed: {data.get('error_message')}")

            time.sleep(interval)

        raise TimeoutError("Content generation timed out")
    ```
  </Accordion>

  <Accordion title="Filtering by Content Type" icon="filter">
    Use content type filters to retrieve specific types of generated content:

    ```bash theme={null}
    # Get only images
    curl "https://api.junis.ai/api/external/content?content_type=image"

    # Get only videos
    curl "https://api.junis.ai/api/external/content?content_type=video"

    # Get failed content for monitoring
    curl "https://api.junis.ai/api/external/content?status=failed"
    ```
  </Accordion>

  <Accordion title="Handling Storage URLs" icon="cloud">
    Generated content has two URLs:

    * **`output_url`**: Replicate's CDN URL (may expire)
    * **`storage_url`**: Permanent Kakao Cloud storage URL

    Always prefer `storage_url` for persistent access to content.
  </Accordion>

  <Accordion title="Credit Cost Tracking" icon="coins">
    The `credit_cost` field shows the credit deducted for each generation. Use this for:

    * Billing reconciliation
    * Usage monitoring
    * Cost optimization

    Note: Credit costs support 6 decimal places for precision.
  </Accordion>
</AccordionGroup>

***

## Related Resources

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    Learn about API key scopes and authentication
  </Card>

  <Card title="Chat Completions" icon="comments" href="/api-reference/chat-completions">
    Generate content through AI conversations
  </Card>

  <Card title="Agents API" icon="robot" href="/api-reference/agents">
    Invoke specific agents directly
  </Card>

  <Card title="Error Codes" icon="triangle-exclamation" href="/api-reference/error-codes">
    Full list of error codes and solutions
  </Card>
</CardGroup>
