Outputs & Decks API
API endpoints for managing Outputs and Decks - the system for tracking user-generated content across the Emerge platform.
Key Concepts
Output
A global parent record for ALL generated content (images, videos, etc.).
- Tracks the lifecycle of a generation: pending → processing → completed/failed
- Links to the source collection, job, and storage (flat_file)
- Supports custodial ownership for users who haven't signed up yet
Deck
Groups related outputs over time, tied to a specific collection.
- Think of it like an "album" of generations from a collection
- Auto-created when a user generates their first output from a collection
- Supports multiple decks per collection (different generation sessions)
Custodial Ownership
Content can be held "in custody" for social users (Farcaster, Twitter, etc.) who haven't created a full account yet. When they sign up, custody is transferred.
Response Format
All endpoints return responses in this format:
{
"data": { /* response data */ },
"error": null | "Error message"
}Authentication
All endpoints require the user_id header:
user_id: <uuid>Output Endpoints
Create Pending Output
Creates a new output record in pending status when a generation job starts.
POST /outputsRequest Body:
{
"collection_id": "uuid", // Required: The collection this output belongs to
"job_id": "uuid", // Optional: Link to job record
"source": "miniapp", // Optional: Where the generation originated
"input_metadata": { ... }, // Optional: Input parameters for the generation
"social_org": "farcaster", // Optional: For custodial outputs
"social_identifier": "username", // Optional: Platform-specific identifier
"deck_id": "uuid", // Optional: Specific deck to add to
"auto_create_deck": true // Optional: Auto-create deck if none exists (default: true)
}Source values:
direct_api- API callai_terminal- AI Terminalminiapp- Farcaster miniappstudio_component- Studio componentstudio_workflow- Studio workflowload_test- Load testingunknown- Unknown source
Response (201):
{
"data": {
"id": "uuid",
"collection_id": "uuid",
"deck_id": "uuid",
"job_id": "uuid",
"status": "pending",
"source": "miniapp",
"is_custodial": true,
"custodied_for": "uuid",
"created_at": "2024-01-10T..."
},
"error": null
}Complete Output
Marks an output as completed with the generated URL.
PATCH /outputs/:id/completeRequest Body:
{
"url": "https://cdn.example.com/file.mp4", // Required: URL of the generated content
"mime_type": "video/mp4", // Optional: MIME type
"thumbnail_url": "https://...", // Optional: Thumbnail URL
"flat_file_id": 12345, // Optional: Link to flat_file record
"output_metadata": { ... } // Optional: Generation output data
}Response (200):
{
"data": {
"id": "uuid",
"status": "completed",
"url": "https://cdn.example.com/file.mp4",
"mime_type": "video/mp4",
"completed_at": "2024-01-10T..."
},
"error": null
}Fail Output
Marks an output as failed with an error message.
PATCH /outputs/:id/failRequest Body:
{
"error_message": "Generation failed: timeout"
}Response (200):
{
"data": {
"id": "uuid",
"status": "failed",
"error_message": "Generation failed: timeout"
},
"error": null
}Hide Output (Soft Delete)
Hides an output from user-facing views.
DELETE /outputs/:idResponse (200):
{
"data": {
"id": "uuid",
"status": "hidden"
},
"error": null
}Get Output
Retrieves a single output by ID.
GET /outputs/:idResponse (200):
{
"data": {
"id": "uuid",
"url": "https://...",
"mime_type": "video/mp4",
"status": "completed",
"collection_id": "uuid",
"deck_id": "uuid",
"deck": {
"id": "uuid",
"name": "My Deck"
},
"collection": {
"id": "uuid",
"title": "Veo Video Generator"
},
"created_at": "...",
"completed_at": "..."
},
"error": null
}Move Output to Deck
Moves an output to a different deck (or removes from deck).
PATCH /outputs/:id/deckRequest Body:
{
"deck_id": "uuid" // null to remove from deck
}Response (200):
{
"data": {
"id": "uuid",
"deck_id": "uuid"
},
"error": null
}List Collection Outputs
Lists outputs for a collection, optionally filtered by deck or user.
GET /collections/:collectionId/outputsQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
deck_id | uuid | Filter by deck |
status | string | Filter by status (pending, completed, failed) |
social_org | string | Filter by social platform (custodial) |
social_identifier | string | Filter by social identifier |
limit | number | Max results (default: 50) |
offset | number | Pagination offset (default: 0) |
Response (200):
{
"data": [
{
"id": "uuid",
"url": "https://...",
"status": "completed",
"deck": { "id": "uuid", "name": "My Deck" }
}
],
"error": null
}Get Collection Output Stats
Returns statistics about outputs for a collection.
GET /collections/:collectionId/outputs/statsResponse (200):
{
"data": {
"total": 150,
"byStatus": {
"completed": 120,
"pending": 5,
"failed": 20,
"hidden": 5
}
},
"error": null
}Develop Output (Video Transformation)
The "develop" feature allows transforming an existing output using a global collection (a reusable workflow). For example, turning an image into a video.
Develop Output
Creates a new output derived from an existing output using a global collection's workflow.
POST /outputs/:id/developRequest Body:
{
"collection_id": "uuid", // Required: The global collection to use
"variables": { // Optional: Additional variables
"aspect_ratio": "16:9",
"duration": "5s"
}
}Response (202 - Accepted):
{
"data": {
"job_id": "uuid",
"output_id": "uuid",
"status": "pending",
"develop_collection": {
"id": "uuid",
"title": "Image to Video",
"input_type": "image",
"output_type": "video"
},
"source_output": {
"id": "uuid",
"url": "https://...",
"mime_type": "image/png"
}
},
"error": null
}Notes:
- The new output is placed in the same deck as the source output
- The source output must be in
completedstatus - The global collection must have
is_global: true - Input type must match (e.g., image collection for image source)
List Global Collections
Lists available global collections for developing outputs.
GET /outputs/develop/collectionsQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
input_type | string | Filter by input type (image, video, text) |
Response (200):
{
"data": [
{
"id": "uuid",
"title": "Image to Video",
"description": "Transform images into videos using Veo",
"input_type": "image",
"output_type": "video",
"cover_image_url": "https://..."
},
{
"id": "uuid",
"title": "Upscale Image",
"description": "4x upscale using Real-ESRGAN",
"input_type": "image",
"output_type": "image",
"cover_image_url": "https://..."
}
],
"error": null
}Deck Endpoints
Create Deck
Creates a new deck for a collection.
POST /decksRequest Body:
{
"collection_id": "uuid", // Required
"name": "My Video Collection", // Optional
"description": "Videos from...", // Optional
"social_org": "farcaster", // Optional: For custodial decks
"social_identifier": "username" // Optional
}Response (201):
{
"data": {
"id": "uuid",
"collection_id": "uuid",
"name": "My Video Collection",
"status": "active",
"output_count": 0,
"created_at": "..."
},
"error": null
}Get Deck
Retrieves a deck with its outputs.
GET /decks/:idResponse (200):
{
"data": {
"id": "uuid",
"name": "My Deck",
"status": "active",
"output_count": 5,
"collection": {
"id": "uuid",
"title": "Veo Generator",
"cover_image_url": "https://..."
},
"outputs": [
{
"id": "uuid",
"url": "https://...",
"status": "completed",
"mime_type": "video/mp4",
"position": 1
}
]
},
"error": null
}Update Deck
Updates deck properties.
PATCH /decks/:idRequest Body:
{
"name": "Updated Name",
"description": "New description",
"cover_output_id": "uuid",
"status": "published"
}Status values:
active- Normal deck, can receive new outputsarchived- Hidden from default viewspublished- Shared/published decklocked- Cannot add new outputs
Response (200):
{
"data": {
"id": "uuid",
"name": "Updated Name",
"status": "published"
},
"error": null
}Archive Deck (Soft Delete)
Archives a deck, hiding it from default views.
DELETE /decks/:idResponse (200):
{
"data": {
"id": "uuid",
"status": "archived"
},
"error": null
}Publish Deck
Marks a deck as published/shareable.
POST /decks/:id/publishResponse (200):
{
"data": {
"id": "uuid",
"status": "published",
"published_at": "2024-01-10T..."
},
"error": null
}Lock Deck
Locks a deck to prevent new outputs from being added.
POST /decks/:id/lockResponse (200):
{
"data": {
"id": "uuid",
"status": "locked"
},
"error": null
}Get Deck Stats
Returns statistics about outputs in a deck.
GET /decks/:id/statsResponse (200):
{
"data": {
"byStatus": {
"completed": 10,
"pending": 2,
"failed": 1
}
},
"error": null
}List Collection Decks
Lists decks for a specific collection.
GET /collections/:collectionId/decksQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
social_org | string | Filter by social platform |
social_identifier | string | Filter by social identifier |
Response (200):
{
"data": [
{
"id": "uuid",
"name": "My Deck",
"status": "active",
"output_count": 5,
"created_at": "..."
}
],
"error": null
}List User Decks
Lists all decks for the current user across all collections.
GET /decksQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
social_org | string | Filter by social platform (custodial) |
social_identifier | string | Filter by social identifier |
Response (200):
{
"data": [
{
"id": "uuid",
"name": "My Deck",
"status": "active",
"output_count": 5,
"collection": {
"id": "uuid",
"title": "Veo Generator"
}
}
],
"error": null
}Video Streaming (Mux Integration)
Videos uploaded through the platform are automatically processed by Mux for adaptive streaming. The flat_file record is updated with:
mux_asset_id: Mux's internal asset identifiermux_playback_id: The ID used for streaming playback
Displaying Videos
When displaying videos, check for mux_playback_id:
// If mux_playback_id exists, use MuxPlayer
if (flatFile.mux_playback_id) {
return (
<MuxPlayer
playbackId={flatFile.mux_playback_id}
streamType="on-demand"
/>
);
}
// Otherwise fall back to native video
return <video src={flatFile.url} controls />;Forensics/Debug View
The forensics API returns flat_files with Mux data:
GET /api/jobs/:jobId/forensicsResponse includes _flat_files array with Mux IDs:
{
"job": {
"payload": {
"_flat_files": [
{
"id": 12345,
"url": "generations/...",
"mime_type": "video/mp4",
"mux_asset_id": "1L3400tF301xX5bFw1vl9WOG71QZz02xy02hVFBU2ThZ7mE",
"mux_playback_id": "7iwyZezQo4fjZoYPOMV9NWe1vuXMg6fE5lBKqQvnXOE"
}
]
}
}
}Error Codes
| Status | Meaning |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Missing user_id header |
| 404 | Not Found - Resource doesn't exist |
| 500 | Internal Server Error |
Architecture Diagrams
Data Model
Output Lifecycle
Develop Output Flow
Custodial Ownership Model
Video Display Decision Tree
Data Flow Example
User generates content in miniapp:
Create pending output:
POST /outputs { collection_id, source: "miniapp", social_org: "farcaster", social_identifier: "vitalik" } → Creates output + auto-creates deckGeneration completes:
PATCH /outputs/:id/complete { url, flat_file_id, mime_type: "image/png" }User wants to make it a video:
POST /outputs/:id/develop { collection_id: "image-to-video-global-collection" } → Creates new output in same deck, starts jobVideo completes, Mux processes it:
- flat_file updated with mux_playback_id
- Output marked completed
User views their deck:
GET /decks/:id → Returns deck with all outputs (image + video)
