diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..df467911 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +superpowers/ diff --git a/agents.mdx b/agents.mdx index 02dfd895..afbc5729 100644 --- a/agents.mdx +++ b/agents.mdx @@ -1,96 +1,173 @@ --- -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 that act on a user's behalf. Follow the steps in order. -Get a working API key in a single unauthenticated request: + +**Just trying the API yourself?** See [Quickstart](/quickstart) for a 5-minute hello-world. This page is the production operating manual. It covers the throwaway-vs-account decision, the roster, the filesystem, and the agent loop. + -```bash -curl -X POST "https://api.recoupable.com/api/agents/signup" \ - -H "Content-Type: application/json" \ - -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}' -``` +## 0. Choose your path -Response: +**Ask the human which path they want before authenticating.** Guessing wrong creates records under a throwaway account that can't be recovered if the API key is lost. The user re-prompts later and their roster is gone. -```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." -} -``` +Use this question. Paraphrase if needed, but keep the trade-off explicit: -That's it. Store `api_key`, pass it in the `x-api-key` header on every subsequent request, and you're done. +> "Are you just exploring Recoup, or do you want me to set this up against your account so the work persists? If you have an account, what email should I use? Otherwise I'll create a temporary account, but you won't be able to save artists, releases, or scheduled tasks under it." - -**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: +Once you have the answer, match the human's intent to the right path: -```bash -export RECOUP_API_KEY=$(curl -s -X POST "https://api.recoupable.com/api/agents/signup" \ - -H "Content-Type: application/json" \ - -d '{"email": "agent+'$(date +%s)-$RANDOM'@recoupable.com"}' | jq -r .api_key) -``` +| Human's answer | Auth path | Then | +|----------------|-----------|------| +| "Just exploring / quick demo / one-shot research" | Throwaway [`agent+...@recoupable.com`](#1-authenticate) signup | Use research and content endpoints. **Don't create artists.** They'll orphan when the API key is lost. | +| "I have an account, here's my email" (existing roster) | Sign in with their real email | List [`/api/artists`](/api-reference/artists/list); work with the roster they already have | +| "I have an account, here's my email" (new artist) | Sign in with their real email | Run the [`create-artist`](https://github.com/recoupable/skills/tree/main/skills/create-artist) skill | +| "I don't have an account but I want to set one up" | Sign in with their real email | After auth, run the [`create-artist`](https://github.com/recoupable/skills/tree/main/skills/create-artist) skill to start their roster | -Verify it worked: +**The key distinction:** `agent+` emails create isolated, unrecoverable accounts. Use them ONLY for one-shot work (research, content generation) where losing the API key has no cost. For anything that creates persistent records (artists, releases, scheduled tasks), use the user's real email. -```bash -curl -H "x-api-key: $RECOUP_API_KEY" https://api.recoupable.com/api/accounts/id -``` - +**When you can skip the question:** if the human's instruction explicitly names the path (e.g., *"just try the demo"*, *"use my Recoup account, my email is x@y.com"*, or you were invoked autonomously by another agent with no human in the loop), you don't need to ask. Proceed directly. - -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. - +## 1. Authenticate -## How it works +If your human has an API key, pass it via `x-api-key`. If not, generate one based on the path you chose above. **Note**: the throwaway `agent+...@recoupable.com` path returns the API key immediately on signup with no verification step. Skip steps 2 and 3 below. -Two unauthenticated endpoints power agent onboarding: + + + ```bash + curl -X POST "https://api.recoupable.com/api/agents/signup" \ + -H "Content-Type: application/json" \ + -d '{"email": "user@example.com"}' + ``` + For an `agent+...@recoupable.com` email, the response includes `api_key` directly. Store it (e.g. `export RECOUP_API_KEY=your-api-key`) and you're done. For any other email, the response says a verification code was sent; continue with steps 2 and 3. + + + 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://api.recoupable.com/api/agents/verify" \ + -H "Content-Type: application/json" \ + -d '{"email": "user@example.com", "code": "123456"}' + ``` + Store the returned `api_key` (e.g. `export RECOUP_API_KEY=your-api-key`) and pass it as `x-api-key` on every request. + + -- **[`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. +**After authenticating, immediately check the roster.** Don't wait for the human to tell you what to do. -Multiple API keys per account are supported — each signup or verification generates a new key without revoking existing ones. + +`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. + -## Standard signup (email verification) +--- -If you're building a human-facing integration and want the user to verify their real email, use any non-`agent+` address: +## 2. Understand the roster -Step 1 — request a verification code: +After getting a key, your next call should always be to check what the human has: ```bash -curl -X POST "https://api.recoupable.com/api/agents/signup" \ - -H "Content-Type: application/json" \ - -d '{"email": "you@example.com"}' +# List all artists available to this account +curl "https://api.recoupable.com/api/artists" \ + -H "x-api-key: $RECOUP_API_KEY" + +# List organizations (labels/teams) the account belongs to +curl "https://api.recoupable.com/api/organizations" \ + -H "x-api-key: $RECOUP_API_KEY" +``` + +**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. + +**If the human has organizations**, pass `organization_id` to scope to a specific label's roster. + +**If neither is specified**, you operate at the account level and can see everything available to the human. + +--- + +## 3. Know the filesystem + +Each account has a persistent filesystem backed by a GitHub repo. This is where artist context lives. Files agents use to do informed work. + +### Artist directory structure + ``` +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 +``` + +The `RECOUP.md` file ties the folder to the platform. It contains YAML frontmatter with `artistName`, `artistSlug`, and `artistId`. -Step 2 — submit the 6-digit code from the verification email: +### Accessing sandbox files ```bash -curl -X POST "https://api.recoupable.com/api/agents/verify" \ +# List the full file tree +curl "https://api.recoupable.com/api/sandboxes" \ + -H "x-api-key: $RECOUP_API_KEY" + +# Read a specific file +curl "https://api.recoupable.com/api/sandboxes/file?path=orgs/my-label/artists/drake/context/artist.md" \ + -H "x-api-key: $RECOUP_API_KEY" + +# Upload files to the repo +# path is top-level (target directory); each file needs url + name +curl -X POST "https://api.recoupable.com/api/sandboxes/files" \ + -H "x-api-key: $RECOUP_API_KEY" \ -H "Content-Type: application/json" \ - -d '{"email": "you@example.com", "code": "123456"}' + -d '{"path": "orgs/my-label/artists/drake/context", "files": [{"url": "https://...", "name": "audience.md"}]}' ``` -Response: +--- -```json -{ - "account_id": "123e4567-e89b-12d3-a456-426614174000", - "api_key": "recoup_sk_abc123...", - "message": "Verified" -} -``` +## 4. Decide what to do -## Using your API key + + + 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. -Pass the returned `api_key` in the `x-api-key` header on every authenticated request: + **Content.** Generate images, videos, and captions with the content endpoints. Artist context from the filesystem makes output more on-brand. -```bash -curl -X GET "https://api.recoupable.com/api/tasks" \ - -H "x-api-key: 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`. + + 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 + + If the human only needs it once, just do it. Don't create a task for everything. + + + +--- + +## Base URL + +``` +https://api.recoupable.com/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/comments/get.mdx b/api-reference/comments/get.mdx deleted file mode 100644 index 6cfa7a8a..00000000 --- a/api-reference/comments/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Comments -openapi: "/api-reference/openapi/social.json GET /api/comments" ---- 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/ai.json b/api-reference/openapi/ai.json index cb79ead5..4cde75a1 100644 --- a/api-reference/openapi/ai.json +++ b/api-reference/openapi/ai.json @@ -10,7 +10,7 @@ }, "servers": [ { - "url": "https://recoup-api.vercel.app" + "url": "https://api.recoupable.com" } ], "paths": { diff --git a/api-reference/openapi/content.json b/api-reference/openapi/content.json index 09c2a710..fb170277 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, @@ -428,7 +428,7 @@ }, "/api/image/generate": { "get": { - "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", @@ -476,7 +476,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, @@ -544,7 +544,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": [] @@ -576,7 +576,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": { @@ -586,7 +586,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -610,7 +610,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 `runIds` (an array of run IDs — one per generated piece) for polling progress via [`GET /api/tasks/runs`](/api-reference/tasks/runs).", "security": [ { "apiKeyAuth": [] @@ -632,7 +633,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": { @@ -642,7 +643,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": { @@ -652,7 +653,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -662,7 +663,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": { @@ -676,7 +677,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": [] @@ -697,7 +698,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -744,7 +745,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -812,7 +813,7 @@ } }, "400": { - "description": "Bad request — artist_account_id is required", + "description": "Bad request \u2014 artist_account_id is required", "content": { "application/json": { "schema": { @@ -822,7 +823,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -832,7 +833,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": { @@ -846,7 +847,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": [] @@ -902,7 +903,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -938,7 +939,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" } } } @@ -967,7 +968,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, @@ -1104,7 +1105,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": { @@ -1114,7 +1115,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1138,7 +1139,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": [] @@ -1170,7 +1171,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": { @@ -1180,7 +1181,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1236,7 +1237,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": { @@ -1246,7 +1247,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1302,7 +1303,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": { @@ -1312,7 +1313,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1336,7 +1337,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": [] @@ -1368,7 +1369,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": { @@ -1378,7 +1379,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1434,7 +1435,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": { @@ -1444,7 +1445,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1509,7 +1510,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": { @@ -1519,7 +1520,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1576,7 +1577,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": { @@ -1586,7 +1587,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1651,7 +1652,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": { @@ -1661,7 +1662,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1685,7 +1686,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": [] @@ -1717,7 +1718,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": { @@ -1727,7 +1728,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1751,7 +1752,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": [] @@ -1829,7 +1830,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": { @@ -1839,7 +1840,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -1924,7 +1925,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": { @@ -1934,7 +1935,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -2366,13 +2367,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" }, @@ -2455,7 +2477,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" @@ -2484,7 +2506,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", @@ -2646,9 +2668,6 @@ }, "ContentCreateVideoRequest": { "type": "object", - "required": [ - "image_url" - ], "properties": { "template": { "type": "string", @@ -2673,7 +2692,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": "Optional. URL of an image used as the input frame, style reference, or starting frame depending on the chosen `mode`. Omit for `prompt` mode (text-only generation)." }, "end_image_url": { "type": "string", @@ -2944,7 +2963,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", @@ -3551,7 +3570,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", @@ -3585,7 +3604,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", @@ -3676,7 +3695,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 de1c2578..dddb59aa 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": { @@ -592,13 +596,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" + } } } }, @@ -642,29 +646,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": { @@ -1414,7 +1418,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": { @@ -1428,7 +1432,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": [] @@ -1460,7 +1464,7 @@ } }, "400": { - "description": "Bad request — missing or invalid fields", + "description": "Bad request \u2014 missing or invalid fields", "content": { "application/json": { "schema": { @@ -1470,7 +1474,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": { @@ -1480,7 +1484,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": { @@ -2848,7 +2852,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": { @@ -2864,7 +2868,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": { @@ -3578,7 +3582,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 b33d6f40..5ff1edc1 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", @@ -3020,7 +3020,7 @@ "id": { "type": "string", "format": "uuid", - "description": "UUID of the memory message" + "description": "UUID of the message" }, "room_id": { "type": "string", @@ -3029,12 +3029,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/openapi/social.json b/api-reference/openapi/social.json index 53804f88..f394e9c7 100644 --- a/api-reference/openapi/social.json +++ b/api-reference/openapi/social.json @@ -122,75 +122,6 @@ } } }, - "/api/comments": { - "get": { - "description": "Retrieve comments associated with an artist or a specific post, with support for pagination. This endpoint returns raw comment data including the comment text, associated post, and commenter's social profile reference.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch comments for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "post_id", - "in": "query", - "description": "Filter comments by specific post", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "Page number for pagination (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "Number of comments per page (default: 10)", - "required": false, - "schema": { - "type": "integer", - "default": 10 - } - } - ], - "responses": { - "200": { - "description": "Comments retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommentsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommentsErrorResponse" - } - } - } - } - } - } - }, "/api/spotify/search": { "get": { "description": "Search for artists, albums, tracks, and playlists using the Spotify API. This endpoint is a proxy to the official Spotify Search API.", @@ -482,12 +413,12 @@ }, "/api/apify/runs/{runId}": { "get": { - "description": "Check the status and retrieve results from Apify scraper runs. This endpoint uses the Apify API Client to fetch the current status of a scraper run and its results if available. Use the runId returned from endpoints like Instagram Comments, Instagram Profiles, Social Scrape, or Artist Socials Scrape to poll for results.", + "description": "Check the status and retrieve results from Apify scraper runs. This endpoint uses the Apify API Client to fetch the current status of a scraper run and its results if available. Use the runId returned from POST /api/social/scrape or POST /api/artist/socials-scrape to poll for results.", "parameters": [ { "name": "runId", "in": "path", - "description": "The ID of the Apify run to check status for. This is returned when starting a scrape via Instagram Comments, Instagram Profiles, Social Scrape, or Artist Socials Scrape endpoints.", + "description": "The ID of the Apify run to check status for. This is returned when starting a scrape via POST /api/social/scrape or POST /api/artist/socials-scrape.", "required": true, "schema": { "type": "string" @@ -748,7 +679,7 @@ }, "/api/connectors/actions": { "get": { - "description": "List the executable actions available across the authenticated account's connectors. Each action is a single tool that can be invoked via POST /api/connectors/actions — for example, the `googlesheets` connector exposes actions like `GOOGLESHEETS_WRITE_SPREADSHEET`. Actions whose parent connector is not yet connected are returned with `isConnected: false` and cannot be executed until the connector is authorized via POST /api/connectors.", + "description": "List the executable actions available across the authenticated account's connectors. Each action is a single tool that can be invoked via POST /api/connectors/actions \u2014 for example, the `googlesheets` connector exposes actions like `GOOGLESHEETS_WRITE_SPREADSHEET`. Actions whose parent connector is not yet connected are returned with `isConnected: false` and cannot be executed until the connector is authorized via POST /api/connectors.", "parameters": [ { "name": "account_id", @@ -773,7 +704,7 @@ } }, "400": { - "description": "Bad request — invalid account_id format", + "description": "Bad request \u2014 invalid account_id format", "content": { "application/json": { "schema": { @@ -783,7 +714,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -793,7 +724,7 @@ } }, "403": { - "description": "Forbidden — no access to the specified account", + "description": "Forbidden \u2014 no access to the specified account", "content": { "application/json": { "schema": { @@ -805,7 +736,7 @@ } }, "post": { - "description": "Execute a connector action with the given parameters. The `actionSlug` must come from a prior call to GET /api/connectors/actions, and `parameters` must match the `parameters` JSON Schema returned for that action. The action's parent connector must be currently connected (`isConnected: true` in the catalog) — otherwise this endpoint returns 409. The `result` field passes through whatever the underlying connector returns; its shape is action-specific.", + "description": "Execute a connector action with the given parameters. The `actionSlug` must come from a prior call to GET /api/connectors/actions, and `parameters` must match the `parameters` JSON Schema returned for that action. The action's parent connector must be currently connected (`isConnected: true` in the catalog) \u2014 otherwise this endpoint returns 409. The `result` field passes through whatever the underlying connector returns; its shape is action-specific.", "requestBody": { "description": "Action to execute and the parameters for it", "required": true, @@ -829,7 +760,7 @@ } }, "400": { - "description": "Bad request — missing or invalid parameters (e.g. `parameters` does not match the action's schema)", + "description": "Bad request \u2014 missing or invalid parameters (e.g. `parameters` does not match the action's schema)", "content": { "application/json": { "schema": { @@ -839,7 +770,7 @@ } }, "401": { - "description": "Unauthorized — invalid or missing API key", + "description": "Unauthorized \u2014 invalid or missing API key", "content": { "application/json": { "schema": { @@ -849,7 +780,7 @@ } }, "403": { - "description": "Forbidden — no access to the specified account", + "description": "Forbidden \u2014 no access to the specified account", "content": { "application/json": { "schema": { @@ -949,7 +880,7 @@ "type": "object", "additionalProperties": true }, - "description": "Array of dataset items returned by the scraper. The structure of each item varies depending on the scraper type (Instagram Profile, Instagram Comments, etc.)", + "description": "Array of dataset items returned by the scraper. The structure of each item varies depending on the upstream Apify scraper that was invoked (Instagram profile scraper, Instagram comments scraper, TikTok scraper, etc.) \u2014 not the Recoup endpoint that triggered it.", "example": [ { "id": "123456789", @@ -2216,7 +2147,7 @@ "properties": { "slug": { "type": "string", - "description": "Unique identifier for the action — pass this as `actionSlug` when calling POST /api/connectors/actions. Action slugs are always UPPERCASE_SNAKE_CASE (e.g. `GITHUB_CREATE_ISSUE`, `GMAIL_FETCH_EMAILS`, `GOOGLESHEETS_WRITE_SPREADSHEET`)." + "description": "Unique identifier for the action \u2014 pass this as `actionSlug` when calling POST /api/connectors/actions. Action slugs are always UPPERCASE_SNAKE_CASE (e.g. `GITHUB_CREATE_ISSUE`, `GMAIL_FETCH_EMAILS`, `GOOGLESHEETS_WRITE_SPREADSHEET`)." }, "name": { "type": "string", @@ -2256,7 +2187,7 @@ "items": { "$ref": "#/components/schemas/ConnectorAction" }, - "description": "Available actions across all connectors the authenticated account has access to. Both connected and unconnected actions are returned — check `isConnected` per action before attempting execution." + "description": "Available actions across all connectors the authenticated account has access to. Both connected and unconnected actions are returned \u2014 check `isConnected` per action before attempting execution." } } }, @@ -2273,7 +2204,7 @@ }, "parameters": { "type": "object", - "description": "Action-specific parameters matching the `parameters` JSON Schema returned by GET /api/connectors/actions for this `actionSlug`. The connector validates these against the cached schema before executing — invalid shapes return 400. Required.", + "description": "Action-specific parameters matching the `parameters` JSON Schema returned by GET /api/connectors/actions for this `actionSlug`. The connector validates these against the cached schema before executing \u2014 invalid shapes return 400. Required.", "additionalProperties": true }, "account_id": { @@ -2296,7 +2227,7 @@ "result": { "type": "object", "additionalProperties": true, - "description": "Pass-through of the underlying connector's response payload. Shape is action-specific — consult the action's parameters schema and the third-party service's own documentation for what to expect. The server-side wrapper does not transform this field." + "description": "Pass-through of the underlying connector's response payload. Shape is action-specific \u2014 consult the action's parameters schema and the third-party service's own documentation for what to expect. The server-side wrapper does not transform this field." }, "executedAt": { "type": "string", 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 fd5f08e5..f8769004 100644 --- a/authentication.mdx +++ b/authentication.mdx @@ -1,115 +1,106 @@ --- 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, or to pass an API key to the [MCP server](/mcp). 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; MCP clients passing an API key | -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 +## Concepts + +The API operates on three entity types. Authentication and access control resolve against these. + +| 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, distributor, catalog company, management firm, 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. | + +--- -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. +## Create a key -### Creating an API Key +Two ways to get a key: -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** +- **Via API.** See [Quickstart](/quickstart#1-get-your-api-key) for the two-call signup + verify flow. When an agent runs this on behalf of a human, the agent passes the code the human reads back from their inbox. +- **Via dashboard.** Go to [chat.recoupable.com/keys](https://chat.recoupable.com/keys), sign in, and create one. -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://api.recoupable.com/api/tasks" \ +curl "https://api.recoupable.com/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://api.recoupable.com/api/tasks" \ +curl "https://api.recoupable.com/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 fa4d5f1e..81c5a585 100644 --- a/cli.mdx +++ b/cli.mdx @@ -6,9 +6,9 @@ description: "Install the Recoup CLI and interact with the platform from your te 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. -**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. +**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. +**Agents:** if a command isn't listed below, don't retry. Fall back to the corresponding REST endpoint linked under each command. ## Install @@ -39,7 +39,7 @@ Get an API key from the [API Keys page](https://chat.recoupable.com/keys) or use | Variable | Required | Default | Description | |----------|----------|---------|-------------| -| `RECOUP_API_KEY` | Yes | — | Your Recoup API key | +| `RECOUP_API_KEY` | Yes | (none) | Your Recoup API key | | `RECOUP_API_URL` | No | `https://api.recoupable.com` | API base URL override | All commands support `--json` for machine-readable output and `--help` for usage info. @@ -145,7 +145,7 @@ One of `--preset` or `--prompt` is required. The other flags are optional. ## content -Content creation pipeline — generate AI-powered social videos for artists. +Content creation pipeline. Generate AI-powered social videos for artists. ### List templates diff --git a/content-agent.mdx b/content-agent.mdx index 67fc9ecd..c81f44db 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://api.recoupable.com/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://api.recoupable.com/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://api.recoupable.com/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. -| 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 | +| 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. Six 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. | -### Data Flow + +[`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. + + +## Video 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 | `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://api.recoupable.com/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://api.recoupable.com/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://api.recoupable.com`) | +| `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/credits.mdx b/credits.mdx new file mode 100644 index 00000000..0ec6b828 --- /dev/null +++ b/credits.mdx @@ -0,0 +1,67 @@ +--- +title: "Credits" +description: "How Recoup credits work: what's billed, how to check your balance, and how to upgrade." +--- + +Some Recoup endpoints are billed in **credits**. Primarily endpoints that hit external data providers, run AI inference, or generate content. The rest of the API is free at the API layer. + +--- + +## What's billed + +| Family | Billed? | Notes | +|--------|---------|-------| +| **Research** (`/api/research/*`) | Yes | Each successful call deducts credits. Costs vary by endpoint and parameters (e.g. `enrich` charges by processor tier; `extract` charges by URL count). | +| **Content generation** (`/api/image/generate`) | Yes | Image generation is priced per call. | +| **AI Chat streaming** (`POST /api/chat`) | Yes | Variable cost based on model token usage, with a per-request minimum. | +| **Everything else** | Free at the API layer | Artist CRUD, sandboxes, sessions, scheduled tasks, social integrations, account/org management, agent signup, Spotify proxies, etc. Subscription gating may still apply. | + +Failed calls (4xx / 5xx) do **not** deduct credits. Deduction happens only after the upstream call succeeds. + +--- + +## Check your balance + +```bash +curl -sS https://api.recoupable.com/api/credits/get \ + -H "x-api-key: $RECOUP_API_KEY" +``` + +Response shape: + +```json +{ + "remaining_credits": 245, + "account_id": "acc_…" +} +``` + +--- + +## Subscription + +Recoup has two tiers. Both refill on a monthly cycle. + +| Tier | How you get it | Monthly credits | +|------|---------------|----------------| +| **Free** | Default for every new account | Monthly allowance refills automatically | +| **Pro** | Stripe subscription via the chat dashboard | Substantially higher monthly allowance | + +### Upgrade to Pro + +1. Sign in at [chat.recoupable.com](https://chat.recoupable.com) +2. Open Billing → **Subscribe** +3. Stripe checkout creates a subscription tied to the account your API key authenticates against. New subscriptions include a **30-day trial** + +### Check your tier + +```bash +curl -sS https://api.recoupable.com/api/accounts/$ACCOUNT_ID/subscription \ + -H "x-api-key: $RECOUP_API_KEY" +``` + +Get `$ACCOUNT_ID` from [`GET /api/accounts/id`](/api-reference/accounts/id) if you don't already have it. Response includes `isPro` (boolean), `status`, `plan`, and `source` (whether the subscription comes from the account itself or an organization the account belongs to). Full schema at [Get Subscription](/api-reference/accounts/subscription-get). + +### One-time top-ups + +**Coming soon.** Today the only way to add credits beyond the monthly refill is to subscribe (or wait for the next cycle). Per-request top-ups are on the roadmap. diff --git a/docs.json b/docs.json index fdf0a2cf..b0640d44 100644 --- a/docs.json +++ b/docs.json @@ -1,66 +1,73 @@ { "$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": "/logo/icon-lightmode.svg", + "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" }, - "favicon": "/favicon.ico", "navigation": { "tabs": [ { - "tab": "Quickstart", + "tab": "Overview", "groups": [ { - "group": "Getting started", + "group": "Start here", "pages": [ "index", "quickstart", - "cli", - "mcp", - "authentication" - ] - } - ] - }, - { - "tab": "Artists", - "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" + "authentication", + "credits", + "agents" ] }, { - "group": "Fans", + "group": "Interfaces", "pages": [ - "api-reference/fans/get" + "cli", + "mcp", + "content-agent" ] } ] }, { - "tab": "Research", + "tab": "Chat", "groups": [ { - "group": "Chat", + "group": "AI Chat", "pages": [ "api-reference/chat/stream", "api-reference/chat/create", @@ -75,6 +82,17 @@ "api-reference/chat/compact" ] }, + { + "group": "Models", + "pages": [ + "api-reference/ai/models" + ] + } + ] + }, + { + "tab": "Research", + "groups": [ { "group": "Artist discovery", "pages": [ @@ -131,7 +149,7 @@ ] }, { - "group": "Web & social", + "group": "Web intelligence", "pages": [ "api-reference/research/instagram-posts", "api-reference/research/web", @@ -140,19 +158,71 @@ "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": [] + }, + { + "group": "Social Scraping", + "pages": [ + "api-reference/social/scrape", + "api-reference/apify/scraper" + ] } ] }, { - "tab": "Releases", + "tab": "Artists", "groups": [ { - "group": "Songs & Catalogs", + "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" + ] + } + ] + }, + { + "tab": "Catalog", + "groups": [ + { + "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", @@ -165,68 +235,83 @@ "tab": "Content", "groups": [ { - "group": "Workflows", + "group": "Generate", "pages": [ - "workflows/generate-music-video" + "api-reference/content/generate-image", + "api-reference/content/generate-video", + "api-reference/content/generate-caption" ] }, { - "group": "Content Creation", + "group": "Edit", "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/upscale" + ] + }, + { + "group": "Analyze", + "pages": [ "api-reference/content/analyze-video", + "api-reference/content/transcribe-audio" + ] + }, + { + "group": "Templates", + "pages": [ "api-reference/content/templates", "api-reference/content/template-detail", "api-reference/content/validate", - "api-reference/content/estimate", + "api-reference/content/estimate" + ] + }, + { + "group": "Legacy", + "pages": [ + "api-reference/content/create", "api-reference/image/generation", "api-reference/transcribe/audio" ] }, { - "group": "Posts & Comments", + "group": "Content Agent", "pages": [ - "api-reference/posts/get", - "api-reference/comments/get" + "api-reference/content-agent/webhook", + "api-reference/content-agent/callback" ] } ] }, { - "tab": "Social Media", + "tab": "Automation", "groups": [ { - "group": "Social", + "group": "Scheduled Tasks", "pages": [ - "api-reference/social/scrape" + "api-reference/tasks/get", + "api-reference/tasks/create", + "api-reference/tasks/update", + "api-reference/tasks/delete", + "api-reference/tasks/runs" ] }, { - "group": "Spotify", + "group": "Pulses", "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/pulses/update", + "api-reference/pulses/list" ] }, { - "group": "Apify", + "group": "Notifications", "pages": [ - "api-reference/apify/scraper" + "api-reference/notifications/create" ] } ] }, { - "tab": "Agents & Sandboxes", + "tab": "Accounts", "groups": [ { "group": "Agent Onboarding", @@ -236,27 +321,21 @@ ] }, { - "group": "Agents", - "pages": [ - "agents", - "content-agent" - ] - }, - { - "group": "Tasks", + "group": "Accounts", "pages": [ - "api-reference/tasks/get", - "api-reference/tasks/create", - "api-reference/tasks/update", - "api-reference/tasks/delete", - "api-reference/tasks/runs" + "api-reference/accounts/get", + "api-reference/accounts/id", + "api-reference/accounts/create", + "api-reference/accounts/update", + "api-reference/accounts/add-artist" ] }, { - "group": "Content Agent", + "group": "Organizations", "pages": [ - "api-reference/content-agent/webhook", - "api-reference/content-agent/callback" + "api-reference/organizations/list", + "api-reference/organizations/create", + "api-reference/organizations/add-artist" ] }, { @@ -275,45 +354,20 @@ "group": "Sessions", "pages": [ "api-reference/sessions/create", - "api-reference/sessions/get" - ] - }, - { - "group": "Session Sandboxes", - "pages": [ + "api-reference/sessions/get", "api-reference/sandbox/create", "api-reference/sandbox/status", "api-reference/sandbox/reconnect" ] - } - ] - }, - { - "tab": "Accounts", - "groups": [ - { - "group": "Pulses", - "pages": [ - "api-reference/pulses/update", - "api-reference/pulses/list" - ] - }, - { - "group": "Accounts", - "pages": [ - "api-reference/accounts/get", - "api-reference/accounts/id", - "api-reference/accounts/create", - "api-reference/accounts/update", - "api-reference/accounts/add-artist" - ] }, { - "group": "Organizations", + "group": "Connectors", "pages": [ - "api-reference/organizations/list", - "api-reference/organizations/create", - "api-reference/organizations/add-artist" + "api-reference/connectors/list", + "api-reference/connectors/authorize", + "api-reference/connectors/disconnect", + "api-reference/connectors/list-actions", + "api-reference/connectors/execute-action" ] }, { @@ -338,69 +392,77 @@ "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" ] - }, - { - "group": "Notifications", - "pages": [ - "api-reference/notifications/create" - ] } ] }, { - "tab": "Tools & Reference", + "tab": "Workflows", + "pages": [ + "workflows", + "workflows/create-artist", + "workflows/generate-music-video" + ] + }, + { + "tab": "Skills & Plugins", "groups": [ { - "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": "Skills", + "pages": [ + "skills", + "skills/getting-started", + "skills/recoup-api", + "skills/setup-sandbox", + "skills/artist-workspace", + "skills/create-artist", + "skills/music-industry-research", + "skills/content-creation", + "skills/song-writing", + "skills/trend-to-song", + "skills/release-management", + "skills/streaming-growth" ] }, { - "group": "AI", + "group": "Plugins", "pages": [ - "api-reference/ai/models" + "plugins/music-catalog-diligence" ] } ] } ], "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": [] } }, + "redirects": [ + { + "source": "/plugins", + "destination": "/skills" + } + ], "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" @@ -408,8 +470,8 @@ ], "primary": { "type": "button", - "label": "Dashboard", - "href": "https://chat.recoupable.com" + "label": "Get API Key", + "href": "https://chat.recoupable.com/keys" } }, "contextual": { diff --git a/favicon.ico b/favicon.ico deleted file mode 100644 index 993c7246..00000000 Binary files a/favicon.ico and /dev/null differ 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 cdea1a32..7f02faa3 100644 --- a/index.mdx +++ b/index.mdx @@ -1,187 +1,169 @@ --- -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 operate the music business." --- -# Welcome to the Recoup API + +**AI agent?** Base URL: `https://api.recoupable.com/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. +Whether you're an indie artist, a label, a distributor, a catalog company, or a management firm, you're juggling research, content, marketing, distribution, and fan engagement all at once. That's what agents are for. Recoup is the agent harness for the music business, built by people who've done it: not just the context (your catalog, artists, releases, fans), but the domain expertise and workflows that operate it day-to-day. Agents do the work that used to take a full team, 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://api.recoupable.com/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. - -This is where record labels, musicians, and managers start to build on Recoup AI technology like chat, tasks, agents, and more. - -## Base URL - -All API requests should be made to: - -```bash -https://api.recoupable.com/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) +## Get started -```bash -curl -X GET "https://api.recoupable.com/api/artists?accountId=YOUR_ACCOUNT_ID" \ - -H "Content-Type: application/json" \ - -H "x-api-key: YOUR_API_KEY" -``` +- **[Quickstart](/quickstart):** get an API key and make your first call. Under a minute. +- **[Agent onboarding](/agents):** the operating manual for AI agents using Recoup in production. Covers the throwaway-vs-account decision, the roster, and the persistent filesystem. +- **[Authentication](/authentication):** reference for API keys, Bearer tokens, and access scoping. - -Keep your API key secure. Do not share it publicly or commit it to version control. - +--- -## 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 them. - 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 +--- -The API is organized into six main sections. Use these links to jump to the right area. +## What's in the API + +Organized by what agents actually do when running a music business. + + Stream completions, manage threads, copy or delete messages, compact long histories. 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. + 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 and posts. The people side of your roster. - 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 roster. - Spotify, Instagram, X (Twitter), and generic social scraping. Search artists, scrape profiles and comments, track trends, and manage OAuth connectors. + Generate images, videos, captions; transcribe audio; edit, upscale, analyze video. Compose primitives yourself, or use the full pipeline end to end with templates and cost estimation. - 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://api.recoupable.com/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://api.recoupable.com/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://api.recoupable.com/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, templates) | [`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) | +| AI (language model catalog) | [`openapi/ai.json`](/api-reference/openapi/ai.json) | +| Sessions (agent sessions for sandbox runs) | [`openapi/sessions.json`](/api-reference/openapi/sessions.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..0b8bf4e0 --- /dev/null +++ b/logo/icon-lightmode.svg @@ -0,0 +1,10 @@ + + + + + + + + + + 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 f4ca139f..e75f3095 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 the full Recoup tool catalog 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://api.recoupable.com/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://api.recoupable.com/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. | +Tools are 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://api.recoupable.com/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). | + +If your account belongs to an organization, your key can target any account in that org by passing `account_id` on tools that accept it. Otherwise, your key only operates on your own data. There's no separate "org-scoped" key type. Access is determined by the account's organization membership. See [Authentication](/authentication#access-control) for the full access rules. + diff --git a/plugins/music-catalog-diligence.mdx b/plugins/music-catalog-diligence.mdx new file mode 100644 index 00000000..85867f17 --- /dev/null +++ b/plugins/music-catalog-diligence.mdx @@ -0,0 +1,23 @@ +--- +title: "Catalog due diligence" +description: "Review royalties, rights, valuation, and deal materials for music catalog transactions across buyer, seller, lender, or post-close use cases." +--- + +A bundled toolkit for music catalog M&A and financing. Drives the full diligence workflow: ingest a data room, normalize royalty statements, audit rights and chain of title, build a valuation model, and produce an IC memo or financing pack. Built around a shared QC discipline so every artifact lands with citations and confidence levels. + +**Bundles:** 10 skills (`catalog-ingest`, `royalty-audit`, `rights-diligence`, `catalog-analysis`, `financing-underwrite`, `seller-prep`, `post-close-admin`, `ic-memo-package`, `diligence-kickoff`, plus shared QC), 9 slash commands, and 5 sub-agent personas. + +## Install + +| Agent | How | +|---|---| +| **Claude Code** | `/plugin marketplace add recoupable/plugins` then `/plugin install music-catalog-diligence@recoupable-plugins` | +| **Claude Cowork** | Customize → Plugins → + → Create plugin → Add marketplace → paste `https://github.com/recoupable/plugins` → Sync | +| **Codex** | `codex plugin marketplace add recoupable/plugins`, then in a session: `codex /plugins` → search → Install | +| **Cursor** | Manual clone. See the [Skills & Plugins page](/skills#cursor) for the exact commands. | + +Full per-runtime instructions on the [Skills & Plugins page](/skills#install-1). + +## Source + +The full plugin (skills, commands, agents, references) lives at [`recoupable/music-catalog-diligence`](https://github.com/recoupable/music-catalog-diligence). diff --git a/quickstart.mdx b/quickstart.mdx index 92afeee3..68bc8671 100644 --- a/quickstart.mdx +++ b/quickstart.mdx @@ -1,175 +1,132 @@ --- 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 +A 5-minute hello-world. Get an API key, hit the research endpoint, optionally connect an MCP-compatible agent. -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`: + +**Building an AI agent that acts on a user's behalf?** See [Agent onboarding](/agents) instead. It covers the throwaway-vs-account decision, the user's roster, and the persistent filesystem. This page assumes you're trying the API yourself. + + +## 1. Get your API key ```bash -export RECOUP_API_KEY=$(curl -s -X POST "https://api.recoupable.com/api/agents/signup" \ +# 1. Trigger a verification code to your inbox +curl -s -X POST "https://api.recoupable.com/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://api.recoupable.com/api/accounts/id +# 2. Check your email, then exchange the code for a key +export RECOUP_API_KEY=$(curl -s -X POST "https://api.recoupable.com/api/agents/verify" \ + -H "Content-Type: application/json" \ + -d '{"email": "you@example.com", "code": "123456"}' | jq -er '.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://api.recoupable.com/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: +Start with search. It works for any artist on earth: ```bash cURL -curl -X GET "https://api.recoupable.com/api/tasks" \ - -H "Content-Type: application/json" \ - -H "x-api-key: YOUR_API_KEY" +curl "https://api.recoupable.com/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://api.recoupable.com/api/tasks", - headers=headers + "https://api.recoupable.com/api/research", + params={"q": "Drake"}, + headers={"x-api-key": os.environ["RECOUP_API_KEY"]}, ) print(response.json()) ``` ```javascript JavaScript -const response = await fetch("https://api.recoupable.com/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://api.recoupable.com/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://api.recoupable.com/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://api.recoupable.com/api/research/metrics?artist=Drake&source=spotify" \ + -H "x-api-key: $RECOUP_API_KEY" + +# Audience demographics (age, gender, geography) +curl "https://api.recoupable.com/api/research/audience?artist=Drake" \ + -H "x-api-key: $RECOUP_API_KEY" + +# Editorial playlist placements +curl "https://api.recoupable.com/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://api.recoupable.com/mcp +``` -## Next Steps +Pass your API key as a Bearer token. Your agent gets access to the full Recoup tool catalog. See the [MCP guide](/mcp) for setup. -With your API key ready, you can now: +--- + +## Next steps - Fetch artist profiles and social accounts. + Metrics across 14 platforms, audience data, playlists, career history, and web intelligence. - Access fan data across all connected social platforms. + 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..aac475dc --- /dev/null +++ b/skills.mdx @@ -0,0 +1,199 @@ +--- +title: "Skills & Plugins" +description: "Two ways agents extend themselves on Recoup: reusable workflow units, or bundled toolkits." +--- + +Recoup gives agents two extension points: + +- A **skill** is a self-contained folder containing a `SKILL.md` plus any references, scripts, or assets it needs. It teaches an agent how to do one task. Installed individually, loaded by the agent when the task fits. +- A **plugin** is a bundle. Multiple skills wired together with slash commands and sub-agents around one workflow, installed once into the agent runtime. + +The API tells an agent **how** to take action. Skills and plugins tell it **when** and **why**. + +--- + +## Skills + +Each skill below links to its source `SKILL.md` in [`recoupable/skills`](https://github.com/recoupable/skills). That's what the agent loads at runtime, and where the full instructions live. + +### Setup + +Run these first when an agent connects to Recoup. They handle authentication, sandbox scaffolding, and the eight-step process for creating a new artist. + +| Skill | What it does | Install | +|---|---|---| +| [Set up Recoup](/skills/getting-started) | Set up Recoup from scratch. Get an API key, verify it, and make the first call via REST or MCP. | `npx skills add recoupable/skills --skill getting-started` | +| [Use the Recoup API](/skills/recoup-api) | The agent's universal client for the Recoup API inside a sandbox. Handles auth, scoping, and connector actions for Google Docs, Drive, Sheets, Gmail, TikTok. | `npx skills add recoupable/skills --skill recoup-api` | +| [Bootstrap a sandbox](/skills/setup-sandbox) | Scaffold the workspace for an account's orgs and artists when a sandbox has no existing file system. | `npx skills add recoupable/skills --skill setup-sandbox` | +| [Work with an artist](/skills/artist-workspace) | Manage an artist's directory: identity, brand, voice, audience, songs, face guides. | `npx skills add recoupable/skills --skill artist-workspace` | +| [Create an artist](/skills/create-artist) | End-to-end 8-step process for creating, identifying, and enriching a new artist account from a single name. | `npx skills add recoupable/skills --skill create-artist` | + +### Doing the work + +Run during the agent's actual day: research, content, songwriting, releases, growth. + +| Skill | What it does | Install | +|---|---|---| +| [Research the music industry](/skills/music-industry-research) | Use the `/api/research/*` endpoints for analytics, audience demographics, playlists, charts, and people search. | `npx skills add recoupable/skills --skill music-industry-research` | +| [Create content](/skills/content-creation) | Umbrella skill that composes the content endpoints (image, video, caption, transcribe, edit, upscale, analyze) into short-form videos, Reels, TikToks, and lipsync clips. | `npx skills add recoupable/skills --skill content-creation` | +| [Write a song](/skills/song-writing) | Write and evaluate songs using the 7 C's framework: hook, clarity, character, and the rest. | `npx skills add recoupable/skills --skill song-writing` | +| [Turn a trend into a song](/skills/trend-to-song) | Reverse the traditional workflow. Start from a cultural moment and build a song + distribution plan around it. | `npx skills add recoupable/skills --skill trend-to-song` | +| [Plan a release](/skills/release-management) | Plan a release end-to-end: `RELEASE.md` documents, DSP pitches, press one-sheets, production specs, tour coordination. | `npx skills add recoupable/skills --skill release-management` | +| [Grow streaming](/skills/streaming-growth) | Grow a new artist past the streaming milestones that unlock Spotify Showcase, Marquee, and algorithmic boosting. | `npx skills add recoupable/skills --skill streaming-growth` | + +### Install + +The fastest way is the [`skills`](https://github.com/vercel-labs/add-skill) CLI. It works with Claude Code, Codex, OpenCode, Cursor, and 50+ other agents. + +```bash +# Everything +npx skills add recoupable/skills + +# One skill +npx skills add recoupable/skills --skill recoup-api + +# Preview before installing +npx skills add recoupable/skills --list +``` + +Add `-a claude-code` to target a specific agent, `--global` to install across every project, or `-y` to skip the confirmation prompt (CI-friendly). Full CLI reference: [vercel-labs/add-skill](https://github.com/vercel-labs/add-skill). + +#### Other paths + +```bash +# Claude Code marketplace +/plugin marketplace add recoupable/skills + +# Manual clone +git clone https://github.com/recoupable/skills.git +``` + +### 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 it. 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, like "playlist push," "release plan," or "growth strategy." +--- + +# My Skill + +Step-by-step instructions the agent follows. +``` + +--- + +## Plugins + +A plugin is a packaged toolkit. Multiple skills, slash commands, and sub-agents bundled around one workflow, so a team can install the whole thing into the agent they already use instead of wiring pieces together themselves. + +The marketplace lives at [recoupable/plugins](https://github.com/recoupable/plugins). Each plugin is its own Git repo so it can be developed, versioned, and distributed independently. + +### Available plugins + +| Plugin | What it does | +|---|---| +| [Catalog due diligence](/plugins/music-catalog-diligence) | Review royalties, rights, valuation, and deal materials for music catalog transactions across buyer, seller, lender, or post-close use cases. Bundles 10 skills, 9 slash commands, and 5 sub-agent personas. | + +### Install + +The plugin is hosted on GitHub at [`recoupable/music-catalog-diligence`](https://github.com/recoupable/music-catalog-diligence). Each agent reads from that source in a slightly different way. + +These instructions are written for the agent. Surface the command (or click sequence) literally to the user when prompted. + +#### Claude Code + +```bash +/plugin marketplace add recoupable/plugins +/plugin install music-catalog-diligence@recoupable-plugins +``` + +The first command registers the [registry repo](https://github.com/recoupable/plugins) as a Git-backed marketplace. The second installs the plugin from it. After install, the plugin's slash commands (`/catalog-diligence`, `/catalog-kickoff`, etc.) appear immediately. If they don't, restart the conversation. + +#### Claude Cowork + +1. Open Claude Desktop and switch to the **Cowork** tab +2. Click **Customize** in the left sidebar → **Plugins** +3. Click the **+** button → **Create plugin** → **Add marketplace** +4. Paste the marketplace URL: `https://github.com/recoupable/plugins` +5. Click **Sync** + +Cowork pulls the marketplace's `.claude-plugin/marketplace.json`, fetches each listed plugin from its source repo, and installs them as Personal plugins. After install, `music-catalog-diligence` appears in the Personal Plugins list and its slash commands (`/catalog-diligence`, `/catalog-kickoff`, etc.) are available in any Cowork task. + +Cowork plugins require a paid Claude plan (Pro, Max, Team, or Enterprise). Plugins run locally on the user's machine. Updates pull automatically when we push to the marketplace repo. + +#### Codex + +```bash +codex plugin marketplace add recoupable/plugins +``` + +Then inside a Codex session, open the plugin directory and install the plugin: + +```bash +codex /plugins +``` + +Search for `music-catalog-diligence`, select it, and click **Install**. After install, invoke the plugin by describing the task (e.g. "kick off catalog diligence on this data room") or by typing `@music-catalog-diligence`. + +The marketplace add command is fully scriptable. The install step currently goes through the interactive `/plugins` UI; there's no headless one-shot install yet. + +#### Cursor + +Cursor's curated marketplace doesn't list `recoupable/music-catalog-diligence` yet, so the only path today is a manual local install: + +```bash +mkdir -p ~/.cursor/plugins/local +git clone https://github.com/recoupable/music-catalog-diligence.git ~/.cursor/plugins/local/music-catalog-diligence +``` + +Then have the user reload the Cursor window (`Cmd+Shift+P` → **Reload Window**) so the plugin gets picked up. Important: Cursor doesn't follow symlinks in `~/.cursor/plugins/local/`. The directory must be a real copy. + +To pull updates later, run `git -C ~/.cursor/plugins/local/music-catalog-diligence pull` and reload the window again. + +### How a plugin is structured + +Every plugin lives in its own repo, then gets registered in [recoupable/plugins](https://github.com/recoupable/plugins). Manifests for each agent runtime sit at the plugin root: + +```text +my-plugin/ +├── .claude-plugin/plugin.json ← Claude Code manifest +├── .codex-plugin/plugin.json ← Codex manifest (+ skills bundling) +├── .cursor-plugin/plugin.json ← Cursor manifest +├── skills/ ← bundled skills (SKILL.md files) +├── commands/ ← slash-command definitions +├── agents/ ← optional sub-agent personas +├── references/ ← long-form domain material +├── scripts/ ← executable helpers +└── README.md +``` + +Claude Code and Cursor load the full plugin surface (skills, commands, agents). Codex loads the bundled `skills/` through `.codex-plugin/plugin.json`. Claude-specific commands and agents remain available through Claude Code, and will surface in Codex when its packaging path supports them. + +--- + +## Contribute + +**Skills.** 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. + +**Plugins.** Open a PR against [recoupable/plugins](https://github.com/recoupable/plugins) with your repo and a marketplace entry. The bar: + +- A clear workflow the plugin owns end-to-end (not just one skill, which belongs in [recoupable/skills](https://github.com/recoupable/skills)) +- Skills, commands, and agents that compose into the workflow +- Tests or fixtures that prove the workflow runs against representative data +- A `README.md` that says who it's for in one paragraph diff --git a/skills/artist-workspace.mdx b/skills/artist-workspace.mdx new file mode 100644 index 00000000..4a5069c2 --- /dev/null +++ b/skills/artist-workspace.mdx @@ -0,0 +1,16 @@ +--- +title: "Work with an artist" +description: "Manage an artist's directory: identity, brand, voice, audience, songs, face guides." +--- + +Runs implicitly any time the agent touches artist-specific context. Adding or updating identity, brand, voice, audience, songs, or face guides. Also fires on any task where the user mentions an artist by name and the work touches their files. + +## Install + +```bash +npx skills add recoupable/skills --skill artist-workspace +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/artist-workspace`](https://github.com/recoupable/skills/tree/main/skills/artist-workspace). diff --git a/skills/content-creation.mdx b/skills/content-creation.mdx new file mode 100644 index 00000000..fcc6a070 --- /dev/null +++ b/skills/content-creation.mdx @@ -0,0 +1,16 @@ +--- +title: "Create content" +description: "Compose the content endpoints (image, video, caption, transcribe, edit, upscale, analyze) into short-form videos, Reels, TikToks, and lipsync clips." +--- + +The umbrella skill for everything the content endpoints produce. Triggers when the user asks to create content, make a video, generate an image, produce a TikTok or Reel, add captions, or iterate on existing content (regenerate images, try different audio, adjust text, upscale). Today the most common output is a short-form video; narrower per-output skills (`make-a-video`, `make-an-image`, `make-a-caption`) may split out later as separate entries. + +## Install + +```bash +npx skills add recoupable/skills --skill content-creation +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/content-creation`](https://github.com/recoupable/skills/tree/main/skills/content-creation). diff --git a/skills/create-artist.mdx b/skills/create-artist.mdx new file mode 100644 index 00000000..5434e00f --- /dev/null +++ b/skills/create-artist.mdx @@ -0,0 +1,16 @@ +--- +title: "Create an artist" +description: "End-to-end 8-step process for creating, identifying, and enriching a new artist account from a single name." +--- + +Triggers on "create artist", "onboard X", "add this artist", "set up a new artist", or any task that starts a brand-new artist record from a name. For editing or extending an *existing* artist, use [Work with an artist](/skills/artist-workspace) instead. + +## Install + +```bash +npx skills add recoupable/skills --skill create-artist +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/create-artist`](https://github.com/recoupable/skills/tree/main/skills/create-artist). diff --git a/skills/getting-started.mdx b/skills/getting-started.mdx new file mode 100644 index 00000000..4ae05e9b --- /dev/null +++ b/skills/getting-started.mdx @@ -0,0 +1,16 @@ +--- +title: "Set up Recoup" +description: "Get an API key, verify it, and make the first call via REST or MCP." +--- + +The agent's bootstrap. Run this when the user says "set up Recoup", "install Recoup", "get an API key", "connect to Recoup", or any first-time setup phrase. + +## Install + +```bash +npx skills add recoupable/skills --skill getting-started +``` + +## Source + +The full instructions live at [`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..ef355e70 --- /dev/null +++ b/skills/music-industry-research.mdx @@ -0,0 +1,16 @@ +--- +title: "Research the music industry" +description: "Use the /api/research/* endpoints for analytics, audience demographics, playlists, charts, and people search." +--- + +Triggers when the user asks about an artist's analytics, streaming numbers, audience demographics, playlist placements, similar artists, charts, or tour and venue data. Also fires on phrases like "find me people in [function]," "tell me about [entity]," or "what does this page say." + +## Install + +```bash +npx skills add recoupable/skills --skill music-industry-research +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/music-industry-research`](https://github.com/recoupable/skills/tree/main/skills/music-industry-research). diff --git a/skills/recoup-api.mdx b/skills/recoup-api.mdx new file mode 100644 index 00000000..98252565 --- /dev/null +++ b/skills/recoup-api.mdx @@ -0,0 +1,16 @@ +--- +title: "Use the Recoup API" +description: "The agent's universal client for the Recoup API inside a sandbox: auth, scoping, and connector actions for Google Docs, Drive, Sheets, Gmail, TikTok." +--- + +Loads implicitly before any `curl` against `api.recoupable.com` so the agent picks the right base URL, headers, scoping flags, and uses the org's existing connectors instead of holding third-party credentials. + +## Install + +```bash +npx skills add recoupable/skills --skill recoup-api +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/recoup-api`](https://github.com/recoupable/skills/tree/main/skills/recoup-api). diff --git a/skills/release-management.mdx b/skills/release-management.mdx new file mode 100644 index 00000000..1db7ed12 --- /dev/null +++ b/skills/release-management.mdx @@ -0,0 +1,16 @@ +--- +title: "Plan a release" +description: "Plan a release end-to-end: RELEASE.md documents, DSP pitches, press one-sheets, production specs, tour coordination." +--- + +Triggers when the 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`. + +## Install + +```bash +npx skills add recoupable/skills --skill release-management +``` + +## Source + +The full instructions live at [`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..7c6eed69 --- /dev/null +++ b/skills/setup-sandbox.mdx @@ -0,0 +1,16 @@ +--- +title: "Bootstrap a sandbox" +description: "Scaffold the workspace for an account's orgs and artists when a sandbox has no existing file system." +--- + +Runs once when a sandbox is fresh. If the sandbox already has an `orgs/` directory at the root, this is a no-op; the skill skips itself. + +## Install + +```bash +npx skills add recoupable/skills --skill setup-sandbox +``` + +## Source + +The full instructions live at [`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..e5367d2c --- /dev/null +++ b/skills/song-writing.mdx @@ -0,0 +1,16 @@ +--- +title: "Write a song" +description: "Write and evaluate songs using the 7 C's framework: hook, clarity, character, and the rest." +--- + +Use both as a generation guide (brainstorming song ideas, writing lyrics, refining hooks) and as a critique tool when reviewing an existing draft. + +## Install + +```bash +npx skills add recoupable/skills --skill song-writing +``` + +## Source + +The full instructions live at [`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..e74074a7 --- /dev/null +++ b/skills/streaming-growth.mdx @@ -0,0 +1,16 @@ +--- +title: "Grow streaming" +description: "Grow a new artist past the streaming milestones that unlock Spotify Showcase, Marquee, and algorithmic boosting." +--- + +Triggers on "how do we get more streams," "unlock Spotify ads," "playlist push," "get to a thousand listeners," or any growth question for a near-zero artist. Covers playlist pitching benchmarks, Spotify Showcase thresholds, and DSP advertising. + +## Install + +```bash +npx skills add recoupable/skills --skill streaming-growth +``` + +## Source + +The full instructions live at [`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..685a4508 --- /dev/null +++ b/skills/trend-to-song.mdx @@ -0,0 +1,16 @@ +--- +title: "Turn a trend into a song" +description: "Reverse the traditional workflow. Start from a cultural moment and build a song + distribution plan around it." +--- + +Triggers when 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. Phrases like "make a song about this trend," "capitalize on this moment," "trend-jack," or "burner project." + +## Install + +```bash +npx skills add recoupable/skills --skill trend-to-song +``` + +## Source + +The full instructions live at [`recoupable/skills/skills/trend-to-song`](https://github.com/recoupable/skills/tree/main/skills/trend-to-song). diff --git a/workflows.mdx b/workflows.mdx new file mode 100644 index 00000000..c498e814 --- /dev/null +++ b/workflows.mdx @@ -0,0 +1,38 @@ +--- +title: "Workflows" +description: "End-to-end guides that chain Recoup API calls into a finished result. Agent-ready, framework-agnostic, copy-paste runnable." +--- + +A workflow is a public, step-by-step guide that takes an outcome (a new artist record, a music video, a release-day push) and shows the exact API calls, in order, to get there. Each page is written so an LLM can fetch it as raw markdown (`/workflows/some-workflow.md`) and follow it without parsing HTML. + +Workflows are different from [Skills](/skills). A skill is a self-contained folder (a `SKILL.md` plus any references, scripts, or assets) installed locally via `npx skills` and loaded from disk. A workflow is the docs-site version: readable by any agent, anywhere, with no install step. The same content can ship as both; pick the surface that fits how your agent works. + +## Hand it to your LLM + +Every workflow page is served as raw markdown at its path plus `.md`. Drop the URL into your agent and let it follow the steps: + +```text +Follow this guide step by step. Use the prerequisites at the top to gather inputs, then walk every step in order: + +https://developers.recoupable.com/workflows/generate-music-video.md +``` + +The agent fetches, reads the checklist, and runs the API calls itself. + +## Available workflows + +| Workflow | What it produces | +|----------|------------------| +| [Create an artist](/workflows/create-artist) | A canonical artist record in your account, enriched from social handles, ready to drive research and content. | +| [Generate a music video](/workflows/generate-music-video) | A 9:16 social-ready music video (image, motion, captions) composed from a single artist + song. | + +## Writing a workflow + +If you've shipped something end-to-end on Recoup that would help others (release-day, fan engagement, distribution flow, royalty audit), open a PR against [recoupable/docs](https://github.com/recoupable/docs) under `workflows/`. + +The bar: + +- A concrete outcome the workflow owns end-to-end, not a single API call +- A copy-pasteable prompt at the top so an LLM can run it in one shot +- Step-by-step API calls in execution order, with the request body and the field of the response the next step depends on +- A note on what the workflow doesn't enforce (auth, retries, rate limits) so readers know what they own diff --git a/workflows/create-artist.mdx b/workflows/create-artist.mdx index 99d70b1d..538d0cde 100644 --- a/workflows/create-artist.mdx +++ b/workflows/create-artist.mdx @@ -3,25 +3,25 @@ title: 'Create a New Artist' description: 'End-to-end workflow to create, research and enrich a new artist account in a single session.' --- -This is the canonical recipe used internally by Recoup's chat agent. Follow it step-by-step to bring a new artist account up to "researched + enriched" parity from a sandbox or any external agent. +This is the canonical workflow used internally by Recoup's chat agent. Follow it step-by-step to bring a new artist account up to "researched + enriched" parity from a sandbox or any external agent. -The chain is 8 sequential API calls. Long deterministic chains executed from prose memory tend to drop steps — the agent reads the doc once, runs a couple of calls, and forgets the rest. To prevent that from a sandbox, **drive the work from a checklist file**: scaffold the artist's `RECOUP.md` with one checkbox per step before any API call, then tick each box and persist captured values back to the frontmatter as you go. The file becomes the workflow state, and a fresh turn can resume by reading it. +The chain is 8 sequential API calls. Long deterministic chains executed from prose memory tend to drop steps. The agent reads the doc once, runs a couple of calls, and forgets the rest. To prevent that from a sandbox, **drive the work from a checklist file**: scaffold the artist's `RECOUP.md` with one checkbox per step before any API call, then tick each box and persist captured values back to the frontmatter as you go. The file becomes the workflow state, and a fresh turn can resume by reading it. ## Prerequisites -- `$RECOUP_ACCESS_TOKEN` — Bearer token for `api.recoupable.com` -- `$RECOUP_ORG_ID` — the org the artist should belong to (recommended in sandboxes) +- `$RECOUP_ACCESS_TOKEN`: Bearer token for `api.recoupable.com` +- `$RECOUP_ORG_ID`: the org the artist should belong to (recommended in sandboxes) - An artist name to create (e.g. `ARTIST_NAME="The Weeknd"`) The flow has three phases, run from a single checklist file: -1. **Create + identify** — `POST /api/artists`, then find the canonical Spotify match -2. **Enrich** — `PATCH` the artist with image/label/socials, then run structured research (Chartmetric profile/career/playlists) plus a web search for narrative context and additional socials -3. **Synthesize + persist** — generate a knowledge-base report, save it (RECOUP.md tree or hosted URL), then optionally `PATCH` the `knowledges` array +1. **Create + identify.** `POST /api/artists`, then find the canonical Spotify match. +2. **Enrich.** `PATCH` the artist with image/label/socials, then run structured research (Chartmetric profile/career/playlists) plus a web search for narrative context and additional socials. +3. **Synthesize + persist.** Generate a knowledge-base report, save it (RECOUP.md tree or hosted URL), then optionally `PATCH` the `knowledges` array. ## Step 0: Scaffold the workspace BEFORE any API call -Pick a slug, make the directory, and write the initial `RECOUP.md` template — frontmatter holds the values the chain captures (filled as you go); body holds the unchecked steps: +Pick a slug, make the directory, and write the initial `RECOUP.md` template. Frontmatter holds the values the chain captures (filled as you go); body holds the unchecked steps: ```bash ARTIST_SLUG=$(echo "$ARTIST_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]\+/-/g; s/^-//; s/-$//') @@ -43,22 +43,22 @@ cmArtistId: ## Setup checklist -- [ ] 1. Create the artist (\`POST /api/artists\`) — capture \`account_id\` → \`artistId\` -- [ ] 2. Find canonical Spotify match (\`GET /api/spotify/search\`) — capture \`id\`, \`external_urls.spotify\`, \`images[0].url\` -- [ ] 3. PATCH artist with image + Spotify profile URL -- [ ] 4. Structured research — \`/research/lookup\` (capture \`cmArtistId\`) → \`/research/profile\` + \`/research/career\` + \`/research/playlists\` + \`/research/web\`. Save responses under \`## Research\` in this file. -- [ ] 5. Pull Spotify catalog → write \`releases/{album-slug}/RELEASE.md\` per album + \`releases/top-tracks.md\` -- [ ] 6. Web search for additional socials (instagram / tiktok / twitter / youtube) -- [ ] 7. PATCH artist with discovered socials -- [ ] 8. Synthesize knowledge base — append it as \`## Knowledge base\` in this file +- [ ] 1. Create the artist (\`POST /api/artists\`). Capture \`account_id\` → \`artistId\`. +- [ ] 2. Find canonical Spotify match (\`GET /api/spotify/search\`). Capture \`id\`, \`external_urls.spotify\`, \`images[0].url\`. +- [ ] 3. PATCH artist with image + Spotify profile URL. +- [ ] 4. Structured research: \`/research/lookup\` (capture \`cmArtistId\`) → \`/research/profile\` + \`/research/career\` + \`/research/playlists\` + \`/research/web\`. Save responses under \`## Research\` in this file. +- [ ] 5. Pull Spotify catalog. Write \`releases/{album-slug}/RELEASE.md\` per album + \`releases/top-tracks.md\`. +- [ ] 6. Web search for additional socials (instagram / tiktok / twitter / youtube). +- [ ] 7. PATCH artist with discovered socials. +- [ ] 8. Synthesize knowledge base. Append it as \`## Knowledge base\` in this file. ## Notes EOF ``` -The sandbox is already scoped to a single Recoupable organization (its repo *is* the org), so artists live at the top level — there is no `orgs/` directory. Don't proceed to step 1 until the file exists on disk. +The sandbox is already scoped to a single Recoupable organization (its repo *is* the org), so artists live at the top level. There is no `orgs/` directory. Don't proceed to step 1 until the file exists on disk. -**After every step that follows, do two writes back to `RECOUP.md`:** tick the checkbox for the step you just ran (`- [ ]` → `- [x]`) and persist any captured value into the frontmatter. Later steps read those values from the frontmatter — never re-derive what's already saved. +**After every step that follows, do two writes back to `RECOUP.md`:** tick the checkbox for the step you just ran (`- [ ]` → `- [x]`) and persist any captured value into the frontmatter. Later steps read those values from the frontmatter. Never re-derive what's already saved. ## Resuming a partial setup @@ -69,7 +69,7 @@ If `$ARTIST_DIR/RECOUP.md` already exists, do not re-scaffold and do not re-run grep -n '^- \[ \]' "$ARTIST_DIR/RECOUP.md" | head -1 ``` -If every item is checked, the artist is fully set up — confirm with the user before doing anything else. +If every item is checked, the artist is fully set up. Confirm with the user before doing anything else. ## Step 1: Create the artist @@ -83,7 +83,7 @@ ARTIST_RESPONSE=$(curl -sS -X POST "https://api.recoupable.com/api/artists" \ ARTIST_ID=$(echo "$ARTIST_RESPONSE" | jq -r '.artist.account_id') ``` -Capture `account_id` as `$ARTIST_ID` — every subsequent step needs it. `organization_id` is optional but should be included when running inside a sandbox so the artist is scoped to the right org. +Capture `account_id` as `$ARTIST_ID`. Every subsequent step needs it. `organization_id` is optional but should be included when running inside a sandbox so the artist is scoped to the right org. See [Create Artist](/api-reference/artists/create) for the full request/response schema. @@ -123,7 +123,7 @@ See [Spotify Search](/api-reference/spotify/search) for the full query parameter ## Step 3: Set basic profile + Spotify URL -One `PATCH` covers the image and the Spotify social URL. Use **uppercase** platform keys in `profileUrls` (the API matches platforms case-sensitively — see the reference table below). +One `PATCH` covers the image and the Spotify social URL. Use **uppercase** platform keys in `profileUrls` (the API matches platforms case-sensitively; see the reference table below). ```bash curl -sS -X PATCH "https://api.recoupable.com/api/artists/$ARTIST_ID" \ @@ -133,13 +133,13 @@ curl -sS -X PATCH "https://api.recoupable.com/api/artists/$ARTIST_ID" \ '{image: $image, profileUrls: {SPOTIFY: $url}}')" ``` -This single endpoint replaces what the chat tool chain runs as four separate MCP calls (`update_account_info` ×2, `update_artist_socials` ×2). Add `label` to the body once you discover one in the structured research (step 4 — comes back from `/api/research/profile`). See [Update Artist](/api-reference/artists/update) for the full body schema. +This single endpoint replaces what the chat tool chain runs as four separate MCP calls (`update_account_info` ×2, `update_artist_socials` ×2). Add `label` to the body once you discover one in the structured research (step 4 returns it from `/api/research/profile`). See [Update Artist](/api-reference/artists/update) for the full body schema. **After this step:** tick `- [ ] 3.` → `- [x] 3.`. ## Step 4: Run structured research -Don't use `POST /api/research/deep` here — it tends to hang in sandboxes and returns paraphrased prose. Instead, fan out across four bounded structured endpoints (one prerequisite lookup + three structured pulls + one web search). The outputs are typed JSON the agent can use directly without paraphrasing. +Don't use `POST /api/research/deep` here. It tends to hang in sandboxes and returns paraphrased prose. Instead, fan out across four bounded structured endpoints (one prerequisite lookup + three structured pulls + one web search). The outputs are typed JSON the agent can use directly without paraphrasing. ### 4a: Look up the Chartmetric `artist_id` @@ -152,14 +152,14 @@ LOOKUP=$(curl -sS -G "https://api.recoupable.com/api/research/lookup" \ CM_ARTIST_ID=$(echo "$LOOKUP" | jq -r '.artist.id // empty') -[ -n "$CM_ARTIST_ID" ] || { echo "No Chartmetric match for Spotify ID $SPOTIFY_ARTIST_ID — skipping structured research"; } +[ -n "$CM_ARTIST_ID" ] || { echo "No Chartmetric match for Spotify ID $SPOTIFY_ARTIST_ID; skipping structured research"; } ``` -If the lookup fails (rare — most Spotify-discoverable artists have a Chartmetric profile), skip 4b–4d and just run 4e (web search). See [Artist Lookup](/api-reference/research/lookup) for the request/response schema. +If the lookup fails (rare; most Spotify-discoverable artists have a Chartmetric profile), skip 4b through 4d and just run 4e (web search). See [Artist Lookup](/api-reference/research/lookup) for the request/response schema. ### 4b: Pull the artist profile -Returns bio, genres, social URLs, label, career stage, and basic metrics — most of what deep research used to paraphrase. +Returns bio, genres, social URLs, label, career stage, and basic metrics. Most of what deep research used to paraphrase. ```bash PROFILE=$(curl -sS -G "https://api.recoupable.com/api/research/profile" \ @@ -171,7 +171,7 @@ See [Artist Profile](/api-reference/research/profile) for the response schema. ### 4c: Pull the career timeline -Career milestones, trajectory, and career-stage classification — covers the "notable achievements" portion of what deep research returned. +Career milestones, trajectory, and career-stage classification. Covers the "notable achievements" portion of what deep research returned. ```bash CAREER=$(curl -sS -G "https://api.recoupable.com/api/research/career" \ @@ -207,7 +207,7 @@ RESEARCH_WEB=$(curl -sS -X POST "https://api.recoupable.com/api/research/web" \ See [Web Search](/api-reference/research/web) for the request/response schema. -**After this step:** persist `cmArtistId: $CM_ARTIST_ID` into the frontmatter, save the four response payloads (profile, career, playlists, web) into a new `## Research` section of `RECOUP.md` — one subsection per endpoint, each with the raw JSON or a tight markdown summary so step 8 can compose from it. Tick `- [ ] 4.` → `- [x] 4.`. +**After this step:** persist `cmArtistId: $CM_ARTIST_ID` into the frontmatter, save the four response payloads (profile, career, playlists, web) into a new `## Research` section of `RECOUP.md`. Use one subsection per endpoint, each with the raw JSON or a tight markdown summary so step 8 can compose from it. Tick `- [ ] 4.` → `- [x] 4.`. ## Step 5: Pull the Spotify catalog @@ -230,7 +230,7 @@ ALBUM_DETAIL=$(curl -sS -G "https://api.recoupable.com/api/spotify/album" \ See [Spotify Top Tracks](/api-reference/spotify/artist-top-tracks), [Spotify Artist Albums](/api-reference/spotify/artist-albums), and [Spotify Album](/api-reference/spotify/album) for full schemas. -**After this step:** populate the artist's `releases/` folder — write one `releases/{release-slug}/RELEASE.md` per album (album slugs are bare, `-ep` / `-single` / `-compilation` suffixes for other types) using the per-album `GET /api/spotify/album?id=$ALBUM_ID` response, and write the top tracks snapshot to `releases/top-tracks.md`. `RELEASE.md` is the 18-section master release-management document (project snapshot, identifiers, narrative, audience, DSP strategy, marketing, social, PR, visuals, physical/merch/touring, team, budget, KPI tracking, links hub, plus Outstanding Deliverables and a Document History log) — Step 5 fills the Spotify-derivable fields and leaves the rest as `⚠️ TBD`. The full template + the field-by-field Spotify mapping live in the [`artist-workspace`](https://github.com/recoupable/skills/tree/main/skills/artist-workspace) skill at `references/release-template.md`. Tick `- [ ] 5.` → `- [x] 5.`. +**After this step:** populate the artist's `releases/` folder. Write one `releases/{release-slug}/RELEASE.md` per album (album slugs are bare, with `-ep` / `-single` / `-compilation` suffixes for other types) using the per-album `GET /api/spotify/album?id=$ALBUM_ID` response, and write the top tracks snapshot to `releases/top-tracks.md`. `RELEASE.md` is the 18-section master release-management document (project snapshot, identifiers, narrative, audience, DSP strategy, marketing, social, PR, visuals, physical/merch/touring, team, budget, KPI tracking, links hub, plus Outstanding Deliverables and a Document History log). Step 5 fills the Spotify-derivable fields and leaves the rest as `⚠️ TBD`. The full template plus the field-by-field Spotify mapping live in the [`artist-workspace`](https://github.com/recoupable/skills/tree/main/skills/artist-workspace) skill at `references/release-template.md`. Tick `- [ ] 5.` → `- [x] 5.`. ## Step 6: Search the web for additional socials @@ -272,7 +272,7 @@ See [Update Artist](/api-reference/artists/update) for the full body schema. ## Step 8: Synthesize the knowledge base -Combine the structured research outputs (`## Research` section — profile, career, playlists, web), the Spotify catalog (`releases/`), and the discovered socials into a comprehensive markdown report. Recommended sections: +Combine the structured research outputs (the `## Research` section with profile, career, playlists, web), the Spotify catalog (`releases/`), and the discovered socials into a comprehensive markdown report. Recommended sections: - Artist biography and origin - Discography highlights (top tracks + key albums) @@ -281,7 +281,7 @@ Combine the structured research outputs (`## Research` section — profile, care - Recent activity / press - Notable collaborations and achievements -Append the report to the same `RECOUP.md` you scaffolded in Step 0 — add it as a `## Knowledge base` section below the checklist. The path is: +Append the report to the same `RECOUP.md` you scaffolded in Step 0. Add it as a `## Knowledge base` section below the checklist. The path is: ``` artists/$ARTIST_SLUG/RECOUP.md @@ -306,11 +306,11 @@ This dovetails with the [`artist-workspace`](https://github.com/recoupable/skill | `facebook.com` | `FACEBOOK` | | `threads.net`, `threads.com` | `THREADS` | -URLs that don't match any of these are silently skipped — they won't be saved. +URLs that don't match any of these are silently skipped. They won't be saved. ## What this workflow doesn't enforce -There's no server-side orchestrator forcing each step to run in order — the chain is honor-system. The `RECOUP.md` checklist is what gives you determinism in practice: as long as you tick boxes and persist values after each step, a fresh turn (or a different agent) can pick up exactly where the last one stopped. If you skip a checkbox or skip the persist, the next turn won't know that step ran and may either redo it or, worse, treat downstream calls as ready when they aren't. +There's no server-side orchestrator forcing each step to run in order. The chain is honor-system. The `RECOUP.md` checklist is what gives you determinism in practice: as long as you tick boxes and persist values after each step, a fresh turn (or a different agent) can pick up exactly where the last one stopped. If you skip a checkbox or skip the persist, the next turn won't know that step ran and may either redo it or, worse, treat downstream calls as ready when they aren't. A few constraints to honor: diff --git a/workflows/generate-music-video.mdx b/workflows/generate-music-video.mdx index 461648cb..6e773139 100644 --- a/workflows/generate-music-video.mdx +++ b/workflows/generate-music-video.mdx @@ -1,13 +1,13 @@ --- title: 'Generate a Music Video' -description: 'End-to-end workflow to produce a vertical, social-ready music video — image, motion, caption — from an artist and a song.' +description: 'End-to-end workflow to produce a vertical, social-ready music video (image, motion, caption) from an artist and a song.' --- -This is the canonical recipe used internally by Recoup's `create-content` background task. Two paths are documented below: the **async pipeline** that an LLM agent should use, and the **manual recipe** for humans (or for cases where you want to swap a single step). +This is the canonical workflow used internally by Recoup's `create-content` background task. Two paths are documented below: the **async pipeline** that an LLM agent should use, and the **manual walkthrough** for humans (or for cases where you want to swap a single step). ## Hand it to your LLM -The fastest way to use this guide is to point an LLM at it directly — every page on this site is also served as raw markdown at the same path with a `.md` suffix, so models can fetch and follow it without parsing HTML: +The fastest way to use this guide is to point an LLM at it directly. Every page on this site is also served as raw markdown at the same path with a `.md` suffix, so models can fetch and follow it without parsing HTML: ``` Generate a music video for The Weeknd – "Blinding Lights" using @@ -18,9 +18,9 @@ Swap in your own artist and song. The LLM will resolve the artist, kick off the ## Running as an agent? Use the async pipeline -`POST /api/content/video` is synchronous and routinely takes 60–180s. Most agent shells (Claude Cowork, OpenAI tool calls, etc.) cap a single command at 30–60s and kill background processes when the shell exits — the manual recipe below is effectively un-runnable from those environments. +`POST /api/content/video` is synchronous and routinely takes 60–180s. Most agent shells (Claude Cowork, OpenAI tool calls, etc.) cap a single command at 30–60s and kill background processes when the shell exits. The manual walkthrough below is effectively un-runnable from those environments. -Use the async path instead — same five steps, run server-side: +Use the async path instead. Same five steps, run server-side: ```bash # Trigger @@ -61,7 +61,7 @@ ARTIST_ACCOUNT_ID=$(curl -sS "https://api.recoupable.com/api/artists?org_id=$ORG | jq -r --arg name "$ARTIST_NAME" '.artists[] | select(.name == $name) | .account_id') ``` -The artist record exposes both `id` and `account_id` (both UUIDs). Use **`account_id`** — `id` is the artist row's primary key, `account_id` is the underlying account that owns it. The two are easy to swap; you'll get a 404 from `/api/content/create` if you pass the wrong one. +The artist record exposes both `id` and `account_id` (both UUIDs). Use **`account_id`**. `id` is the artist row's primary key, `account_id` is the underlying account that owns it. The two are easy to swap; you'll get a 404 from `/api/content/create` if you pass the wrong one. ## Where the song lives @@ -75,36 +75,36 @@ Step 5 (and the async pipeline's lipsync mode) need a `song.mp3`. **Don't assume /clips.json ``` - Discover the repo with [`GET /api/sandboxes`](/api-reference/sandboxes/list) (returns `github_repo` and a `filetree`); fetch a file with [`GET /api/sandboxes/file?path=…`](/api-reference/sandboxes/file). **Binary files (`.mp3`, `.png`, `.mp4`) come back base64-encoded in the `content` field — decode before writing to disk.** + Discover the repo with [`GET /api/sandboxes`](/api-reference/sandboxes/list) (returns `github_repo` and a `filetree`); fetch a file with [`GET /api/sandboxes/file?path=…`](/api-reference/sandboxes/file). **Binary files (`.mp3`, `.png`, `.mp4`) come back base64-encoded in the `content` field. Decode before writing to disk.** 2. **If no song is in the sandbox, ask the user how to proceed.** Two options to offer: - - *"Want me to fetch the audio from YouTube?"* — agent downloads via `yt-dlp` (or equivalent), saves locally; user is responsible for any rights / DSP-licensing implications. - - *"Want to supply the song yourself?"* — user uploads / drops a path; agent reads from there. + - *"Want me to fetch the audio from YouTube?"* The agent downloads via `yt-dlp` (or equivalent), saves locally; user is responsible for any rights / DSP-licensing implications. + - *"Want to supply the song yourself?"* User uploads / drops a path; agent reads from there. Don't pick a path silently. The cost of fetching the wrong song from YouTube (or fetching one at all) is enough that the user should make the call. 3. **Don't fall back to "use a placeholder track."** A music video without the song is not a deliverable. -## Manual recipe (humans + targeted overrides) +## Manual walkthrough (humans + targeted overrides) The rest of this page walks the same steps you can run by hand or call individually if you want to swap a single stage (different prompt for image, different motion, different caption length). ### Prerequisites -- An auth credential for `api.recoupable.com`. Two options — pick one and use it for every call below: +- An auth credential for `api.recoupable.com`. Two options. Pick one and use it for every call below: - **API key** (`recoup_sk_…`, recommended for sandbox / agent use): pass as `-H "x-api-key: $RECOUP_API_KEY"`. - One-shot agent: `POST /api/agents/signup` with an `agent+{unique}@recoupable.com` email returns the key immediately. - Real-email signup: same endpoint with a real email mails a 6-digit code; complete with `POST /api/agents/verify`. See [Agents](/agents). - **Privy access token** (for end-user flows in chat/UI): pass as `-H "Authorization: Bearer $RECOUP_ACCESS_TOKEN"`. - The examples below use `x-api-key`. Substitute `Authorization: Bearer …` if you're using a Privy token. - `$ARTIST_NAME`, `$SONG_TITLE`, `$SONG_LYRICS_CLIP` (a 1–2 sentence mood snippet) -- `$REFERENCE_IMAGE_URL` *(optional)* — an artist photo or album cover to seed the image; if your template's purpose is "show this exact image" (e.g. `album-record-store`), set this and skip image generation in step 2 -- A `song.mp3` for step 5. **Don't ask the user for a local file** — fetch from the artist's repo via `/api/sandboxes/file`. +- `$REFERENCE_IMAGE_URL` *(optional)*: an artist photo or album cover to seed the image. If your template's purpose is "show this exact image" (e.g. `album-record-store`), set this and skip image generation in step 2. +- A `song.mp3` for step 5. **Don't ask the user for a local file.** Fetch from the artist's repo via `/api/sandboxes/file`. - `ffmpeg` installed locally for step 5 ### Step 0: Scaffold the workspace BEFORE any API call -The `VIDEO.md` checklist *is* the workflow state — tick boxes and persist values back to the frontmatter as you go. To resume later, find the first unchecked box. +The `VIDEO.md` checklist *is* the workflow state. Tick boxes and persist values back to the frontmatter as you go. To resume later, find the first unchecked box. ```bash VIDEO_SLUG=$(echo "$SONG_TITLE" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-//; s/-$//') @@ -122,17 +122,17 @@ captionText: finalVideoPath: --- -# $SONG_TITLE — $ARTIST_NAME +# $SONG_TITLE: $ARTIST_NAME ## Pipeline checklist -- [ ] 1. Pick template (\`GET /api/content/templates\` + detail) — capture \`template\` -- [ ] 2. Generate the base image (\`POST /api/content/image\`) — capture \`imageUrl\` - - [ ] 2a. (Optional) Upscale image (\`POST /api/content/upscale\` with \`type: "image"\`) -- [ ] 3. Generate the video (\`POST /api/content/video\`) — capture \`videoUrl\` - - [ ] 3a. (Optional) Upscale video (\`POST /api/content/upscale\` with \`type: "video"\`) -- [ ] 4. Generate the caption (\`POST /api/content/caption\`) — capture \`captionText\` -- [ ] 5. Compose 9:16 final with audio + caption (local \`ffmpeg\`) — capture \`finalVideoPath\` +- [ ] 1. Pick template (\`GET /api/content/templates\` + detail). Capture \`template\`. +- [ ] 2. Generate the base image (\`POST /api/content/image\`). Capture \`imageUrl\`. + - [ ] 2a. (Optional) Upscale image (\`POST /api/content/upscale\` with \`type: "image"\`). +- [ ] 3. Generate the video (\`POST /api/content/video\`). Capture \`videoUrl\`. + - [ ] 3a. (Optional) Upscale video (\`POST /api/content/upscale\` with \`type: "video"\`). +- [ ] 4. Generate the caption (\`POST /api/content/caption\`). Capture \`captionText\`. +- [ ] 5. Compose 9:16 final with audio + caption (local \`ffmpeg\`). Capture \`finalVideoPath\`. ## Notes EOF @@ -140,12 +140,12 @@ EOF ### Step 1: Pick a template (required: list **and** detail) -Templates carry the prompt, reference images, and styling that drive the rest of the chain — you can't write a good Step 2 prompt without them. List, pick, then fetch detail: +Templates carry the prompt, reference images, and styling that drive the rest of the chain. You can't write a good Step 2 prompt without them. List, pick, then fetch detail: ```bash curl -sS "https://api.recoupable.com/api/content/templates" \ -H "x-api-key: $RECOUP_API_KEY" \ - | jq -r '.templates[] | "\(.id) — \(.description)"' + | jq -r '.templates[] | "\(.id): \(.description)"' TEMPLATE="album-record-store" # or artist-caption-{bedroom,outside,stage} @@ -153,7 +153,7 @@ TEMPLATE_DETAIL=$(curl -sS "https://api.recoupable.com/api/content/templates/$TE -H "x-api-key: $RECOUP_API_KEY") ``` -**Templates that list "Requires: face image"** (e.g. `artist-caption-bedroom`) will fall back to their bundled reference images and produce a generic-likeness subject if you don't supply one — they don't 400. Pass `$REFERENCE_IMAGE_URL` if you want the model to preserve a specific artist's likeness, or omit it for a stock-feeling result. +**Templates that list "Requires: face image"** (e.g. `artist-caption-bedroom`) will fall back to their bundled reference images and produce a generic-likeness subject if you don't supply one. They don't 400. Pass `$REFERENCE_IMAGE_URL` if you want the model to preserve a specific artist's likeness, or omit it for a stock-feeling result. See [List Templates](/api-reference/content/templates) and [Template Detail](/api-reference/content/template-detail). @@ -161,12 +161,12 @@ See [List Templates](/api-reference/content/templates) and [Template Detail](/ap ### Step 2: Generate the base image -Use the template's own prompt and reference images — don't write your own from scratch. The template encodes the visual style; freeform prompts almost always drift off-brand. +Use the template's own prompt and reference images. Don't write your own from scratch. The template encodes the visual style; freeform prompts almost always drift off-brand. ```bash PROMPT=$(echo "$TEMPLATE_DETAIL" | jq -r '.image.prompt') REFS=$(echo "$TEMPLATE_DETAIL" | jq -c '[.image.reference_images[]?]') -# $REFS is 5–15 URLs depending on the template — pass all of them via images[] +# $REFS is 5–15 URLs depending on the template; pass all of them via images[] IMAGE_URL=$(curl -sS -X POST "https://api.recoupable.com/api/content/image" \ -H "x-api-key: $RECOUP_API_KEY" -H "Content-Type: application/json" \ @@ -195,14 +195,14 @@ IMAGE_URL=$(curl -sS -X POST "https://api.recoupable.com/api/content/upscale" \ -d "$(jq -n --arg url "$IMAGE_URL" '{url: $url, type: "image"}')" \ | jq -r '.url') -# Video (after step 3) — same call, type: "video", reassign $VIDEO_URL +# Video (after step 3): same call, type: "video", reassign $VIDEO_URL ``` See [Upscale](/api-reference/content/upscale). ### Step 3: Generate the video -Pass the image and a short motion prompt. For lipsync, also pass a presigned `audio_url` to a song clip — the model will animate the artist's mouth. +Pass the image and a short motion prompt. For lipsync, also pass a presigned `audio_url` to a song clip and the model will animate the artist's mouth. ```bash MOTION=$(echo "$TEMPLATE_DETAIL" | jq -r '.video.movements[0] // "Slow camera drift, subtle subject motion"') @@ -237,7 +237,7 @@ CAPTION_STROKE=$(echo "$CAPTION_RESPONSE" | jq -r '.borderColor // "black"') CAPTION_FONT_SIZE=$(echo "$CAPTION_RESPONSE" | jq -r '.maxFontSize // 48') ``` -`length` accepts `"short"` (default), `"medium"`, `"long"`, or `"none"` to skip. The four styling fields (`font`, `color`, `borderColor`, `maxFontSize`) are template-driven hints — Step 5 wires them into ffmpeg's `drawtext` so the burned-in caption matches the template's brand. +`length` accepts `"short"` (default), `"medium"`, `"long"`, or `"none"` to skip. The four styling fields (`font`, `color`, `borderColor`, `maxFontSize`) are template-driven hints. Step 5 wires them into ffmpeg's `drawtext` so the burned-in caption matches the template's brand. See [Generate Caption](/api-reference/content/generate-caption). @@ -252,10 +252,10 @@ curl -sS -o "$VIDEO_DIR/clip.mp4" "$VIDEO_URL" SONG_PATH="$VIDEO_DIR/song.mp3" # see "Where the song lives" above FINAL_PATH="$VIDEO_DIR/final.mp4" -# Write caption to a file — drawtext reads it via textfile=, sidesteps shell-escaping (apostrophes, etc.) +# Write caption to a file. drawtext reads it via textfile=, sidestepping shell-escaping (apostrophes, etc.) echo -n "$CAPTION_TEXT" > "$VIDEO_DIR/caption.txt" -# Single-line filter graph — newlines inside -filter_complex are literal characters and break the [v] label +# Single-line filter graph: newlines inside -filter_complex are literal characters and break the [v] label ffmpeg -y \ -stream_loop -1 -i "$VIDEO_DIR/clip.mp4" \ -i "$SONG_PATH" \ @@ -267,12 +267,6 @@ ffmpeg -y \ **After:** write `finalVideoPath`, tick the box. With every box ticked, the music video is complete. -## Step 6: Publish (optional) - -Once the MP4 is rendered, push it to the artist's socials with the [Connectors API](/api-reference/connectors/list). One heads-up worth knowing: - -- **TikTok URL ownership.** `TIKTOK_PUBLISH_VIDEO` (pull-from-URL mode) requires the source domain be verified in the TikTok dev portal. `fal.media` URLs will fail with `url_ownership_unverified` — use `TIKTOK_UPLOAD_VIDEO` instead, which accepts the same URL and uploads server-side. - --- -The checklist is the source of truth — if a box isn't ticked, treat the step as not run. +The checklist is the source of truth. If a box isn't ticked, treat the step as not run.