Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions api-reference/sites/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
title: "Sites"
description: "Create, generate, and publish fan experiences through the API or MCP."
---

Sites uses the same backend operations from the web app, HTTP API, and MCP. A new site is a **private draft**. Generation never publishes it automatically.

## Authentication

Private HTTP endpoints accept exactly one of `x-api-key: YOUR_API_KEY` or `Authorization: Bearer YOUR_PRIVY_ACCESS_TOKEN`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: This page names the Privy token placeholder YOUR_PRIVY_ACCESS_TOKEN, but authentication.mdx (the canonical auth page) uses YOUR_PRIVY_JWT for the identical header. Align the placeholder so readers searching for the token name get one spelling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/sites/overview.mdx, line 10:

<comment>This page names the Privy token placeholder `YOUR_PRIVY_ACCESS_TOKEN`, but `authentication.mdx` (the canonical auth page) uses `YOUR_PRIVY_JWT` for the identical header. Align the placeholder so readers searching for the token name get one spelling.</comment>

<file context>
@@ -0,0 +1,79 @@
+
+## Authentication
+
+Private HTTP endpoints accept exactly one of `x-api-key: YOUR_API_KEY` or `Authorization: Bearer YOUR_PRIVY_ACCESS_TOKEN`.
+MCP uses the existing authenticated `https://api.recoupable.dev/mcp` connection.
+
</file context>
Suggested change
Private HTTP endpoints accept exactly one of `x-api-key: YOUR_API_KEY` or `Authorization: Bearer YOUR_PRIVY_ACCESS_TOKEN`.
Private HTTP endpoints accept exactly one of `x-api-key: YOUR_API_KEY` or `Authorization: Bearer YOUR_PRIVY_JWT`.

MCP uses the existing authenticated `https://api.recoupable.dev/mcp` connection.

The caller is derived from authentication. Do not send an `account_id`. An optional `organizationId` selects a workspace the caller can access. Omit it for the authenticated account's workspace.

## Endpoints and tools

| HTTP | MCP tool | Result |
| --- | --- | --- |
| `GET /api/sites` | `list_sites` | `{ sites: [...] }` |
| `POST /api/sites` | `create_site` | `{ site: ... }`, HTTP 201 |
| `GET /api/sites/{id}` | `get_site` | `{ site: ... }` |
| `PATCH /api/sites/{id}` action `generate` | `generate_site` | Updated private draft |
| `PATCH /api/sites/{id}` action `publish` | `publish_site` | Saved draft becomes public |
| `PATCH /api/sites/{id}` action `unpublish` | `unpublish_site` | Public snapshot removed, draft retained |
| `GET /api/sites/{id}/signups` | `get_site_signups` | `{ signups: [{ email, created_at }] }`, up to 10,000 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The GET /api/sites/{id}/signups row caps results at 10,000 but never says what happens beyond that. A site with more signups returns incomplete data, and readers cannot tell whether the response is silently truncated, ordered, or paginated. State the cutoff behavior (e.g., which 10,000 are returned and whether pagination exists) so consumers do not silently export a partial list.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/sites/overview.mdx, line 25:

<comment>The `GET /api/sites/{id}/signups` row caps results at 10,000 but never says what happens beyond that. A site with more signups returns incomplete data, and readers cannot tell whether the response is silently truncated, ordered, or paginated. State the cutoff behavior (e.g., which 10,000 are returned and whether pagination exists) so consumers do not silently export a partial list.</comment>

<file context>
@@ -0,0 +1,79 @@
+| `PATCH /api/sites/{id}` action `generate` | `generate_site` | Updated private draft |
+| `PATCH /api/sites/{id}` action `publish` | `publish_site` | Saved draft becomes public |
+| `PATCH /api/sites/{id}` action `unpublish` | `unpublish_site` | Public snapshot removed, draft retained |
+| `GET /api/sites/{id}/signups` | `get_site_signups` | `{ signups: [{ email, created_at }] }`, up to 10,000 |
+| `POST /api/sites/assets` | `upload_site_asset` | `{ asset: { url, name, type } }` |
+
</file context>
Suggested change
| `GET /api/sites/{id}/signups` | `get_site_signups` | `{ signups: [{ email, created_at }] }`, up to 10,000 |
| `GET /api/sites/{id}/signups` | `get_site_signups` | `{ signups: [{ email, created_at }] }`, up to the 10,000 most recent (no pagination) |

| `POST /api/sites/assets` | `upload_site_asset` | `{ asset: { url, name, type } }` |

Listing accepts optional `organizationId` and `artistId` query parameters. All private reads and writes verify workspace access. Signup emails are never part of the public response.

## Create and generate

Create a draft with a Spotify track, album, or playlist URL. Recoup retrieves its title and artwork. The brief is optional; without it, Recoup chooses a playable concept. Alternatively, supply both a name and a brief without a release URL.

```bash
curl https://api.recoupable.dev/api/sites \
-H "x-api-key: $RECOUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"releaseUrl":"https://open.spotify.com/track/TRACK_ID","brief":"Build a maze game"}'
```

Optional creation fields: `name` (120 characters), `brief` (6,000), `organizationId`, `artistId`, and `assets` (up to eight workspace-owned assets returned by the upload endpoint). An artist must be accessible to the caller and belong to the selected organization when one is used.

Read the returned `site.id` and `site.revision`, then generate:

```json
{
"action": "generate",
"revision": 0,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The text above this body says to "Read the returned site.id and site.revision", then the example hardcodes revision: 0. A reader who follows the instruction gets a revision that may not be 0, which makes the example look stale. Use a placeholder consistent with the publish example's CURRENT_REVISION.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/sites/overview.mdx, line 48:

<comment>The text above this body says to "Read the returned `site.id` and `site.revision`", then the example hardcodes `revision: 0`. A reader who follows the instruction gets a revision that may not be 0, which makes the example look stale. Use a placeholder consistent with the publish example's `CURRENT_REVISION`.</comment>

<file context>
@@ -0,0 +1,79 @@
+```json
+{
+  "action": "generate",
+  "revision": 0,
+  "instruction": "Build a maze game with touch and keyboard controls."
+}
</file context>

"instruction": "Build a maze game with touch and keyboard controls."
}
```

Send that body to `PATCH /api/sites/{id}`. MCP's `generate_site` accepts `id`, `revision`, and `instruction` without an `action` field. Generation uses GPT-6 Astra by default and may take several minutes; use a client timeout that permits up to 300 seconds.

Generation failures leave the saved draft unchanged. A `409` means another edit changed the revision; read the site again before retrying.

## Publish

After reviewing the draft, send `{"action":"publish","revision":CURRENT_REVISION}` to the same PATCH endpoint, or call `publish_site` with `id` and `revision`.
The public page is `https://chat.recoupable.dev/s/{id}`.

Unpublish with `action: "unpublish"`, or `unpublish_site`. Agents should publish only when explicitly instructed.

## Uploads

HTTP uploads are multipart forms with a `file` field and optional `organizationId` query parameter. Supported formats: JPEG, PNG, WebP, MP3, and WAV, up to 4 MB per file. Images are re-encoded to WebP. Audio is checked for its file signature.

MCP's `upload_site_asset` accepts `name`, `contentType`, `base64` file bytes, and optional `organizationId`. It uses the same validation and storage path as HTTP.

## Public endpoints

- `GET /api/sites/public/{id}` returns `{ snapshot: ... }` for a published site only. Drafts, account identifiers, and signup data are excluded.
- `POST /api/sites/public/{id}/signup` accepts `{"email":"fan@example.com","consent":"yes"}`. An optional `website` honeypot must be empty. Duplicate submissions succeed without disclosing list membership. Unpublished sites reject signups.

Public pages render in the chat app. The API owns snapshots, generation, uploads, and signup persistence. Spotify OAuth and the browser music player remain in the web app.

## Errors

`400` invalid input; `401` missing/invalid authentication; `403` workspace or artist access denied; `404` missing/unpublished site; `409` stale revision; `422` Spotify metadata unavailable; `503` temporary operation failure.
11 changes: 11 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,17 @@
]
}
]
},
{
"tab": "Sites",
"groups": [
{
"group": "Sites",
"pages": [
"api-reference/sites/overview"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new Sites tab links only overview.mdx, which is a hand-written prose page, while every other API-reference tab links frontmatter-only pages that Mintlify auto-generates from an OpenAPI spec. There is no Sites spec anywhere in api-reference/openapi/, so the eight HTTP endpoints documented in the PR will not render as API-reference operations with parameter and response schemas, and this page departs from the repo's binding rule that api-reference pages be frontmatter-only. Add the Sites endpoints to a spec file under api-reference/openapi/ and expose them via frontmatter-only pages instead of burying the contract in prose.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs.json, line 433:

<comment>The new Sites tab links only overview.mdx, which is a hand-written prose page, while every other API-reference tab links frontmatter-only pages that Mintlify auto-generates from an OpenAPI spec. There is no Sites spec anywhere in api-reference/openapi/, so the eight HTTP endpoints documented in the PR will not render as API-reference operations with parameter and response schemas, and this page departs from the repo's binding rule that api-reference pages be frontmatter-only. Add the Sites endpoints to a spec file under api-reference/openapi/ and expose them via frontmatter-only pages instead of burying the contract in prose.</comment>

<file context>
@@ -423,6 +423,17 @@
+          {
+            "group": "Sites",
+            "pages": [
+              "api-reference/sites/overview"
+            ]
+          }
</file context>

]
}
]
}
],
"global": {
Expand Down