381 lines
8.7 KiB
Markdown
381 lines
8.7 KiB
Markdown
# Live URL & CDN API
|
|
|
|
Public CDN endpoints for image serving and live URL generation. For authenticated API, see [image-generation.md](image-generation.md).
|
|
|
|
---
|
|
|
|
## CDN Image Serving
|
|
|
|
```
|
|
GET /cdn/:orgSlug/:projectSlug/img/:filenameOrAlias
|
|
```
|
|
|
|
**Authentication:** None - Public endpoint
|
|
|
|
Serve images by filename or project-scoped alias.
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `orgSlug` | Organization identifier |
|
|
| `projectSlug` | Project identifier |
|
|
| `filenameOrAlias` | Filename or `@alias` |
|
|
|
|
**Examples:**
|
|
|
|
```
|
|
# By filename
|
|
GET /cdn/acme/website/img/hero-background.jpg
|
|
|
|
# By alias
|
|
GET /cdn/acme/website/img/@hero
|
|
```
|
|
|
|
**Response:** Raw image bytes (not JSON)
|
|
|
|
**Response Headers:**
|
|
|
|
| Header | Value |
|
|
|--------|-------|
|
|
| `Content-Type` | `image/jpeg`, `image/png`, etc. |
|
|
| `Content-Length` | File size in bytes |
|
|
| `Cache-Control` | `public, max-age=31536000` (1 year) |
|
|
| `X-Image-Id` | Image UUID |
|
|
|
|
---
|
|
|
|
## Live URL Generation
|
|
|
|
```
|
|
GET /cdn/:orgSlug/:projectSlug/live/:scope
|
|
```
|
|
|
|
**Authentication:** None - Public endpoint
|
|
|
|
Generate images on-demand via URL parameters with automatic caching.
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `orgSlug` | Organization identifier |
|
|
| `projectSlug` | Project identifier |
|
|
| `scope` | Scope identifier (alphanumeric, hyphens, underscores) |
|
|
|
|
**Query Parameters:**
|
|
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `prompt` | string | Yes | - | Image description |
|
|
| `aspectRatio` | string | No | `"1:1"` | Aspect ratio |
|
|
| `autoEnhance` | boolean | No | `true` | Enable prompt enhancement |
|
|
| `template` | string | No | `"general"` | Enhancement template |
|
|
|
|
**Example:**
|
|
|
|
```
|
|
GET /cdn/acme/website/live/hero-section?prompt=mountain+landscape&aspectRatio=16:9
|
|
```
|
|
|
|
**Response:** Raw image bytes
|
|
|
|
### Cache Behavior
|
|
|
|
**Cache HIT** - Image exists in cache:
|
|
- Returns instantly
|
|
- No rate limit check
|
|
- Headers include `X-Cache-Status: HIT`
|
|
|
|
**Cache MISS** - New generation:
|
|
- Generates image using AI
|
|
- Stores in cache
|
|
- Counts toward rate limit
|
|
- Headers include `X-Cache-Status: MISS`
|
|
|
|
**Cache Key:** Computed from `projectId + scope + prompt + aspectRatio + autoEnhance + template`
|
|
|
|
### Response Headers
|
|
|
|
**Cache HIT:**
|
|
|
|
| Header | Value |
|
|
|--------|-------|
|
|
| `Content-Type` | `image/jpeg` |
|
|
| `Cache-Control` | `public, max-age=31536000` |
|
|
| `X-Cache-Status` | `HIT` |
|
|
| `X-Scope` | Scope identifier |
|
|
| `X-Image-Id` | Image UUID |
|
|
|
|
**Cache MISS:**
|
|
|
|
| Header | Value |
|
|
|--------|-------|
|
|
| `Content-Type` | `image/jpeg` |
|
|
| `Cache-Control` | `public, max-age=31536000` |
|
|
| `X-Cache-Status` | `MISS` |
|
|
| `X-Scope` | Scope identifier |
|
|
| `X-Generation-Id` | Generation UUID |
|
|
| `X-Image-Id` | Image UUID |
|
|
| `X-RateLimit-Limit` | `10` |
|
|
| `X-RateLimit-Remaining` | Remaining requests |
|
|
| `X-RateLimit-Reset` | Seconds until reset |
|
|
|
|
---
|
|
|
|
## IP Rate Limiting
|
|
|
|
Live URLs are rate limited by IP address:
|
|
|
|
| Limit | Value |
|
|
|-------|-------|
|
|
| New generations | 10 per hour per IP |
|
|
| Cache hits | Unlimited |
|
|
|
|
**Note:** Only cache MISS (new generations) count toward the limit. Cache HIT requests are not limited.
|
|
|
|
Rate limit headers are included on MISS responses:
|
|
- `X-RateLimit-Limit`: Maximum requests (10)
|
|
- `X-RateLimit-Remaining`: Remaining requests
|
|
- `X-RateLimit-Reset`: Seconds until reset
|
|
|
|
---
|
|
|
|
## Scope Management
|
|
|
|
Scopes organize live URL generation budgets. All scope endpoints require Project Key authentication.
|
|
|
|
### Create Scope
|
|
|
|
```
|
|
POST /api/v1/live/scopes
|
|
```
|
|
|
|
**Request Body:**
|
|
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `slug` | string | Yes | - | Unique identifier |
|
|
| `allowNewGenerations` | boolean | No | `true` | Allow new generations |
|
|
| `newGenerationsLimit` | number | No | `30` | Max generations in scope |
|
|
| `meta` | object | No | `{}` | Custom metadata |
|
|
|
|
**Example:**
|
|
|
|
```json
|
|
{
|
|
"slug": "hero-section",
|
|
"allowNewGenerations": true,
|
|
"newGenerationsLimit": 50,
|
|
"meta": { "description": "Hero section images" }
|
|
}
|
|
```
|
|
|
|
**Response:** `201 Created`
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "scope-123",
|
|
"projectId": "project-456",
|
|
"slug": "hero-section",
|
|
"allowNewGenerations": true,
|
|
"newGenerationsLimit": 50,
|
|
"currentGenerations": 0,
|
|
"lastGeneratedAt": null,
|
|
"meta": { "description": "Hero section images" },
|
|
"createdAt": "2025-11-28T10:00:00.000Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Lazy Scope Creation
|
|
|
|
Scopes are auto-created on first live URL request if `project.allowNewLiveScopes = true`:
|
|
|
|
```
|
|
GET /cdn/acme/website/live/new-scope?prompt=...
|
|
// Creates "new-scope" with default settings
|
|
```
|
|
|
|
### List Scopes
|
|
|
|
```
|
|
GET /api/v1/live/scopes
|
|
```
|
|
|
|
**Query Parameters:**
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `slug` | string | - | Filter by exact slug |
|
|
| `limit` | number | `20` | Results per page (max: 100) |
|
|
| `offset` | number | `0` | Pagination offset |
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "scope-123",
|
|
"slug": "hero-section",
|
|
"allowNewGenerations": true,
|
|
"newGenerationsLimit": 50,
|
|
"currentGenerations": 12,
|
|
"lastGeneratedAt": "2025-11-28T09:30:00.000Z"
|
|
}
|
|
],
|
|
"pagination": { "limit": 20, "offset": 0, "total": 3, "hasMore": false }
|
|
}
|
|
```
|
|
|
|
### Get Scope
|
|
|
|
```
|
|
GET /api/v1/live/scopes/:slug
|
|
```
|
|
|
|
Returns scope with statistics (currentGenerations, lastGeneratedAt).
|
|
|
|
### Update Scope
|
|
|
|
```
|
|
PUT /api/v1/live/scopes/:slug
|
|
```
|
|
|
|
```json
|
|
{
|
|
"allowNewGenerations": false,
|
|
"newGenerationsLimit": 100,
|
|
"meta": { "description": "Updated" }
|
|
}
|
|
```
|
|
|
|
Changes take effect immediately for new requests.
|
|
|
|
### Regenerate Scope Images
|
|
|
|
```
|
|
POST /api/v1/live/scopes/:slug/regenerate
|
|
```
|
|
|
|
**Request Body:**
|
|
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `imageId` | string | Specific image UUID (optional) |
|
|
|
|
**Behavior:**
|
|
- If `imageId` provided: Regenerate only that image
|
|
- If `imageId` omitted: Regenerate all images in scope
|
|
|
|
Images are regenerated with exact same parameters. IDs and URLs are preserved.
|
|
|
|
### Delete Scope
|
|
|
|
```
|
|
DELETE /api/v1/live/scopes/:slug
|
|
```
|
|
|
|
**Cascade Behavior:**
|
|
- Scope record is **hard deleted**
|
|
- All images in scope are **hard deleted** (with MinIO cleanup)
|
|
- Follows alias protection rules (aliased images may be kept)
|
|
|
|
> **Warning:** This permanently deletes all cached images in the scope.
|
|
|
|
---
|
|
|
|
## Scope Settings
|
|
|
|
| Setting | Type | Default | Description |
|
|
|---------|------|---------|-------------|
|
|
| `slug` | string | - | Unique identifier within project |
|
|
| `allowNewGenerations` | boolean | `true` | Whether new generations are allowed |
|
|
| `newGenerationsLimit` | number | `30` | Maximum generations in scope |
|
|
|
|
When `allowNewGenerations: false`:
|
|
- Cache HITs still work
|
|
- New prompts return 403 error
|
|
|
|
When `newGenerationsLimit` reached:
|
|
- Cache HITs still work
|
|
- New prompts return 429 error
|
|
|
|
---
|
|
|
|
## Authenticated Live Endpoint
|
|
|
|
```
|
|
GET /api/v1/live?prompt=...
|
|
```
|
|
|
|
**Authentication:** Project Key required
|
|
|
|
Alternative to CDN endpoint with prompt caching by hash.
|
|
|
|
**Query Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `prompt` | string | Yes | Image description |
|
|
|
|
**Cache Behavior:**
|
|
- Cache key: SHA-256 hash of prompt
|
|
- Cache stored in `prompt_url_cache` table
|
|
- Tracks hit count and last access
|
|
|
|
**Response Headers:**
|
|
- `X-Cache-Status`: `HIT` or `MISS`
|
|
- `X-Cache-Hit-Count`: Number of cache hits (on HIT)
|
|
|
|
---
|
|
|
|
## Error Codes
|
|
|
|
| HTTP Status | Code | Description |
|
|
|-------------|------|-------------|
|
|
| 400 | `SCOPE_INVALID_FORMAT` | Invalid scope slug format |
|
|
| 403 | `SCOPE_CREATION_DISABLED` | New scope creation not allowed |
|
|
| 404 | `ORG_NOT_FOUND` | Organization not found |
|
|
| 404 | `PROJECT_NOT_FOUND` | Project not found |
|
|
| 404 | `SCOPE_NOT_FOUND` | Scope does not exist |
|
|
| 409 | `SCOPE_ALREADY_EXISTS` | Scope slug already in use |
|
|
| 429 | `IP_RATE_LIMIT_EXCEEDED` | IP rate limit (10/hour) exceeded |
|
|
| 429 | `SCOPE_GENERATION_LIMIT_EXCEEDED` | Scope limit reached |
|
|
|
|
---
|
|
|
|
## Use Cases
|
|
|
|
### Dynamic Hero Images
|
|
|
|
```html
|
|
<img src="/cdn/acme/website/live/hero?prompt=professional+office+workspace&aspectRatio=16:9" />
|
|
```
|
|
|
|
First load generates, subsequent loads are cached.
|
|
|
|
### Product Placeholders
|
|
|
|
```html
|
|
<img src="/cdn/acme/store/live/products?prompt=product+placeholder+gray+box&aspectRatio=1:1" />
|
|
```
|
|
|
|
### Blog Post Images
|
|
|
|
```html
|
|
<img src="/cdn/acme/blog/live/posts?prompt=abstract+technology+background&aspectRatio=16:9&template=illustration" />
|
|
```
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [Basic Generation](image-generation.md) - API-based generation
|
|
- [Advanced Generation](image-generation-advanced.md) - References, aliases, flows
|
|
- [Image Upload](images-upload.md) - Upload and manage images
|