Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.recoupable.com/llms.txt

Use this file to discover all available pages before exploring further.

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. 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 recoup-api.vercel.app
  • $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 + identifyPOST /api/artists, then find the canonical Spotify match
  2. EnrichPATCH 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:
ARTIST_SLUG=$(echo "$ARTIST_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]\+/-/g; s/^-//; s/-$//')
ARTIST_DIR="artists/$ARTIST_SLUG"
mkdir -p "$ARTIST_DIR"

cat > "$ARTIST_DIR/RECOUP.md" <<EOF
---
artistName: $ARTIST_NAME
artistSlug: $ARTIST_SLUG
artistId:
spotifyArtistId:
spotifyProfileUrl:
imageUrl:
cmArtistId:
---

# $ARTIST_NAME

## 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

## 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. 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

If $ARTIST_DIR/RECOUP.md already exists, do not re-scaffold and do not re-run completed steps. Read the file, find the first unchecked item, and resume from there using the values already saved in the frontmatter:
# Show the next unchecked step
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.

Step 1: Create the artist

ARTIST_RESPONSE=$(curl -sS -X POST "https://recoup-api.vercel.app/api/artists" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg name "$ARTIST_NAME" --arg org "$RECOUP_ORG_ID" \
        '{name: $name, organization_id: $org}')")

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. See Create Artist for the full request/response schema. After this step: write artistId: $ARTIST_ID into the frontmatter and tick - [ ] 1.- [x] 1. in RECOUP.md.

Step 2: Find the canonical Spotify match

SPOTIFY=$(curl -sS -G "https://recoup-api.vercel.app/api/spotify/search" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "q=$ARTIST_NAME" \
  --data-urlencode "type=artist" \
  --data-urlencode "limit=10")
Pick the best match: prefer an exact case-insensitive name match; if multiple, prefer the highest popularity score. Export the fields the rest of the chain needs:
MATCH=$(echo "$SPOTIFY" | jq --arg name "$ARTIST_NAME" '
  .artists.items
  | (map(select((.name | ascii_downcase) == ($name | ascii_downcase))) | sort_by(-.popularity) | first)
    // (sort_by(-.popularity) | first)
')

SPOTIFY_ARTIST_ID=$(echo "$MATCH" | jq -r '.id // empty')
SPOTIFY_PROFILE_URL=$(echo "$MATCH" | jq -r '.external_urls.spotify // empty')
SPOTIFY_IMAGE_URL=$(echo "$MATCH" | jq -r '.images[0].url // empty')

[ -n "$SPOTIFY_ARTIST_ID" ] || { echo "No Spotify match for $ARTIST_NAME"; exit 1; }
Also keep genres, followers.total, and popularity from $MATCH for the KB report later. See Spotify Search for the full query parameters and response schema. After this step: write spotifyArtistId, spotifyProfileUrl, and imageUrl into the frontmatter, save genres / followers.total / popularity to the ## Notes section, and tick - [ ] 2.- [x] 2..

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).
curl -sS -X PATCH "https://recoup-api.vercel.app/api/artists/$ARTIST_ID" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg image "$SPOTIFY_IMAGE_URL" --arg url "$SPOTIFY_PROFILE_URL" \
        '{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 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.

4a: Look up the Chartmetric artist_id

Most of the structured research endpoints take a Chartmetric artist_id, not the Spotify ID. Resolve it once and reuse it for the rest of step 4.
LOOKUP=$(curl -sS -G "https://recoup-api.vercel.app/api/research/lookup" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "spotifyId=$SPOTIFY_ARTIST_ID")

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"; }
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 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.
PROFILE=$(curl -sS -G "https://recoup-api.vercel.app/api/research/profile" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$CM_ARTIST_ID")
See Artist 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=$(curl -sS -G "https://recoup-api.vercel.app/api/research/career" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$CM_ARTIST_ID")
See Career Timeline for the response schema.

4d: Pull editorial + algorithmic playlist placements

Replaces the “playlists / radio rotations / editorial features” portion of the deep-research Spotify-presence query.
PLAYLISTS=$(curl -sS -G "https://recoup-api.vercel.app/api/research/playlists" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$CM_ARTIST_ID")
See Artist Playlists for the response schema.

4e: Web search for narrative / press / collaborations

Structured endpoints don’t cover press coverage, cultural narrative, or recent feature/collab announcements. Fill that gap with a single web search.
RESEARCH_WEB=$(curl -sS -X POST "https://recoup-api.vercel.app/api/research/web" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg name "$ARTIST_NAME" \
        '{query: ($name + " biography press recent collaborations")}')")
See Web Search 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..

Step 5: Pull the Spotify catalog

TOP_TRACKS=$(curl -sS -G "https://recoup-api.vercel.app/api/spotify/artist/topTracks" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$SPOTIFY_ARTIST_ID")

ALBUMS=$(curl -sS -G "https://recoup-api.vercel.app/api/spotify/artist/albums" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$SPOTIFY_ARTIST_ID")

# For each notable album, drill in (ALBUM_ID from $ALBUMS):
ALBUM_DETAIL=$(curl -sS -G "https://recoup-api.vercel.app/api/spotify/album" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  --data-urlencode "id=$ALBUM_ID")
$SPOTIFY_ARTIST_ID is the value you exported in step 2. See Spotify Top Tracks, Spotify Artist Albums, and 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 skill at references/release-template.md. Tick - [ ] 5.- [x] 5..

Step 6: Search the web for additional socials

SOCIALS_SEARCH=$(curl -sS -X POST "https://recoup-api.vercel.app/api/research/web" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg name "$ARTIST_NAME" \
        '{query: ($name + " official instagram tiktok twitter youtube")}')")
Parse the results to extract any new social URLs whose host matches the platform reference table below. See Web Search for the request/response schema. After this step: save the discovered URLs (one per platform) into the ## Notes section so step 7 can read them without re-querying. Tick - [ ] 6.- [x] 6..

Step 7: PATCH the artist with the discovered socials

curl -sS -X PATCH "https://recoup-api.vercel.app/api/artists/$ARTIST_ID" \
  -H "Authorization: Bearer $RECOUP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profileUrls": {
      "INSTAGRAM": "https://instagram.com/...",
      "TIKTOK": "https://tiktok.com/@...",
      "TWITTER": "https://x.com/...",
      "YOUTUBE": "https://youtube.com/@..."
    }
  }'
Only include keys for platforms you actually found URLs for. The PATCH preserves existing socials for keys you omit, so this is safe to run incrementally. See Update Artist for the full body schema. After this step: tick - [ ] 7.- [x] 7..

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:
  • Artist biography and origin
  • Discography highlights (top tracks + key albums)
  • Spotify presence (genres, listener count, notable playlists)
  • Social media footprint
  • 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:
artists/$ARTIST_SLUG/RECOUP.md
This dovetails with the artist-workspace skill’s filesystem conventions, so future sandbox sessions can read both the checklist and the KB without needing a hosted URL. After this step: tick - [ ] 8.- [x] 8.. With every box ticked, the artist is fully set up.

Platform key reference

profileUrls keys are uppercase platform identifiers, inferred from the URL host. Recognized platforms:
URL containsprofileUrls key
spotify.comSPOTIFY
instagram.comINSTAGRAM
tiktok.comTIKTOK
x.com, twitter.comTWITTER
youtube.YOUTUBE
apple.comAPPLE
facebook.comFACEBOOK
threads.net, threads.comTHREADS
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. A few constraints to honor:
  • Run steps in order. The frontmatter values written at one step are the inputs for later steps.
  • Don’t continue past a 4xx/5xx without recovery. Leave the box unchecked, write the error to ## Notes, and resolve before resuming.
  • Treat the file as the source of truth. If something isn’t on disk, don’t assume it ran.