diff --git a/agents.mdx b/agents.mdx
index 8bbf1f04..d2fbeed9 100644
--- a/agents.mdx
+++ b/agents.mdx
@@ -1,96 +1,147 @@
---
-title: 'Agents'
-description: 'Programmatic agent onboarding — sign up and obtain API keys in one call, no dashboard, no human in the loop.'
+title: "Agent Onboarding"
+description: "The operating manual for AI agents using the Recoup API."
---
-## Quickest start
+This page is for AI agents. Follow these steps in order.
+
+## 1. Authenticate
+
+If your human has an API key, pass it via `x-api-key`. If not, generate one:
+
+
+
+ ```bash
+ curl -X POST "https://recoup-api.vercel.app/api/agents/signup" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "user@example.com"}'
+ ```
+
+
+ A 6-digit code was sent to their inbox. Ask them: *"Check your email for a verification code and share it with me."*
+
+
+ ```bash
+ curl -X POST "https://recoup-api.vercel.app/api/agents/verify" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "user@example.com", "code": "123456"}'
+ ```
+ Store the returned `api_key`. Pass it as `x-api-key` on every request.
+
+
+
+**After authenticating, immediately check the roster.** Don't wait for the human to tell you what to do.
+
+
+`agent+` emails create a **separate account** — `agent+user@example.com` is NOT linked to `user@example.com`. To work on behalf of an existing human, use their real email.
+
-Get a working API key in a single unauthenticated request:
-
-```bash
-curl -X POST "https://recoup-api.vercel.app/api/agents/signup" \
- -H "Content-Type: application/json" \
- -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}'
-```
-
-Response:
-
-```json
-{
- "account_id": "123e4567-e89b-12d3-a456-426614174000",
- "api_key": "recoup_sk_abc123...",
- "message": "If this is a new agent+ email, your API key is included. Otherwise, check your email for a verification code."
-}
-```
+---
-That's it. Store `api_key`, pass it in the `x-api-key` header on every subsequent request, and you're done.
+## 2. Understand the roster
-
-**One-liner — sign up and export the key in one shot.** Drop this into your shell and you'll have `$RECOUP_API_KEY` ready to use on the next line:
+After getting a key, your next call should always be to check what the human has:
```bash
-export RECOUP_API_KEY=$(curl -s -X POST "https://recoup-api.vercel.app/api/agents/signup" \
- -H "Content-Type: application/json" \
- -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}' | jq -r .api_key)
+# List all artists available to this account
+curl "https://recoup-api.vercel.app/api/artists" \
+ -H "x-api-key: $API_KEY"
+
+# List organizations (labels/teams) the account belongs to
+curl "https://recoup-api.vercel.app/api/organizations" \
+ -H "x-api-key: $API_KEY"
```
-Verify it worked:
+**If the human has artists**, you can scope work to a specific artist by passing `artist_account_id` on supported endpoints. Research, content, tasks, and fan data all become artist-specific.
-```bash
-curl -H "x-api-key: $RECOUP_API_KEY" https://recoup-api.vercel.app/api/accounts/id
-```
-
+**If the human has organizations**, pass `organization_id` to scope to a specific label's roster.
-
-The `agent+{unique-suffix}@recoupable.com` shape is the recommended path for agents — it always returns an API key instantly, with no email verification required. Combining `$(date +%s)` with `$RANDOM` guarantees a fresh, collision-free address on every call (including multiple signups within the same second) and is portable across macOS and Linux shells.
-
+**If neither is specified**, you operate at the account level and can see everything available to the human.
-## How it works
+---
-Two unauthenticated endpoints power agent onboarding:
+## 3. Know the filesystem
-- **[`POST /api/agents/signup`](/api-reference/agents/signup)** — Register with an email address. Emails with the `agent+` prefix that have never been seen before receive an API key immediately. Any other email (or a previously-used `agent+` address) receives a 6-digit verification code via email.
-- **[`POST /api/agents/verify`](/api-reference/agents/verify)** — Submit the verification code to receive an API key.
+Each account has a persistent filesystem backed by a GitHub repo. This is where artist context lives — the files agents use to do informed work.
-Multiple API keys per account are supported — each signup or verification generates a new key without revoking existing ones.
+### Artist directory structure
-## Standard signup (email verification)
+```
+orgs/{org-name}/artists/{artist-slug}/
+├── RECOUP.md # Identity file (artistName, artistSlug, artistId)
+├── context/
+│ ├── artist.md # Brand voice, bio, constraints
+│ ├── audience.md # Audience insights, resonance
+│ ├── era.json # Current era metadata
+│ └── images/
+│ └── face-guide.png # Face reference for visual content
+├── songs/{song-slug}/
+│ └── {song-slug}.mp3 # Audio files
+├── releases/{release-slug}/
+│ └── RELEASE.md # Release plan and metadata
+└── config/
+ └── content-creation/
+ └── config.json # Pipeline overrides
+```
-If you're building a human-facing integration and want the user to verify their real email, use any non-`agent+` address:
+The `RECOUP.md` file ties the folder to the platform — it contains YAML frontmatter with `artistName`, `artistSlug`, and `artistId`.
-Step 1 — request a verification code:
+### Accessing sandbox files
```bash
-curl -X POST "https://recoup-api.vercel.app/api/agents/signup" \
+# List the full file tree
+curl "https://recoup-api.vercel.app/api/sandboxes" \
+ -H "x-api-key: $API_KEY"
+
+# Read a specific file
+curl "https://recoup-api.vercel.app/api/sandboxes/file?path=orgs/my-label/artists/drake/context/artist.md" \
+ -H "x-api-key: $API_KEY"
+
+# Upload files to the repo
+# path is top-level (target directory); each file needs url + name
+curl -X POST "https://recoup-api.vercel.app/api/sandboxes/files" \
+ -H "x-api-key: $API_KEY" \
-H "Content-Type: application/json" \
- -d '{"email": "you@example.com"}'
+ -d '{"path": "orgs/my-label/artists/drake/context", "files": [{"url": "https://...", "name": "audience.md"}]}'
```
-Step 2 — submit the 6-digit code from the verification email:
+---
-```bash
-curl -X POST "https://recoup-api.vercel.app/api/agents/verify" \
- -H "Content-Type: application/json" \
- -d '{"email": "you@example.com", "code": "123456"}'
-```
+## 4. Decide what to do
-Response:
+
+
+ Call `GET /api/artists`. If they have artists, list them and ask which one to work with. If not, you can research any artist with `GET /api/research?q=...` or create one with `POST /api/artists`.
+
+
+ **Research** — use the 30+ research endpoints. Pass `artist_account_id` to scope to a rostered artist, or search by name for any artist globally.
-```json
-{
- "account_id": "123e4567-e89b-12d3-a456-426614174000",
- "api_key": "recoup_sk_abc123...",
- "message": "Verified"
-}
-```
+ **Content** — generate images, videos, and captions with the content endpoints. Artist context from the filesystem makes output more on-brand.
-## Using your API key
+ **Manage** — plan and track releases by creating and updating `RELEASE.md` files in the artist's `releases/` directory. Add songs to catalogs, update artist context, and organize the roster.
+
+
+ Save research, generated content, or notes to the artist's directory in the filesystem so future calls have more context. Use `POST /api/sandboxes/files` to upload files to the repo.
+
+
+ If the human asks for something more than once, or if the work is time-sensitive and repeating, turn it into a task with `POST /api/tasks`.
-Pass the returned `api_key` in the `x-api-key` header on every authenticated request:
+ Good candidates for tasks:
+ - Daily or weekly reports (streaming stats, fan growth, playlist adds)
+ - Monitoring competitors or trending artists
+ - Generating recurring content (weekly social posts, monthly recaps)
+ - Checking release milestones as a date approaches
-```bash
-curl -X GET "https://recoup-api.vercel.app/api/tasks" \
- -H "x-api-key: YOUR_API_KEY"
+ If the human only needs it once, just do it. Don't create a task for everything.
+
+
+
+---
+
+## Base URL
+
+```
+https://recoup-api.vercel.app/api
```
-See [Authentication](/authentication) for the full authentication model, including organization access and Bearer token support, and [Quickstart](/quickstart) for your first end-to-end request.
+All endpoints require `x-api-key` header unless noted. See [Authentication](/authentication) for the full auth model, and the [endpoint map](/#for-ai-agents) for every available endpoint.
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/authentication.mdx b/authentication.mdx
index e7b7850e..ff5bde36 100644
--- a/authentication.mdx
+++ b/authentication.mdx
@@ -1,115 +1,109 @@
---
title: "Authentication"
-description: "How authentication works in the Recoup API — API keys, access tokens, and organization access control."
+description: "API keys and Bearer tokens — how to authenticate every request to the Recoup API."
---
-## Overview
+**Use API keys** for server-to-server, CLI, and agent integrations. **Use Bearer tokens** for frontend apps authenticated via Privy. Include exactly one — providing both returns `401`.
-Every request to the Recoup API must be authenticated using exactly one of two mechanisms:
-
-| Method | Header | Use case |
+| Method | Header | Best for |
|--------|--------|----------|
-| API Key | `x-api-key` | Server-to-server integrations |
-| Access Token | `Authorization: Bearer ` | Frontend apps authenticated via Privy |
-
-Providing both headers in the same request will result in a `401` error.
+| API Key | `x-api-key` | Servers, scripts, CLI, AI agents |
+| Bearer Token | `Authorization: Bearer ` | Frontend apps via Privy |
-Agent onboarding endpoints (`POST /api/agents/signup` and `POST /api/agents/verify`) are **unauthenticated** — they exist so agents can obtain their first API key. See the [Agents guide](/agents) for details.
+The [agent signup and verify](/agents) endpoints (`POST /api/agents/signup` and `POST /api/agents/verify`) are both unauthenticated — they let agents get their first key without any credentials.
---
-## API Keys
+## Create a key
+
+### Sign up via API
+
+```bash
+# Step 1 — request a code
+curl -X POST "https://recoup-api.vercel.app/api/agents/signup" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "you@example.com"}'
+
+# Step 2 — submit the code from your inbox
+curl -X POST "https://recoup-api.vercel.app/api/agents/verify" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "you@example.com", "code": "123456"}'
+```
-API keys are the primary way to authenticate programmatic access to the Recoup API. All API keys are **personal keys** — they are always tied to the account that created them.
+When an agent runs the same flow on behalf of a human, the agent passes the code the human reads back from their inbox.
-### Creating an API Key
+### From the dashboard
-1. Navigate to [chat.recoupable.com/keys](https://chat.recoupable.com/keys)
-2. Enter a descriptive name (e.g. `"Production Server"`)
-3. Click **Create API Key**
+Go to [chat.recoupable.com/keys](https://chat.recoupable.com/keys), sign in, and create a key.
-Copy your API key immediately — it is only shown once. Keys are stored as a secure HMAC-SHA256 hash and cannot be retrieved after creation.
+Keys are shown once. They are stored as HMAC-SHA256 hashes and cannot be retrieved after creation.
-### Using an API Key
+---
-Pass your key in the `x-api-key` header:
+## Use a key
```bash
-curl -X GET "https://recoup-api.vercel.app/api/tasks" \
+curl "https://recoup-api.vercel.app/api/research?q=Drake" \
-H "x-api-key: YOUR_API_KEY"
```
-### Access to Organizations
+---
-If your account belongs to one or more organizations, your API key can access data across those organizations by passing an `account_id` parameter on supported endpoints. This lets you filter to any account within an organization your key has access to.
+## Organization access
-- **No org membership** — the key can only access its own account's data
-- **Org member** — the key can pass `account_id` to filter to any account within that organization
+If your account belongs to an organization, your key can access data for any account in that org by passing `account_id`:
-
-Org membership is determined by the account's [organizations](/api-reference/organizations/list). An account gains access to an org when it is added as a member.
-
+- **No org** — key accesses its own data only
+- **Org member** — key can pass `account_id` to access any member's data
---
-## Access Tokens (Privy)
+## Bearer tokens (Privy)
-If you're building a frontend application that authenticates users via [Privy](https://privy.io), you can pass the user's Privy JWT as a Bearer token instead of an API key.
+For frontend apps with [Privy](https://privy.io) authentication:
```bash
-curl -X GET "https://recoup-api.vercel.app/api/tasks" \
+curl "https://recoup-api.vercel.app/api/tasks" \
-H "Authorization: Bearer YOUR_PRIVY_JWT"
```
-The API validates the token against Privy, extracts the user's email, and resolves it to the corresponding Recoup account. Bearer tokens always authenticate as a personal account — they cannot act on behalf of an organization.
+The API validates the JWT against Privy, extracts the user's email, and resolves it to a Recoup account.
---
-## How We Verify Access on API Calls
-
-Every authenticated request goes through `validateAuthContext`, which enforces the following access rules:
+## Access control
-### API Key or Bearer Token
-
-By default, requests access the key owner's own account. When `account_id` is provided:
+Scoping parameters follow the same organization-membership rule:
```
-Request includes account_id override?
- ├── Same as key owner → Allowed (self-access)
- ├── Key owner is a member of an org that contains account_id → Allowed
- └── No matching org membership → 403 Forbidden
+Request includes account_id?
+ ├── Same as key owner → allowed
+ ├── Shares an organization → allowed
+ └── No shared org → 403
+
+Request includes organization_id?
+ ├── Key owner is a member of that org → allowed
+ └── Not a member → 403
+
+Request includes artist_account_id?
+ ├── Artist belongs to the key owner → allowed
+ ├── Artist belongs to an org the key owner is a member of → allowed
+ └── Neither → 403
```
-Membership is verified by checking the key owner's [organizations](/api-reference/organizations/list) for a record linking the account to the target account's organization.
-
-
-The Recoup internal admin organization has universal access to all accounts.
-
-
-### Organization Access via `organization_id`
-
-Some endpoints accept an `organization_id` parameter. When provided, the API additionally validates that the authenticated account is either:
-
-- A **member** of the organization, or
-- The **organization account itself**
-
----
-
-## Error Responses
+## Errors
| Status | Cause |
|--------|-------|
-| `401` | Missing or invalid credentials, or both `x-api-key` and `Authorization` headers provided |
-| `403` | Valid credentials but insufficient access to the requested `account_id` or `organization_id` |
-
----
+| `401` | Missing/invalid credentials, or both headers |
+| `403` | Valid credentials, insufficient access |
-## Security Notes
+## Security
-- API keys are **never stored in plaintext** — only an HMAC-SHA256 hash (keyed with your project secret) is persisted in the database
-- **Never include `account_id` in your API key creation request** — the account is always derived from your authenticated credentials
-- Rotate keys immediately if compromised via the [API Keys Management Page](https://chat.recoupable.com/keys)
+- Keys stored as HMAC-SHA256 hashes — never plaintext
+- Rotate compromised keys at [chat.recoupable.com/keys](https://chat.recoupable.com/keys)
+- Never commit keys to version control
diff --git a/cli.mdx b/cli.mdx
index f64a3615..95145bfc 100644
--- a/cli.mdx
+++ b/cli.mdx
@@ -1,19 +1,25 @@
---
title: "CLI"
-description: "Install and use the Recoup CLI to interact with the platform from your terminal."
+description: "Install the Recoup CLI and interact with the platform from your terminal."
---
-The Recoup CLI (`@recoupable/cli`) is a command-line wrapper around the Recoup API. It's available as a global npm package and is pre-installed in sandbox environments.
+The Recoup CLI (`@recoupable/cli`) wraps the Recoup API for terminal-first workflows. It's available as a global npm package and comes pre-installed in sandbox environments.
-## Installation
+
+**The CLI is in beta.** The commands listed below are what's shipped today (v0.1.13). For research workflows and most content operations, call the [REST API](/api-reference) directly — the CLI is gradually catching up.
+
+**Agents:** if a command isn't listed below, don't retry — fall back to the corresponding REST endpoint linked under each command.
+
+
+## Install
```bash
npm install -g @recoupable/cli
```
-## Authentication
+## Authenticate
-Set your API key as an environment variable. You can get a key from the [API Keys page](https://chat.recoupable.com/keys).
+Set your API key as an environment variable:
```bash
export RECOUP_API_KEY=your-api-key
@@ -25,6 +31,10 @@ Verify it works:
recoup whoami
```
+
+Get an API key from the [API Keys page](https://chat.recoupable.com/keys) or use the [agent signup](/agents) for instant key generation.
+
+
## Configuration
| Variable | Required | Default | Description |
@@ -34,7 +44,11 @@ recoup whoami
All commands support `--json` for machine-readable output and `--help` for usage info.
-## whoami
+---
+
+## Commands
+
+### whoami
Show the authenticated account. See [`GET /api/accounts/id`](/api-reference/accounts/id).
@@ -43,50 +57,44 @@ recoup whoami
recoup whoami --json
```
-## orgs
+### orgs
-Manage organizations. See [`GET /api/organizations`](/api-reference/organizations/list).
+List organizations. See [`GET /api/organizations`](/api-reference/organizations/list).
```bash
recoup orgs list
recoup orgs list --account
-recoup orgs list --json
```
-## artists
+### artists
-Manage artists. See [`GET /api/artists`](/api-reference/artists/list).
+List artists. See [`GET /api/artists`](/api-reference/artists/list).
```bash
recoup artists list
recoup artists list --org
recoup artists list --account
-recoup artists list --json
```
-## notifications
+### notifications
-Send a notification email to the authenticated account's email address. The recipient is automatically resolved from your API key — no need to specify a `to` address.
+Send a notification email to the authenticated account. See [`POST /api/notifications`](/api-reference/notifications/create).
```bash
recoup notifications --subject "Pulse Report" --text "Here's your weekly summary."
-recoup notifications --subject "Update" --cc manager@example.com --text "New release scheduled."
-recoup notifications --subject "Weekly Pulse" --html "
"
```
| Flag | Required | Description |
|------|----------|-------------|
| `--subject ` | Yes | Email subject line |
-| `--text ` | No | Plain text or Markdown body (rendered as HTML) |
+| `--text ` | No | Plain text or Markdown body |
| `--html ` | No | Raw HTML body (takes precedence over `--text`) |
| `--cc ` | No | CC recipient (repeatable) |
| `--room-id ` | No | Room ID for a chat link in the email footer |
| `--account ` | No | Send to a specific account (org keys only) |
-This command wraps [`POST /api/notifications`](/api-reference/notifications/create).
-
-## chats
+### chats
Manage chats. See [`GET /api/chats`](/api-reference/chat/chats) and [`POST /api/chats`](/api-reference/chat/create).
@@ -94,10 +102,9 @@ Manage chats. See [`GET /api/chats`](/api-reference/chat/chats) and [`POST /api/
recoup chats list
recoup chats create --name "My Topic"
recoup chats create --name "My Topic" --artist
-recoup chats list --json
```
-## sandboxes
+### sandboxes
Manage sandboxes. See [`GET /api/sandboxes`](/api-reference/sandboxes/list) and [`POST /api/sandboxes`](/api-reference/sandboxes/create).
@@ -105,399 +112,69 @@ Manage sandboxes. See [`GET /api/sandboxes`](/api-reference/sandboxes/list) and
recoup sandboxes list
recoup sandboxes create
recoup sandboxes create --command "ls -la"
-recoup sandboxes list --json
```
-## tasks
+### tasks
-Check the status of background task runs. See [`GET /api/tasks/runs`](/api-reference/tasks/runs).
+Check background task status. See [`GET /api/tasks/runs`](/api-reference/tasks/runs).
```bash
recoup tasks status --run
-recoup tasks status --run --json
-```
-
-| Flag | Required | Description |
-|------|----------|-------------|
-| `--run ` | Yes | Trigger.dev run ID |
-
-## research
-
-Music industry research — streaming metrics, audience demographics, playlist placements, competitive analysis, and web intelligence. All data is accessed through your `RECOUP_API_KEY`.
-
-Artist-scoped commands (like `metrics`, `audience`, `similar`) accept an **artist name** or a **Recoup artist ID** (UUID). The API resolves the artist automatically. If the name is ambiguous (multiple matches), the API returns the top results for disambiguation.
-
-### Search for an artist
-
-```bash
-recoup research "Drake"
-recoup research "Phoebe Bridgers" --json
-```
-
-See [`GET /api/research`](/api-reference/research/search).
-
-### Lookup by platform URL
-
-Find an artist from a Spotify URL, Apple Music link, or any platform ID.
-
-```bash
-recoup research lookup "https://open.spotify.com/artist/3TVXtAsR1Inumwj472S9r4"
-recoup research lookup "3TVXtAsR1Inumwj472S9r4"
-```
-
-See [`GET /api/research/lookup`](/api-reference/research/lookup).
-
-### Artist profile and career
-
-```bash
-recoup research profile "Drake"
-recoup research career "Drake"
-recoup research insights "Drake"
-```
-
-| Subcommand | Description | API endpoint |
-|------------|-------------|-------------|
-| `profile` | Full artist profile — bio, genres, social URLs, label | [`GET /api/research/profile`](/api-reference/research/profile) |
-| `career` | Career timeline and key milestones | [`GET /api/research/career`](/api-reference/research/career) |
-| `insights` | AI-generated observations and trends | [`GET /api/research/insights`](/api-reference/research/insights) |
-
-### Streaming and social metrics
-
-Get platform-specific metrics over time. Supports 14 platforms.
-
-```bash
-recoup research metrics "Drake" --source spotify
-recoup research metrics "Drake" --source instagram
-recoup research metrics "Drake" --source tiktok
-recoup research metrics "Drake" --source youtube_channel
```
-Valid `--source` values: `spotify`, `instagram`, `tiktok`, `twitter`, `facebook`, `youtube_channel`, `youtube_artist`, `soundcloud`, `deezer`, `twitch`, `line`, `melon`, `wikipedia`, `bandsintown`.
-
-See [`GET /api/research/metrics`](/api-reference/research/metrics).
+### songs
-### Audience and geography
+Run AI music analysis. See [`POST /api/songs/analyze`](/api-reference/songs/analyze) and [`GET /api/songs/analyze/presets`](/api-reference/songs/analyze-presets).
```bash
-recoup research audience "Drake"
-recoup research audience "Drake" --platform tiktok
-recoup research audience "Drake" --platform youtube
-recoup research cities "Drake"
-```
-
-| Subcommand | Description | API endpoint |
-|------------|-------------|-------------|
-| `audience` | Age, gender, country breakdown. `--platform`: `instagram` (default), `tiktok`, `youtube` | [`GET /api/research/audience`](/api-reference/research/audience) |
-| `cities` | Top cities by listener concentration | [`GET /api/research/cities`](/api-reference/research/cities) |
-
-### Social URLs
-
-Get all social and streaming links for an artist.
-
-```bash
-recoup research urls "Drake"
-```
-
-See [`GET /api/research/urls`](/api-reference/research/urls).
-
-### Instagram posts
-
-Get an artist's top Instagram posts and reels by engagement.
-
-```bash
-recoup research instagram-posts "Drake"
-```
-
-See [`GET /api/research/instagram-posts`](/api-reference/research/instagram-posts).
-
-### Competitive landscape
-
-```bash
-recoup research similar "Drake"
-recoup research similar "Drake" --audience high --genre high --limit 20
-```
-
-Configuration options: `--audience`, `--genre`, `--mood`, `--musicality` (values: `high`, `medium`, `low`).
-
-See [`GET /api/research/similar`](/api-reference/research/similar).
-
-### Playlists
-
-```bash
-recoup research playlists "Drake"
-recoup research playlists "Drake" --platform applemusic
-recoup research playlists "Drake" --editorial
-recoup research playlists "Drake" --status past --since 2025-01-01
-recoup research playlists "Drake" --sort followers --limit 50
-```
-
-| Flag | Description |
-|------|-------------|
-| `--platform
` | `spotify` (default), `applemusic`, `deezer`, `amazon`, `youtube` |
-| `--editorial` | Only editorial playlists |
-| `--status ` | `current` (default) or `past` |
-| `--since ` | Filter by date (YYYY-MM-DD) |
-| `--sort ` | Sort results (e.g., `followers`) |
-| `--limit ` | Max results |
-
-See [`GET /api/research/playlists`](/api-reference/research/playlists).
-
-### Discography
-
-```bash
-recoup research albums "Drake"
-recoup research tracks "Drake"
-```
-
-See [`GET /api/research/albums`](/api-reference/research/albums) and [`GET /api/research/tracks`](/api-reference/research/tracks).
-
-### Track details
-
-Get metadata for a specific track — look up by name or Spotify URL.
-
-```bash
-recoup research track "God's Plan"
-recoup research track "https://open.spotify.com/track/2grjqo0Frpf2..."
-```
-
-See [`GET /api/research/track`](/api-reference/research/track).
-
-### Playlist and curator details
-
-Get metadata for a specific playlist or its curator.
-
-```bash
-recoup research playlist spotify 37i9dQZF1DXcBWIGoYBM5M
-recoup research curator spotify 1
-```
-
-See [`GET /api/research/playlist`](/api-reference/research/playlist) and [`GET /api/research/curator`](/api-reference/research/curator).
-
-### Discover artists
-
-Find artists by criteria — country, genre, listener ranges, growth rate.
-
-```bash
-recoup research discover --country US --spotify-listeners 100000 500000
-recoup research discover --genre 86 --sort weekly_diff.sp_monthly_listeners
-```
-
-| Flag | Description |
-|------|-------------|
-| `--country ` | ISO country code (US, BR, GB, etc.) |
-| `--genre ` | Genre ID (use `recoup research genres` to list) |
-| `--spotify-listeners ` | Monthly listener range |
-| `--sort ` | Sort field (e.g., `weekly_diff.sp_monthly_listeners`) |
-| `--limit ` | Max results |
-
-See [`GET /api/research/discover`](/api-reference/research/discover).
-
-### Milestones
-
-Get an artist's activity feed — playlist adds, chart entries, and notable events.
-
-```bash
-recoup research milestones "Drake"
-recoup research milestones "Drake" --json
-```
-
-See [`GET /api/research/milestones`](/api-reference/research/milestones).
-
-### Venues
-
-Get venues an artist has performed at, including capacity and location.
-
-```bash
-recoup research venues "Drake"
-recoup research venues "Drake" --json
-```
-
-See [`GET /api/research/venues`](/api-reference/research/venues).
-
-### Rank
-
-Get an artist's global Chartmetric ranking.
-
-```bash
-recoup research rank "Drake"
-recoup research rank "Drake" --json
-```
-
-See [`GET /api/research/rank`](/api-reference/research/rank).
-
-### Charts
-
-Get global chart positions for a platform. NOT artist-scoped — returns the full chart.
-
-```bash
-recoup research charts --platform spotify
-recoup research charts --platform spotify --country US
-recoup research charts --platform applemusic --country GB --interval weekly --json
+recoup songs presets
+recoup songs analyze --preset catalog_metadata --audio https://example.com/track.mp3
+recoup songs analyze --prompt "Describe the production style" --audio https://example.com/track.mp3
```
| Flag | Required | Description |
|------|----------|-------------|
-| `--platform ` | Yes | Chart platform (spotify, applemusic, tiktok, youtube, itunes, shazam) |
-| `--country ` | No | ISO country code (US, GB, DE, etc.) |
-| `--interval ` | No | Time interval (e.g. daily, weekly) |
-| `--type ` | No | Chart type (varies by platform) |
-| `--latest` | No | Return only the most recent chart |
-
-See [`GET /api/research/charts`](/api-reference/research/charts).
-
-### Radio stations
-
-List radio stations tracked by Chartmetric.
-
-```bash
-recoup research radio
-recoup research radio --json
-```
-
-See [`GET /api/research/radio`](/api-reference/research/radio).
-
-### Reference data
-
-```bash
-recoup research genres
-recoup research festivals
-```
-
-See [`GET /api/research/genres`](/api-reference/research/genres) and [`GET /api/research/festivals`](/api-reference/research/festivals).
-
-### Web research
-
-Search the web for narrative context, press coverage, and cultural information that structured data doesn't cover.
-
-```bash
-recoup research web "Drake brand partnerships sync licensing"
-recoup research web "Phoebe Bridgers fan community psychographics"
-```
-
-See [`POST /api/research/web`](/api-reference/research/web).
-
-### Deep research report
-
-Comprehensive multi-source research that synthesizes information from across the web into a cited report.
-
-```bash
-recoup research report "Drake"
-recoup research report "Tell me everything about Phoebe Bridgers — bio, streaming metrics, fan base, competitive landscape, and revenue opportunities"
-```
-
-See [`POST /api/research/deep`](/api-reference/research/deep).
-
-### People search
-
-Search for people in the music industry — artists, managers, A&R reps, producers. Returns profiles with LinkedIn data.
-
-```bash
-recoup research people "A&R reps at Atlantic Records"
-recoup research people "music managers in Los Angeles R&B"
-```
-
-See [`POST /api/research/people`](/api-reference/research/people).
-
-### Extract URL
-
-Extract clean markdown content from any public URL. Handles JavaScript-heavy pages and PDFs.
-
-```bash
-recoup research extract "https://en.wikipedia.org/wiki/Drake_(musician)" --objective "biography and discography"
-recoup research extract "https://open.spotify.com/artist/..." --full-content
-```
-
-Accepts up to 10 URLs per call.
-
-See [`POST /api/research/extract`](/api-reference/research/extract).
-
-### Enrich
-
-Get structured data about any entity from web research. Provide a description and a JSON schema — get typed data back with citations.
-
-```bash
-recoup research enrich "Drake rapper" --schema '{"properties": {"real_name": {"type": "string"}, "label": {"type": "string"}, "hometown": {"type": "string"}}}'
-```
-
-Processors: `base` (fast, default), `core` (balanced), `ultra` (comprehensive).
-
-See [`POST /api/research/enrich`](/api-reference/research/enrich).
-
-### Using Recoup artist IDs
-
-Artist IDs are supported on artist-scoped commands (see the note above). Example:
-
-```bash
-recoup research metrics de05ba8c-7e29-4f1a-93a7-3635653599f6 --source spotify
-```
-
-### Workflow example: full artist research
-
-```bash
-# Pull structured data (all by name, run in parallel)
-recoup research metrics "Phoebe Bridgers" --source spotify --json
-recoup research audience "Phoebe Bridgers" --json
-recoup research cities "Phoebe Bridgers" --json
-recoup research similar "Phoebe Bridgers" --audience high --genre high --json
-recoup research playlists "Phoebe Bridgers" --editorial --json
-
-# Add web context
-recoup research web "Phoebe Bridgers biography career milestones" --json
-recoup research web "Phoebe Bridgers fan community brand partnerships" --json
-```
+| `--audio ` | Yes | Public URL to the audio file (MP3, WAV, FLAC) |
+| `--preset ` | No | Curated analysis preset (omit when using `--prompt`) |
+| `--prompt ` | No | Custom text prompt (omit when using `--preset`) |
+| `--max-tokens ` | No | Max tokens to generate (default 512) |
---
## content
-Content-creation pipeline commands. Generate AI-powered social videos for artists.
+Content creation pipeline — generate AI-powered social videos for artists.
### List templates
-List available content templates. See [`GET /api/content/templates`](/api-reference/content/templates).
-
```bash
recoup content templates
-recoup content templates --json
```
-### Validate artist
+### Validate an artist
-Check that an artist has the required assets (face-guide, songs, context files) before creating content. See [`POST /api/content/validate`](/api-reference/content/validate).
+Check that an artist has the required assets before creating content. See [`GET /api/content/validate`](/api-reference/content/validate).
```bash
recoup content validate --artist
-recoup content validate --artist --json
```
-| Flag | Required | Description |
-|------|----------|-------------|
-| `--artist ` | Yes | Artist account ID |
-
### Estimate cost
-Preview the estimated cost and duration for a content run without starting it. See [`POST /api/content/estimate`](/api-reference/content/estimate).
+Preview estimated cost and duration before kicking off the pipeline. See [`POST /api/content/estimate`](/api-reference/content/estimate).
```bash
recoup content estimate --artist
-recoup content estimate --artist --template --json
+recoup content estimate --artist --template
```
-| Flag | Required | Description |
-|------|----------|-------------|
-| `--artist ` | Yes | Artist account ID |
-| `--template ` | No | Template name (default: random) |
-| `--lipsync` | No | Enable lipsync mode |
-| `--upscale` | No | Enable upscaling |
-
### Create content
-Trigger the full content-creation pipeline. Returns a run ID you can check with [`recoup tasks status`](/cli#tasks). See [`POST /api/content`](/api-reference/content/create).
+Run the full content-creation pipeline for an artist. See [`POST /api/content/create`](/api-reference/content/create).
```bash
recoup content create --artist
recoup content create --artist --template --lipsync --upscale
-recoup content create --artist --json
```
| Flag | Required | Description |
@@ -507,3 +184,7 @@ recoup content create --artist --json
| `--lipsync` | No | Enable lipsync mode |
| `--upscale` | No | Enable upscaling |
| `--caption-length ` | No | Max caption length in characters |
+
+
+For finer-grained control (individual image, video, caption, transcription, edit, upscale, or analyze operations), call the [content REST endpoints](/api-reference/content/generate-image) directly. Those primitives aren't yet exposed as individual CLI subcommands.
+
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) |
diff --git a/docs.json b/docs.json
index 9dec041b..8beb0719 100644
--- a/docs.json
+++ b/docs.json
@@ -1,83 +1,72 @@
{
"$schema": "https://mintlify.com/docs.json",
- "theme": "mint",
+ "theme": "sequoia",
"name": "Recoup",
"colors": {
- "primary": "#345A5D",
- "light": "#4A7A7D",
- "dark": "#1E3A3D"
+ "primary": "#0a0a0a",
+ "light": "#ededed",
+ "dark": "#0a0a0a"
},
"favicon": "/favicon.ico",
+ "appearance": {
+ "default": "system"
+ },
+ "fonts": {
+ "heading": {
+ "family": "Geist Pixel Square",
+ "weight": 400,
+ "source": "/fonts/GeistPixel/GeistPixel-Square.woff2",
+ "format": "woff2"
+ },
+ "body": {
+ "family": "Geist",
+ "weight": 400,
+ "source": "/fonts/Geist/Geist-Variable.woff2",
+ "format": "woff2"
+ }
+ },
+ "background": {
+ "color": {
+ "light": "#f3f3f3",
+ "dark": "#171717"
+ }
+ },
+ "styling": {
+ "eyebrows": "breadcrumbs",
+ "codeblocks": "dark"
+ },
+ "icons": {
+ "library": "lucide"
+ },
"navigation": {
"tabs": [
{
- "tab": "Quickstart",
+ "tab": "Overview",
"groups": [
{
- "group": "Getting started",
+ "group": "Start here",
"pages": [
"index",
"quickstart",
- "cli",
- "mcp",
- "authentication"
+ "authentication",
+ "agents"
]
},
{
- "group": "Agents",
+ "group": "Interfaces",
"pages": [
- "agents",
+ "cli",
+ "mcp",
"content-agent"
]
}
]
},
{
- "tab": "Artists",
+ "tab": "Chat",
"groups": [
{
- "group": "Workflows",
- "pages": [
- "workflows/create-artist"
- ]
- },
- {
- "group": "Artists",
- "pages": [
- "api-reference/artists/list",
- "api-reference/artists/create",
- "api-reference/artists/update",
- "api-reference/artists/pin",
- "api-reference/artists/unpin",
- "api-reference/artists/delete",
- "api-reference/artists/socials",
- "api-reference/artist/socials-scrape",
- "api-reference/artist/profile"
- ]
- },
- {
- "group": "Fans",
- "pages": [
- "api-reference/fans/get"
- ]
- },
- {
- "group": "Tasks",
- "pages": [
- "api-reference/tasks/get",
- "api-reference/tasks/create",
- "api-reference/tasks/update",
- "api-reference/tasks/delete",
- "api-reference/tasks/runs"
- ]
- }
- ]
- },
- {
- "tab": "Research",
- "groups": [
- {
- "group": "Chat",
+ "group": "AI Chat",
"pages": [
"api-reference/chat/stream",
"api-reference/chat/create",
@@ -91,7 +80,12 @@
"api-reference/chat/generate",
"api-reference/chat/compact"
]
- },
+ }
+ ]
+ },
+ {
+ "tab": "Research",
+ "groups": [
{
"group": "Artist discovery",
"pages": [
@@ -148,7 +142,7 @@
]
},
{
- "group": "Web & social",
+ "group": "Web intelligence",
"pages": [
"api-reference/research/instagram-posts",
"api-reference/research/web",
@@ -157,19 +151,81 @@
"api-reference/research/extract",
"api-reference/research/enrich"
]
+ },
+ {
+ "group": "Spotify",
+ "pages": [
+ "api-reference/spotify/search",
+ "api-reference/spotify/artist",
+ "api-reference/spotify/artist-albums",
+ "api-reference/spotify/artist-top-tracks",
+ "api-reference/spotify/album"
+ ]
+ },
+ {
+ "group": "Instagram",
+ "pages": [
+ "api-reference/instagram/comments",
+ "api-reference/instagram/profiles"
+ ]
+ },
+ {
+ "group": "Social Scraping",
+ "pages": [
+ "api-reference/social/scrape",
+ "api-reference/apify/scraper"
+ ]
+ }
+ ]
+ },
+ {
+ "tab": "Artists",
+ "groups": [
+ {
+ "group": "Workflows",
+ "pages": [
+ "workflows/create-artist"
+ ]
+ },
+ {
+ "group": "Artist Management",
+ "pages": [
+ "api-reference/artists/list",
+ "api-reference/artists/create",
+ "api-reference/artists/update",
+ "api-reference/artists/pin",
+ "api-reference/artists/unpin",
+ "api-reference/artists/delete",
+ "api-reference/artist/profile",
+ "api-reference/artists/socials",
+ "api-reference/artist/socials-scrape"
+ ]
+ },
+ {
+ "group": "Fans & Posts",
+ "pages": [
+ "api-reference/fans/get",
+ "api-reference/posts/get",
+ "api-reference/comments/get"
+ ]
}
]
},
{
- "tab": "Releases",
+ "tab": "Catalog",
"groups": [
{
- "group": "Songs & Catalogs",
+ "group": "Songs",
"pages": [
"api-reference/songs/songs",
"api-reference/songs/create",
"api-reference/songs/analyze",
- "api-reference/songs/analyze-presets",
+ "api-reference/songs/analyze-presets"
+ ]
+ },
+ {
+ "group": "Catalogs",
+ "pages": [
"api-reference/songs/catalogs",
"api-reference/songs/catalog-songs",
"api-reference/songs/catalog-songs-add",
@@ -182,92 +238,77 @@
"tab": "Content",
"groups": [
{
- "group": "Content Creation",
+ "group": "Generate",
"pages": [
- "api-reference/content/create",
"api-reference/content/generate-image",
"api-reference/content/generate-video",
- "api-reference/content/generate-caption",
- "api-reference/content/transcribe-audio",
- "api-reference/content/edit",
- "api-reference/content/upscale",
- "api-reference/content/analyze-video",
- "api-reference/content/templates",
- "api-reference/content/template-detail",
- "api-reference/content/validate",
- "api-reference/content/estimate"
+ "api-reference/content/generate-caption"
]
},
{
- "group": "Posts & Comments",
+ "group": "Edit",
"pages": [
- "api-reference/posts/get",
- "api-reference/comments/get"
+ "api-reference/content/edit",
+ "api-reference/content/upscale"
]
},
{
- "group": "Content Agent",
+ "group": "Analyze",
"pages": [
- "api-reference/content-agent/webhook",
- "api-reference/content-agent/callback"
+ "api-reference/content/analyze-video",
+ "api-reference/content/transcribe-audio"
]
},
{
- "group": "Image",
+ "group": "Templates",
"pages": [
- "api-reference/image/generation"
+ "api-reference/content/templates",
+ "api-reference/content/template-detail",
+ "api-reference/content/validate",
+ "api-reference/content/estimate"
]
},
{
- "group": "Transcribe",
+ "group": "Legacy",
"pages": [
+ "api-reference/content/create",
+ "api-reference/image/generation",
"api-reference/transcribe/audio"
]
},
{
- "group": "Sandboxes",
+ "group": "Content Agent",
"pages": [
- "api-reference/sandboxes/list",
- "api-reference/sandboxes/create",
- "api-reference/sandboxes/snapshot",
- "api-reference/sandboxes/delete",
- "api-reference/sandboxes/setup",
- "api-reference/sandboxes/file",
- "api-reference/sandboxes/upload"
+ "api-reference/content-agent/webhook",
+ "api-reference/content-agent/callback"
]
}
]
},
{
- "tab": "Social Media",
+ "tab": "Automation",
"groups": [
{
- "group": "Social",
- "pages": [
- "api-reference/social/scrape"
- ]
- },
- {
- "group": "Spotify",
+ "group": "Scheduled Tasks",
"pages": [
- "api-reference/spotify/search",
- "api-reference/spotify/artist",
- "api-reference/spotify/artist-albums",
- "api-reference/spotify/artist-top-tracks",
- "api-reference/spotify/album"
+ "api-reference/tasks/get",
+ "api-reference/tasks/create",
+ "api-reference/tasks/update",
+ "api-reference/tasks/delete",
+ "api-reference/tasks/runs"
]
},
{
- "group": "Instagram",
+ "group": "Pulses",
"pages": [
- "api-reference/instagram/comments",
- "api-reference/instagram/profiles"
+ "api-reference/pulses/update",
+ "api-reference/pulses/list"
]
},
{
- "group": "Apify",
+ "group": "Notifications",
"pages": [
- "api-reference/apify/scraper"
+ "api-reference/notifications/create"
]
}
]
@@ -282,23 +323,6 @@
"api-reference/agents/verify"
]
},
- {
- "group": "Connectors",
- "pages": [
- "api-reference/connectors/list",
- "api-reference/connectors/authorize",
- "api-reference/connectors/disconnect",
- "api-reference/connectors/list-actions",
- "api-reference/connectors/execute-action"
- ]
- },
- {
- "group": "Pulses",
- "pages": [
- "api-reference/pulses/update",
- "api-reference/pulses/list"
- ]
- },
{
"group": "Accounts",
"pages": [
@@ -317,6 +341,28 @@
"api-reference/organizations/add-artist"
]
},
+ {
+ "group": "Sandboxes",
+ "pages": [
+ "api-reference/sandboxes/list",
+ "api-reference/sandboxes/create",
+ "api-reference/sandboxes/snapshot",
+ "api-reference/sandboxes/delete",
+ "api-reference/sandboxes/setup",
+ "api-reference/sandboxes/file",
+ "api-reference/sandboxes/upload"
+ ]
+ },
+ {
+ "group": "Connectors",
+ "pages": [
+ "api-reference/connectors/list",
+ "api-reference/connectors/authorize",
+ "api-reference/connectors/disconnect",
+ "api-reference/connectors/list-actions",
+ "api-reference/connectors/execute-action"
+ ]
+ },
{
"group": "Workspaces",
"pages": [
@@ -337,48 +383,71 @@
"api-reference/admins/sandboxes-orgs",
"api-reference/admins/emails",
"api-reference/admins/privy",
+ "api-reference/admins/agent-signups",
"api-reference/admins/coding-agent-slack-tags",
"api-reference/admins/coding-pr",
"api-reference/admins/content-slack-tags",
- "api-reference/admins/agent-signups",
"api-reference/admins/artists-pro"
]
+ }
+ ]
+ },
+ {
+ "tab": "Skills",
+ "groups": [
+ {
+ "group": "Overview",
+ "pages": [
+ "skills"
+ ]
},
{
- "group": "Notifications",
+ "group": "Foundational",
"pages": [
- "api-reference/notifications/create"
+ "skills/getting-started",
+ "skills/setup-sandbox",
+ "skills/artist-workspace"
+ ]
+ },
+ {
+ "group": "Research & analytics",
+ "pages": [
+ "skills/music-industry-research",
+ "skills/chart-metric",
+ "skills/streaming-growth"
+ ]
+ },
+ {
+ "group": "Creative work",
+ "pages": [
+ "skills/song-writing",
+ "skills/trend-to-song",
+ "skills/content-creation",
+ "skills/release-management"
]
}
]
}
],
"global": {
- "anchors": [
- {
- "anchor": "Recoup App",
- "href": "https://chat.recoupable.com",
- "icon": "rocket"
- },
- {
- "anchor": "Website",
- "href": "https://recoupable.com",
- "icon": "globe"
- },
- {
- "anchor": "Blog",
- "href": "https://research.recoupable.com/",
- "icon": "newspaper"
- }
- ]
+ "anchors": []
}
},
"logo": {
- "light": "/logo/light.svg",
- "dark": "/logo/dark.png"
+ "light": "/logo/wordmark-lightmode.svg",
+ "dark": "/logo/wordmark-darkmode.svg",
+ "href": "https://recoupable.com"
},
"navbar": {
"links": [
+ {
+ "label": "Blog",
+ "href": "https://research.recoupable.com/"
+ },
+ {
+ "label": "GitHub",
+ "href": "https://github.com/recoupable"
+ },
{
"label": "Support",
"href": "mailto:agent@recoupable.com"
@@ -386,8 +455,8 @@
],
"primary": {
"type": "button",
- "label": "Dashboard",
- "href": "https://chat.recoupable.com"
+ "label": "Get API Key",
+ "href": "https://chat.recoupable.com/keys"
}
},
"contextual": {
@@ -405,13 +474,15 @@
"footer": {
"socials": {
"x": "https://x.com/recoupai",
- "github": "https://github.com/recoupable-com",
- "linkedin": "https://www.linkedin.com/company/recoupable"
+ "github": "https://github.com/recoupable",
+ "linkedin": "https://www.linkedin.com/company/recoupable",
+ "website": "https://recoupable.com"
}
},
"metatags": {
"og:image": "/images/icon-with-background.png",
- "og:site_name": "Recoup",
+ "og:site_name": "Recoup API",
+ "og:description": "Music intelligence API \u2014 40+ tools for artist research, content creation, and music business automation. Built for developers and AI agents.",
"twitter:card": "summary_large_image"
}
}
diff --git a/fonts/Geist/Geist-Variable.woff2 b/fonts/Geist/Geist-Variable.woff2
new file mode 100644
index 00000000..b2f01210
Binary files /dev/null and b/fonts/Geist/Geist-Variable.woff2 differ
diff --git a/fonts/Geist/Geist-VariableItalic.woff2 b/fonts/Geist/Geist-VariableItalic.woff2
new file mode 100644
index 00000000..6179bb5e
Binary files /dev/null and b/fonts/Geist/Geist-VariableItalic.woff2 differ
diff --git a/fonts/GeistMono/GeistMono-Variable.woff2 b/fonts/GeistMono/GeistMono-Variable.woff2
new file mode 100644
index 00000000..dbdb8c2d
Binary files /dev/null and b/fonts/GeistMono/GeistMono-Variable.woff2 differ
diff --git a/fonts/GeistMono/GeistMono-VariableItalic.woff2 b/fonts/GeistMono/GeistMono-VariableItalic.woff2
new file mode 100644
index 00000000..7fe203b0
Binary files /dev/null and b/fonts/GeistMono/GeistMono-VariableItalic.woff2 differ
diff --git a/fonts/GeistPixel/GeistPixel-Circle.woff2 b/fonts/GeistPixel/GeistPixel-Circle.woff2
new file mode 100644
index 00000000..100da9fb
Binary files /dev/null and b/fonts/GeistPixel/GeistPixel-Circle.woff2 differ
diff --git a/fonts/GeistPixel/GeistPixel-Grid.woff2 b/fonts/GeistPixel/GeistPixel-Grid.woff2
new file mode 100644
index 00000000..9cfd59fe
Binary files /dev/null and b/fonts/GeistPixel/GeistPixel-Grid.woff2 differ
diff --git a/fonts/GeistPixel/GeistPixel-Line.woff2 b/fonts/GeistPixel/GeistPixel-Line.woff2
new file mode 100644
index 00000000..b4ff341d
Binary files /dev/null and b/fonts/GeistPixel/GeistPixel-Line.woff2 differ
diff --git a/fonts/GeistPixel/GeistPixel-Square.woff2 b/fonts/GeistPixel/GeistPixel-Square.woff2
new file mode 100644
index 00000000..232cae2c
Binary files /dev/null and b/fonts/GeistPixel/GeistPixel-Square.woff2 differ
diff --git a/fonts/GeistPixel/GeistPixel-Triangle.woff2 b/fonts/GeistPixel/GeistPixel-Triangle.woff2
new file mode 100644
index 00000000..c6017a87
Binary files /dev/null and b/fonts/GeistPixel/GeistPixel-Triangle.woff2 differ
diff --git a/fonts/InstrumentSerif/InstrumentSerif-Italic.ttf b/fonts/InstrumentSerif/InstrumentSerif-Italic.ttf
new file mode 100644
index 00000000..32c6b8e4
Binary files /dev/null and b/fonts/InstrumentSerif/InstrumentSerif-Italic.ttf differ
diff --git a/fonts/InstrumentSerif/InstrumentSerif-Regular.ttf b/fonts/InstrumentSerif/InstrumentSerif-Regular.ttf
new file mode 100644
index 00000000..7efd9364
Binary files /dev/null and b/fonts/InstrumentSerif/InstrumentSerif-Regular.ttf differ
diff --git a/fonts/InstrumentSerif/OFL.txt b/fonts/InstrumentSerif/OFL.txt
new file mode 100644
index 00000000..0531e871
--- /dev/null
+++ b/fonts/InstrumentSerif/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2022 The Instrument Serif Project Authors (https://github.com/Instrument/instrument-serif)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/fonts/PlusJakartaSans/PlusJakartaSans-Variable.ttf b/fonts/PlusJakartaSans/PlusJakartaSans-Variable.ttf
new file mode 100644
index 00000000..bdd49850
Binary files /dev/null and b/fonts/PlusJakartaSans/PlusJakartaSans-Variable.ttf differ
diff --git a/fonts/PlusJakartaSans/PlusJakartaSans-VariableItalic.ttf b/fonts/PlusJakartaSans/PlusJakartaSans-VariableItalic.ttf
new file mode 100644
index 00000000..7de3b5b8
Binary files /dev/null and b/fonts/PlusJakartaSans/PlusJakartaSans-VariableItalic.ttf differ
diff --git a/index.mdx b/index.mdx
index e2e5cbf0..df8ead8d 100644
--- a/index.mdx
+++ b/index.mdx
@@ -1,187 +1,214 @@
---
-title: "Recoup API Documentation"
-description: "Use the Recoup API to build your record label. Access research, content creation, chat, artist analytics, social media, and platform management endpoints."
+title: "What is Recoup?"
+description: "Infrastructure for agents to run record labels."
---
-# Welcome to the Recoup API
+
+**AI agent?** Base URL: `https://recoup-api.vercel.app/api`. Use `x-api-key` if your human has a key. Otherwise, `POST /api/agents/signup` with their email — ask them for the verification code from their inbox, then `POST /api/agents/verify` to get a key. [Agent guide →](/agents) | [Endpoint map ↓](#for-ai-agents)
+
-Use the Recoup API to build your record label. Generate content, Access artist analytics, Manage catalogs, Team chats, and task automation to power your record labels.
+Running a record label takes a full team. Research, content, marketing, distribution, fan engagement. Whether you're an artist doing it all yourself or a label team managing a roster, that's a lot of work. That's what agents are for. Recoup captures context around your catalog, artists, releases, and fans, and structures it so agents can perform the work of a major label — programmatically.
-## Quickest start — one curl call
-
-Get a working API key in a single unauthenticated request. No dashboard, no browser, no human in the loop.
-
-```bash
-export RECOUP_API_KEY=$(curl -s -X POST "https://recoup-api.vercel.app/api/agents/signup" \
- -H "Content-Type: application/json" \
- -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}' | jq -r .api_key)
-```
-
-`$RECOUP_API_KEY` is now ready to pass in the `x-api-key` header on any request. See the [Agents guide](/agents) for the full signup and verification flow.
-
-## What is Recoup?
+---
-Recoup is an AI agent platform for smarter song rollouts, unforgettable fan experiences, and lasting artist growth. Empowering music executives with actionable insights and next-gen tools.
+## Core concepts
+
+| Concept | What it is |
+|---------|------------|
+| **Account** | A user or agent that authenticates with an API key. When no artist is specified, you see everything available to the account. |
+| **Organization** | A label or team that groups multiple accounts. Pass `organization_id` to scope to a specific roster. |
+| **Artist** | A managed artist with profile, social handles, and linked catalog. Pass `artist_account_id` to scope to a specific artist. |
+| **Filesystem** | A persistent Git repo where artist context lives — brand voice, audience insights, songs, release plans, and generated content. |
+
+## How it works
+
+The shape of an agent loop on Recoup.
+
+
+
+ Use the human's API key — that's how the agent inherits their roster, label, and history. If they don't have one, `POST /agents/signup` with their email, then pass the verification code from their inbox to `/agents/verify`.
+
+
+ `GET /accounts` and `/organizations` tell you what the human gave the agent access to. Pass `artist_account_id` or `organization_id` on subsequent calls to scope the work.
+
+
+ `/research/*` for outside-world data on any artist. `/artists/*` and `/songs/*` for what's already inside the label. The Filesystem holds the agent's persistent notes — brand voice, audience insights, prior decisions.
+
+
+ Your LLM reasons over the context. Recoup doesn't decide; it gives you the inputs and accepts the outputs. Call `/content/*` to make assets, `/tasks/*` to schedule recurring work, `/notifications/*` to message the human.
+
+
+ Write the new state back to the Filesystem. The next agent run picks up exactly where this one stopped.
+
+
-This is where record labels, musicians, and managers start to build on Recoup AI technology like chat, tasks, agents, and more.
+---
-## Base URL
+## Get an API key
-All API requests should be made to:
+Two calls. No dashboard.
```bash
-https://recoup-api.vercel.app/api
-```
-
-## Authentication
-
-Most API endpoints are authenticated using an API key passed in the `x-api-key` header. The only exceptions are the [agent onboarding](/agents) endpoints — [`POST /api/agents/signup`](/api-reference/agents/signup) and [`POST /api/agents/verify`](/api-reference/agents/verify) — which are intentionally unauthenticated so agents can obtain their first API key.
-
-1. Navigate to the [API Keys Management Page](https://chat.recoupable.com/keys)
-2. Sign in with your account
-3. Create a new API key and copy it immediately (it's only shown once)
+# 1. Trigger a verification code to the human's inbox
+curl -s -X POST "https://recoup-api.vercel.app/api/agents/signup" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "human@example.com"}'
-```bash
-curl -X GET "https://recoup-api.vercel.app/api/artists?accountId=YOUR_ACCOUNT_ID" \
+# 2. Ask the human for the code, then exchange it for a key
+export RECOUP_API_KEY=$(curl -s -X POST "https://recoup-api.vercel.app/api/agents/verify" \
-H "Content-Type: application/json" \
- -H "x-api-key: YOUR_API_KEY"
+ -d '{"email": "human@example.com", "code": "123456"}' | jq -r .api_key)
```
-
-Keep your API key secure. Do not share it publicly or commit it to version control.
-
+
+The key is tied to the human's account, so the agent inherits everything they've already set up — artists, organizations, prior work. See the [Agents guide](/agents) for the full flow.
+
+
+---
-## Get Started
+## Three interfaces
-
+
- Get an API key in one curl call. The fastest path for AI agents — no dashboard required.
+ Standard HTTP endpoints. Pass your API key in `x-api-key` and call any of the 40+ endpoints.
- Get your API key and make your first request in minutes.
+ Connect Claude, ChatGPT, Cursor, or any MCP-compatible agent directly. One URL.
- Install and use the Recoup CLI to interact with the platform from your terminal.
-
-
- Connect Recoup to AI assistants via the Model Context Protocol.
+ `recoup whoami` to verify, `recoup artists list` to explore. Install with `npm i -g @recoupable/cli`.
-## API Sections
+---
+
+## What's in the API
-The API is organized into six main sections. Use these links to jump to the right area.
+Organized by what agents actually do when running a label.
+
+ Stream completions, manage threads, copy or delete messages, compact long histories. 11 endpoints. Pass `artist_account_id` to scope responses to a specific artist.
+
- 30 endpoints for artist research: search, lookup, profile, metrics, audience, cities, similar artists, playlists, albums, tracks, career history, insights, genres, festivals, web presence, and more.
+ 31 endpoints. Streaming metrics, audience demographics, playlist placements, festivals, charts, deep research, and web extraction across Chartmetric, Spotify, Instagram, and X.
- Generate images, videos, and captions. Transcribe audio, edit content, upscale media, analyze videos, manage templates, and estimate costs.
+ Add artists, link social accounts, pin priority work, browse fans, posts, and comments. The people side of your label.
- Conversations with artist context. Create, stream, and generate messages. Copy messages, delete trailing messages, and manage chat history.
+ Songs, catalogs, and AI-driven audio analysis. Organize releases into collections. The music side of your label.
- Spotify, Instagram, X (Twitter), and generic social scraping. Search artists, scrape profiles and comments, track trends, and manage OAuth connectors.
+ 7 endpoints — generate images, videos, captions; transcribe audio; edit, upscale, analyze video. Compose them yourself, end to end.
- Songs, catalogs, and task management. Analyze songs, manage catalog collections, and schedule recurring tasks with cron-based automation.
+ Schedule recurring tasks. Trigger pulses on events. Dispatch notifications when work completes.
- Accounts, organizations, workspaces, subscriptions, pulses, notifications, sandboxes, and admin tools.
+ Sign up agents, scope to organizations, connect external platforms via OAuth, run isolated sandboxes, manage subscriptions.
-## Agents
+---
+
+## Guides
- Content creation agent accessible via Slack. Generates images, videos, and captions for artists automatically.
+ API key → first request → working integration. Under a minute.
- API key authentication, account-scoped access, and organization-level permissions.
+ API keys, Bearer tokens, and organization-level access control.
+
+
+ Programmatic signup for AI agents. API key in two calls (signup + verify) — no browser required.
+
+
+ Slack bot that generates social-ready artist videos on @mention.
-## Quick Reference for LLMs
-
-If you are an LLM navigating these docs, here is a summary of the endpoint structure:
-
-- **`/api/artists/*`** — Artist management (list, create, socials, socials-scrape, profile)
-- **`/api/research/*`** — Artist research (search, lookup, profile, metrics, audience, cities, similar, urls, instagram-posts, playlists, albums, track, tracks, career, insights, genres, festivals, web, deep, people, extract, enrich, milestones, venues, rank, charts, radio, discover, curator, playlist)
-- **`/api/content/*`** — Content creation (create, generate-image, generate-video, generate-caption, transcribe-audio, edit, upscale, analyze-video, templates, validate, estimate)
-- **`/api/chat/*`** — Chat (chats, artist, messages, messages-copy, messages-trailing-delete, create, update, delete, generate, stream, compact)
-- **`/api/songs/*`** — Songs and catalogs (songs, create, analyze, analyze-presets, catalogs, catalogs-create, catalogs-delete, catalog-songs, catalog-songs-add, catalog-songs-delete)
-- **`/api/tasks/*`** — Task automation (get, create, update, delete, runs)
-- **`/api/spotify/*`** — Spotify (search, artist, artist-albums, artist-top-tracks, album)
-- **`/api/instagram/*`** — Instagram (comments, profiles)
-- **`/api/x/*`** — X/Twitter (search, trends)
-- **`/api/connectors/*`** — OAuth connectors (list, authorize, disconnect)
-- **`/api/accounts/*`** — Accounts (get, id, create, update, add-artist)
-- **`/api/organizations/*`** — Organizations (list, create, add-artist)
-- **`/api/sandboxes/*`** — Sandboxes (list, create, snapshot, delete, setup, file, upload)
-- **`/api/content-agent/*`** — Content agent webhooks (webhook, callback)
-- **`/api/agents/*`** — Agent onboarding (signup, verify) — no auth required
-
-Base URL: `https://recoup-api.vercel.app/api`
-
-[OpenAPI Specification](https://github.com/sweetmantech/docs/blob/main/api-reference/openapi.json)
-
-## Need Help?
-
-
- Reach out to our team at agent@recoupable.com for assistance with the Recoup API.
-
+---
+
+## Base URL
+
+```
+https://recoup-api.vercel.app/api
+```
+
+All endpoints require `x-api-key` header authentication unless noted.
+
+---
+
+## For AI agents
+
+If you are an LLM or AI agent, fetch the canonical OpenAPI specifications — they're the single source of truth for endpoint paths, parameters, and response shapes. Base URL: `https://recoup-api.vercel.app/api`.
+
+| Domain | OpenAPI spec |
+|--------|--------------|
+| Research (streaming metrics, audience, playlists, charts, web intelligence) | [`openapi/research.json`](/api-reference/openapi/research.json) |
+| Content (images, videos, captions, transcription, editing, upscaling, analysis) | [`openapi/content.json`](/api-reference/openapi/content.json) |
+| Releases (artists, songs, catalogs) | [`openapi/releases.json`](/api-reference/openapi/releases.json) |
+| Accounts (agents, accounts, organizations, sandboxes, subscriptions, admins) | [`openapi/accounts.json`](/api-reference/openapi/accounts.json) |
+| Social (Spotify, Instagram, X, social scraping, connectors) | [`openapi/social.json`](/api-reference/openapi/social.json) |
+
+Authentication: `x-api-key` header (or `Authorization: Bearer ` for Privy). To get a key, `POST /api/agents/signup` with the human's email, then `POST /api/agents/verify` with the code from their inbox. Full flow at [/agents](/agents).
+
+For a guided entry point by category, use the top navigation — every endpoint has its own reference page.
diff --git a/logo/dark.png b/logo/dark.png
deleted file mode 100644
index edb03d37..00000000
Binary files a/logo/dark.png and /dev/null differ
diff --git a/logo/icon-darkmode.svg b/logo/icon-darkmode.svg
new file mode 100644
index 00000000..e4fa96f1
--- /dev/null
+++ b/logo/icon-darkmode.svg
@@ -0,0 +1,10 @@
+
diff --git a/logo/icon-lightmode.svg b/logo/icon-lightmode.svg
new file mode 100644
index 00000000..04452dc1
--- /dev/null
+++ b/logo/icon-lightmode.svg
@@ -0,0 +1,9 @@
+
diff --git a/logo/light.svg b/logo/light.svg
deleted file mode 100644
index fa35f853..00000000
--- a/logo/light.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/logo/wordmark-darkmode.svg b/logo/wordmark-darkmode.svg
new file mode 100644
index 00000000..772a6f50
--- /dev/null
+++ b/logo/wordmark-darkmode.svg
@@ -0,0 +1,4 @@
+
diff --git a/logo/wordmark-lightmode.svg b/logo/wordmark-lightmode.svg
new file mode 100644
index 00000000..4533ac1a
--- /dev/null
+++ b/logo/wordmark-lightmode.svg
@@ -0,0 +1,4 @@
+
diff --git a/mcp.mdx b/mcp.mdx
index 05709d87..ec24e52b 100644
--- a/mcp.mdx
+++ b/mcp.mdx
@@ -1,78 +1,161 @@
---
-title: "MCP"
-description: "Connect AI agents to the Recoup platform using the Model Context Protocol (MCP) server."
+title: "MCP Server"
+description: "Connect any AI agent to Recoup via the Model Context Protocol — Claude, ChatGPT, Cursor, and 40+ Recoup tools natively."
---
-The Recoup API exposes an [MCP](https://modelcontextprotocol.io/) server that AI agents can connect to for tool use. The server is available at:
+Recoup exposes an [MCP](https://modelcontextprotocol.io/) server so any AI agent can use Recoup tools natively. Claude, ChatGPT, Cursor, Windsurf, and any MCP-compatible agent can research artists across Spotify and the open web, generate images and videos, manage catalogs, schedule tasks, and more — without writing API calls.
```
https://recoup-api.vercel.app/mcp
```
-## Authentication
+## Setup
-All MCP tools require an API key. Pass it as a Bearer token in the `Authorization` header when connecting to the MCP server.
+Pass your API key as a Bearer token when connecting:
-You can get a key from the [API Keys page](https://chat.recoupable.com/keys).
+```typescript
+import { Client } from "@modelcontextprotocol/sdk/client/index.js";
+import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
-## Tools
+const RECOUP_API_KEY = process.env.RECOUP_API_KEY;
-### prompt_sandbox
+const transport = new StreamableHTTPClientTransport(
+ new URL("https://recoup-api.vercel.app/mcp"),
+ { requestInit: { headers: { Authorization: `Bearer ${RECOUP_API_KEY}` } } },
+);
-Send a prompt to OpenClaw running in a persistent per-account sandbox. The sandbox is reused across calls — if one is already running it picks up where you left off, otherwise a new one is created from the account's latest snapshot.
+const client = new Client({ name: "my-agent", version: "1.0.0" });
+await client.connect(transport);
+```
-Returns raw `stdout` and `stderr` from the command. The sandbox stays alive after each prompt for follow-up interactions.
+Get a key from the [API Keys page](https://chat.recoupable.com/keys) or use the [agent signup](/agents) for instant generation.
-**Input schema:**
+
+Privy JWTs are also accepted as Bearer tokens for browser-based agents that already authenticate users via Privy.
+
-| Parameter | Type | Required | Description |
-|-----------|------|----------|-------------|
-| `prompt` | `string` | Yes | The prompt to send to OpenClaw in the sandbox. |
+---
-**Response fields:**
+## Tool catalog
-| Field | Type | Description |
-|-------|------|-------------|
-| `sandboxId` | `string` | The Vercel Sandbox ID. |
-| `stdout` | `string` | Standard output from the command. |
-| `stderr` | `string` | Standard error from the command. |
-| `exitCode` | `number` | Process exit code (`0` = success). |
-| `created` | `boolean` | `true` if a new sandbox was created, `false` if an existing one was reused. |
+The server exposes 40+ tools organized by domain. Every tool returns structured JSON suitable for chaining into multi-step agent workflows.
-**Example usage (TypeScript with MCP SDK):**
+### Artists
-```typescript
-import { Client } from "@modelcontextprotocol/sdk/client/index.js";
-import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
+| Tool | What it does |
+|------|-------------|
+| `create_new_artist` | Create a new artist account in the system. |
+| `get_artist_socials` | Retrieve all socials (handle, avatar, profile URL, bio, follower count, following count) associated with an artist. |
+| `update_artist_socials` | Update the social profiles linked to an artist. |
+| `update_account_info` | Update an artist's `account_info` record. |
-const transport = new StreamableHTTPClientTransport(
- new URL("https://recoup-api.vercel.app/mcp"),
- { requestInit: { headers: { Authorization: `Bearer ${RECOUP_API_KEY}` } } },
-);
+### Catalog
-const client = new Client({ name: "my-agent", version: "1.0.0" });
-await client.connect(transport);
+| Tool | What it does |
+|------|-------------|
+| `select_catalogs` | Get catalogs for an account. |
+| `select_catalog_songs` | Find songs in the catalog for playlists or music recommendation tasks. |
+| `insert_catalog_songs` | Add songs to a catalog by ISRC in batch. |
+
+### Chats
+
+| Tool | What it does |
+|------|-------------|
+| `get_chats` | Get chat conversations for accounts. |
+| `compact_chats` | Compact one or more chat conversations into concise summaries. |
+
+### Content — images, video, audio
+
+| Tool | What it does |
+|------|-------------|
+| `generate_image` | Generate an image from a text prompt. |
+| `edit_image` | Edit existing images. |
+| `search_google_images` | Search for existing images on Google Images. |
+| `generate_sora_2_video` | Generate a video from a text prompt using OpenAI's Sora 2. |
+| `retrieve_sora_2_video` | Retrieve the status and details of a video generation job. |
+| `retrieve_sora_2_video_content` | Download the rendered video content for a completed job. |
+| `transcribe_audio` | Transcribe audio (music, podcast, voice memo) using OpenAI Whisper. |
+| `analyze_music` | Analyze music or answer music questions using Recoup's Audio Language Model. |
+### Research
+
+| Tool | What it does |
+|------|-------------|
+| `search_web` | Default web search tool — use first for any general information lookup. |
+| `web_deep_research` | Multi-source deep web research with comprehensive analysis. |
+| `artist_deep_research` | Comprehensive cross-platform research on a specific artist with a generated report. |
+| `spotify_deep_research` | Deep research on an artist using a Spotify ID. |
+
+### Spotify
+
+| Tool | What it does |
+|------|-------------|
+| `get_spotify_search` | Search Spotify for artists, albums, tracks, or playlists by name. |
+| `get_spotify_album` | Retrieve Spotify catalog information for a single album. |
+| `get_spotify_artist_albums` | Retrieve Spotify catalog information about an artist's albums. |
+| `get_spotify_artist_top_tracks` | Retrieve an artist's top tracks by country. |
+
+### YouTube
+
+| Tool | What it does |
+|------|-------------|
+| `youtube_login` | Check YouTube authentication status for an account. |
+| `get_youtube_channels` | Get YouTube channel information for an account. |
+| `get_youtube_channel_video_list` | Get a list of videos for a specific YouTube channel. |
+| `get_youtube_revenue` | Get estimated revenue for a date range for a YouTube account. |
+| `set_youtube_thumbnail` | Set a custom thumbnail for a YouTube video. |
+
+### Tasks
+
+Background work scheduled and managed through the Recoup task system.
+
+| Tool | What it does |
+|------|-------------|
+| `get_tasks` | List existing tasks. |
+| `create_task` | Create a new task. |
+| `update_task` | Update an existing task. |
+| `delete_task` | Delete a task. |
+| `get_task_run_status` | Get the status of a task run by its run ID. |
+
+### Pulses
+
+| Tool | What it does |
+|------|-------------|
+| `get_pulses` | Get pulse statuses for accounts. |
+| `update_pulse` | Update the pulse status for an account. |
+
+### Sandbox
+
+| Tool | What it does |
+|------|-------------|
+| `prompt_sandbox` | Create a per-account sandbox and run an OpenClaw prompt inside it. Returns the sandbox ID and a run ID for tracking progress. |
+
+### Utilities
+
+| Tool | What it does |
+|------|-------------|
+| `get_local_time` | Get the current local time/date. |
+| `send_email` | Send an email via Resend. |
+| `contact_team` | Send a message to the Recoup team. |
+| `generate_txt_file` | Create a downloadable text file from provided contents. |
+| `create_knowledge_base` | Save a plain-text knowledge base entry to permanent Arweave storage. |
+
+---
+
+## Calling a tool
+
+Once connected, call any tool by name. Example — kick off an OpenClaw prompt in a sandbox:
+
+```typescript
const result = await client.callTool({
name: "prompt_sandbox",
arguments: { prompt: "list all files in the orgs directory" },
});
-
console.log(result.content);
```
-### run_sandbox_command
-
-Create a sandbox and run a shell command or OpenClaw prompt in it. Unlike `prompt_sandbox`, this creates a **new sandbox each call** and runs the command asynchronously via a background task. Returns a sandbox ID and run ID to track progress.
-
-See [`POST /api/sandboxes`](/api-reference/sandboxes/create) for the equivalent REST endpoint.
-
-**Input schema:**
+Each tool's input schema is published over the MCP protocol, so your agent gets typed parameter help automatically.
-| Parameter | Type | Required | Description |
-|-----------|------|----------|-------------|
-| `command` | `string` | No | Shell command to run. Cannot be used with `prompt`. |
-| `args` | `string[]` | No | Arguments for the command. |
-| `cwd` | `string` | No | Working directory for the command. |
-| `prompt` | `string` | No | OpenClaw prompt. Cannot be used with `command`. |
-| `account_id` | `string` | No | Target a specific account (org API keys only). |
+
+**Org-scoped keys** can target any account in their organization by passing `account_id` on tools that accept it. Personal API keys can only operate on their own data.
+
diff --git a/quickstart.mdx b/quickstart.mdx
index 29092dde..85a2a70a 100644
--- a/quickstart.mdx
+++ b/quickstart.mdx
@@ -1,175 +1,126 @@
---
title: "Quickstart"
-description: "Get a Recoup API key in one call and make your first request — no browser, no dashboard."
+description: "API key in 2 calls. First request in minutes. No signup form, no dashboard."
---
-## Quickest start
-
-Sign up your agent and get an API key in a single API call — no dashboard, no browser, no human in the loop. This one-liner signs up a fresh `agent+` address and exports the returned key to `$RECOUP_API_KEY`:
+## 1. Get your API key
```bash
-export RECOUP_API_KEY=$(curl -s -X POST "https://recoup-api.vercel.app/api/agents/signup" \
+# 1. Trigger a verification code to your inbox
+curl -s -X POST "https://recoup-api.vercel.app/api/agents/signup" \
-H "Content-Type: application/json" \
- -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}' | jq -r .api_key)
-```
+ -d '{"email": "you@example.com"}'
-Verify it worked:
-
-```bash
-curl -H "x-api-key: $RECOUP_API_KEY" https://recoup-api.vercel.app/api/accounts/id
+# 2. Check your email, then exchange the code for a key
+export RECOUP_API_KEY=$(curl -s -X POST "https://recoup-api.vercel.app/api/agents/verify" \
+ -H "Content-Type: application/json" \
+ -d '{"email": "you@example.com", "code": "123456"}' | jq -r .api_key)
```
-The `agent+{timestamp}@recoupable.com` shape is the fastest path for agents — it guarantees a fresh `agent+` address and returns an API key instantly without email verification.
+Prefer the dashboard? Create keys at [chat.recoupable.com/keys](https://chat.recoupable.com/keys). See the [Agents guide](/agents) for the full flow including how an agent passes the code on behalf of a human.
-For the full signup + email-verification flow, see the [Agents guide](/agents).
-
-## Base URL
-
-All API requests should be made to:
-
-```bash
-https://recoup-api.vercel.app/api
-```
+---
-## Your First Request
+## 2. Search for an artist
-Once you have an API key, include it in the `x-api-key` header on every request. Here's a simple call that retrieves your scheduled tasks:
+The research API has 30+ endpoints. Start with search — it works for any artist on earth:
```bash cURL
-curl -X GET "https://recoup-api.vercel.app/api/tasks" \
- -H "Content-Type: application/json" \
- -H "x-api-key: YOUR_API_KEY"
+curl "https://recoup-api.vercel.app/api/research?q=Drake" \
+ -H "x-api-key: $RECOUP_API_KEY"
```
```python Python
+import os
import requests
-headers = {
- "Content-Type": "application/json",
- "x-api-key": "YOUR_API_KEY"
-}
-
response = requests.get(
- "https://recoup-api.vercel.app/api/tasks",
- headers=headers
+ "https://recoup-api.vercel.app/api/research",
+ params={"q": "Drake"},
+ headers={"x-api-key": os.environ["RECOUP_API_KEY"]},
)
print(response.json())
```
```javascript JavaScript
-const response = await fetch("https://recoup-api.vercel.app/api/tasks", {
- headers: {
- "Content-Type": "application/json",
- "x-api-key": "YOUR_API_KEY",
- },
-});
-const data = await response.json();
-console.log(data);
-```
-
-```typescript TypeScript
-interface Task {
- id: string;
- title: string;
- prompt: string;
- schedule: string;
- account_id: string;
- artist_account_id: string;
- enabled: boolean;
-}
-
-interface TasksResponse {
- status: "success" | "error";
- tasks: Task[];
-}
-
-const response = await fetch("https://recoup-api.vercel.app/api/tasks", {
- headers: {
- "Content-Type": "application/json",
- "x-api-key": "YOUR_API_KEY",
- },
-});
-const data: TasksResponse = await response.json();
-console.log(data.tasks);
+const response = await fetch(
+ "https://recoup-api.vercel.app/api/research?q=Drake",
+ { headers: { "x-api-key": process.env.RECOUP_API_KEY } },
+);
+console.log(await response.json());
```
-**Example Response:**
-
-```json
-{
- "status": "success",
- "tasks": [
- {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "title": "Daily Fan Report",
- "prompt": "Generate a summary of new fans from the past 24 hours",
- "schedule": "0 9 * * *",
- "account_id": "123e4567-e89b-12d3-a456-426614174000",
- "artist_account_id": "987fcdeb-51a2-3b4c-d5e6-789012345678",
- "enabled": true
- }
- ]
-}
+---
+
+## 3. Go deeper
+
+Once you have an artist, pull data across 14 platforms:
+
+```bash
+# Streaming metrics (Spotify, Instagram, TikTok, YouTube, and 10 more)
+curl "https://recoup-api.vercel.app/api/research/metrics?artist=Drake&source=spotify" \
+ -H "x-api-key: $RECOUP_API_KEY"
+
+# Audience demographics (age, gender, geography)
+curl "https://recoup-api.vercel.app/api/research/audience?artist=Drake" \
+ -H "x-api-key: $RECOUP_API_KEY"
+
+# Editorial playlist placements
+curl "https://recoup-api.vercel.app/api/research/playlists?artist=Drake&editorial=true" \
+ -H "x-api-key: $RECOUP_API_KEY"
```
-
-For full documentation on the Tasks API including filtering options, see the [Tasks API Reference](/api-reference/tasks/get).
-
+See the [Research tab](/api-reference/research/search) for all 30+ research endpoints.
-## Prefer the dashboard?
+---
-If you're a human building an integration, you can also create API keys from the web console instead of the signup endpoint:
+## 4. Connect your AI agent
-1. Navigate to the [Recoup API Keys Management Page](https://chat.recoupable.com/keys)
-2. Sign in with your account
-3. Enter a descriptive name (e.g. "Production Server")
-4. Click **Create API Key**
+If you're using Claude, ChatGPT, Cursor, or any MCP-compatible tool, connect directly:
-
-Copy and securely store your API key immediately — it will only be shown once.
-
+```
+https://recoup-api.vercel.app/mcp
+```
-## Next Steps
+Pass your API key as a Bearer token. Your agent gets access to all 40+ endpoints. See the [MCP guide](/mcp) for setup.
-With your API key ready, you can now:
+---
+
+## Next steps
- Fetch artist profiles and social accounts.
+ 30+ endpoints — metrics across 14 platforms, audience data, playlists, career history, web intelligence.
- Access fan data across all connected social platforms.
+ 7 endpoints for images, videos, captions, transcription, editing, upscaling, and analysis.
- Build AI-powered conversations with artist context.
+ Full command reference — research, content, chats, sandboxes, tasks.
- Schedule and automate recurring tasks.
+ API keys, Bearer tokens, org-level access, and security.
-
-## Support
-
-If you need help or have questions about the API, please contact our support team at [agent@recoupable.com](mailto:agent@recoupable.com).
diff --git a/skills.mdx b/skills.mdx
new file mode 100644
index 00000000..83c5d5a8
--- /dev/null
+++ b/skills.mdx
@@ -0,0 +1,66 @@
+---
+title: "Skills"
+description: "Markdown playbooks that teach AI agents how to do music industry work. The other half of the agent equation."
+---
+
+*An agent asked to "help me grow my new artist past 1,000 monthly listeners" finds the `streaming-growth` skill, loads it, and follows the playbook — playlist pitching benchmarks, Spotify Showcase thresholds, decision frameworks.*
+
+The API tells an agent **how** to take action. Skills tell it **when** and **why**.
+
+A Skill is a markdown file an agent reads to get domain-specific instructions for a task. They live in a separate repo so any agent (Claude Code, Cursor, or your own) can install them without coupling to a specific platform.
+
+The sidebar lists every skill, grouped by purpose. Each docs page summarizes when the agent uses the skill, what it produces, and which API endpoints it depends on. The canonical instructions stay in the source repo on GitHub.
+
+---
+
+## Install
+
+### Claude Code
+
+```bash
+/plugin marketplace add recoupable/skills
+```
+
+### Any other agent
+
+```bash
+git clone https://github.com/recoupable/skills.git
+```
+
+Point your agent at the resulting `skills/` directory. The agent loads each `SKILL.md` and uses its `description` field to decide when the skill applies.
+
+---
+
+## How a Skill is structured
+
+Every skill is a directory with a `SKILL.md` at the root. The `description` field in the YAML frontmatter is what the agent reads to decide when to invoke the skill — write it as a trigger, not a summary.
+
+```text
+skills/
+└── my-skill/
+ ├── SKILL.md ← required (frontmatter + instructions)
+ ├── references/ ← optional — docs the agent loads on demand
+ ├── scripts/ ← optional — executable helpers
+ └── assets/ ← optional — templates, fonts, icons
+```
+
+Minimum viable `SKILL.md`:
+
+```markdown
+---
+name: my-skill
+description: One-line trigger that tells the agent when to use this. Include the kinds of phrases users say — "playlist push," "release plan," "growth strategy."
+---
+
+# My Skill
+
+Step-by-step instructions the agent follows.
+```
+
+---
+
+## Writing your own
+
+Add a directory under `skills/` in [recoupable/skills](https://github.com/recoupable/skills), follow the structure above, and open a PR. See [contributing.md](https://github.com/recoupable/skills/blob/main/contributing.md) for the full guidelines.
+
+The bar: a skill should be specific enough that an agent would correctly invoke it without your help, and complete enough that it can finish the task without asking the user follow-ups it could have answered itself.
diff --git a/skills/artist-workspace.mdx b/skills/artist-workspace.mdx
new file mode 100644
index 00000000..b2c6fce1
--- /dev/null
+++ b/skills/artist-workspace.mdx
@@ -0,0 +1,25 @@
+---
+title: "artist-workspace"
+description: "Manage artist directories — identity, brand, voice, audience, songs, face guides."
+---
+
+Every managed artist has a workspace at `orgs/{org}/artists/{artist-slug}/`. This skill teaches the agent the conventions for what files belong where, when to create them, and how to read existing context before overwriting anything.
+
+## When to use it
+
+Adding or updating any artist-specific context — identity, brand, voice, audience, songs, face guides — or the user mentions an artist by name and the task touches their files. Also runs implicitly before research, content, or release work that needs to be artist-scoped.
+
+## What it produces
+
+Updates inside the artist directory: `RECOUP.md` (workspace anchor), `context/artist.md` (source of truth for who the artist is), `brand/`, `audience/`, `songs/`, `face-guide/` — populated only when there's real content for them.
+
+## Endpoints it uses
+
+- [`GET /api/artists`](/api-reference/artists/list)
+- [`POST /api/artists`](/api-reference/artists/create)
+- [`GET /api/artist-profile`](/api-reference/artist/profile)
+- [`GET /api/artists/{id}/socials`](/api-reference/artists/socials)
+
+## Source
+
+[`recoupable/skills/skills/artist-workspace`](https://github.com/recoupable/skills/tree/main/skills/artist-workspace)
diff --git a/skills/chart-metric.mdx b/skills/chart-metric.mdx
new file mode 100644
index 00000000..a2e3994d
--- /dev/null
+++ b/skills/chart-metric.mdx
@@ -0,0 +1,22 @@
+---
+title: "chart-metric"
+description: "Query and analyze music data from the Chartmetric API directly."
+---
+
+The escape hatch when the Recoup `/api/research/*` endpoints don't expose the field you need. Hits Chartmetric's API directly via Python helper scripts.
+
+## When to use it
+
+You need a data point from Chartmetric that the Recoup research surface doesn't return — usually deeper historical series, raw chart history, or metadata fields the Recoup wrapper omits. For everything Recoup already exposes, use [`music-industry-research`](/skills/music-industry-research) instead.
+
+## What it produces
+
+A direct Chartmetric API response, usually fed back into the agent's reasoning or written to a file in the artist workspace.
+
+## Endpoints it uses
+
+None on the Recoup API. This skill calls Chartmetric directly using a `CHARTMETRIC_REFRESH_TOKEN` environment variable.
+
+## Source
+
+[`recoupable/skills/skills/chart-metric`](https://github.com/recoupable/skills/tree/main/skills/chart-metric)
diff --git a/skills/content-creation.mdx b/skills/content-creation.mdx
new file mode 100644
index 00000000..d8cd8cb2
--- /dev/null
+++ b/skills/content-creation.mdx
@@ -0,0 +1,28 @@
+---
+title: "Content Creation"
+description: "Compose the content endpoints (image, video, caption, transcribe, edit, upscale, analyze) into short-form videos, Reels, TikToks, and lipsync clips."
+---
+
+Turns the seven content primitives into finished assets. Picks the right combination of generate, transcribe, edit, upscale, and analyze for the specific output the user asked for — and iterates on quality (regenerate, re-prompt, re-mux) when the first pass isn't right.
+
+## When to use it
+
+User asks to create content, make a video, generate an image, produce a TikTok or Reel, create a promotional clip, add captions, or create visual content for an artist. Also use when iterating on existing content — regenerating images, trying different audio, adjusting text, upscaling for higher quality.
+
+## What it produces
+
+A finished asset (image, video, captioned clip, lipsync, upscaled version) saved into the artist workspace, with the underlying generation parameters logged for reproducibility.
+
+## Endpoints it uses
+
+- [`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)
+- [`POST /api/content/transcribe`](/api-reference/content/transcribe-audio)
+- [`PATCH /api/content`](/api-reference/content/edit)
+- [`POST /api/content/upscale`](/api-reference/content/upscale)
+- [`POST /api/content/analyze`](/api-reference/content/analyze-video)
+
+## Source
+
+[`recoupable/skills/skills/content-creation`](https://github.com/recoupable/skills/tree/main/skills/content-creation)
diff --git a/skills/getting-started.mdx b/skills/getting-started.mdx
new file mode 100644
index 00000000..05369dad
--- /dev/null
+++ b/skills/getting-started.mdx
@@ -0,0 +1,23 @@
+---
+title: "getting-started"
+description: "Set up Recoup from scratch — get an API key, verify it, and make the first call via REST or MCP."
+---
+
+The agent's bootstrap. Walks through getting an API key, picking REST or MCP, and confirming the key works before any other skill runs.
+
+## When to use it
+
+User says "set up Recoup", "install Recoup", "get an API key", "connect to Recoup", "onboard to Recoup", or an agent needs to configure itself before it can call anything else.
+
+## What it produces
+
+A working `RECOUP_API_KEY` environment variable, the chosen base URL (REST or MCP), and a verified first response.
+
+## Endpoints it uses
+
+- [`POST /api/agents/signup`](/api-reference/agents/signup)
+- [`POST /api/agents/verify`](/api-reference/agents/verify)
+
+## Source
+
+[`recoupable/skills/skills/getting-started`](https://github.com/recoupable/skills/tree/main/skills/getting-started)
diff --git a/skills/music-industry-research.mdx b/skills/music-industry-research.mdx
new file mode 100644
index 00000000..df98e5c4
--- /dev/null
+++ b/skills/music-industry-research.mdx
@@ -0,0 +1,24 @@
+---
+title: "music-industry-research"
+description: "Use the /api/research/* endpoints for analytics, audience demographics, playlists, charts, and people search."
+---
+
+The decision tree for picking the right `/api/research/*` endpoint based on what the user actually asked. Includes a routing table from natural-language questions to specific endpoint combinations.
+
+## When to use it
+
+User asks about an artist's analytics, streaming numbers, audience demographics, playlist placements, similar artists, charts, tour or venue data, or any music industry research. Also triggers on "find me people in [function]," "tell me about [entity]," or "what does this page say."
+
+Common phrasings: "Spotify followers," "monthly listeners," "TikTok trends," "Instagram audience," "playlist pitching," "competitive analysis," "how is [artist] doing," "research [artist]," "find me [people]."
+
+## What it produces
+
+A structured research output answering the user's question — usually a synthesis across multiple `/research/*` calls (e.g. profile + metrics + audience + similar artists), formatted for either the agent's continued reasoning or direct delivery to the user.
+
+## Endpoints it uses
+
+All of [Research](/api-reference/research/search) (31 endpoints). The skill's decision tree picks the minimal set per query.
+
+## Source
+
+[`recoupable/skills/skills/music-industry-research`](https://github.com/recoupable/skills/tree/main/skills/music-industry-research)
diff --git a/skills/release-management.mdx b/skills/release-management.mdx
new file mode 100644
index 00000000..2908061f
--- /dev/null
+++ b/skills/release-management.mdx
@@ -0,0 +1,27 @@
+---
+title: "release-management"
+description: "Plan a release end to end — RELEASE.md documents, DSP pitches, press one-sheets, production specs, tour coordination."
+---
+
+A release campaign — album, EP, single, project — managed via a single `RELEASE.md` document inside the artist workspace. The skill creates, updates, and pulls data from these documents, and generates the deliverables a real release needs (DSP pitches, press one-sheets, production specs, tour coordination notes).
+
+## When to use it
+
+User mentions an artist's album, EP, single, or project, or asks about release planning, DSP pitches, metadata, marketing, press materials, physical production, or tour coordination. The skill first infers which artist and release the user means, then finds or creates the corresponding `RELEASE.md`.
+
+## What it produces
+
+A `RELEASE.md` at `orgs/{org}/artists/{artist-slug}/releases/{release-slug}/` that holds the canonical release plan, plus any of the standard deliverables — DSP one-pager, press release, production spec, tour brief — generated from it.
+
+## Endpoints it uses
+
+- [`POST /api/songs`](/api-reference/songs/create)
+- [`GET /api/songs`](/api-reference/songs/songs)
+- [`GET /api/research/playlists`](/api-reference/research/playlists)
+- [`GET /api/research/curator`](/api-reference/research/curator)
+- [`GET /api/research/festivals`](/api-reference/research/festivals)
+- [`GET /api/research/venues`](/api-reference/research/venues)
+
+## Source
+
+[`recoupable/skills/skills/release-management`](https://github.com/recoupable/skills/tree/main/skills/release-management)
diff --git a/skills/setup-sandbox.mdx b/skills/setup-sandbox.mdx
new file mode 100644
index 00000000..74f7bb7e
--- /dev/null
+++ b/skills/setup-sandbox.mdx
@@ -0,0 +1,24 @@
+---
+title: "setup-sandbox"
+description: "Scaffold the workspace for an account's orgs and artists when a sandbox has no existing file system."
+---
+
+The first run inside a fresh sandbox. Fetches the account's organizations and artists, then creates the directory layout the rest of the skills assume.
+
+## When to use it
+
+A sandbox has just been created and has no existing file system. If the sandbox already has an `orgs/` directory at the root, this skill is a no-op — skip it.
+
+## What it produces
+
+A scaffolded `orgs/{org}/artists/{artist-slug}/` folder tree mirroring the account's actual roster, plus the root `RECOUP.md` files that downstream skills (`artist-workspace`, `release-management`) read to orient themselves.
+
+## Endpoints it uses
+
+- [`GET /api/accounts`](/api-reference/accounts/get)
+- [`GET /api/organizations`](/api-reference/organizations/list)
+- [`GET /api/artists`](/api-reference/artists/list)
+
+## Source
+
+[`recoupable/skills/skills/setup-sandbox`](https://github.com/recoupable/skills/tree/main/skills/setup-sandbox)
diff --git a/skills/song-writing.mdx b/skills/song-writing.mdx
new file mode 100644
index 00000000..30de5348
--- /dev/null
+++ b/skills/song-writing.mdx
@@ -0,0 +1,22 @@
+---
+title: "song-writing"
+description: "Write and evaluate songs using the 7 C's framework — hook, clarity, character, and the rest."
+---
+
+A structured framework for writing and evaluating song lyrics and concepts. The 7 C's check whether a song is memorable, clear, and authentic before it ships.
+
+## When to use it
+
+Brainstorming song ideas, writing lyrics, evaluating song drafts, refining hooks, or improving existing songs. Use it both as a generation guide and as a critique tool when reviewing a draft.
+
+## What it produces
+
+A song or lyric set scored against the 7 C's, with specific revision suggestions for whichever C's are weak. Output is usually written to the artist's `songs/` directory.
+
+## Endpoints it uses
+
+None. Pure methodology — the agent's LLM does the work.
+
+## Source
+
+[`recoupable/skills/skills/song-writing`](https://github.com/recoupable/skills/tree/main/skills/song-writing)
diff --git a/skills/streaming-growth.mdx b/skills/streaming-growth.mdx
new file mode 100644
index 00000000..8478ec91
--- /dev/null
+++ b/skills/streaming-growth.mdx
@@ -0,0 +1,25 @@
+---
+title: "streaming-growth"
+description: "Grow a new artist past the streaming milestones that unlock Spotify Showcase, Marquee, and algorithmic boosting."
+---
+
+A playbook for getting an early-stage artist past the listener thresholds that unlock platform tools — once you're past them, growth compounds. Includes real cost benchmarks (playlist push pricing, ad CPCs, click-to-listen rates) and a decision framework for which path to invest in.
+
+## When to use it
+
+User asks about getting more streams, unlocking Spotify Showcase or Marquee, increasing Spotify Popularity score, playlist pitching, DSP advertising, or growing an artist from near-zero. Triggers: "how do we get more streams," "unlock Spotify ads," "playlist push," "get to a thousand listeners," "artist growth strategy," "Spotify Popularity score."
+
+## What it produces
+
+A growth plan tailored to the artist's current monthly listeners, with a recommended path (playlist pitching vs. paid ads vs. organic) and concrete benchmarks for cost, conversion, and time to threshold.
+
+## Endpoints it uses
+
+- [`GET /api/research/metrics`](/api-reference/research/metrics)
+- [`GET /api/research/audience`](/api-reference/research/audience)
+- [`GET /api/research/playlists`](/api-reference/research/playlists)
+- [`GET /api/research/similar`](/api-reference/research/similar)
+
+## Source
+
+[`recoupable/skills/skills/streaming-growth`](https://github.com/recoupable/skills/tree/main/skills/streaming-growth)
diff --git a/skills/trend-to-song.mdx b/skills/trend-to-song.mdx
new file mode 100644
index 00000000..21214c65
--- /dev/null
+++ b/skills/trend-to-song.mdx
@@ -0,0 +1,25 @@
+---
+title: "trend-to-song"
+description: "Reverse the traditional workflow — start from a cultural moment and build a song + distribution plan around it."
+---
+
+Flips the usual music workflow. Instead of song-first, then marketing — you start from a trend, viral moment, or cultural event and reverse-engineer a song and distribution strategy that lands inside that moment's window.
+
+## When to use it
+
+Someone identifies a trending topic, viral moment, reality TV drama, meme, or cultural event and wants to turn it into a song with a campaign. Triggers: "make a song about this trend," "capitalize on this moment," "reverse engineer from the market," "cultural moment to song," "trend-jack," "burner page strategy."
+
+## What it produces
+
+A trend brief (what the moment is, why it's resonating, who's reacting), a song concept that fits inside it, and a distribution plan — usually involving burner pages, paid promotion, and a tight shipping window before the moment fades.
+
+## Endpoints it uses
+
+- [`POST /api/research/web`](/api-reference/research/web)
+- [`GET /api/research/audience`](/api-reference/research/audience)
+- [`POST /api/content/image`](/api-reference/content/generate-image)
+- [`POST /api/content/video`](/api-reference/content/generate-video)
+
+## Source
+
+[`recoupable/skills/skills/trend-to-song`](https://github.com/recoupable/skills/tree/main/skills/trend-to-song)