diff --git a/api-reference/image/generation.mdx b/api-reference/image/generation.mdx index 9895a338..80ea33f1 100644 --- a/api-reference/image/generation.mdx +++ b/api-reference/image/generation.mdx @@ -1,4 +1,4 @@ --- -title: 'Generate Image' +title: 'Generate Image (Legacy)' openapi: "/api-reference/openapi/content.json GET /api/image/generate" --- diff --git a/api-reference/openapi/content.json b/api-reference/openapi/content.json index 56cb5170..71e957ab 100644 --- a/api-reference/openapi/content.json +++ b/api-reference/openapi/content.json @@ -360,7 +360,7 @@ }, "/api/sandboxes/files": { "post": { - "description": "Upload one or more files to the authenticated account's sandbox GitHub repository. Accepts an array of file URLs and commits each file to the specified directory path within the repository. Supports submodule resolution — if the target path falls within a git submodule, the file is committed to the submodule's repository. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "description": "Upload one or more files to the authenticated account's sandbox GitHub repository. Accepts an array of file URLs and commits each file to the specified directory path within the repository. Supports submodule resolution \u2014 if the target path falls within a git submodule, the file is committed to the submodule's repository. Authentication is handled via the x-api-key header or Authorization Bearer token.", "requestBody": { "description": "JSON body containing file URLs and target path", "required": true, @@ -433,7 +433,7 @@ "url": "https://recoup-api.vercel.app" } ], - "description": "Generate high-quality images using AI models. Images are automatically stored on Arweave and include In Process moment metadata for provenance and ownership tracking.", + "description": "**Legacy.** Predates the current `/api/content/*` primitives. Generates images via the x402 payment protocol and stores results on Arweave with In Process moment metadata for provenance tracking. Still in use (including by the MCP server). New integrations should prefer the lighter [`POST /api/content/image`](/api-reference/content/generate-image), which returns the generated image directly without auto-storage side effects.", "parameters": [ { "name": "prompt", @@ -481,7 +481,7 @@ }, "/api/transcribe": { "post": { - "description": "Transcribe audio files using OpenAI Whisper. The API saves both the original audio file and the generated markdown transcript to the customer's files in Supabase Storage.", + "description": "**Legacy.** Predates the current `/api/content/*` primitives. Transcribes audio using OpenAI Whisper and writes both the audio file and the transcript to backend storage as files on the account/artist. New integrations should prefer the stateless [`POST /api/content/transcribe`](/api-reference/content/transcribe-audio), which returns the transcript with word-level timestamps and no side effects.", "requestBody": { "description": "Audio transcription request", "required": true, @@ -549,7 +549,7 @@ }, "/api/content": { "patch": { - "description": "Apply ffmpeg edits to a video — trim, crop, resize, or overlay text. Pass a `template` for a preset edit pipeline, or build your own with an `operations` array.", + "description": "Apply ffmpeg edits to a video \u2014 trim, crop, resize, or overlay text. Pass a `template` for a preset edit pipeline, or build your own with an `operations` array.", "security": [ { "apiKeyAuth": [] @@ -581,7 +581,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -591,7 +591,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -615,7 +615,8 @@ }, "/api/content/create": { "post": { - "description": "Trigger the content creation pipeline for an artist. Provide `artist_account_id` to identify the target artist. Validates the artist has all required files (face guide, songs) unless overridden via `songs` URLs or `images`, then triggers a background task that generates a short-form video. Returns `runIds` — an array of run IDs that can each be polled via [GET /api/tasks/runs](/api-reference/tasks/runs).", + "deprecated": true, + "description": "**Legacy pipeline.** Runs the full content-creation pipeline (image, video, caption, edit, upscale) in a single call. Powers the Content Agent Slack bot. New integrations should compose the individual primitives ([`POST /api/content/image`](/api-reference/content/generate-image), [`POST /api/content/video`](/api-reference/content/generate-video), [`POST /api/content/caption`](/api-reference/content/generate-caption), and so on) for finer-grained control.\n\nTriggers the content creation pipeline for an artist. Provide `artist_account_id` to identify the target artist. Validates the artist has all required files (face guide, songs) unless overridden via `songs` URLs or `images`, then triggers a background task that generates a short-form video. Returns `{run_id}` for polling progress via [`GET /api/tasks/runs`](/api-reference/tasks/runs).", "security": [ { "apiKeyAuth": [] @@ -637,7 +638,7 @@ }, "responses": { "202": { - "description": "Pipeline triggered successfully. Returns `runIds` — an array of run IDs. Poll each via [GET /api/tasks/runs](/api-reference/tasks/runs) to check progress.", + "description": "Pipeline triggered successfully. Returns `runIds` \u2014 an array of run IDs. Poll each via [GET /api/tasks/runs](/api-reference/tasks/runs) to check progress.", "content": { "application/json": { "schema": { @@ -647,7 +648,7 @@ } }, "400": { - "description": "Validation failed — missing artist identifier, artist is missing required files, or template not found", + "description": "Validation failed \u2014 missing artist identifier, artist is missing required files, or template not found", "content": { "application/json": { "schema": { @@ -657,7 +658,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -667,7 +668,7 @@ } }, "404": { - "description": "Artist not found — the provided artist_account_id does not match any artist", + "description": "Artist not found \u2014 the provided artist_account_id does not match any artist", "content": { "application/json": { "schema": { @@ -681,7 +682,7 @@ }, "/api/content/templates": { "get": { - "description": "List all available content creation templates. Templates are optional — every content primitive works without one. When you do use a template, it provides a complete creative recipe: image prompts, video motion config, caption style rules, and edit operations. Returns template ID and description only — enough to pick the right one.", + "description": "List all available content creation templates. Templates are optional \u2014 every content primitive works without one. When you do use a template, it provides a complete creative recipe: image prompts, video motion config, caption style rules, and edit operations. Returns template ID and description only \u2014 enough to pick the right one.", "security": [ { "apiKeyAuth": [] @@ -702,7 +703,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -749,7 +750,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -817,7 +818,7 @@ } }, "400": { - "description": "Bad request — artist_account_id is required", + "description": "Bad request \u2014 artist_account_id is required", "content": { "application/json": { "schema": { @@ -827,7 +828,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -837,7 +838,7 @@ } }, "404": { - "description": "Artist not found — the provided artist_account_id does not match any artist", + "description": "Artist not found \u2014 the provided artist_account_id does not match any artist", "content": { "application/json": { "schema": { @@ -851,7 +852,7 @@ }, "/api/content/estimate": { "get": { - "description": "Estimate the cost of running the content creation pipeline. Calculates per-step and per-video costs based on current pricing. Supports comparing multiple workflow profiles (e.g., premium vs. budget) and projecting batch costs. This endpoint is informational only — it does not trigger any pipeline execution or spend credits.", + "description": "Estimate the cost of running the content creation pipeline. Calculates per-step and per-video costs based on current pricing. Supports comparing multiple workflow profiles (e.g., premium vs. budget) and projecting batch costs. This endpoint is informational only \u2014 it does not trigger any pipeline execution or spend credits.", "security": [ { "apiKeyAuth": [] @@ -907,7 +908,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -943,7 +944,7 @@ "application/json": { "schema": { "type": "object", - "description": "Slack Events API envelope — the shape depends on the event type" + "description": "Slack Events API envelope \u2014 the shape depends on the event type" } } } @@ -972,7 +973,7 @@ }, "/api/content-agent/callback": { "post": { - "description": "Internal callback endpoint for the `poll-content-run` Trigger.dev task. Receives content generation results and posts them back to the originating Slack thread. Authenticated via the `x-callback-secret` header.\n\nThis endpoint is not intended for external use — it is called automatically by the polling task when content runs complete, fail, or time out.", + "description": "Internal callback endpoint for the `poll-content-run` Trigger.dev task. Receives content generation results and posts them back to the originating Slack thread. Authenticated via the `x-callback-secret` header.\n\nThis endpoint is not intended for external use \u2014 it is called automatically by the polling task when content runs complete, fail, or time out.", "requestBody": { "description": "Content generation results from the polling task", "required": true, @@ -1109,7 +1110,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1119,7 +1120,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1143,7 +1144,7 @@ }, "/api/content/analyze": { "post": { - "description": "Analyze a video and answer questions about it. Pass a video URL and a text prompt — for example, \"Describe what happens\" or \"Rate the visual quality 1-10.\" Returns the generated text.", + "description": "Analyze a video and answer questions about it. Pass a video URL and a text prompt \u2014 for example, \"Describe what happens\" or \"Rate the visual quality 1-10.\" Returns the generated text.", "security": [ { "apiKeyAuth": [] @@ -1175,7 +1176,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1185,7 +1186,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1241,7 +1242,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1251,7 +1252,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1307,7 +1308,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1317,7 +1318,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1341,7 +1342,7 @@ }, "/api/content/video": { "post": { - "description": "Generate a video. Set `mode` to control what kind of video you get:\n\n- `prompt` — create a video from a text description\n- `animate` — animate a still image\n- `reference` — use an image as a style/subject reference (not the first frame)\n- `extend` — continue an existing video\n- `first-last` — generate a video that transitions between two images\n- `lipsync` — sync face movement to an audio clip\n\nIf `mode` is omitted, it's inferred from the inputs you provide.", + "description": "Generate a video. Set `mode` to control what kind of video you get:\n\n- `prompt` \u2014 create a video from a text description\n- `animate` \u2014 animate a still image\n- `reference` \u2014 use an image as a style/subject reference (not the first frame)\n- `extend` \u2014 continue an existing video\n- `first-last` \u2014 generate a video that transitions between two images\n- `lipsync` \u2014 sync face movement to an audio clip\n\nIf `mode` is omitted, it's inferred from the inputs you provide.", "security": [ { "apiKeyAuth": [] @@ -1373,7 +1374,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1383,7 +1384,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1439,7 +1440,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1449,7 +1450,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1514,7 +1515,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1524,7 +1525,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1581,7 +1582,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1591,7 +1592,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1656,7 +1657,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1666,7 +1667,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1690,7 +1691,7 @@ }, "/api/music/plan": { "post": { - "description": "Create a composition plan from a text prompt. A composition plan is a structured representation of a song — sections, styles, lyrics, and durations — that you can review and tweak before passing to the compose endpoint. This endpoint is free and does not consume credits.", + "description": "Create a composition plan from a text prompt. A composition plan is a structured representation of a song \u2014 sections, styles, lyrics, and durations \u2014 that you can review and tweak before passing to the compose endpoint. This endpoint is free and does not consume credits.", "security": [ { "apiKeyAuth": [] @@ -1722,7 +1723,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1732,7 +1733,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1756,7 +1757,7 @@ }, "/api/music/video-to-music": { "post": { - "description": "Generate background music from video files. Upload 1–10 video files via multipart/form-data (max 200 MB total). The AI analyzes the video content and generates music that matches the mood, pacing, and style. Optionally provide a text description and style tags to guide the output.", + "description": "Generate background music from video files. Upload 1\u201310 video files via multipart/form-data (max 200 MB total). The AI analyzes the video content and generates music that matches the mood, pacing, and style. Optionally provide a text description and style tags to guide the output.", "security": [ { "apiKeyAuth": [] @@ -1834,7 +1835,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1844,7 +1845,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1929,7 +1930,7 @@ } }, "400": { - "description": "Validation failed — invalid or missing request body fields", + "description": "Validation failed \u2014 invalid or missing request body fields", "content": { "application/json": { "schema": { @@ -1939,7 +1940,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -2371,13 +2372,34 @@ }, "aspect_ratio": { "type": "string", - "enum": ["auto", "21:9", "16:9", "3:2", "4:3", "5:4", "1:1", "4:5", "3:4", "2:3", "9:16", "4:1", "1:4", "8:1", "1:8"], + "enum": [ + "auto", + "21:9", + "16:9", + "3:2", + "4:3", + "5:4", + "1:1", + "4:5", + "3:4", + "2:3", + "9:16", + "4:1", + "1:4", + "8:1", + "1:8" + ], "default": "auto", "description": "Aspect ratio of the generated image" }, "resolution": { "type": "string", - "enum": ["0.5K", "1K", "2K", "4K"], + "enum": [ + "0.5K", + "1K", + "2K", + "4K" + ], "default": "1K", "description": "Output resolution" }, @@ -2460,7 +2482,7 @@ "items": { "type": "string" }, - "description": "Optional list of song slugs or public URLs to use for the audio track. Song slugs match filenames without extension from the artist's `songs/` directory (e.g. `\"hiccups\"` for `hiccups.mp3`). Public URLs (e.g. `\"https://example.com/my-song.mp3\"`) are downloaded, transcribed, and clipped directly — bypassing the Git repo. When omitted, all songs in the artist's repo are eligible.", + "description": "Optional list of song slugs or public URLs to use for the audio track. Song slugs match filenames without extension from the artist's `songs/` directory (e.g. `\"hiccups\"` for `hiccups.mp3`). Public URLs (e.g. `\"https://example.com/my-song.mp3\"`) are downloaded, transcribed, and clipped directly \u2014 bypassing the Git repo. When omitted, all songs in the artist's repo are eligible.", "example": [ "hiccups", "https://example.com/unreleased-track.mp3" @@ -2489,7 +2511,7 @@ "status", "artist_account_id" ], - "description": "Confirmation that the content creation pipeline has been triggered. Always returns `runIds` as an array — even for a single run, it contains one element.", + "description": "Confirmation that the content creation pipeline has been triggered. Always returns `runIds` as an array \u2014 even for a single run, it contains one element.", "properties": { "runIds": { "type": "array", @@ -2678,7 +2700,7 @@ "image_url": { "type": "string", "format": "uri", - "description": "Required. Image URL used as the input frame. The underlying model (fal-ai/veo3.1/fast/image-to-video) requires an image — text-only prompt mode is not supported. Generate an image first via POST /api/content/image if needed." + "description": "Required. Image URL used as the input frame. The underlying model (fal-ai/veo3.1/fast/image-to-video) requires an image \u2014 text-only prompt mode is not supported. Generate an image first via POST /api/content/image if needed." }, "end_image_url": { "type": "string", @@ -2949,7 +2971,7 @@ "id", "description" ], - "description": "A content creation template — a complete creative recipe defining visual style, composition, caption rules, and edit operations. Templates are optional; all primitives work without one.", + "description": "A content creation template \u2014 a complete creative recipe defining visual style, composition, caption rules, and edit operations. Templates are optional; all primitives work without one.", "properties": { "id": { "type": "string", @@ -3556,7 +3578,7 @@ "properties": { "prompt": { "type": "string", - "description": "Text prompt describing the desired song — mood, genre, instruments, lyrics, structure." + "description": "Text prompt describing the desired song \u2014 mood, genre, instruments, lyrics, structure." }, "composition_plan": { "type": "object", @@ -3590,7 +3612,7 @@ "properties": { "prompt": { "type": "string", - "description": "Text prompt describing the desired song — mood, genre, instruments, lyrics, structure." + "description": "Text prompt describing the desired song \u2014 mood, genre, instruments, lyrics, structure." }, "composition_plan": { "type": "object", @@ -3681,7 +3703,7 @@ "properties": { "prompt": { "type": "string", - "description": "Text prompt describing the desired song — mood, genre, instruments, lyrics, structure." + "description": "Text prompt describing the desired song \u2014 mood, genre, instruments, lyrics, structure." }, "composition_plan": { "type": "object", diff --git a/api-reference/openapi/releases.json b/api-reference/openapi/releases.json index 464f8159..2eb16d34 100644 --- a/api-reference/openapi/releases.json +++ b/api-reference/openapi/releases.json @@ -139,11 +139,15 @@ } }, "patch": { - "summary": "Update scheduled task", + "summary": "Update Task", "description": "Update an existing scheduled task. Only the id field is required; any additional fields you include will be updated on the task. The response shape matches the GET endpoint (an array containing the updated task).", "security": [ - { "apiKeyAuth": [] }, - { "bearerAuth": [] } + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } ], "requestBody": { "description": "JSON object with `id` and optional fields to merge onto the task.", @@ -192,7 +196,7 @@ } }, "400": { - "description": "Bad request — missing `id`, empty strings where a field is provided, or other validation failure from the request body. The body reports the first Zod issue via `missing_fields` and `error`.", + "description": "Bad request \u2014 missing `id`, empty strings where a field is provided, or other validation failure from the request body. The body reports the first Zod issue via `missing_fields` and `error`.", "content": { "application/json": { "schema": { @@ -496,13 +500,13 @@ } } }, - "400": { - "description": "Bad request - invalid artist ID path parameter", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PinArtistErrorResponse" - } + "400": { + "description": "Bad request - invalid artist ID path parameter", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PinArtistErrorResponse" + } } } }, @@ -546,29 +550,29 @@ } ], "responses": { - "200": { - "description": "Artist unpinned.", - "content": { - "application/json": { - "schema": { + "200": { + "description": "Artist unpinned.", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/PinArtistResponse" } - } - } - }, - "400": { - "description": "Bad request - invalid artist ID path parameter", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PinArtistErrorResponse" + } } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid authentication" - }, + }, + "400": { + "description": "Bad request - invalid artist ID path parameter", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PinArtistErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid authentication" + }, "403": { "description": "Forbidden - the authenticated account cannot access this artist", "content": { @@ -1338,7 +1342,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key / Bearer token", + "description": "Unauthorized \u2014 invalid or missing API key / Bearer token", "content": { "application/json": { "schema": { @@ -1352,7 +1356,7 @@ }, "/api/songs/analyze": { "post": { - "description": "Analyze music using a state-of-the-art Audio Language Model that listens directly to the audio waveform. Unlike text-based AI, this model processes the actual sound — identifying harmony, structure, timbre, lyrics, and cultural context through deep music understanding. Supports audio up to 20 minutes (MP3, WAV, FLAC). Two modes: (1) **Presets** — pass a `preset` name like `catalog_metadata`, `mood_tags`, or `full_report` for structured, optimized output. (2) **Custom prompt** — pass a `prompt` for free-form questions. The `full_report` preset runs all 13 presets in parallel and returns a comprehensive music intelligence report. Use `GET /api/songs/analyze/presets` to list available presets.", + "description": "Analyze music using a state-of-the-art Audio Language Model that listens directly to the audio waveform. Unlike text-based AI, this model processes the actual sound \u2014 identifying harmony, structure, timbre, lyrics, and cultural context through deep music understanding. Supports audio up to 20 minutes (MP3, WAV, FLAC). Two modes: (1) **Presets** \u2014 pass a `preset` name like `catalog_metadata`, `mood_tags`, or `full_report` for structured, optimized output. (2) **Custom prompt** \u2014 pass a `prompt` for free-form questions. The `full_report` preset runs all 13 presets in parallel and returns a comprehensive music intelligence report. Use `GET /api/songs/analyze/presets` to list available presets.", "security": [ { "apiKeyAuth": [] @@ -1384,7 +1388,7 @@ } }, "400": { - "description": "Bad request — missing or invalid fields", + "description": "Bad request \u2014 missing or invalid fields", "content": { "application/json": { "schema": { @@ -1394,7 +1398,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key / Bearer token", + "description": "Unauthorized \u2014 invalid or missing API key / Bearer token", "content": { "application/json": { "schema": { @@ -1404,7 +1408,7 @@ } }, "500": { - "description": "Server error — upstream model unavailable or inference failed", + "description": "Server error \u2014 upstream model unavailable or inference failed", "content": { "application/json": { "schema": { @@ -2722,7 +2726,7 @@ "audio_url": { "type": "string", "format": "uri", - "description": "Public URL to an audio file (MP3, WAV, or FLAC — up to 20 minutes)", + "description": "Public URL to an audio file (MP3, WAV, or FLAC \u2014 up to 20 minutes)", "example": "https://example.com/song.mp3" }, "max_new_tokens": { @@ -2738,7 +2742,7 @@ "minimum": 0, "maximum": 2, "default": 1, - "description": "Controls output creativity — higher values produce more varied responses", + "description": "Controls output creativity \u2014 higher values produce more varied responses", "example": 0.7 }, "top_p": { @@ -3381,7 +3385,7 @@ }, "profileUrls": { "type": "object", - "description": "Map of uppercase platform identifier to social profile URL. Each entry replaces the existing social for that platform; platforms not included are preserved. Recognized keys: SPOTIFY, INSTAGRAM, TIKTOK, TWITTER, YOUTUBE, APPLE, FACEBOOK, THREADS. Keys are matched case-sensitively — lowercase keys will create duplicate socials instead of replacing the existing entry.", + "description": "Map of uppercase platform identifier to social profile URL. Each entry replaces the existing social for that platform; platforms not included are preserved. Recognized keys: SPOTIFY, INSTAGRAM, TIKTOK, TWITTER, YOUTUBE, APPLE, FACEBOOK, THREADS. Keys are matched case-sensitively \u2014 lowercase keys will create duplicate socials instead of replacing the existing entry.", "additionalProperties": { "type": "string" }, diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index 5a292243..343aaa91 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -195,7 +195,7 @@ } }, "delete": { - "description": "Delete a chat room by ID. This operation also removes related room records (memory emails, memories) before deleting the room itself.", + "description": "Delete a chat room by ID. This operation also removes related room records (memory emails, messages) before deleting the room itself.", "requestBody": { "description": "Chat deletion parameters", "required": true, @@ -332,7 +332,7 @@ }, "/api/chats/{id}/messages": { "get": { - "description": "Retrieve all messages (memories) for a specific chat room in chronological order.", + "description": "Retrieve all messages for a specific chat room in chronological order.", "parameters": [ { "name": "id", @@ -3030,7 +3030,7 @@ "id": { "type": "string", "format": "uuid", - "description": "UUID of the memory message" + "description": "UUID of the message" }, "room_id": { "type": "string", @@ -3039,12 +3039,12 @@ }, "content": { "type": "object", - "description": "Structured message payload stored for the memory" + "description": "Structured message payload" }, "updated_at": { "type": "string", "format": "date-time", - "description": "ISO timestamp of the memory update" + "description": "ISO timestamp of the message update" } } }, diff --git a/api-reference/research/search.mdx b/api-reference/research/search.mdx index 482602a7..5aa0160d 100644 --- a/api-reference/research/search.mdx +++ b/api-reference/research/search.mdx @@ -1,4 +1,4 @@ --- -title: 'Search' +title: 'Artist Search' openapi: "/api-reference/openapi/research.json GET /api/research" --- diff --git a/api-reference/spotify/search.mdx b/api-reference/spotify/search.mdx index f49c5460..2b0f1938 100644 --- a/api-reference/spotify/search.mdx +++ b/api-reference/spotify/search.mdx @@ -1,4 +1,4 @@ --- -title: 'Search' +title: 'Spotify Search' openapi: "/api-reference/openapi/social.json GET /api/spotify/search" --- diff --git a/api-reference/transcribe/audio.mdx b/api-reference/transcribe/audio.mdx index 30861ee2..3a13871f 100644 --- a/api-reference/transcribe/audio.mdx +++ b/api-reference/transcribe/audio.mdx @@ -1,4 +1,4 @@ --- -title: 'Transcribe Audio' +title: 'Transcribe Audio (Legacy)' openapi: "/api-reference/openapi/content.json POST /api/transcribe" --- diff --git a/content-agent.mdx b/content-agent.mdx index 4f78a55e..cd7d9a36 100644 --- a/content-agent.mdx +++ b/content-agent.mdx @@ -1,112 +1,11 @@ --- -title: 'Content' -description: 'Generate images, videos, captions, and social-ready content using AI-powered primitives' +title: "Content Agent" +description: "AI content creation agent accessible via Slack — generates social-ready artist videos on @mention." --- -## Overview +The Recoup Content Agent is a Slack bot that generates social-ready artist videos on @mention. It connects to the content creation pipeline and delivers results directly in your Slack thread. -Recoup's content API gives you seven independent primitives for generating and editing visual content. Each primitive does one thing well. You orchestrate them. - -**Every primitive works without a template.** Pass your own prompt, reference images, and parameters directly. Templates are optional shortcuts — opinionated creative recipes that pre-fill parameters for a specific look. - -## Primitives - -| Primitive | Endpoint | What it does | -|-----------|----------|-------------| -| Generate Image | [POST /api/content/image](/api-reference/content/generate-image) | Create an image from a text prompt, optionally with a reference image for face/style | -| Generate Video | [POST /api/content/video](/api-reference/content/generate-video) | Create a video — 6 modes: prompt, animate, reference, extend, first-last, lipsync | -| Generate Caption | [POST /api/content/caption](/api-reference/content/generate-caption) | Generate on-screen text for social media videos | -| Transcribe Audio | [POST /api/content/transcribe](/api-reference/content/transcribe-audio) | Transcribe audio to timestamped lyrics/text | -| Edit Content | [PATCH /api/content](/api-reference/content/edit) | Trim, crop, resize, overlay text, or add audio — one processing pass | -| Upscale | [POST /api/content/upscale](/api-reference/content/upscale) | Upscale image or video resolution (up to 4x) | -| Analyze Video | [POST /api/content/analyze](/api-reference/content/analyze-video) | AI video analysis — describe scenes, check quality, evaluate content | - -There is also [POST /api/content/create](/api-reference/content/create) which runs the full pipeline in one call — use it when you want a video without creative control over each step. - -## How It Works - -### Without a template (malleable mode) - -Pass your own parameters directly to any primitive. Maximum creative control. - -```bash -# Generate an image with your own prompt -curl -X POST https://recoup-api.vercel.app/api/content/image \ - -H "x-api-key: YOUR_KEY" \ - -H "Content-Type: application/json" \ - -d '{"prompt": "A moody portrait in a dimly lit room, front-facing phone camera"}' - -# Generate a video from that image -curl -X POST https://recoup-api.vercel.app/api/content/video \ - -H "x-api-key: YOUR_KEY" \ - -H "Content-Type: application/json" \ - -d '{"image_url": "IMAGE_URL_FROM_ABOVE", "prompt": "subtle breathing motion, nearly still"}' -``` - -### With a template (shortcut mode) - -Pass a template ID and the primitive fills in prompts, reference images, and style rules automatically. You can still override any parameter. - -```bash -# Same image, but the template provides the prompt and reference images -curl -X POST https://recoup-api.vercel.app/api/content/image \ - -H "x-api-key: YOUR_KEY" \ - -H "Content-Type: application/json" \ - -d '{"template": "artist-caption-bedroom", "reference_image_url": "YOUR_FACE_IMAGE"}' -``` - -Use [GET /api/content/templates](/api-reference/content/templates) to see available templates with descriptions. - -## Templates - -A template is a complete creative recipe — it defines what a piece of content looks like across every primitive: - -- **Image config**: prompt, reference images, style rules (camera, lighting, composition) -- **Video config**: mood variations, movement descriptions -- **Caption config**: tone, formatting rules, example captions -- **Edit config**: crop ratio, text overlay style, audio mixing - -Templates are optional. They save time by pre-filling parameters with curated defaults. When you see customers repeatedly creating the same kind of content, that pattern becomes a template. - -### Override priority - -When using a template, your explicit parameters always win: - -1. **Your params** — highest priority. What you pass overrides everything. -2. **Artist context** — if the artist has a style guide, it personalizes the template. -3. **Template defaults** — lowest priority. The recipe's built-in values. - -## Video Modes - -The video primitive supports 6 generation modes: - -| Mode | What it does | Required inputs | -|------|-------------|-----------------| -| `prompt` | Create from text description | `prompt` | -| `animate` | Animate a still image | `image_url`, `prompt` | -| `reference` | Use image as style reference (not first frame) | `image_url`, `prompt` | -| `extend` | Continue an existing video | `video_url`, `prompt` | -| `first-last` | Transition between two images | `image_url`, `end_image_url`, `prompt` | -| `lipsync` | Sync face to audio | `image_url`, `audio_url` | - -Set `mode` explicitly, or omit it and the API infers the mode from the inputs you provide. - -## Iteration - -Each primitive is independent. Redo any step without rerunning the whole pipeline: - -- Bad image? Regenerate with a different prompt or reference -- Caption too long? Regenerate with `length: "short"` -- Video glitchy? Analyze it, then regenerate with adjusted params -- Clip too short? Use `extend` mode to continue it -- Low quality? Upscale the image or video -- Everything good but wrong caption? Just re-run the edit step - -## Content Agent (Slack Bot) - -The **Recoup Content Agent** is a Slack bot that generates social-ready artist videos on @mention. It plugs into the content creation pipeline and delivers results directly in your Slack thread. - -### @Mention Syntax +## @Mention syntax ``` @RecoupContentAgent [template] [batch=N] [lipsync] @@ -115,13 +14,13 @@ The **Recoup Content Agent** is a Slack bot that generates social-ready artist v | Parameter | Required | Description | |-----------|----------|-------------| | `artist_account_id` | Yes | UUID of the artist account | -| `template` | No | Content template name. Optional — when omitted, the pipeline runs with default settings. See [GET /api/content/templates](/api-reference/content/templates) for options. | -| `batch=N` | No | Number of videos to generate (1-30, default 1) | +| `template` | No | Content template name — see [GET /api/content/templates](/api-reference/content/templates) | +| `batch=N` | No | Number of videos to generate (1–30, default 1) | | `lipsync` | No | Enable lipsync mode (audio baked into video) | -### Examples +## Examples -**Basic — single video with default template:** +**Single video with default template:** ``` @RecoupContentAgent abc-123-uuid ``` @@ -136,66 +35,95 @@ The **Recoup Content Agent** is a Slack bot that generates social-ready artist v @RecoupContentAgent abc-123-uuid batch=3 lipsync ``` -### Architecture +--- + +## Endpoints it uses + +The content API provides seven independent endpoints. Each does one thing well. You orchestrate them. + +| Endpoint | Path | What it does | +|-----------|----------|-------------| +| Generate Image | [POST /api/content/image](/api-reference/content/generate-image) | Create an image from a text prompt with optional reference image | +| Generate Video | [POST /api/content/video](/api-reference/content/generate-video) | Create a video — 6 modes: prompt, animate, reference, extend, first-last, lipsync | +| Generate Caption | [POST /api/content/caption](/api-reference/content/generate-caption) | Generate on-screen text for social media videos | +| Transcribe Audio | [POST /api/content/transcribe](/api-reference/content/transcribe-audio) | Transcribe audio to timestamped lyrics/text | +| Edit Content | [PATCH /api/content](/api-reference/content/edit) | Trim, crop, resize, overlay text, or add audio | +| Upscale | [POST /api/content/upscale](/api-reference/content/upscale) | Upscale image or video resolution (up to 4x) | +| Analyze Video | [POST /api/content/analyze](/api-reference/content/analyze-video) | AI video analysis — describe scenes, check quality | + + +[`POST /api/content/create`](/api-reference/content/create) (legacy) runs the full pipeline in a single call. It still works, but new integrations should call the individual endpoints above directly — the pipeline is being phased out. + -| Component | Location | Purpose | -|-----------|----------|---------| -| Slack webhook | `POST /api/content-agent/slack` | Receives @mention events | -| Callback endpoint | `POST /api/content-agent/callback` | Receives polling results | -| Bot singleton | `lib/content-agent/bot.ts` | Chat SDK with Slack adapter + Redis state | -| Mention handler | `lib/content-agent/handlers/` | Parses args, validates artist, triggers pipeline | -| Poll task | `poll-content-run` (Trigger.dev) | Monitors content runs, posts results via callback | +## Video modes -### Data Flow +| Mode | What it does | Required inputs | +|------|-------------|-----------------| +| `prompt` | Create from text description | `prompt` | +| `animate` | Animate a still image | `image_url`, `prompt` | +| `reference` | Use image as style reference | `image_url`, `prompt` | +| `extend` | Continue an existing video | `video_url`, `prompt` | +| `first-last` | Transition between two images | `image_url`, `end_image_url`, `prompt` | +| `lipsync` | Sync face to audio | `image_url`, `audio_url` | + +--- + +## Architecture + +| Component | Purpose | +|-----------|---------| +| Slack webhook (`POST /api/content-agent/slack`) | Receives @mention events | +| Callback endpoint (`POST /api/content-agent/callback`) | Receives polling results | +| Bot singleton (`lib/content-agent/bot.ts`) | Chat SDK with Slack adapter + Redis state | +| Mention handler (`lib/content-agent/handlers/`) | Parses args, validates artist, triggers pipeline | +| Poll task (`poll-content-run`) | Monitors runs, posts results via callback | + +## Data flow 1. **Slack event** → `POST /api/content-agent/slack` handles the webhook -2. **Mention handler** parses the command, calls [`GET /api/content/validate`](/api-reference/content/validate) to check artist readiness -3. **Content creation** triggered via [`POST /api/content/create`](/api-reference/content/create) — returns `runIds` -4. **Poll task** (`poll-content-run`) monitors the Trigger.dev runs every 30 seconds (up to 30 minutes) -5. **Callback** → [`POST /api/content-agent/callback`](/api-reference/content-agent/callback) receives results and posts video URLs back to the Slack thread +2. **Mention handler** parses the command, calls [`GET /api/content/validate`](/api-reference/content/validate) +3. **Content creation** triggered via [`POST /api/content/create`](/api-reference/content/create) +4. **Poll task** monitors runs every 30 seconds (up to 30 minutes) +5. **Callback** posts video URLs back to the Slack thread + +--- -### Setup +## Setup -#### 1. Create a Slack App +### 1. Create a Slack App -1. Go to [api.slack.com/apps](https://api.slack.com/apps) and create a new app -2. Under **OAuth & Permissions**, add bot scopes: - - `chat:write` — post messages - - `app_mentions:read` — receive @mention events -3. Under **Event Subscriptions**: - - Enable events - - Set the request URL to `https://recoup-api.vercel.app/api/content-agent/slack` - - Subscribe to `app_mention` bot event -4. Install the app to your workspace +1. Go to [api.slack.com/apps](https://api.slack.com/apps) +2. Add bot scopes: `chat:write`, `app_mentions:read` +3. Enable Event Subscriptions → set request URL to `https://recoup-api.vercel.app/api/content-agent/slack` +4. Subscribe to `app_mention` bot event +5. Install the app to your workspace -#### 2. Configure Environment Variables +### 2. Configure environment variables | Variable | Where | Description | |----------|-------|-------------| -| `SLACK_CONTENT_BOT_TOKEN` | API (Vercel) | Bot OAuth token (`xoxb-...`) from Slack app | -| `SLACK_CONTENT_SIGNING_SECRET` | API (Vercel) | Signing secret from Slack app **Basic Information** | -| `CONTENT_AGENT_CALLBACK_SECRET` | API + Tasks | Shared secret for callback authentication (generate a random string) | -| `RECOUP_API_KEY` | API + Tasks | Recoup API key for authenticating pipeline requests | -| `RECOUP_API_BASE_URL` | Tasks (Trigger.dev) | API base URL (e.g., `https://recoup-api.vercel.app`) | +| `SLACK_CONTENT_BOT_TOKEN` | API | Bot OAuth token (`xoxb-...`) | +| `SLACK_CONTENT_SIGNING_SECRET` | API | Signing secret from Slack app | +| `CONTENT_AGENT_CALLBACK_SECRET` | API + Tasks | Shared secret for callback auth | +| `RECOUP_API_KEY` | API + Tasks | Recoup API key for pipeline requests | +| `RECOUP_API_BASE_URL` | Tasks | API base URL | -#### 3. Verify +### 3. Verify -Mention the bot in any Slack channel where it's been added: +Mention the bot in any channel where it's been added: ``` @RecoupContentAgent ``` -You should see: -1. An immediate acknowledgment message -2. A video URL reply in the thread after ~5-10 minutes +You should see an immediate acknowledgment followed by a video URL reply in the thread after ~5–10 minutes. -### Troubleshooting +## Troubleshooting | Issue | Cause | Fix | |-------|-------|-----| | No response from bot | Event subscription URL not configured | Check Slack app Event Subscriptions | | "Artist not found" | Invalid `artist_account_id` | Verify the UUID exists in the platform | -| "No GitHub repository found" | Artist missing repo config | Ensure the artist account has a linked GitHub repo | -| Timeout after 30 min | Pipeline took too long | Check Trigger.dev dashboard for the failed run | -| "Unsupported template" | Invalid template name | Use [`GET /api/content/templates`](/api-reference/content/templates) to list available templates | +| "No GitHub repository found" | Artist missing repo config | Ensure the artist has a linked GitHub repo | +| Timeout after 30 min | Pipeline took too long | Check Trigger.dev dashboard | +| "Unsupported template" | Invalid template name | Use [`GET /api/content/templates`](/api-reference/content/templates) |