diff --git a/api-reference/accounts/add-artist.mdx b/api-reference/accounts/add-artist.mdx deleted file mode 100644 index 33f2fe3..0000000 --- a/api-reference/accounts/add-artist.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Add Artist to Account' -openapi: 'POST /api/accounts/artists' ---- diff --git a/api-reference/accounts/create.mdx b/api-reference/accounts/create.mdx deleted file mode 100644 index 67d37c6..0000000 --- a/api-reference/accounts/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Account' -openapi: 'POST /api/accounts' ---- diff --git a/api-reference/accounts/get.mdx b/api-reference/accounts/get.mdx deleted file mode 100644 index eb63b7b..0000000 --- a/api-reference/accounts/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Account' -openapi: 'GET /api/accounts/{id}' ---- diff --git a/api-reference/accounts/id.mdx b/api-reference/accounts/id.mdx deleted file mode 100644 index 33a52d9..0000000 --- a/api-reference/accounts/id.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Account ID' -openapi: 'GET /api/accounts/id' ---- diff --git a/api-reference/accounts/update.mdx b/api-reference/accounts/update.mdx deleted file mode 100644 index dc622e4..0000000 --- a/api-reference/accounts/update.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Account' -openapi: 'PATCH /api/accounts' ---- diff --git a/api-reference/admins/check.mdx b/api-reference/admins/check.mdx deleted file mode 100644 index 5d874fd..0000000 --- a/api-reference/admins/check.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Check Admin Status' -openapi: 'GET /api/admins' ---- diff --git a/api-reference/admins/coding-agent-slack-tags.mdx b/api-reference/admins/coding-agent-slack-tags.mdx deleted file mode 100644 index c10eeb5..0000000 --- a/api-reference/admins/coding-agent-slack-tags.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Coding Agent Slack Tags (Admin)' -openapi: 'GET /api/admins/coding/slack' ---- diff --git a/api-reference/admins/coding-pr.mdx b/api-reference/admins/coding-pr.mdx deleted file mode 100644 index ce9ae16..0000000 --- a/api-reference/admins/coding-pr.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Coding Agent PR Merged Status (Admin)' -openapi: 'GET /api/admins/coding/pr' ---- diff --git a/api-reference/admins/content-slack-tags.mdx b/api-reference/admins/content-slack-tags.mdx deleted file mode 100644 index 00dcafe..0000000 --- a/api-reference/admins/content-slack-tags.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Content Agent Slack Tags (Admin)' -openapi: 'GET /api/admins/content/slack' ---- diff --git a/api-reference/admins/emails.mdx b/api-reference/admins/emails.mdx deleted file mode 100644 index 5e92c9f..0000000 --- a/api-reference/admins/emails.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Account Emails (Admin)' -openapi: 'GET /api/admins/emails' ---- diff --git a/api-reference/admins/privy.mdx b/api-reference/admins/privy.mdx deleted file mode 100644 index d91e468..0000000 --- a/api-reference/admins/privy.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Privy Logins (Admin)' -openapi: 'GET /api/admins/privy' ---- diff --git a/api-reference/admins/sandboxes-orgs.mdx b/api-reference/admins/sandboxes-orgs.mdx deleted file mode 100644 index 575b81f..0000000 --- a/api-reference/admins/sandboxes-orgs.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Org Repo Stats (Admin)' -openapi: 'GET /api/admins/sandboxes/orgs' ---- diff --git a/api-reference/admins/sandboxes.mdx b/api-reference/admins/sandboxes.mdx deleted file mode 100644 index 473fce7..0000000 --- a/api-reference/admins/sandboxes.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Account Sandboxes (Admin)' -openapi: 'GET /api/admins/sandboxes' ---- diff --git a/api-reference/apify/scraper.mdx b/api-reference/apify/scraper.mdx deleted file mode 100644 index 9c47bde..0000000 --- a/api-reference/apify/scraper.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Scraper Results' -openapi: 'GET /api/apify/scraper' ---- diff --git a/api-reference/artist/profile.mdx b/api-reference/artist/profile.mdx deleted file mode 100644 index 9b4d78e..0000000 --- a/api-reference/artist/profile.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Artist Profile -openapi: GET /api/artist-profile ---- diff --git a/api-reference/artist/segments.mdx b/api-reference/artist/segments.mdx deleted file mode 100644 index d584010..0000000 --- a/api-reference/artist/segments.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Artist Segments -openapi: GET /api/artist/segments ---- diff --git a/api-reference/artist/socials-scrape.mdx b/api-reference/artist/socials-scrape.mdx deleted file mode 100644 index 39436ca..0000000 --- a/api-reference/artist/socials-scrape.mdx +++ /dev/null @@ -1,3 +0,0 @@ ---- -openapi: post /api/artist/socials/scrape ---- diff --git a/api-reference/artist/socials.mdx b/api-reference/artist/socials.mdx deleted file mode 100644 index b3062f6..0000000 --- a/api-reference/artist/socials.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Artist Socials -openapi: GET /api/artist/socials ---- diff --git a/api-reference/artists/create.mdx b/api-reference/artists/create.mdx deleted file mode 100644 index df5c2c7..0000000 --- a/api-reference/artists/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Artist' -openapi: 'POST /api/artists' ---- diff --git a/api-reference/artists/list.mdx b/api-reference/artists/list.mdx deleted file mode 100644 index 0d4fff2..0000000 --- a/api-reference/artists/list.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Artists' -openapi: 'GET /api/artists' ---- diff --git a/api-reference/chat/artist.mdx b/api-reference/chat/artist.mdx deleted file mode 100644 index dbab957..0000000 --- a/api-reference/chat/artist.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Get Chat Artist" -openapi: GET /api/chats/{id}/artist ---- diff --git a/api-reference/chat/chats.mdx b/api-reference/chat/chats.mdx deleted file mode 100644 index a25f088..0000000 --- a/api-reference/chat/chats.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Chats -openapi: GET /api/chats ---- diff --git a/api-reference/chat/compact.mdx b/api-reference/chat/compact.mdx deleted file mode 100644 index 96148e4..0000000 --- a/api-reference/chat/compact.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Compact Chats' -openapi: 'POST /api/chats/compact' ---- diff --git a/api-reference/chat/create.mdx b/api-reference/chat/create.mdx deleted file mode 100644 index 395a9f3..0000000 --- a/api-reference/chat/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Chat' -openapi: post /api/chats ---- diff --git a/api-reference/chat/delete.mdx b/api-reference/chat/delete.mdx deleted file mode 100644 index 2818761..0000000 --- a/api-reference/chat/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Chat' -openapi: delete /api/chats ---- diff --git a/api-reference/chat/generate.mdx b/api-reference/chat/generate.mdx deleted file mode 100644 index c84a9df..0000000 --- a/api-reference/chat/generate.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Generate Chat -openapi: post /api/chat/generate ---- diff --git a/api-reference/chat/messages-copy.mdx b/api-reference/chat/messages-copy.mdx deleted file mode 100644 index a6b34c7..0000000 --- a/api-reference/chat/messages-copy.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Copy Chat Messages" -openapi: POST /api/chats/{id}/messages/copy ---- diff --git a/api-reference/chat/messages-trailing-delete.mdx b/api-reference/chat/messages-trailing-delete.mdx deleted file mode 100644 index a756de8..0000000 --- a/api-reference/chat/messages-trailing-delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Delete Trailing Chat Messages" -openapi: "DELETE /api/chats/{id}/messages/trailing" ---- diff --git a/api-reference/chat/messages.mdx b/api-reference/chat/messages.mdx deleted file mode 100644 index 34db510..0000000 --- a/api-reference/chat/messages.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Chat Messages -openapi: GET /api/chats/{id}/messages ---- diff --git a/api-reference/chat/segment.mdx b/api-reference/chat/segment.mdx deleted file mode 100644 index 34becf2..0000000 --- a/api-reference/chat/segment.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Get Chat Segment" -openapi: GET /api/chats/{id}/segment ---- diff --git a/api-reference/chat/stream.mdx b/api-reference/chat/stream.mdx deleted file mode 100644 index 7944368..0000000 --- a/api-reference/chat/stream.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Stream Chat -openapi: post /api/chat ---- diff --git a/api-reference/chat/update.mdx b/api-reference/chat/update.mdx deleted file mode 100644 index 4ece8e1..0000000 --- a/api-reference/chat/update.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Chat' -openapi: patch /api/chats ---- diff --git a/api-reference/comments/get.mdx b/api-reference/comments/get.mdx deleted file mode 100644 index 6302f31..0000000 --- a/api-reference/comments/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Comments -openapi: GET /api/comments ---- diff --git a/api-reference/connectors/authorize.mdx b/api-reference/connectors/authorize.mdx deleted file mode 100644 index 3114fc2..0000000 --- a/api-reference/connectors/authorize.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Authorize Connector' -openapi: 'POST /api/connectors' ---- diff --git a/api-reference/connectors/disconnect.mdx b/api-reference/connectors/disconnect.mdx deleted file mode 100644 index ff03791..0000000 --- a/api-reference/connectors/disconnect.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Disconnect Connector' -openapi: 'DELETE /api/connectors' ---- diff --git a/api-reference/connectors/list.mdx b/api-reference/connectors/list.mdx deleted file mode 100644 index e8ccd7d..0000000 --- a/api-reference/connectors/list.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Connectors' -openapi: 'GET /api/connectors' ---- diff --git a/api-reference/content-agent/callback.mdx b/api-reference/content-agent/callback.mdx deleted file mode 100644 index 1be4bdf..0000000 --- a/api-reference/content-agent/callback.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Task Callback' -openapi: 'POST /api/content-agent/callback' ---- diff --git a/api-reference/content-agent/webhook.mdx b/api-reference/content-agent/webhook.mdx deleted file mode 100644 index 723d8bc..0000000 --- a/api-reference/content-agent/webhook.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Slack Webhook' -openapi: 'POST /api/content-agent/{platform}' ---- diff --git a/api-reference/content/create.mdx b/api-reference/content/create.mdx deleted file mode 100644 index d9f0af3..0000000 --- a/api-reference/content/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Content' -openapi: 'POST /api/content/create' ---- diff --git a/api-reference/content/estimate.mdx b/api-reference/content/estimate.mdx deleted file mode 100644 index 244dd93..0000000 --- a/api-reference/content/estimate.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Estimate Cost' -openapi: 'GET /api/content/estimate' ---- diff --git a/api-reference/content/templates.mdx b/api-reference/content/templates.mdx deleted file mode 100644 index ff8a568..0000000 --- a/api-reference/content/templates.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Templates' -openapi: 'GET /api/content/templates' ---- diff --git a/api-reference/content/validate.mdx b/api-reference/content/validate.mdx deleted file mode 100644 index d716603..0000000 --- a/api-reference/content/validate.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Validate Artist' -openapi: 'GET /api/content/validate' ---- diff --git a/api-reference/fans/get.mdx b/api-reference/fans/get.mdx deleted file mode 100644 index 3722cc8..0000000 --- a/api-reference/fans/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Artist Fans -openapi: GET /api/fans ---- diff --git a/api-reference/image/generation.mdx b/api-reference/image/generation.mdx deleted file mode 100644 index 74a53ac..0000000 --- a/api-reference/image/generation.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Generate Image' -openapi: 'GET /api/image/generate' ---- diff --git a/api-reference/instagram/comments.mdx b/api-reference/instagram/comments.mdx deleted file mode 100644 index d7baf70..0000000 --- a/api-reference/instagram/comments.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Comments' -openapi: 'GET /api/instagram/comments' ---- diff --git a/api-reference/instagram/profiles.mdx b/api-reference/instagram/profiles.mdx deleted file mode 100644 index 80a4094..0000000 --- a/api-reference/instagram/profiles.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Profiles' -openapi: 'GET /api/instagram/profiles' ---- diff --git a/api-reference/introduction.mdx b/api-reference/introduction.mdx index 057216c..db828d7 100644 --- a/api-reference/introduction.mdx +++ b/api-reference/introduction.mdx @@ -8,11 +8,11 @@ description: 'API documentation for the Recoup platform - AI agents for the musi Welcome to the Recoup API documentation. Recoup is an AI agent platform for the music industry that provides artist analytics, fan segmentation, and AI-powered chat assistants. Build smarter song rollouts, create unforgettable fan experiences, and drive lasting artist growth. - View the OpenAPI specification file on GitHub + View the per-domain OpenAPI specification files on GitHub ## Base URL diff --git a/api-reference/notifications/create.mdx b/api-reference/notifications/create.mdx deleted file mode 100644 index 664176c..0000000 --- a/api-reference/notifications/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Send Notification' -openapi: 'POST /api/notifications' ---- diff --git a/api-reference/openapi.json b/api-reference/openapi.json deleted file mode 100644 index 456a946..0000000 --- a/api-reference/openapi.json +++ /dev/null @@ -1,12076 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "Recoup API", - "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", - "license": { - "name": "MIT" - }, - "version": "1.0.0" - }, - "servers": [ - { - "url": "https://recoup-api.vercel.app" - } - ], - "security": [ - { - "apiKeyAuth": [] - } - ], - "paths": { - "/api/tasks": { - "get": { - "description": "Retrieve scheduled tasks. The response includes recent_runs (last 5 runs) and upcoming (next scheduled run times) sourced directly from the Trigger.dev API. Supports filtering by id, account_id, or artist_account_id.", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "Filter by task ID (UUID). Returns a single task matching the provided ID.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "account_id", - "in": "query", - "description": "Filter tasks to only include those for the specified account.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "artist_account_id", - "in": "query", - "description": "Filter tasks to only include those for the specified artist account.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Tasks retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TasksResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Create a new scheduled task. All fields are required. The response shape matches the GET endpoint (an array containing the created task).", - "requestBody": { - "description": "Task to create", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTaskRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Task created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TasksResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "patch": { - "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).", - "requestBody": { - "description": "Task fields to update", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTaskRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Task updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TasksResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "delete": { - "description": "Delete an existing scheduled task by its ID. Returns the status of the delete operation.", - "requestBody": { - "description": "Task to delete", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTaskRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Task deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTaskResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/tasks/runs": { - "get": { - "description": "Returns an array of task runs. When runId is provided, the array contains that single run. When omitted, returns recent runs for the authenticated account. Use account_id to query runs for a specific account within your organizations.", - "parameters": [ - { - "name": "runId", - "in": "query", - "description": "The unique identifier of a specific task run to retrieve. If omitted, returns a list of recent runs for the authenticated account.", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of runs to return when listing (ignored when runId is provided). Default 20, max 100.", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "minimum": 1, - "maximum": 100 - } - }, - { - "name": "account_id", - "in": "query", - "description": "Filter runs by account ID. When provided, returns runs tagged with account:. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Task runs retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TaskRunListResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Task run not found (only when runId is provided)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not accessible with the provided credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/accounts/{id}": { - "get": { - "description": "Retrieve detailed account information by ID. Returns the account with associated profile info, emails, and wallet addresses.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The unique identifier (UUID) of the account", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Account retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetAccountResponse" - } - } - } - }, - "404": { - "description": "Account not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/accounts/id": { - "get": { - "description": "Retrieve the ID of the authenticated account associated with the provided credentials. This is useful when you have an API key or access token but do not yet know the corresponding accountId.", - "parameters": [], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Account ID retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetAccountIdResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/accounts": { - "post": { - "description": "Create a new account or retrieve an existing account by email or wallet address. If an account with the provided email or wallet already exists, returns that account. Otherwise creates a new account and initializes credits.", - "requestBody": { - "description": "Account credentials to create or lookup", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateAccountRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Account created or retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountDataResponse" - } - } - } - }, - "400": { - "description": "Bad request - failed to create account", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - }, - "patch": { - "description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges.", - "requestBody": { - "description": "Account fields to update", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateAccountRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Account updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountDataResponse" - } - } - } - }, - "400": { - "description": "Bad request - account not found or update failed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/accounts/artists": { - "post": { - "description": "Add an artist to an account's list of associated artists. If the artist is already associated with the account, returns success without modification.", - "requestBody": { - "description": "Account and artist identifiers", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddArtistToAccountRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Artist added to account successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddArtistSuccessResponse" - } - } - } - }, - "400": { - "description": "Bad request - account not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/artists": { - "get": { - "description": "Retrieve artists accessible to the authenticated account. The account is derived from the API key or Bearer token. When org_id is omitted, returns only the account's own artists. Pass org_id to view artists in a specific organization. Pass account_id to filter to a specific account the API key has access to.", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "Filter to a specific account's artists. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "org_id", - "in": "query", - "description": "Filter to artists in a specific organization. When omitted, returns only personal (non-organization) artists.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Artists retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistsErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid authentication" - }, - "403": { - "description": "Forbidden - account_id is not accessible with the provided credentials" - } - } - }, - "post": { - "description": "Create a new artist account. The artist can optionally be linked to an organization.", - "requestBody": { - "description": "Artist creation parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateArtistRequest" - } - } - } - }, - "responses": { - "201": { - "description": "Artist created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateArtistResponse" - } - } - } - }, - "400": { - "description": "Bad request - validation error or invalid JSON", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateArtistError" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/artist/segments": { - "get": { - "description": "Retrieve all segments associated with an artist. This endpoint should be called before using the Segment Fans endpoint to obtain the necessary segment IDs. Supports pagination.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch segments for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Segments retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSegmentsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSegmentsErrorResponse" - } - } - } - } - } - } - }, - "/api/artist/socials": { - "get": { - "description": "Retrieve all social media profiles associated with an artist. This endpoint should be called before using the Social Posts endpoint to obtain the necessary social IDs.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch social profiles for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Social profiles retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSocialsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSocialsErrorResponse" - } - } - } - } - } - } - }, - "/api/artist/socials/scrape": { - "post": { - "description": "Trigger scrape jobs for all social profiles linked to an artist. Provide an artist_account_id, and the API will look up the artist's socials and invoke a scraping job for each social profile. Each scrape returns Apify run metadata so you can poll for status and retrieve results.", - "requestBody": { - "description": "Artist to scrape socials for", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSocialsScrapeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Scrape jobs triggered successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSocialsScrapeResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistSocialsErrorResponse" - } - } - } - } - } - } - }, - "/api/artist-profile": { - "get": { - "description": "Retrieve comprehensive profile information for an artist across all connected social media platforms, including profile details and post metrics.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch profile data for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Artist profile retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistProfileResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistProfileErrorResponse" - } - } - } - } - } - } - }, - "/api/segment/fans": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve all social profiles from fans within a specific segment. This endpoint should be called after obtaining segment IDs from the Artist Segments endpoint. Supports pagination for large fan lists.", - "parameters": [ - { - "name": "segment_id", - "in": "query", - "description": "The unique identifier of the segment to fetch fans for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Segment fans retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SegmentFansResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SegmentFansErrorResponse" - } - } - } - } - } - } - }, - "/api/fans": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve all social profiles from fans of an artist across all platforms. This endpoint aggregates fan data from all connected social media platforms. Supports pagination for large fan lists.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch fans for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Artist fans retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistFansResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistFansErrorResponse" - } - } - } - } - } - } - }, - "/api/posts": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve all social media posts from an artist across all platforms. This endpoint aggregates posts from all connected social media profiles for the specified artist. Supports pagination for large post collections.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "The unique identifier of the artist account to fetch posts for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Artist posts retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistPostsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ArtistPostsErrorResponse" - } - } - } - } - } - } - }, - "/api/comments": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "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/post/comments": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve comments for a specific social media post. This endpoint should be called after obtaining post IDs from the Social Posts endpoint. Returns detailed information about each commenter including their profile data, follower counts, and geographic region.", - "parameters": [ - { - "name": "post_id", - "in": "query", - "description": "The unique identifier of the post to fetch comments for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Post comments retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PostCommentsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PostCommentsErrorResponse" - } - } - } - } - } - } - }, - "/api/chats": { - "get": { - "description": "Retrieve chat rooms (conversations) for the authenticated account. If the account has access to organizations, pass account_id to filter to a specific account within those organizations. Optionally filter by an artist_account_id. The endpoint returns metadata about each room, including the topic, associated artist, and last updated timestamp.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "Optional. Filter chats to only include those for the specified artist.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "account_id", - "in": "query", - "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Chats retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid query parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatsErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Create a new chat room. Optionally associate it with an artist and/or provide a client-generated chat ID. Pass accountId to create a chat on behalf of a specific account the API key has access to.", - "requestBody": { - "description": "Chat creation parameters", - "required": false, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateChatRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Chat created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateChatResponse" - } - } - } - }, - "400": { - "description": "Bad request - failed to create chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateChatErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - API key does not have access to the specified accountId", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateChatErrorResponse" - } - } - } - } - } - }, - "patch": { - "description": "Update a chat room's topic (display name). The chatId is required; the topic field will be updated. Topic must be between 3 and 50 characters.", - "requestBody": { - "description": "Chat fields to update", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateChatRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Chat updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateChatResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters or validation error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateChatErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - API key does not have access to this chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - chat room does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateChatErrorResponse" - } - } - } - } - } - }, - "delete": { - "description": "Delete a chat room by ID. This operation also removes related room records (memory emails, memories, room-report links, and segment-room links) before deleting the room itself.", - "requestBody": { - "description": "Chat deletion parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteChatRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Chat deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteChatResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters or validation error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteChatErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - API key does not have access to this chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - chat room does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteChatErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - failed to delete chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteChatErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/{id}/artist": { - "get": { - "description": "Retrieve the artist associated with a specific chat room. Returns 404 if the chat does not exist or is not accessible by the authenticated caller.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The unique identifier (UUID) of the chat room.", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Chat artist resolved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatArtistResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid chat id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatArtistErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - chat does not exist or is not accessible", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatArtistErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/{id}/segment": { - "get": { - "description": "Retrieve the segment associated with a specific chat room. Returns 404 if the chat does not exist or is not accessible by the authenticated caller.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The unique identifier (UUID) of the chat room.", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Chat segment resolved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatSegmentResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid chat id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatSegmentErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - chat does not exist or is not accessible", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatSegmentErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/{id}/messages": { - "get": { - "description": "Retrieve all messages (memories) for a specific chat room in chronological order.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The unique identifier (UUID) of the chat room.", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Messages retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatMessagesResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid chat id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatMessagesErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - caller does not have access to this chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - chat does not exist or is not accessible", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatMessagesErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - failed to retrieve messages", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetChatMessagesErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/{id}/messages/copy": { - "post": { - "description": "Copy all messages from the source chat (`id` path param) to a target chat (`targetChatId` in request body). By default, existing target messages are cleared before copy.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The source chat room UUID.", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "requestBody": { - "description": "Copy target options", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Messages copied successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid payload or chat identifiers", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - caller lacks access to source or target chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" - } - } - } - }, - "404": { - "description": "Not found - source or target chat does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - failed to copy messages", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/{id}/messages/trailing": { - "delete": { - "description": "Delete all messages in a chat from a given message onward (inclusive), identified by `from_message_id`.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The unique identifier (UUID) of the chat room.", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "from_message_id", - "in": "query", - "description": "The message UUID from which trailing messages should be deleted (inclusive).", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Trailing messages deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid or missing query/path parameters or message does not belong to chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - access denied to this chat", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" - } - } - } - }, - "404": { - "description": "Not found - chat or message does not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - failed to delete trailing messages", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" - } - } - } - } - } - } - }, - "/api/chats/compact": { - "post": { - "description": "Compact one or more chat conversations into summarized versions. This reduces the size of chat history while preserving key information. Optionally provide a prompt to control what information gets preserved in the compacted summary.", - "requestBody": { - "description": "Chat compaction parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CompactChatsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Chats compacted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CompactChatsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "404": { - "description": "Not found - one or more chat IDs do not exist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/chat/generate": { - "post": { - "servers": [ - { - "url": "https://recoup-api.vercel.app" - } - ], - "description": "Generate AI-powered text responses using the Recoup chat system. This endpoint processes chat requests and returns generated text along with metadata about the generation process.", - "security": [ - { - "apiKeyAuth": [] - } - ], - "requestBody": { - "description": "Chat generation request", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChatGenerateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Chat generated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChatGenerateResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChatGenerateErrorResponse" - } - } - } - } - } - } - }, - "/api/chat": { - "post": { - "servers": [ - { - "url": "https://recoup-api.vercel.app" - } - ], - "description": "Stream AI-powered chat responses using the Recoup chat system. This endpoint mirrors the request payload of the Chat Generate API but returns a streaming response compatible with the Vercel AI SDK `createUIMessageStreamResponse`. The stream emits UI message parts encoded as data chunks that can be parsed with `createUIMessageStreamParser`.", - "security": [ - { - "apiKeyAuth": [] - } - ], - "requestBody": { - "description": "Chat stream request", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChatStreamRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Streaming response with UI message parts. Events include: message-start (assistant begins message), message-delta (incremental updates), message-end (assistant finishes message), error (stream error), and metadata (usage data).", - "content": { - "text/event-stream": { - "schema": { - "type": "string", - "description": "Server-Sent Events stream containing UI message parts" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChatStreamErrorResponse" - } - } - } - } - } - } - }, - "/api/organizations": { - "get": { - "description": "Retrieve all organizations that the authenticated account belongs to. Pass account_id to retrieve organizations for a specific account the API key has access to.", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Organizations retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOrganizationsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid query parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationsErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Create a new organization. The creator is automatically added as a member of the organization.", - "requestBody": { - "description": "Organization creation parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrganizationRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Organization created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrganizationResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationsErrorResponse" - } - } - } - } - } - } - }, - "/api/organizations/artists": { - "post": { - "description": "Add an artist to an organization. This allows organization members to access and manage the artist. This endpoint is idempotent - calling it multiple times with the same artistId and organizationId will not create duplicate records.", - "requestBody": { - "description": "Artist-organization association parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddArtistToOrganizationRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Artist added to organization successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddArtistToOrganizationResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationsErrorResponse" - } - } - } - } - } - } - }, - "/api/spotify/search": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Search for artists, albums, tracks, and playlists using the Spotify API. This endpoint is a proxy to the official Spotify Search API.", - "parameters": [ - { - "name": "q", - "in": "query", - "description": "The search query keywords and optional field filters", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "type", - "in": "query", - "description": "A comma-separated list of item types to search across: album, artist, playlist, track, show, episode, audiobook", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "market", - "in": "query", - "description": "An ISO 3166-1 alpha-2 country code or 'from_token'", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of results to return (default: 20, min: 1, max: 50)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "minimum": 1, - "maximum": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "The index of the first result to return (default: 0, max: 10000)", - "required": false, - "schema": { - "type": "integer", - "default": 0, - "maximum": 10000 - } - } - ], - "responses": { - "200": { - "description": "Search results retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifySearchResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyErrorResponse" - } - } - } - } - } - } - }, - "/api/spotify/artist/": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Get Spotify catalog information for a single artist identified by their unique Spotify ID.", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "The Spotify ID of the artist", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Artist retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyGetArtistResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyErrorResponse" - } - } - } - } - } - } - }, - "/api/spotify/artist/albums": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Get Spotify catalog information about an artist's albums.", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "The Spotify ID of the artist", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "include_groups", - "in": "query", - "description": "A comma-separated list of keywords to filter the response. Valid values are: album, single, appears_on, compilation", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "market", - "in": "query", - "description": "An ISO 3166-1 alpha-2 country code. If specified, only content available in that market will be returned", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "The maximum number of items to return (default: 20, min: 1, max: 50)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "minimum": 1, - "maximum": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "The index of the first item to return (default: 0)", - "required": false, - "schema": { - "type": "integer", - "default": 0 - } - } - ], - "responses": { - "200": { - "description": "Artist albums retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyArtistAlbumsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyErrorResponse" - } - } - } - } - } - } - }, - "/api/spotify/artist/topTracks": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Get an artist's top tracks by country.", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "The Spotify ID of the artist", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "market", - "in": "query", - "description": "An ISO 3166-1 alpha-2 country code. If provided, only tracks available in that market are returned", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Artist top tracks retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyArtistTopTracksResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyErrorResponse" - } - } - } - } - } - } - }, - "/api/spotify/album": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Get Spotify catalog information for a single album.", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "The Spotify ID of the album", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "market", - "in": "query", - "description": "An ISO 3166-1 alpha-2 country code. If provided, only content available in that market is returned", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Album retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyAlbum" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotifyErrorResponse" - } - } - } - } - } - } - }, - "/api/instagram/comments": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Fetch Instagram comments for multiple post URLs using Apify's Instagram Comment Scraper. The actual comment data will be available in the Apify dataset after the run completes.", - "parameters": [ - { - "name": "postUrls", - "in": "query", - "description": "Array of Instagram post URLs to fetch comments for", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - }, - "style": "form", - "explode": true - }, - { - "name": "resultsLimit", - "in": "query", - "description": "Maximum number of comments to fetch (default: 10000)", - "required": false, - "schema": { - "type": "integer", - "default": 10000 - } - }, - { - "name": "isNewestComments", - "in": "query", - "description": "Whether to fetch newest comments first. Set to true for newest first, false for oldest first, or omit for platform default sorting", - "required": false, - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "Apify scraper run started successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApifyRunResult" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InstagramErrorResponse" - } - } - } - } - } - } - }, - "/api/instagram/profiles": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Fetch Instagram profile information for multiple handles using Apify's Instagram Profile Scraper. The actual profile data will be available in the Apify dataset after the run completes.", - "parameters": [ - { - "name": "handles", - "in": "query", - "description": "Array of Instagram handles to fetch profiles for", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - }, - "style": "form", - "explode": true - } - ], - "responses": { - "200": { - "description": "Apify scraper run started successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApifyRunResult" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InstagramErrorResponse" - } - } - } - } - } - } - }, - "/api/apify/scraper": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "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.", - "parameters": [ - { - "name": "runId", - "in": "query", - "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.", - "required": true, - "schema": { - "type": "string" - }, - "example": "abc123xyz" - } - ], - "responses": { - "200": { - "description": "Scraper run status retrieved successfully. Returns status info for in-progress runs, or status info plus data for completed runs.", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "$ref": "#/components/schemas/ApifyScraperInProgressResponse" - }, - { - "$ref": "#/components/schemas/ApifyScraperCompletedResponse" - } - ] - } - } - } - }, - "400": { - "description": "Bad request - missing required runId parameter", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApifyScraperErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - failed to fetch run status from Apify", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApifyScraperErrorResponse" - } - } - } - } - } - } - }, - "/api/sandboxes": { - "get": { - "description": "List all sandboxes associated with the authenticated account and their current statuses. Returns sandbox details including lifecycle state, timeout remaining, and creation timestamp. Pass account_id to retrieve sandboxes for a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", - "parameters": [ - { - "name": "sandbox_id", - "in": "query", - "required": false, - "description": "Filter by a specific sandbox ID. When provided, returns only the sandbox matching this ID. Must be a sandbox that your account or organization is an admin of.", - "schema": { - "type": "string", - "example": "sbx_abc123def456" - } - }, - { - "name": "account_id", - "in": "query", - "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Sandboxes retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxesResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - }, - "post": { - "description": "Create a new ephemeral sandbox environment. Optionally executes a command or an OpenCode prompt if provided. Sandboxes are isolated Linux microVMs that can be used to evaluate account-generated code, run AI agent output safely, or execute reproducible tasks. The sandbox will automatically stop after the timeout period. If no command or prompt is provided, the sandbox is created without triggering any background task. Use the prompt parameter as a shortcut to run `opencode run \"\"` in the sandbox. Pass account_id to create a sandbox for a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", - "requestBody": { - "description": "Optional command execution parameters. If command and prompt are both omitted, sandbox is created without running any command. Use prompt as a shortcut for running OpenCode.", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateSandboxRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Sandbox created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxesResponse" - } - } - } - }, - "400": { - "description": "Bad request - failed to create sandbox", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - }, - "patch": { - "description": "Set a custom snapshot ID for an account. By default, updates the key owner's account. Pass account_id to target a specific account the API key has access to. This allows accounts to use a specific sandbox snapshot when creating new sandboxes, enabling reproducible environments with pre-configured tools, dependencies, and files.", - "requestBody": { - "description": "Snapshot configuration parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateSnapshotRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Snapshot ID updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateSnapshotResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid snapshot ID", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - }, - "delete": { - "description": "Delete a sandbox environment for the authenticated account. This permanently deletes the associated GitHub repository and removes the account's snapshot record from the database. By default, deletes the sandbox for the key owner's account. Pass account_id to target a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", - "requestBody": { - "description": "Optional account targeting parameters", - "required": false, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteSandboxRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Sandbox deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteSandboxResponse" - } - } - } - }, - "400": { - "description": "Bad request - failed to delete sandbox", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - } - }, - "/api/sandboxes/setup": { - "post": { - "description": "Triggers the setup-sandbox background task to create a personal sandbox, provision a GitHub repo, take a snapshot, and shut down. By default, sets up the sandbox for the key owner's account. Pass account_id to target a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", - "requestBody": { - "description": "Optional account targeting parameters", - "required": false, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetupSandboxRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Setup task triggered successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetupSandboxResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid account_id format", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - } - }, - "/api/sandboxes/file": { - "get": { - "description": "Retrieve the raw contents of a file from the authenticated account's sandbox GitHub repository. Resolves the github_repo from the [account's snapshot](/api-reference/sandboxes/list), then fetches the file at the specified path from the repository's main branch. Authentication is handled via the x-api-key header or Authorization Bearer token.", - "parameters": [ - { - "name": "path", - "in": "query", - "required": true, - "description": "The file path within the repository (e.g. \"src/index.ts\" or \"README.md\").", - "schema": { - "type": "string", - "example": "src/index.ts" - } - } - ], - "responses": { - "200": { - "description": "File contents retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxFileResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid path parameter", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account does not have access", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "404": { - "description": "Not found - no snapshot, no github_repo, or file not found in repository", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - } - }, - "/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.", - "requestBody": { - "description": "JSON body containing file URLs and target path", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UploadSandboxFilesRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Files uploaded successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UploadSandboxFilesResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing files or invalid path", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - account does not have access", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - }, - "404": { - "description": "Not found - no snapshot or no github_repo configured", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxErrorResponse" - } - } - } - } - } - } - }, - "/api/x/search": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Search for tweets using the Twitter Search API, powered by agent-twitter-client (no Twitter API key required). Supports various search modes including Top, Latest, Photos, Videos, and Users.", - "parameters": [ - { - "name": "query", - "in": "query", - "description": "The search query. Any Twitter-compatible query format can be used (e.g., '#nodejs', 'from:username', etc.)", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "maxTweets", - "in": "query", - "description": "The maximum number of tweets to return", - "required": true, - "schema": { - "type": "integer" - } - }, - { - "name": "searchMode", - "in": "query", - "description": "The category filter to apply to the search", - "required": false, - "schema": { - "type": "string", - "enum": [ - "Top", - "Latest", - "Photos", - "Videos", - "Users" - ], - "default": "Latest" - } - } - ], - "responses": { - "200": { - "description": "Tweets retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TwitterSearchResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TwitterErrorResponse" - } - } - } - } - } - } - }, - "/api/x/trends": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve the current trending topics from Twitter using the getTrends method from agent-twitter-client (no Twitter API key required).", - "responses": { - "200": { - "description": "Trends retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TwitterTrendsResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TwitterErrorResponse" - } - } - } - } - } - } - }, - "/api/social/scrape": { - "post": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Trigger a social profile scraping job for a given social_id. Use the Get Artist Socials endpoint first to retrieve the social_id values. The response returns Apify run metadata for polling status and retrieving results via the Apify Scraper Results API.", - "requestBody": { - "description": "Social profile to scrape", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SocialScrapeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Scrape job triggered successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApifyRunResult" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SocialErrorResponse" - } - } - } - } - } - } - }, - "/api/social/posts": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve all social media posts from a specific social profile. Call the Artist Socials endpoint first to obtain social IDs.", - "parameters": [ - { - "name": "social_id", - "in": "query", - "description": "The unique identifier (UUID) of the social profile to fetch posts for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "latestFirst", - "in": "query", - "description": "Sort posts by most recent first (default: true)", - "required": false, - "schema": { - "type": "boolean", - "default": true - } - }, - { - "name": "page", - "in": "query", - "description": "The page number to retrieve (default: 1)", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "The number of records per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Posts retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SocialPostsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SocialErrorResponse" - } - } - } - } - } - } - }, - "/api/image/generate": { - "get": { - "servers": [ - { - "url": "https://recoup-api.vercel.app" - } - ], - "description": "Generate high-quality images using AI models. Images are automatically stored on Arweave and include In Process moment metadata for provenance and ownership tracking.", - "parameters": [ - { - "name": "prompt", - "in": "query", - "description": "Text description of the image you want to generate", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "account_id", - "in": "query", - "description": "The unique identifier of the account generating the image", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Image generated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ImageGenerationResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required parameters or invalid input", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ImageGenerationErrorResponse" - } - } - } - } - } - } - }, - "/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.", - "requestBody": { - "description": "Audio transcription request", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Audio transcribed successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required fields or invalid audio URL", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioErrorResponse" - } - } - } - }, - "413": { - "description": "Audio file exceeds the 25MB limit", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioErrorResponse" - } - } - } - }, - "429": { - "description": "Rate limit exceeded", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioErrorResponse" - } - } - } - }, - "500": { - "description": "Server error - OpenAI API key not configured", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TranscribeAudioErrorResponse" - } - } - } - } - } - } - }, - "/api/songs": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve songs from the database with optional filtering by ISRC (International Standard Recording Code) or artist account. This endpoint joins the songs table with song_artists and accounts tables to provide comprehensive song information.", - "parameters": [ - { - "name": "isrc", - "in": "query", - "description": "International Standard Recording Code to filter by specific song", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "artist_account_id", - "in": "query", - "description": "Artist account ID to filter songs by artist", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Songs retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongsErrorResponse" - } - } - } - }, - "404": { - "description": "No songs found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongsErrorResponse" - } - } - } - } - } - }, - "post": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Bulk create or fetch songs by ISRC. For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used.", - "requestBody": { - "description": "Array of songs to create or fetch", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateSongsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Songs created or fetched successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongsErrorResponse" - } - } - } - } - } - } - }, - "/api/catalogs": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve catalogs associated with a specific account. The endpoint joins account_catalogs with catalogs to return catalog metadata for the specified account.", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "The unique identifier of the account to query", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Catalogs retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid account_id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsErrorResponse" - } - } - } - }, - "404": { - "description": "Account not found or no catalogs found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsErrorResponse" - } - } - } - } - } - }, - "post": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Create new catalogs or link existing catalogs to an account. If catalog_id is provided, links the existing catalog. If name is provided without catalog_id, creates a new catalog. If both are provided, catalog_id takes priority.", - "requestBody": { - "description": "Array of catalogs to create or link", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateCatalogsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Catalogs created or linked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters or catalog_id not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsErrorResponse" - } - } - } - } - } - }, - "delete": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Unlink catalogs from an account. If no other accounts are linked to a catalog after removal, the catalog is automatically deleted (cascading to catalog_songs). Otherwise, only the account-catalog relationship is removed.", - "requestBody": { - "description": "Array of catalog-account pairs to remove", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteCatalogsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Catalogs unlinked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing catalog_id or account_id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogsErrorResponse" - } - } - } - } - } - } - }, - "/api/catalogs/songs": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve songs within a specific catalog with pagination support. This endpoint joins catalog_songs with songs, song_artists, and accounts to provide comprehensive song information for a given catalog.", - "parameters": [ - { - "name": "catalog_id", - "in": "query", - "description": "The unique identifier of the catalog to query songs for", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "artistName", - "in": "query", - "description": "Optional. Filters songs to only include those with matching artist name", - "required": false, - "schema": { - "type": "string" - } - }, - { - "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 songs per page (default: 20, max: 100)", - "required": false, - "schema": { - "type": "integer", - "default": 20, - "maximum": 100 - } - } - ], - "responses": { - "200": { - "description": "Catalog songs retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid catalog_id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsErrorResponse" - } - } - } - }, - "404": { - "description": "Catalog not found or no songs in catalog", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsErrorResponse" - } - } - } - } - } - }, - "post": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Batch add songs to a catalog by ISRC. For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used.", - "requestBody": { - "description": "Array of songs to add to catalog", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddCatalogSongsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Songs added to catalog successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing required fields", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsErrorResponse" - } - } - } - } - } - }, - "delete": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Batch remove songs from a catalog by ISRC. Deletes the relationship in catalog_songs for each catalog_id and ISRC pair.", - "requestBody": { - "description": "Array of songs to remove from catalog", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteCatalogSongsRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Songs removed from catalog successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing catalog_id or isrc", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CatalogSongsErrorResponse" - } - } - } - } - } - } - }, - "/api/subscriptions": { - "get": { - "servers": [ - { - "url": "https://api.recoupable.com" - } - ], - "description": "Retrieve subscription information for an account. For accounts with enterprise plans, returns a simplified response indicating enterprise status. For standard accounts, returns the full Stripe subscription object.", - "parameters": [ - { - "name": "accountId", - "in": "query", - "description": "The unique identifier of the account to query", - "required": true, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Subscription information retrieved successfully", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "$ref": "#/components/schemas/SubscriptionResponse" - }, - { - "$ref": "#/components/schemas/EnterpriseSubscriptionResponse" - } - ] - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid accountId", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionErrorResponse" - } - } - } - }, - "404": { - "description": "Account not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionErrorResponse" - } - } - } - } - } - } - }, - "/api/workspaces": { - "post": { - "description": "Create a new workspace account. Workspaces can optionally be linked to an organization.", - "requestBody": { - "description": "Workspace creation parameters", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateWorkspaceRequest" - } - } - } - }, - "responses": { - "201": { - "description": "Workspace created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateWorkspaceResponse" - } - } - } - }, - "400": { - "description": "Bad request - validation error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - access denied to organization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/pulses": { - "get": { - "description": "Retrieve pulse information for the authenticated account. If the account has access to organizations, pass account_id to filter to a specific account within those organizations.", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "active", - "in": "query", - "description": "Filter by active status. Set to 'true' to return only active pulses, 'false' for inactive pulses. If not provided, returns all pulses regardless of active status.", - "required": false, - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ] - } - } - ], - "responses": { - "200": { - "description": "Pulses retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PulsesResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid query parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "patch": { - "description": "Update the pulse settings for an account. Use this to enable or disable the pulse. Returns an array of pulses for consistency with the GET endpoint.", - "requestBody": { - "description": "Pulse fields to update", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePulseRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Pulse updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PulsesResponse" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/connectors": { - "get": { - "description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "Optional account ID to get connectors for a different account (e.g., an artist, workspace, or organization). The authenticated account must have access to the specified account. Omit to get your own account's connectors.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Connectors retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConnectorsResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid account_id format", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - no access to the specified account", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "delete": { - "description": "Disconnect a connected account from a third-party service. This revokes the OAuth connection and removes stored credentials.", - "requestBody": { - "description": "Connection to disconnect", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DisconnectConnectorRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Connector disconnected successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DisconnectConnectorResponse" - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - no access to the specified account or connection", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Generate an OAuth authorization URL for connecting a third-party service. Redirect to the returned URL to complete the OAuth flow.", - "requestBody": { - "description": "Authorization request details", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AuthorizeConnectorRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Authorization URL generated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AuthorizeConnectorResponse" - } - } - } - }, - "400": { - "description": "Bad request - invalid connector or parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "403": { - "description": "Forbidden - no access to the specified account", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/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` \u2014 an array of run IDs that can each be polled via [GET /api/tasks/runs](/api-reference/tasks/runs). Authentication is handled via the x-api-key header.", - "requestBody": { - "description": "Content creation parameters including the target artist and optional template/workflow settings", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentCreateRequest" - } - } - } - }, - "responses": { - "202": { - "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": { - "$ref": "#/components/schemas/ContentCreateResponse" - } - } - } - }, - "400": { - "description": "Validation failed \u2014 missing artist identifier, artist is missing required files, or template not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentCreateErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - }, - "404": { - "description": "Artist not found \u2014 the provided artist_account_id does not match any artist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - } - } - } - }, - "/api/content/templates": { - "get": { - "description": "List all available content creation templates. Templates define the visual style, scene composition, and default workflow settings for generated videos. Each template includes reference images, style guides, caption rules, and prompt configurations.", - "responses": { - "200": { - "description": "Templates retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentTemplatesResponse" - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - } - } - } - }, - "/api/content/validate": { - "get": { - "description": "Check whether an artist has all the required files to run the content creation pipeline. Returns a structured report of each required and recommended file with its status. Required files must be present or the pipeline will fail. Recommended files improve output quality but are not strictly necessary. Provide `artist_account_id` as a query parameter.", - "parameters": [ - { - "name": "artist_account_id", - "in": "query", - "description": "UUID of the artist account to validate. Use [GET /api/artists](/api-reference/artists/list) to find artist account IDs.", - "required": true, - "schema": { - "type": "string", - "format": "uuid", - "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" - } - } - ], - "responses": { - "200": { - "description": "Validation completed. Check the `ready` field to determine if the artist can run the pipeline.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentValidateResponse" - } - } - } - }, - "400": { - "description": "Bad request \u2014 artist_account_id is required", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - }, - "404": { - "description": "Artist not found \u2014 the provided artist_account_id does not match any artist", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - } - } - } - }, - "/api/content/estimate": { - "get": { - "description": "Estimate the cost of running the content creation pipeline. Fetches live pricing from fal.ai and calculates per-step and per-video costs. 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.", - "parameters": [ - { - "name": "lipsync", - "in": "query", - "description": "Which workflow to estimate. `false` for image-to-video, `true` for audio-to-video. If omitted, estimates the default image-to-video workflow.", - "required": false, - "schema": { - "type": "boolean", - "example": false - } - }, - { - "name": "batch", - "in": "query", - "description": "Number of videos to project costs for. Use this to answer questions like \"how much would 30 videos cost?\"", - "required": false, - "schema": { - "type": "integer", - "minimum": 1, - "default": 1, - "example": 1 - } - }, - { - "name": "compare", - "in": "query", - "description": "When `true`, returns estimates for all available workflow profiles (premium, budget, mid) for side-by-side comparison.", - "required": false, - "schema": { - "type": "boolean", - "default": false, - "example": false - } - } - ], - "responses": { - "200": { - "description": "Cost estimate calculated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentEstimateResponse" - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentErrorResponse" - } - } - } - } - } - } - }, - "/api/songs/analyze/presets": { - "get": { - "description": "Lists all available music analysis presets. Each preset is a curated prompt with optimized generation parameters for a specific use case (e.g. catalog metadata enrichment, sync licensing analysis, audience profiling). Requires authentication via API key or Bearer token.", - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Presets listed successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ] - }, - "presets": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Preset identifier to pass in the analyze request" - }, - "label": { - "type": "string", - "description": "Human-readable preset name" - }, - "description": { - "type": "string", - "description": "What this preset does" - }, - "requiresAudio": { - "type": "boolean", - "description": "Whether this preset needs an audio_url" - }, - "responseFormat": { - "type": "string", - "enum": [ - "json", - "text" - ], - "description": "Expected response format" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key / Bearer token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeErrorResponse" - } - } - } - } - } - } - }, - "/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 \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": [] - }, - { - "bearerAuth": [] - } - ], - "requestBody": { - "description": "Music analysis request", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Music analysis completed successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeResponse" - } - } - } - }, - "400": { - "description": "Bad request \u2014 missing or invalid fields", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized \u2014 invalid or missing API key / Bearer token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeErrorResponse" - } - } - } - }, - "500": { - "description": "Server error \u2014 upstream model unavailable or inference failed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SongAnalyzeErrorResponse" - } - } - } - } - } - } - }, - "/api/notifications": { - "post": { - "description": "Send a notification email to the authenticated account's email address via the Resend API. Emails are sent from `Agent by Recoup `. The recipient is automatically resolved from the API key or Bearer token. Supports plain text (rendered as Markdown) or raw HTML bodies, optional CC recipients, custom headers, and an optional room_id to include a chat link in the email footer.", - "requestBody": { - "description": "Notification email payload", - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateNotificationRequest" - } - } - } - }, - "responses": { - "200": { - "description": "Notification sent successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResponse" - } - } - } - }, - "400": { - "description": "Validation error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Authentication required", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "502": { - "description": "Email delivery failed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/api/admins": { - "get": { - "description": "Check if the authenticated account is a Recoup admin. An account is considered an admin if it is a member of the Recoup organization. No input parameters required \u2014 authentication is performed via the x-api-key or Authorization header.", - "parameters": [], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Admin status retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CheckAdminResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/admins/sandboxes": { - "get": { - "description": "Returns a list of all accounts and their sandbox usage statistics. Each item includes the account email, total number of sandboxes created, and the timestamp of the most recently created sandbox. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Account sandbox statistics retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdminSandboxesResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/admins/sandboxes/orgs": { - "get": { - "description": "Returns commit statistics for each repository in the recoupable GitHub organization. Each item includes the repo name, URL, total commit count, latest 5 commit messages, earliest and latest commit timestamps, and the list of account repo URLs that include this org repo as a submodule. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Org repo statistics retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdminSandboxOrgsResponse" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/admins/emails": { - "get": { - "description": "Returns Resend emails including HTML content. Provide either account_id (returns all emails for an account) or email_id (returns a single email by Resend ID). Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token. Email response shape matches the [Resend Retrieve Email API](https://resend.com/docs/api-reference/emails/retrieve-email).", - "parameters": [ - { - "name": "account_id", - "in": "query", - "description": "The account ID to fetch all emails for. Required if email_id is not provided.", - "required": false, - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "email_id", - "in": "query", - "description": "A Resend email ID to fetch a single email. Required if account_id is not provided.", - "required": false, - "schema": { - "type": "string" - } - } - ], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Emails retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdminEmailsResponse" - } - } - } - }, - "400": { - "description": "Bad request - must provide either account_id or email_id", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/admins/coding/slack": { - "get": { - "description": "Returns a list of Slack mentions of the Recoup Coding Agent bot, pulled directly from the Slack API as the source of truth. Each entry includes the tagger's information, the prompt they sent, the timestamp, the channel, and any GitHub pull request URLs opened in response. Also returns aggregate pull request statistics. Supports optional time-period filtering. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [ - { - "name": "period", - "in": "query", - "description": "Time period to filter tags. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", - "required": false, - "schema": { - "type": "string", - "enum": ["all", "daily", "weekly", "monthly"], - "default": "all" - } - } - ], - "security": [ - { "apiKeyAuth": [] }, - { "bearerAuth": [] } - ], - "responses": { - "200": { - "description": "Slack tag analytics retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["status", "total", "total_pull_requests", "tags_with_pull_requests", "tags"], - "properties": { - "status": { - "type": "string", - "enum": ["success"], - "description": "Status of the request" - }, - "total": { - "type": "integer", - "description": "Total number of times the Coding Agent was tagged in the requested period", - "example": 134 - }, - "total_pull_requests": { - "type": "integer", - "description": "Total number of pull requests opened by the Coding Agent across all tags in the requested period", - "example": 121 - }, - "tags_with_pull_requests": { - "type": "integer", - "description": "Number of tags that resulted in at least one pull request being opened", - "example": 84 - }, - "tags": { - "type": "array", - "description": "List of Slack tag events", - "items": { - "type": "object", - "required": ["user_id", "user_name", "prompt", "timestamp", "channel_id", "channel_name"], - "properties": { - "user_id": { - "type": "string", - "description": "Slack ID of the person who tagged the agent", - "example": "U012AB3CD" - }, - "user_name": { - "type": "string", - "description": "Display name of the person who tagged the agent", - "example": "Jane Smith" - }, - "user_avatar": { - "type": ["string", "null"], - "description": "URL of the Slack avatar", - "example": "https://avatars.slack-edge.com/..." - }, - "prompt": { - "type": "string", - "description": "The text of the message sent to the agent", - "example": "add dark mode support to the settings page" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the tag event", - "example": "2024-01-15T10:30:00.000Z" - }, - "channel_id": { - "type": "string", - "description": "Slack channel ID where the tag occurred", - "example": "C012AB3CD" - }, - "channel_name": { - "type": "string", - "description": "Human-readable name of the Slack channel", - "example": "dev-team" - }, - "pull_requests": { - "type": "array", - "description": "GitHub pull request URLs opened by the Coding Agent in response to this prompt, parsed from bot replies in the Slack thread", - "items": { - "type": "string", - "format": "uri", - "example": "https://github.com/recoupable/api/pull/42" - }, - "example": ["https://github.com/recoupable/api/pull/42"] - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - } - } - } - }, - "/api/admins/content/slack": { - "get": { - "description": "Returns a list of Slack mentions of the Recoup Content Agent bot, pulled directly from the Slack API as the source of truth. Each entry includes the tagger's information, the prompt they sent, the timestamp, the channel, and any video link responses. Also returns aggregate video statistics for measuring tag-to-video conversion. Supports optional time-period filtering. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [ - { - "name": "period", - "in": "query", - "description": "Time period to filter tags. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", - "required": false, - "schema": { - "type": "string", - "enum": ["all", "daily", "weekly", "monthly"], - "default": "all" - } - } - ], - "security": [ - { "apiKeyAuth": [] }, - { "bearerAuth": [] } - ], - "responses": { - "200": { - "description": "Slack tag analytics retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["status", "total", "total_videos", "tags_with_videos", "tags"], - "properties": { - "status": { - "type": "string", - "enum": ["success"], - "description": "Status of the request" - }, - "total": { - "type": "integer", - "description": "Total number of times the Content Agent was tagged in the requested period", - "example": 18 - }, - "total_videos": { - "type": "integer", - "description": "Total number of videos generated by the Content Agent across all tags in the requested period", - "example": 12 - }, - "tags_with_videos": { - "type": "integer", - "description": "Number of tags that resulted in at least one video being generated", - "example": 10 - }, - "tags": { - "type": "array", - "description": "List of Slack tag events", - "items": { - "type": "object", - "required": ["user_id", "user_name", "prompt", "timestamp", "channel_id", "channel_name"], - "properties": { - "user_id": { - "type": "string", - "description": "Slack ID of the person who tagged the agent", - "example": "U012AB3CD" - }, - "user_name": { - "type": "string", - "description": "Display name of the person who tagged the agent", - "example": "Jane Smith" - }, - "user_avatar": { - "type": ["string", "null"], - "description": "URL of the Slack avatar", - "example": "https://avatars.slack-edge.com/..." - }, - "prompt": { - "type": "string", - "description": "The text of the message sent to the agent", - "example": "create a highlight reel for the new single release" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the tag event", - "example": "2024-01-15T10:30:00.000Z" - }, - "channel_id": { - "type": "string", - "description": "Slack channel ID where the tag occurred", - "example": "C012AB3CD" - }, - "channel_name": { - "type": "string", - "description": "Human-readable name of the Slack channel", - "example": "content-team" - }, - "video_links": { - "type": "array", - "description": "Video URLs generated by the Content Agent in response to this prompt, parsed from bot replies in the Slack thread", - "items": { - "type": "string", - "format": "uri", - "example": "https://recoupable.com/v/abc123" - }, - "example": ["https://recoupable.com/v/abc123"] - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - } - } - } - }, - "/api/admins/coding/pr": { - "get": { - "description": "Returns the status (open, closed, or merged) for each provided GitHub pull request URL. Accepts one or more `pull_requests` query parameters containing GitHub PR URLs. Uses the GitHub REST API to check each pull request's state. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [ - { - "name": "pull_requests", - "in": "query", - "description": "One or more GitHub pull request URLs to check. Repeat this parameter for each URL. Example: ?pull_requests=https://github.com/org/repo/pull/1&pull_requests=https://github.com/org/repo/pull/2", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "uri" - }, - "minItems": 1, - "maxItems": 50 - }, - "style": "form", - "explode": true - } - ], - "security": [ - { "apiKeyAuth": [] }, - { "bearerAuth": [] } - ], - "responses": { - "200": { - "description": "PR merged status retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["status", "pull_requests"], - "properties": { - "status": { - "type": "string", - "enum": ["success"], - "description": "Status of the request" - }, - "pull_requests": { - "type": "array", - "description": "Status for each provided pull request URL", - "items": { - "type": "object", - "required": ["url", "status"], - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The GitHub pull request URL", - "example": "https://github.com/recoupable/api/pull/42" - }, - "status": { - "type": "string", - "enum": ["open", "closed", "merged"], - "description": "The current status of the pull request", - "example": "merged" - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - missing or invalid pull_requests parameter", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { "$ref": "#/components/schemas/AccountErrorResponse" } - } - } - } - } - } - }, - "/api/admins/privy": { - "get": { - "description": "Returns Privy login statistics for a given time period. Results include counts for new accounts (created_at), active accounts (latest_verified_at), total Privy accounts across all time, and the full, unmodified Privy account objects. See [Privy User object documentation](https://docs.privy.io/api-reference/users/get-all) for the complete type definition. Defaults to period=all (no date filter). Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", - "parameters": [ - { - "name": "period", - "in": "query", - "description": "Time period to filter logins. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", - "required": false, - "schema": { - "type": "string", - "enum": [ - "all", - "daily", - "weekly", - "monthly" - ], - "default": "all" - } - } - ], - "security": [ - { - "apiKeyAuth": [] - }, - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Privy login statistics retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "status", - "total", - "total_new", - "total_active", - "logins" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "total": { - "type": "integer", - "description": "Total number of accounts in Privy across all time (not filtered by period)", - "example": 42 - }, - "total_new": { - "type": "integer", - "description": "Number of accounts created (created_at) within the requested period", - "example": 15 - }, - "total_active": { - "type": "integer", - "description": "Total number of accounts matching either new or active criteria in the requested period", - "example": 30 - }, - "logins": { - "type": "array", - "description": "Full, unmodified Privy account objects. See [Privy User object docs](https://docs.privy.io/api-reference/users/get-all) for the complete type definition.", - "items": { - "type": "object" - } - } - } - } - } - } - }, - "401": { - "description": "Unauthorized - missing or invalid credentials", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "403": { - "description": "Forbidden - authenticated account is not a Recoup admin", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountErrorResponse" - } - } - } - } - } - } - }, - "/api/content-agent/{platform}": { - "post": { - "description": "Webhook endpoint for the Recoup Content Agent Slack bot. Receives @mention events from Slack and triggers content generation for the mentioned artist. The bot parses the mention text for ` [template] [batch=N] [lipsync]`, validates the artist, calls POST /api/content/create, and starts a background polling task that reports results back to the Slack thread.\n\nFor Slack, also handles `url_verification` challenges during app setup.", - "parameters": [ - { - "name": "platform", - "in": "path", - "description": "Chat platform identifier. Currently supports `slack`.", - "required": true, - "schema": { - "type": "string", - "enum": ["slack"] - } - } - ], - "requestBody": { - "description": "Slack Events API payload (app_mention event or url_verification challenge)", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "description": "Slack Events API envelope — the shape depends on the event type" - } - } - } - }, - "responses": { - "200": { - "description": "Event processed successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "ok": { - "type": "boolean" - } - } - } - } - } - }, - "404": { - "description": "Unknown platform" - } - } - } - }, - "/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.", - "requestBody": { - "description": "Content generation results from the polling task", - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["threadId", "status"], - "properties": { - "threadId": { - "type": "string", - "description": "Chat SDK thread identifier for the originating Slack thread" - }, - "status": { - "type": "string", - "enum": ["completed", "failed", "timeout"], - "description": "Overall status of the content generation batch" - }, - "results": { - "type": "array", - "description": "Per-run results", - "items": { - "type": "object", - "required": ["runId", "status"], - "properties": { - "runId": { - "type": "string", - "description": "Trigger.dev run ID" - }, - "status": { - "type": "string", - "enum": ["completed", "failed", "timeout"] - }, - "videoUrl": { - "type": "string", - "description": "URL of the generated video (when completed)" - }, - "captionText": { - "type": "string", - "description": "Generated caption text (when completed)" - }, - "error": { - "type": "string", - "description": "Error message (when failed)" - } - } - } - }, - "message": { - "type": "string", - "description": "Optional human-readable message" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Callback processed and results posted to Slack", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "status": { - "type": "string", - "example": "ok" - } - } - } - } - } - }, - "401": { - "description": "Missing or invalid callback secret" - }, - "400": { - "description": "Invalid request body" - } - }, - "security": [ - { - "callbackSecret": [] - } - ] - } - } - }, - "components": { - "schemas": { - "Error": { - "required": [ - "error", - "message" - ], - "type": "object", - "properties": { - "error": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - } - } - }, - "CreateNotificationRequest": { - "type": "object", - "required": [ - "subject" - ], - "properties": { - "cc": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "description": "Optional CC email addresses", - "example": [ - "cc@example.com" - ] - }, - "subject": { - "type": "string", - "description": "Email subject line", - "example": "Weekly Pulse Report" - }, - "text": { - "type": "string", - "description": "Plain text or Markdown body. Rendered as HTML via Markdown if no `html` is provided.", - "example": "# Pulse Report\n\nHere's your weekly summary." - }, - "html": { - "type": "string", - "description": "Raw HTML body. Takes precedence over `text` when both are provided.", - "example": "

Pulse Report

Here's your weekly summary.

" - }, - "headers": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Optional custom email headers" - }, - "room_id": { - "type": "string", - "description": "Room ID to include a chat link in the email footer" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to send the notification for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, sends the notification for the API key's own account." - } - } - }, - "NotificationResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the notification was sent successfully", - "example": true - }, - "message": { - "type": "string", - "description": "Human-readable result message", - "example": "Email sent successfully from Agent by Recoup to user@example.com." - }, - "id": { - "type": "string", - "description": "Resend email ID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - } - } - }, - "ConnectorInfo": { - "type": "object", - "required": [ - "slug", - "name", - "isConnected" - ], - "properties": { - "slug": { - "type": "string", - "description": "Unique identifier for the connector (e.g., 'googlesheets', 'tiktok')" - }, - "name": { - "type": "string", - "description": "Human-readable name of the connector" - }, - "isConnected": { - "type": "boolean", - "description": "Whether the connector is currently connected" - }, - "connectedAccountId": { - "type": "string", - "description": "The connected account ID (only present when isConnected is true)" - } - } - }, - "ConnectorsResponse": { - "type": "object", - "required": [ - "success", - "connectors" - ], - "properties": { - "success": { - "type": "boolean" - }, - "connectors": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ConnectorInfo" - }, - "description": "List of available connectors with connection status" - } - } - }, - "AuthorizeConnectorRequest": { - "type": "object", - "required": [ - "connector" - ], - "properties": { - "connector": { - "type": "string", - "description": "The connector slug to authorize (e.g., 'googlesheets', 'tiktok')" - }, - "callback_url": { - "type": "string", - "format": "uri", - "description": "Optional custom callback URL after OAuth completion" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Optional account ID to connect a service for a different account (e.g., an artist, workspace, or organization). Use this when connecting an artist's TikTok or other service. The authenticated account must have access. Omit to connect for your own account." - } - } - }, - "AuthorizeConnectorResponse": { - "type": "object", - "required": [ - "success", - "data" - ], - "properties": { - "success": { - "type": "boolean" - }, - "data": { - "type": "object", - "required": [ - "connector", - "redirectUrl" - ], - "properties": { - "connector": { - "type": "string", - "description": "The connector slug being authorized" - }, - "redirectUrl": { - "type": "string", - "format": "uri", - "description": "URL to redirect to for OAuth authorization" - } - } - } - } - }, - "DisconnectConnectorRequest": { - "type": "object", - "required": [ - "connected_account_id" - ], - "properties": { - "connected_account_id": { - "type": "string", - "description": "The connected account ID to disconnect (from ConnectorInfo.connectedAccountId)" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Optional account ID when disconnecting a connection that belongs to a different account (e.g., an artist). Required when the connection was created for another account rather than your own. The authenticated account must have access." - } - } - }, - "DisconnectConnectorResponse": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - }, - "message": { - "type": "string", - "description": "Status message" - } - } - }, - "CompactChatsRequest": { - "type": "object", - "required": [ - "chatId" - ], - "properties": { - "chatId": { - "type": "array", - "minItems": 1, - "items": { - "type": "string", - "format": "uuid" - }, - "description": "Array of chat IDs to compact" - }, - "prompt": { - "type": "string", - "description": "Optional prompt to control what information gets preserved in the compacted summary" - } - } - }, - "CompactChatsResponse": { - "type": "object", - "required": [ - "chats" - ], - "properties": { - "chats": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CompactedChat" - }, - "description": "Array of compacted chat results" - } - } - }, - "CompactedChat": { - "type": "object", - "required": [ - "chatId", - "compacted" - ], - "properties": { - "chatId": { - "type": "string", - "format": "uuid", - "description": "The ID of the chat that was compacted" - }, - "compacted": { - "type": "string", - "description": "The compacted summary text of the chat" - } - } - }, - "TasksResponse": { - "type": "object", - "required": [ - "status", - "tasks" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task" - }, - "description": "Array of task objects" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "Task": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the task" - }, - "title": { - "type": "string", - "description": "Descriptive title or name of the task" - }, - "prompt": { - "type": "string", - "description": "Detailed instruction or prompt for task execution" - }, - "schedule": { - "type": "string", - "description": "Cron expression defining when the task should execute (e.g., '0 10 * * *')" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the associated account" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the associated artist account" - }, - "enabled": { - "type": "boolean", - "nullable": true, - "description": "Whether the task is enabled. Defaults to true." - }, - "trigger_schedule_id": { - "type": "string", - "nullable": true, - "description": "Identifier for the trigger schedule associated with this task" - }, - "recent_runs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskRunResponse" - }, - "description": "Last 5 runs for this task, sourced from the Trigger.dev API." - }, - "upcoming": { - "type": "array", - "items": { - "type": "string", - "format": "date-time" - }, - "description": "Next scheduled run times, sourced from the latest Trigger.dev run payload." - } - } - }, - "CreateTaskRequest": { - "type": "object", - "required": [ - "title", - "prompt", - "schedule", - "account_id", - "artist_account_id" - ], - "properties": { - "title": { - "type": "string", - "description": "Descriptive title of the task", - "example": "Weekly Genre Pulse Check" - }, - "prompt": { - "type": "string", - "description": "Instruction/prompt executed by the task", - "example": "Execute this weekly genre analysis workflow and email a summary to the team." - }, - "schedule": { - "type": "string", - "description": "Cron expression defining when the task runs (e.g., '0 9 * * 4' for Thursdays at 9 AM)", - "example": "0 9 * * 4" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the associated account", - "example": "848cd58d-700f-4b38-ab4c-d9f52a1b2c3d" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the associated artist account", - "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" - } - } - }, - "UpdateTaskRequest": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the task to update", - "example": "aade2bce-55c7-468e-a606-c4e76fb2ea2a" - }, - "title": { - "type": "string", - "description": "New descriptive title of the task", - "example": "Weekly Genre Pulse Check (Updated)" - }, - "prompt": { - "type": "string", - "description": "New instruction/prompt executed by the task", - "example": "Execute this weekly genre analysis workflow and email a summary to the team." - }, - "schedule": { - "type": "string", - "description": "New cron expression defining when the task runs", - "example": "0 10 * * 4" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "New UUID of the associated account", - "example": "848cd58d-700f-4b38-ab4c-d9f52a1b2c3d" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "New UUID of the associated artist account", - "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" - }, - "enabled": { - "type": "boolean", - "nullable": true, - "description": "Whether the task is enabled. Can be true, false, or null.", - "example": true - } - } - }, - "DeleteTaskRequest": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the task to delete", - "example": "aade2bce-55c7-468e-a606-c4e76fb2ea2a" - } - } - }, - "DeleteTaskResponse": { - "type": "object", - "required": [ - "status" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the delete operation" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "Account": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the account" - }, - "name": { - "type": "string", - "description": "Account display name" - }, - "image": { - "type": "string", - "nullable": true, - "description": "Profile image URL" - }, - "instruction": { - "type": "string", - "nullable": true, - "description": "Custom AI instructions for this account" - }, - "knowledges": { - "type": "array", - "nullable": true, - "items": { - "$ref": "#/components/schemas/Knowledge" - }, - "description": "Knowledge base files attached to this account" - }, - "email": { - "type": "string", - "nullable": true, - "description": "Primary email address" - }, - "wallet_address": { - "type": "string", - "nullable": true, - "description": "Connected wallet address" - } - } - }, - "Knowledge": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL to the knowledge file" - }, - "name": { - "type": "string", - "description": "Name of the knowledge file" - }, - "type": { - "type": "string", - "description": "MIME type of the file" - } - } - }, - "GetAccountResponse": { - "type": "object", - "required": [ - "status", - "account" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "account": { - "$ref": "#/components/schemas/Account", - "description": "The account details" - } - } - }, - "GetAccountIdResponse": { - "type": "object", - "required": [ - "status", - "accountId" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "accountId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier (UUID) of the authenticated account" - } - } - }, - "AccountErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateAccountRequest": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address to associate with the account. If an account with this email exists, it will be returned." - }, - "wallet": { - "type": "string", - "description": "Wallet address to associate with the account. If an account with this wallet exists, it will be returned." - } - }, - "description": "At least one of email or wallet should be provided to identify or create an account." - }, - "UpdateAccountRequest": { - "type": "object", - "required": [ - "accountId" - ], - "properties": { - "accountId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the account to update" - }, - "name": { - "type": "string", - "description": "Display name for the account" - }, - "instruction": { - "type": "string", - "description": "Custom instruction or bio for the account" - }, - "organization": { - "type": "string", - "description": "Organization name associated with the account" - }, - "image": { - "type": "string", - "format": "uri", - "description": "URL of the account's profile image" - }, - "jobTitle": { - "type": "string", - "description": "Job title of the account holder" - }, - "roleType": { - "type": "string", - "description": "Role type within the organization" - }, - "companyName": { - "type": "string", - "description": "Company name associated with the account" - }, - "knowledges": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of knowledge areas or expertise" - } - } - }, - "AddArtistToAccountRequest": { - "type": "object", - "required": [ - "email", - "artistId" - ], - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the account to add the artist to" - }, - "artistId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the artist to add" - } - } - }, - "AccountDataResponse": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/AccountData", - "description": "The account data" - } - } - }, - "AccountData": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the account" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "The account ID (same as id, for consistency)" - }, - "name": { - "type": "string", - "description": "Display name of the account" - }, - "email": { - "type": "string", - "format": "email", - "description": "Email address associated with the account" - }, - "wallet": { - "type": "string", - "description": "Wallet address associated with the account" - }, - "image": { - "type": "string", - "format": "uri", - "description": "URL of the account's profile image" - }, - "instruction": { - "type": "string", - "description": "Custom instruction or bio" - }, - "organization": { - "type": "string", - "description": "Organization name" - }, - "job_title": { - "type": "string", - "description": "Job title" - }, - "role_type": { - "type": "string", - "description": "Role type" - }, - "company_name": { - "type": "string", - "description": "Company name" - }, - "knowledges": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of knowledge areas" - } - } - }, - "AddArtistSuccessResponse": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates the artist was successfully added" - } - } - }, - "Artist": { - "type": "object", - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account" - }, - "name": { - "type": "string", - "description": "Artist display name" - }, - "image": { - "type": "string", - "nullable": true, - "description": "Artist profile image URL" - }, - "pinned": { - "type": "boolean", - "description": "Whether the account has pinned this artist" - }, - "socials": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ArtistSocial" - }, - "description": "Social media profiles linked to the artist" - } - } - }, - "ArtistSocial": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social profile" - }, - "platform": { - "type": "string", - "description": "Social media platform (e.g., instagram, twitter, tiktok)" - }, - "username": { - "type": "string", - "description": "Username on the platform" - }, - "profile_url": { - "type": "string", - "description": "Full URL to the social media profile" - } - } - }, - "ArtistsResponse": { - "type": "object", - "required": [ - "status", - "artists" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Artist" - }, - "description": "List of artist objects" - }, - "message": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "ArtistsErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateArtistRequest": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "The name of the artist to create" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to create the artist for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the artist is created for the API key's own account." - }, - "organization_id": { - "type": "string", - "format": "uuid", - "description": "Optional organization ID to link the new artist to" - } - } - }, - "CreateArtistResponse": { - "type": "object", - "required": [ - "artist" - ], - "properties": { - "artist": { - "$ref": "#/components/schemas/CreatedArtist" - } - } - }, - "CreatedArtist": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the created artist account" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account (same as id)" - }, - "name": { - "type": "string", - "description": "Name of the artist" - }, - "created_at": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "ISO timestamp of when the artist was created" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "ISO timestamp of when the artist was last updated" - }, - "image": { - "type": "string", - "nullable": true, - "description": "Artist profile image URL" - }, - "instruction": { - "type": "string", - "nullable": true, - "description": "Custom AI instruction for this artist" - }, - "knowledges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "description": "Knowledge base references for this artist" - }, - "label": { - "type": "string", - "nullable": true, - "description": "Record label name" - }, - "organization": { - "type": "string", - "nullable": true, - "description": "Organization name" - }, - "company_name": { - "type": "string", - "nullable": true, - "description": "Company name" - }, - "job_title": { - "type": "string", - "nullable": true, - "description": "Job title" - }, - "role_type": { - "type": "string", - "nullable": true, - "description": "Role type" - }, - "onboarding_status": { - "type": "string", - "nullable": true, - "description": "Onboarding status" - }, - "onboarding_data": { - "nullable": true, - "description": "Onboarding data" - }, - "account_info": { - "type": "array", - "description": "Account info records" - }, - "account_socials": { - "type": "array", - "description": "Linked social media accounts" - } - } - }, - "CreateArtistError": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "missing_fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of missing or invalid field names" - }, - "error": { - "type": "string", - "description": "Error message describing the validation failure" - }, - "message": { - "type": "string", - "description": "Error message (for invalid JSON or other errors)" - } - } - }, - "ArtistSegment": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist_segments record" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist's accounts record" - }, - "segment_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the segments record" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the segment data was last updated" - }, - "segment_name": { - "type": "string", - "description": "Name of the segment (e.g., 'Twitter Followers')" - }, - "artist_name": { - "type": "string", - "description": "Name of the artist" - } - } - }, - "ArtistSegmentsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of segments available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of segments per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "ArtistSegmentsResponse": { - "type": "object", - "required": [ - "status", - "segments", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "segments": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ArtistSegment" - }, - "description": "List of segment objects associated with the artist" - }, - "pagination": { - "$ref": "#/components/schemas/ArtistSegmentsPagination", - "description": "Pagination metadata for the response" - } - } - }, - "ArtistSegmentsErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "SocialProfile": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist's account_socials record" - }, - "social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist's socials account" - }, - "username": { - "type": "string", - "description": "Username on the platform" - }, - "profile_url": { - "type": "string", - "description": "Direct URL to the profile" - }, - "avatar": { - "type": "string", - "nullable": true, - "description": "URL to the profile avatar image" - }, - "bio": { - "type": "string", - "nullable": true, - "description": "Profile biography or description" - }, - "follower_count": { - "type": "integer", - "nullable": true, - "description": "Number of followers on this platform" - }, - "following_count": { - "type": "integer", - "nullable": true, - "description": "Number of accounts followed on this platform" - }, - "region": { - "type": "string", - "nullable": true, - "description": "Geographic region of the profile" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the profile was last updated" - } - } - }, - "ArtistSocialsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of social profiles available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of social profiles per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "ArtistSocialsResponse": { - "type": "object", - "required": [ - "status", - "socials", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "socials": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SocialProfile" - }, - "description": "List of social media profiles associated with the artist" - }, - "pagination": { - "$ref": "#/components/schemas/ArtistSocialsPagination", - "description": "Pagination metadata for the response" - } - } - }, - "ArtistSocialsErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "ArtistSocialsScrapeRequest": { - "type": "object", - "required": [ - "artist_account_id" - ], - "properties": { - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account to scrape socials for", - "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" - } - } - }, - "ApifyRunResult": { - "type": "object", - "properties": { - "runId": { - "type": "string", - "description": "Unique identifier for the Apify run" - }, - "datasetId": { - "type": "string", - "description": "Unique identifier for the dataset containing scraped data" - }, - "error": { - "type": "string", - "nullable": true, - "description": "Error message if the run failed (null if successful)" - } - } - }, - "InstagramErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "ApifyScraperInProgressResponse": { - "type": "object", - "required": [ - "status", - "datasetId" - ], - "description": "Response when the Apify run is still in progress", - "properties": { - "status": { - "type": "string", - "description": "Current status of the Apify run (e.g., 'RUNNING', 'READY')", - "example": "RUNNING" - }, - "datasetId": { - "type": "string", - "description": "ID of the dataset that will contain the results when the run completes", - "example": "def456uvw" - } - } - }, - "ApifyScraperCompletedResponse": { - "type": "object", - "required": [ - "status", - "datasetId", - "data" - ], - "description": "Response when the Apify run has completed successfully", - "properties": { - "status": { - "type": "string", - "description": "Final status of the Apify run (typically 'SUCCEEDED')", - "example": "SUCCEEDED" - }, - "datasetId": { - "type": "string", - "description": "ID of the dataset containing the results", - "example": "def456uvw" - }, - "data": { - "type": "array", - "items": { - "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.)", - "example": [ - { - "id": "123456789", - "username": "example_user", - "fullName": "Example User", - "biography": "This is a sample biography", - "followersCount": 1000, - "followsCount": 500, - "profilePicUrl": "https://example.com/profile.jpg" - } - ] - } - } - }, - "ApifyScraperErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "description": "Error response from the Apify scraper results endpoint", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status indicating an error occurred" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong", - "example": "runId is required" - } - } - }, - "ArtistSocialsScrapeResponse": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApifyRunResult" - }, - "description": "Array of Apify run results, one for each social profile scraped" - }, - "ArtistProfileSocialProfile": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the social profile" - }, - "username": { - "type": "string", - "description": "Username on the platform" - }, - "profile_url": { - "type": "string", - "description": "Direct URL to the profile" - }, - "avatar": { - "type": "string", - "nullable": true, - "description": "URL to the profile avatar image" - }, - "bio": { - "type": "string", - "nullable": true, - "description": "Profile biography or description" - }, - "follower_count": { - "type": "integer", - "nullable": true, - "description": "Number of followers on this platform" - }, - "following_count": { - "type": "integer", - "nullable": true, - "description": "Number of accounts followed on this platform" - }, - "post_count": { - "type": "integer", - "nullable": true, - "description": "Number of posts on this platform" - }, - "region": { - "type": "string", - "nullable": true, - "description": "Geographic region of the profile" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the profile was last updated" - } - } - }, - "ArtistProfile": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the artist" - }, - "profiles": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ArtistProfileSocialProfile" - }, - "description": "List of social media profiles" - }, - "total_followers": { - "type": "integer", - "description": "Sum of followers across all platforms" - }, - "total_following": { - "type": "integer", - "description": "Sum of following across all platforms" - }, - "total_posts": { - "type": "integer", - "description": "Sum of posts across all platforms" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the data was last updated" - } - } - }, - "ArtistProfileResponse": { - "type": "object", - "required": [ - "status", - "profile" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "profile": { - "$ref": "#/components/schemas/ArtistProfile", - "description": "The artist's comprehensive profile information" - } - } - }, - "ArtistProfileErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "ChatRoom": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the chat room" - }, - "account_id": { - "type": "string", - "format": "uuid", - "nullable": true, - "description": "UUID of the associated account (can be null if not set)" - }, - "topic": { - "type": "string", - "nullable": true, - "description": "Optional topic or description of the room (null if not provided)" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of the last update to the room" - }, - "artist_id": { - "type": "string", - "format": "uuid", - "nullable": true, - "description": "UUID of the associated artist account (null when not applicable)" - } - } - }, - "GetChatsResponse": { - "type": "object", - "required": [ - "status", - "chats" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "chats": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ChatRoom" - }, - "description": "Array of chat room objects" - } - } - }, - "GetChatsErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "GetChatArtistResponse": { - "type": "object", - "required": [ - "status", - "room_id", - "artist_id", - "artist_exists" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "room_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the chat room" - }, - "artist_id": { - "type": "string", - "format": "uuid", - "nullable": true, - "description": "UUID of the artist account associated with the chat, or null when no artist is linked" - }, - "artist_exists": { - "type": "boolean", - "description": "Whether an artist is linked to the chat room" - } - } - }, - "GetChatArtistErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "GetChatSegmentResponse": { - "type": "object", - "required": [ - "status", - "room_id", - "segment_id", - "segment_exists" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "room_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the chat room" - }, - "segment_id": { - "type": "string", - "format": "uuid", - "nullable": true, - "description": "UUID of the segment associated with the chat, or null when no segment is linked" - }, - "segment_exists": { - "type": "boolean", - "description": "Whether a segment is linked to the chat room" - } - } - }, - "GetChatSegmentErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "ChatMessage": { - "type": "object", - "required": [ - "id", - "room_id", - "content", - "updated_at" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the memory message" - }, - "room_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the parent chat room" - }, - "content": { - "type": "object", - "description": "Structured message payload stored for the memory" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of the memory update" - } - } - }, - "GetChatMessagesResponse": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ChatMessage" - }, - "description": "Chronologically ordered list of messages for the chat" - } - } - }, - "GetChatMessagesErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CopyChatMessagesRequest": { - "type": "object", - "required": ["targetChatId"], - "properties": { - "targetChatId": { - "type": "string", - "format": "uuid", - "description": "Target chat room UUID to receive the copied messages." - }, - "clearExisting": { - "type": "boolean", - "default": true, - "description": "When true, existing messages in the target chat are deleted before copy." - } - } - }, - "CopyChatMessagesResponse": { - "type": "object", - "required": ["status", "source_chat_id", "target_chat_id", "copied_count", "cleared_existing"], - "properties": { - "status": { "type": "string", "enum": ["success"], "description": "Status of the request" }, - "source_chat_id": { "type": "string", "format": "uuid", "description": "Source chat room UUID." }, - "target_chat_id": { "type": "string", "format": "uuid", "description": "Target chat room UUID." }, - "copied_count": { "type": "integer", "description": "Number of messages copied from source to target." }, - "cleared_existing": { "type": "boolean", "description": "Whether existing target messages were deleted before copy." } - } - }, - "CopyChatMessagesErrorResponse": { - "type": "object", - "required": ["status", "error"], - "properties": { - "status": { "type": "string", "enum": ["error"], "description": "Status of the request" }, - "error": { "type": "string", "description": "Error message describing what went wrong." } - } - }, - "DeleteTrailingChatMessagesResponse": { - "type": "object", - "required": [ - "status", - "chat_id", - "from_message_id" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "chat_id": { - "type": "string", - "format": "uuid", - "description": "The chat UUID where deletion was applied." - }, - "from_message_id": { - "type": "string", - "format": "uuid", - "description": "The message UUID used as the trailing deletion boundary." - } - } - }, - "DeleteTrailingChatMessagesErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong." - }, - "missing_fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of missing or invalid parameter fields (when validation fails)." - } - } - }, - "CreateChatRequest": { - "type": "object", - "properties": { - "artistId": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account the chat is associated with" - }, - "chatId": { - "type": "string", - "format": "uuid", - "description": "UUID for the new chat (client-generated). If not provided, one will be generated automatically." - }, - "accountId": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to create the chat for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the chat is created for the API key's own account." - }, - "topic": { - "type": "string", - "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." - } - } - }, - "CreateChatResponse": { - "type": "object", - "required": [ - "status", - "chat" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "chat": { - "$ref": "#/components/schemas/ChatRoom", - "description": "The created chat room object" - } - } - }, - "CreateChatErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "UpdateChatRequest": { - "type": "object", - "required": [ - "chatId", - "topic" - ], - "properties": { - "chatId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier (UUID) of the chat room to update" - }, - "topic": { - "type": "string", - "minLength": 3, - "maxLength": 50, - "description": "The new display name for the chat room. Must be between 3 and 50 characters." - } - } - }, - "UpdateChatResponse": { - "type": "object", - "required": [ - "status", - "chat" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "chat": { - "$ref": "#/components/schemas/ChatRoom", - "description": "The updated chat room object" - } - } - }, - "UpdateChatErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "DeleteChatRequest": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier (UUID) of the chat room to delete." - } - } - }, - "DeleteChatResponse": { - "type": "object", - "required": [ - "status", - "id", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The UUID of the deleted chat room." - }, - "message": { - "type": "string", - "description": "Success message describing the deletion result." - } - } - }, - "DeleteChatErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong." - } - } - }, - "UIMessage": { - "type": "object", - "description": "A message in the chat conversation. See https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message for details.", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the message" - }, - "role": { - "type": "string", - "enum": [ - "user", - "assistant", - "system" - ], - "description": "The role of the message sender" - }, - "content": { - "type": "string", - "description": "The text content of the message" - } - } - }, - "ChatGenerateRequest": { - "type": "object", - "description": "Request body for chat generation. Exactly one of 'prompt' or 'messages' must be provided.", - "properties": { - "prompt": { - "type": "string", - "description": "Single text prompt for the assistant. Required if 'messages' is not provided." - }, - "messages": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UIMessage" - }, - "description": "Array of UIMessage objects for context. Required if 'prompt' is not provided." - }, - "artistId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the artist (optional)" - }, - "model": { - "type": "string", - "description": "The AI model to use for text generation (optional)", - "example": "openai/gpt-5-mini" - }, - "excludeTools": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of tool names to exclude from execution", - "example": [ - "create_scheduled_actions" - ] - }, - "roomId": { - "type": "string", - "format": "uuid", - "description": "UUID of the chat room. If not provided, one will be generated automatically." - }, - "topic": { - "type": "string", - "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). Only applies when creating a new room - ignored if room already exists. To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." - } - } - }, - "ContentPart": { - "type": "object", - "description": "A part of the response content. See https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text#content for details.", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "tool-call", - "tool-result" - ], - "description": "The type of content part" - }, - "text": { - "type": "string", - "description": "The text content (present when type is 'text')" - } - } - }, - "ChatGenerateUsage": { - "type": "object", - "description": "Token usage information with detailed breakdown", - "properties": { - "inputTokens": { - "type": "integer", - "description": "Number of input tokens processed" - }, - "outputTokens": { - "type": "integer", - "description": "Number of output tokens generated" - }, - "totalTokens": { - "type": "integer", - "description": "Total tokens used (input + output)" - }, - "reasoningTokens": { - "type": "integer", - "description": "Number of reasoning tokens used" - }, - "cachedInputTokens": { - "type": "integer", - "description": "Number of cached input tokens" - } - } - }, - "ChatGenerateResponseMeta": { - "type": "object", - "description": "Additional response metadata", - "properties": { - "messages": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Response messages" - }, - "headers": { - "type": "object", - "description": "Response headers" - }, - "body": { - "type": "object", - "description": "Response body" - } - } - }, - "ChatGenerateResponse": { - "type": "object", - "description": "Response from the chat generation endpoint", - "properties": { - "text": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ContentPart" - }, - "description": "Array of content parts from the AI model response" - }, - "reasoningText": { - "type": "string", - "nullable": true, - "description": "Optional reasoning or explanation for the response" - }, - "sources": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Optional array of sources used for the response" - }, - "finishReason": { - "type": "string", - "description": "The reason why the generation finished", - "example": "stop" - }, - "usage": { - "$ref": "#/components/schemas/ChatGenerateUsage", - "description": "Token usage information" - }, - "response": { - "$ref": "#/components/schemas/ChatGenerateResponseMeta", - "description": "Additional response metadata" - } - } - }, - "ChatGenerateErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "ChatStreamRequest": { - "type": "object", - "description": "Request body for chat streaming. Exactly one of 'prompt' or 'messages' must be provided.", - "properties": { - "prompt": { - "type": "string", - "description": "Single text prompt for the assistant. Required if 'messages' is not provided." - }, - "messages": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UIMessage" - }, - "description": "Array of UIMessage objects for context. Required if 'prompt' is not provided." - }, - "artistId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the artist (optional)" - }, - "model": { - "type": "string", - "description": "The AI model to use for text generation (optional)", - "example": "openai/gpt-5-mini" - }, - "excludeTools": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of tool names to exclude from execution", - "example": [ - "create_scheduled_actions" - ] - }, - "roomId": { - "type": "string", - "format": "uuid", - "description": "UUID of the chat room. If not provided, one will be generated automatically." - }, - "topic": { - "type": "string", - "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). Only applies when creating a new room - ignored if room already exists. To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." - } - } - }, - "ChatStreamErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "Organization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the membership record" - }, - "organization_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the organization account" - }, - "organization_name": { - "type": "string", - "description": "Display name of the organization" - }, - "organization_image": { - "type": "string", - "nullable": true, - "description": "Organization logo/image URL" - } - } - }, - "GetOrganizationsResponse": { - "type": "object", - "required": [ - "status", - "organizations" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "organizations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Organization" - }, - "description": "List of organizations the account belongs to" - } - } - }, - "OrganizationsErrorResponse": { - "type": "object", - "required": [ - "status", - "message" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateOrganizationRequest": { - "type": "object", - "required": [ - "name", - "accountId" - ], - "properties": { - "name": { - "type": "string", - "description": "The name of the organization to create", - "example": "My New Label" - }, - "accountId": { - "type": "string", - "format": "uuid", - "description": "The account ID of the creator", - "example": "123e4567-e89b-12d3-a456-426614174000" - } - } - }, - "CreatedOrganization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the new organization account" - }, - "name": { - "type": "string", - "description": "Name of the organization" - } - } - }, - "CreateOrganizationResponse": { - "type": "object", - "required": [ - "status", - "organization" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "organization": { - "$ref": "#/components/schemas/CreatedOrganization", - "description": "The created organization" - } - } - }, - "CreateWorkspaceRequest": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the workspace (defaults to \"Untitled\")" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to create the workspace for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the workspace is created for the API key's own account." - }, - "organization_id": { - "type": "string", - "format": "uuid", - "description": "Organization to link the workspace to" - } - } - }, - "CreateWorkspaceResponse": { - "type": "object", - "required": [ - "workspace" - ], - "properties": { - "workspace": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "account_id": { - "type": "string", - "format": "uuid" - }, - "isWorkspace": { - "type": "boolean" - } - } - } - } - }, - "AddArtistToOrganizationRequest": { - "type": "object", - "required": [ - "artistId", - "organizationId" - ], - "properties": { - "artistId": { - "type": "string", - "format": "uuid", - "description": "The account ID of the artist to add", - "example": "artist-account-uuid" - }, - "organizationId": { - "type": "string", - "format": "uuid", - "description": "The account ID of the organization", - "example": "org-account-uuid" - } - } - }, - "AddArtistToOrganizationResponse": { - "type": "object", - "required": [ - "status", - "id" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the created artist-organization link" - } - } - }, - "SpotifyImage": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "The source URL of the image" - }, - "height": { - "type": "integer", - "nullable": true, - "description": "The image height in pixels" - }, - "width": { - "type": "integer", - "nullable": true, - "description": "The image width in pixels" - } - } - }, - "SpotifyExternalUrls": { - "type": "object", - "properties": { - "spotify": { - "type": "string", - "description": "The Spotify URL for the object" - } - } - }, - "SpotifyFollowers": { - "type": "object", - "properties": { - "href": { - "type": "string", - "nullable": true, - "description": "This will always be set to null" - }, - "total": { - "type": "integer", - "description": "The total number of followers" - } - } - }, - "SpotifyArtistObject": { - "type": "object", - "properties": { - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "followers": { - "$ref": "#/components/schemas/SpotifyFollowers" - }, - "genres": { - "type": "array", - "items": { - "type": "string" - }, - "description": "A list of the genres the artist is associated with" - }, - "href": { - "type": "string", - "description": "A link to the Web API endpoint providing full details" - }, - "id": { - "type": "string", - "description": "The Spotify ID for the artist" - }, - "images": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyImage" - }, - "description": "Images of the artist in various sizes" - }, - "name": { - "type": "string", - "description": "The name of the artist" - }, - "popularity": { - "type": "integer", - "description": "The popularity of the artist (0-100)" - }, - "type": { - "type": "string", - "enum": [ - "artist" - ], - "description": "The object type, always 'artist'" - }, - "uri": { - "type": "string", - "description": "The Spotify URI for the artist" - } - } - }, - "SpotifySimplifiedArtist": { - "type": "object", - "properties": { - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "href": { - "type": "string", - "description": "A link to the Web API endpoint providing full details" - }, - "id": { - "type": "string", - "description": "The Spotify ID for the artist" - }, - "name": { - "type": "string", - "description": "The name of the artist" - }, - "type": { - "type": "string", - "enum": [ - "artist" - ], - "description": "The object type, always 'artist'" - }, - "uri": { - "type": "string", - "description": "The Spotify URI for the artist" - } - } - }, - "SpotifyArtistsPaginated": { - "type": "object", - "properties": { - "href": { - "type": "string", - "description": "A link to the Web API endpoint returning the full result" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyArtistObject" - }, - "description": "List of artist objects" - }, - "limit": { - "type": "integer", - "description": "The maximum number of items in the response" - }, - "next": { - "type": "string", - "nullable": true, - "description": "URL to the next page of items" - }, - "offset": { - "type": "integer", - "description": "The offset of the items returned" - }, - "previous": { - "type": "string", - "nullable": true, - "description": "URL to the previous page of items" - }, - "total": { - "type": "integer", - "description": "The total number of items available" - } - } - }, - "SpotifySearchResponse": { - "type": "object", - "properties": { - "artists": { - "$ref": "#/components/schemas/SpotifyArtistsPaginated", - "description": "Search results for artists (if type includes artist)" - }, - "albums": { - "type": "object", - "description": "Search results for albums (if type includes album)" - }, - "tracks": { - "type": "object", - "description": "Search results for tracks (if type includes track)" - }, - "playlists": { - "type": "object", - "description": "Search results for playlists (if type includes playlist)" - } - } - }, - "SpotifyGetArtistResponse": { - "type": "object", - "properties": { - "artist": { - "$ref": "#/components/schemas/SpotifyArtistObject", - "nullable": true, - "description": "The Spotify artist object (null if error)" - }, - "error": { - "type": "object", - "nullable": true, - "description": "Error object if request failed (null if successful)" - } - } - }, - "SpotifySimplifiedAlbum": { - "type": "object", - "properties": { - "album_type": { - "type": "string", - "enum": [ - "album", - "single", - "compilation" - ], - "description": "The type of the album" - }, - "total_tracks": { - "type": "integer", - "description": "The number of tracks in the album" - }, - "available_markets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Markets in which the album is available" - }, - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "href": { - "type": "string", - "description": "A link to the Web API endpoint providing full details" - }, - "id": { - "type": "string", - "description": "The Spotify ID for the album" - }, - "images": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyImage" - }, - "description": "The cover art for the album in various sizes" - }, - "name": { - "type": "string", - "description": "The name of the album" - }, - "release_date": { - "type": "string", - "description": "The date the album was first released" - }, - "release_date_precision": { - "type": "string", - "enum": [ - "year", - "month", - "day" - ], - "description": "The precision with which release_date value is known" - }, - "restrictions": { - "type": "object", - "properties": { - "reason": { - "type": "string", - "description": "The reason for the restriction" - } - }, - "description": "Included when a content restriction is applied" - }, - "type": { - "type": "string", - "enum": [ - "album" - ], - "description": "The object type, always 'album'" - }, - "uri": { - "type": "string", - "description": "The Spotify URI for the album" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedArtist" - }, - "description": "The artists of the album" - }, - "album_group": { - "type": "string", - "enum": [ - "album", - "single", - "compilation", - "appears_on" - ], - "description": "The field to distinguish albums by various groups" - } - } - }, - "SpotifyArtistAlbumsResponse": { - "type": "object", - "properties": { - "href": { - "type": "string", - "description": "A link to the Web API endpoint returning the full result" - }, - "limit": { - "type": "integer", - "description": "The maximum number of items in the response" - }, - "next": { - "type": "string", - "nullable": true, - "description": "URL to the next page of items" - }, - "offset": { - "type": "integer", - "description": "The offset of the items returned" - }, - "previous": { - "type": "string", - "nullable": true, - "description": "URL to the previous page of items" - }, - "total": { - "type": "integer", - "description": "The total number of items available" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedAlbum" - }, - "description": "Array of simplified album objects" - } - } - }, - "SpotifyTrack": { - "type": "object", - "properties": { - "album": { - "$ref": "#/components/schemas/SpotifySimplifiedAlbum", - "description": "The album the track appears on" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedArtist" - }, - "description": "Artists who performed the track" - }, - "available_markets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Markets in which the track is available" - }, - "disc_number": { - "type": "integer", - "description": "Disc number the track is on" - }, - "duration_ms": { - "type": "integer", - "description": "Track length in milliseconds" - }, - "explicit": { - "type": "boolean", - "description": "Whether the track has explicit lyrics" - }, - "external_ids": { - "type": "object", - "properties": { - "isrc": { - "type": "string", - "description": "International Standard Recording Code" - }, - "ean": { - "type": "string", - "description": "International Article Number" - }, - "upc": { - "type": "string", - "description": "Universal Product Code" - } - }, - "description": "Known external IDs for the track" - }, - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "href": { - "type": "string", - "description": "Link to the Web API endpoint with full details" - }, - "id": { - "type": "string", - "description": "Spotify ID for the track" - }, - "is_playable": { - "type": "boolean", - "description": "If true, the track is playable in the given market" - }, - "linked_from": { - "type": "object", - "description": "Information about the originally requested track when track relinking is applied" - }, - "restrictions": { - "type": "object", - "properties": { - "reason": { - "type": "string", - "description": "The reason for the restriction" - } - }, - "description": "Content restriction information" - }, - "name": { - "type": "string", - "description": "Track name" - }, - "popularity": { - "type": "integer", - "description": "Popularity score (0-100)" - }, - "preview_url": { - "type": "string", - "nullable": true, - "description": "URL to a 30 second preview, if available" - }, - "track_number": { - "type": "integer", - "description": "Track number on the album" - }, - "type": { - "type": "string", - "enum": [ - "track" - ], - "description": "The object type, always 'track'" - }, - "uri": { - "type": "string", - "description": "The Spotify URI for the track" - }, - "is_local": { - "type": "boolean", - "description": "Whether the track is from a local file" - } - } - }, - "SpotifyArtistTopTracksResponse": { - "type": "object", - "properties": { - "tracks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyTrack" - }, - "description": "Array of track objects" - } - } - }, - "SpotifySimplifiedTrack": { - "type": "object", - "properties": { - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedArtist" - }, - "description": "The artists who performed the track" - }, - "available_markets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Markets in which the track is available" - }, - "disc_number": { - "type": "integer", - "description": "Disc number the track is on" - }, - "duration_ms": { - "type": "integer", - "description": "Track length in milliseconds" - }, - "explicit": { - "type": "boolean", - "description": "Whether the track has explicit lyrics" - }, - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "href": { - "type": "string", - "description": "Link to the Web API endpoint" - }, - "id": { - "type": "string", - "description": "Spotify ID for the track" - }, - "is_playable": { - "type": "boolean", - "description": "If true, the track is playable" - }, - "linked_from": { - "type": "object", - "description": "Track relinking info" - }, - "restrictions": { - "type": "object", - "properties": { - "reason": { - "type": "string" - } - } - }, - "name": { - "type": "string", - "description": "Track name" - }, - "preview_url": { - "type": "string", - "nullable": true, - "description": "URL to a 30 second preview" - }, - "track_number": { - "type": "integer", - "description": "Track number on the album" - }, - "type": { - "type": "string", - "enum": [ - "track" - ] - }, - "uri": { - "type": "string", - "description": "Spotify URI for the track" - }, - "is_local": { - "type": "boolean", - "description": "Whether from a local file" - } - } - }, - "SpotifyAlbumTracks": { - "type": "object", - "properties": { - "href": { - "type": "string", - "description": "A link to the Web API endpoint" - }, - "limit": { - "type": "integer", - "description": "The maximum number of items in the response" - }, - "next": { - "type": "string", - "nullable": true, - "description": "URL to the next page of items" - }, - "offset": { - "type": "integer", - "description": "The offset of the items returned" - }, - "previous": { - "type": "string", - "nullable": true, - "description": "URL to the previous page" - }, - "total": { - "type": "integer", - "description": "Total number of items available" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedTrack" - }, - "description": "Array of simplified track objects" - } - } - }, - "SpotifyCopyright": { - "type": "object", - "properties": { - "text": { - "type": "string", - "description": "The copyright text" - }, - "type": { - "type": "string", - "description": "The type of copyright" - } - } - }, - "SpotifyAlbum": { - "type": "object", - "properties": { - "album_type": { - "type": "string", - "enum": [ - "album", - "single", - "compilation" - ], - "description": "The type of the album" - }, - "total_tracks": { - "type": "integer", - "description": "The number of tracks in the album" - }, - "available_markets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Markets in which the album is available" - }, - "external_urls": { - "$ref": "#/components/schemas/SpotifyExternalUrls" - }, - "href": { - "type": "string", - "description": "A link to the Web API endpoint providing full details" - }, - "id": { - "type": "string", - "description": "The Spotify ID for the album" - }, - "images": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyImage" - }, - "description": "The cover art for the album in various sizes" - }, - "name": { - "type": "string", - "description": "The name of the album" - }, - "release_date": { - "type": "string", - "description": "The date the album was first released" - }, - "release_date_precision": { - "type": "string", - "enum": [ - "year", - "month", - "day" - ], - "description": "The precision with which release_date value is known" - }, - "restrictions": { - "type": "object", - "properties": { - "reason": { - "type": "string" - } - }, - "description": "Included when a content restriction is applied" - }, - "type": { - "type": "string", - "enum": [ - "album" - ], - "description": "The object type, always 'album'" - }, - "uri": { - "type": "string", - "description": "The Spotify URI for the album" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifySimplifiedArtist" - }, - "description": "The artists of the album" - }, - "tracks": { - "$ref": "#/components/schemas/SpotifyAlbumTracks", - "description": "The tracks of the album" - }, - "copyrights": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotifyCopyright" - }, - "description": "Copyright statements of the album" - }, - "external_ids": { - "type": "object", - "properties": { - "isrc": { - "type": "string" - }, - "ean": { - "type": "string" - }, - "upc": { - "type": "string" - } - }, - "description": "Known external IDs for the album" - }, - "genres": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated. Always empty." - }, - "label": { - "type": "string", - "description": "The label associated with the album" - }, - "popularity": { - "type": "integer", - "description": "Popularity of the album (0-100)" - } - } - }, - "SpotifyErrorResponse": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "status": { - "type": "integer", - "description": "HTTP status code" - }, - "message": { - "type": "string", - "description": "Error message" - } - }, - "description": "Error details" - } - } - }, - "TwitterPhoto": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Photo ID" - }, - "url": { - "type": "string", - "description": "URL of the photo" - } - } - }, - "TwitterVideo": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Video ID" - }, - "preview": { - "type": "string", - "description": "URL of the video preview image" - }, - "url": { - "type": "string", - "description": "URL of the video" - } - } - }, - "Tweet": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Tweet ID" - }, - "text": { - "type": "string", - "description": "Tweet text content" - }, - "username": { - "type": "string", - "description": "Username of the tweet author" - }, - "timestamp": { - "type": "integer", - "description": "Unix timestamp (ms) of when the tweet was posted" - }, - "createdAt": { - "type": "string", - "description": "ISO timestamp of when the tweet was posted" - }, - "isReply": { - "type": "boolean", - "description": "Whether the tweet is a reply" - }, - "isRetweet": { - "type": "boolean", - "description": "Whether the tweet is a retweet" - }, - "likes": { - "type": "integer", - "description": "Number of likes" - }, - "retweetCount": { - "type": "integer", - "description": "Number of retweets" - }, - "replies": { - "type": "integer", - "description": "Number of replies" - }, - "photos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TwitterPhoto" - }, - "description": "Array of photo objects" - }, - "videos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TwitterVideo" - }, - "description": "Array of video objects" - }, - "urls": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of URLs included in the tweet" - }, - "permanentUrl": { - "type": "string", - "description": "Permanent URL to the tweet" - }, - "quotedStatusId": { - "type": "string", - "description": "ID of the quoted tweet (if applicable)" - }, - "inReplyToStatusId": { - "type": "string", - "description": "ID of the tweet this is replying to (if applicable)" - }, - "hashtags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of hashtags in the tweet" - } - } - }, - "TwitterSearchResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Status of the request", - "enum": [ - "success", - "error" - ] - }, - "tweets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Tweet" - }, - "description": "List of tweet objects" - } - } - }, - "TwitterTrendsResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Status of the request", - "enum": [ - "success", - "error" - ] - }, - "trends": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of current trending topics on Twitter" - } - } - }, - "TwitterErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message" - } - } - }, - "SocialScrapeRequest": { - "type": "object", - "required": [ - "social_id" - ], - "properties": { - "social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social profile to scrape. Obtain this from the Get Artist Socials API." - } - } - }, - "SocialPost": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social's social_posts record" - }, - "post_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social's posts record" - }, - "social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social's socials record" - }, - "post_url": { - "type": "string", - "description": "Direct URL to the post on the platform" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the post data was last updated" - } - } - }, - "SocialPostsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of posts available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of posts per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "SocialPostsResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "posts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SocialPost" - }, - "description": "List of social media posts" - }, - "pagination": { - "$ref": "#/components/schemas/SocialPostsPagination" - } - } - }, - "SocialErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "message": { - "type": "string", - "description": "Error message" - } - } - }, - "GeneratedImage": { - "type": "object", - "description": "A generated image file from the AI model", - "properties": { - "base64": { - "type": "string", - "description": "Image file as a base64 encoded string" - }, - "uint8Array": { - "type": "array", - "items": { - "type": "integer" - }, - "description": "Image file as a Uint8Array (represented as array of numbers in JSON)" - }, - "mediaType": { - "type": "string", - "description": "The IANA media type of the file (e.g., 'image/png', 'image/jpeg')" - } - } - }, - "ImageResponseMeta": { - "type": "object", - "description": "Response metadata from the AI provider", - "properties": { - "finishReason": { - "type": "string", - "description": "Reason the generation finished (e.g., 'stop')" - } - } - }, - "ImageProviderMetadata": { - "type": "object", - "description": "Metadata from the AI provider about the generation", - "properties": { - "model": { - "type": "string", - "description": "The AI model used for generation (e.g., 'dall-e-3', 'gpt-image-1')" - }, - "size": { - "type": "string", - "description": "The size of the generated image (e.g., '1024x1024')" - } - } - }, - "ImageUsage": { - "type": "object", - "description": "Token usage information for the image generation", - "properties": { - "promptTokens": { - "type": "integer", - "description": "Number of tokens used in the prompt" - }, - "completionTokens": { - "type": "integer", - "description": "Number of tokens used in the completion (typically 0 for image generation)" - }, - "totalTokens": { - "type": "integer", - "description": "Total tokens used" - } - } - }, - "ArweaveTransaction": { - "type": "object", - "description": "Arweave transaction object for the stored image", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the Arweave transaction" - }, - "last_tx": { - "type": "string", - "description": "Last transaction reference" - }, - "owner": { - "type": "string", - "description": "Owner address of the transaction" - }, - "tags": { - "type": "array", - "items": { - "type": "object" - }, - "description": "Tags associated with the transaction" - }, - "target": { - "type": "string", - "description": "Target address (empty for data transactions)" - }, - "quantity": { - "type": "string", - "description": "Amount transferred (typically '0' for data transactions)" - }, - "data": { - "type": "string", - "description": "Transaction data (may be empty in response)" - }, - "reward": { - "type": "string", - "description": "Mining reward for the transaction" - }, - "signature": { - "type": "string", - "description": "Transaction signature" - }, - "format": { - "type": "integer", - "description": "Transaction format version" - } - } - }, - "InProcessMoment": { - "type": "object", - "description": "In Process moment metadata for provenance and ownership tracking", - "properties": { - "contractAddress": { - "type": "string", - "description": "Smart contract address for the moment" - }, - "tokenId": { - "type": "string", - "description": "Token ID of the minted moment" - }, - "hash": { - "type": "string", - "description": "Transaction hash of the moment mint" - }, - "chainId": { - "type": "integer", - "description": "Chain ID (e.g., 8453 for Base)" - } - } - }, - "ImageGenerationResponse": { - "type": "object", - "description": "Response from the image generation endpoint, extending Experimental_GenerateImageResult from the AI SDK", - "properties": { - "images": { - "type": "array", - "items": { - "$ref": "#/components/schemas/GeneratedImage" - }, - "description": "Array of generated image objects" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of warning messages, if any" - }, - "responses": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ImageResponseMeta" - }, - "description": "Array of response metadata from the AI provider" - }, - "providerMetadata": { - "$ref": "#/components/schemas/ImageProviderMetadata" - }, - "usage": { - "$ref": "#/components/schemas/ImageUsage" - }, - "imageUrl": { - "type": "string", - "description": "Permanent Arweave URL where the image is stored" - }, - "arweaveResult": { - "$ref": "#/components/schemas/ArweaveTransaction" - }, - "moment": { - "$ref": "#/components/schemas/InProcessMoment" - } - } - }, - "ImageGenerationErrorResponse": { - "type": "object", - "properties": { - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "TranscribeAudioRequest": { - "type": "object", - "required": [ - "audio_url", - "account_id", - "artist_account_id" - ], - "properties": { - "audio_url": { - "type": "string", - "description": "Public URL to the audio file (mp3, wav, m4a, webm)", - "example": "https://example.com/song.mp3" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Owner account ID for file storage", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "Artist account ID for file storage", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "title": { - "type": "string", - "description": "Optional title for the audio and transcription files", - "example": "My Song" - }, - "include_timestamps": { - "type": "boolean", - "description": "Whether to include timestamps in the markdown transcript", - "default": false - } - } - }, - "TranscribeFileInfo": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the file record in the database" - }, - "fileName": { - "type": "string", - "description": "Name of the saved file" - }, - "storageKey": { - "type": "string", - "description": "Storage path in Supabase Storage" - } - } - }, - "TranscribeAudioResponse": { - "type": "object", - "required": [ - "success", - "audioFile", - "transcriptFile", - "text" - ], - "properties": { - "success": { - "type": "boolean", - "description": "Whether the transcription was successful" - }, - "audioFile": { - "$ref": "#/components/schemas/TranscribeFileInfo", - "description": "Information about the saved audio file" - }, - "transcriptFile": { - "$ref": "#/components/schemas/TranscribeFileInfo", - "description": "Information about the saved transcript file" - }, - "text": { - "type": "string", - "description": "The full transcription text" - }, - "language": { - "type": "string", - "description": "Detected language code (e.g., 'en', 'es', 'fr')" - } - } - }, - "TranscribeAudioErrorResponse": { - "type": "object", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "SongArtist": { - "type": "object", - "description": "Artist associated with a song", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the artist account" - }, - "name": { - "type": "string", - "nullable": true, - "description": "Name of the artist (can be null)" - }, - "timestamp": { - "type": "integer", - "nullable": true, - "description": "Timestamp associated with the artist account (can be null)" - } - } - }, - "Song": { - "type": "object", - "description": "A song with its metadata and associated artists", - "properties": { - "isrc": { - "type": "string", - "description": "International Standard Recording Code (primary key)" - }, - "name": { - "type": "string", - "description": "Name of the song" - }, - "album": { - "type": "string", - "description": "Name of the album the song belongs to" - }, - "notes": { - "type": "string", - "description": "Notes for the song" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the song data was last updated" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SongArtist" - }, - "description": "Array of artist objects associated with this song" - } - } - }, - "SongsResponse": { - "type": "object", - "description": "Response containing songs data", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "songs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Song" - }, - "description": "Array of song objects with artist information" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is 'error')" - } - } - }, - "SongsErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateSongInput": { - "type": "object", - "required": [ - "isrc" - ], - "properties": { - "isrc": { - "type": "string", - "description": "International Standard Recording Code of the song to create or fetch" - }, - "name": { - "type": "string", - "description": "Optional. Song name, applied only if internal search cannot find valid info" - }, - "album": { - "type": "string", - "description": "Optional. Album name, applied only if internal search cannot find valid info" - }, - "notes": { - "type": "string", - "description": "Optional. Notes for the song, applied only if internal search cannot find valid info" - }, - "artists": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional array of artist names, applied only if internal search cannot find valid info" - } - } - }, - "CreateSongsRequest": { - "type": "object", - "required": [ - "songs" - ], - "properties": { - "songs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CreateSongInput" - }, - "description": "Array of song inputs for bulk create/fetch" - } - } - }, - "Catalog": { - "type": "object", - "description": "A catalog with its metadata", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the catalog" - }, - "name": { - "type": "string", - "description": "Name of the catalog" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the catalog was created" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the catalog was last updated" - } - } - }, - "CatalogsResponse": { - "type": "object", - "description": "Response containing catalogs data", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "catalogs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Catalog" - }, - "description": "Array of catalog objects" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is 'error')" - } - } - }, - "CatalogsErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateCatalogInput": { - "type": "object", - "required": [ - "account_id" - ], - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "The account to associate the catalog with" - }, - "name": { - "type": "string", - "description": "Catalog name to create if catalog_id is omitted" - }, - "catalog_id": { - "type": "string", - "format": "uuid", - "description": "Existing catalog ID to link to the account" - } - } - }, - "CreateCatalogsRequest": { - "type": "object", - "required": [ - "catalogs" - ], - "properties": { - "catalogs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CreateCatalogInput" - }, - "description": "Array of catalog inputs for bulk create/link operations" - } - } - }, - "DeleteCatalogInput": { - "type": "object", - "required": [ - "catalog_id", - "account_id" - ], - "properties": { - "catalog_id": { - "type": "string", - "format": "uuid", - "description": "Catalog ID to remove" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Account ID whose relationship will be removed" - } - } - }, - "DeleteCatalogsRequest": { - "type": "object", - "required": [ - "catalogs" - ], - "properties": { - "catalogs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DeleteCatalogInput" - }, - "description": "Array of catalog-account pairs to remove" - } - } - }, - "CatalogSong": { - "type": "object", - "description": "A song within a catalog with its metadata and associated artists", - "properties": { - "catalog_id": { - "type": "string", - "format": "uuid", - "description": "Catalog ID this song entry is associated with" - }, - "isrc": { - "type": "string", - "description": "International Standard Recording Code (primary key)" - }, - "name": { - "type": "string", - "description": "Name of the song" - }, - "album": { - "type": "string", - "description": "Name of the album the song belongs to" - }, - "lyrics": { - "type": "string", - "description": "Full lyrics of the song" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the song data was last updated" - }, - "artists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SongArtist" - }, - "description": "Array of artist objects associated with this song" - } - } - }, - "CatalogSongsPagination": { - "type": "object", - "description": "Pagination metadata for catalog songs response", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of songs in the catalog" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of songs per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "CatalogSongsResponse": { - "type": "object", - "description": "Response containing catalog songs data with pagination", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "songs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CatalogSong" - }, - "description": "Array of song objects with artist information" - }, - "pagination": { - "$ref": "#/components/schemas/CatalogSongsPagination", - "description": "Pagination metadata for the response" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is 'error')" - } - } - }, - "CatalogSongsErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "AddCatalogSongInput": { - "type": "object", - "required": [ - "catalog_id", - "isrc" - ], - "properties": { - "catalog_id": { - "type": "string", - "format": "uuid", - "description": "Catalog ID to which the song will be added" - }, - "isrc": { - "type": "string", - "description": "Song ISRC to associate to the catalog" - }, - "name": { - "type": "string", - "description": "Optional. Applied only if internal search cannot find valid info for ISRC" - }, - "album": { - "type": "string", - "description": "Optional. Applied only if internal search cannot find valid info for ISRC" - }, - "notes": { - "type": "string", - "description": "Optional. Applied only if internal search cannot find valid info for ISRC" - }, - "artists": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional array of artist names. Applied only if internal search lacks info" - } - } - }, - "AddCatalogSongsRequest": { - "type": "object", - "required": [ - "songs" - ], - "properties": { - "songs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AddCatalogSongInput" - }, - "description": "Array of songs for batch updates" - } - } - }, - "DeleteCatalogSongInput": { - "type": "object", - "required": [ - "catalog_id", - "isrc" - ], - "properties": { - "catalog_id": { - "type": "string", - "format": "uuid", - "description": "Catalog ID from which the song will be removed" - }, - "isrc": { - "type": "string", - "description": "Song ISRC to remove from the catalog" - } - } - }, - "DeleteCatalogSongsRequest": { - "type": "object", - "required": [ - "songs" - ], - "properties": { - "songs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DeleteCatalogSongInput" - }, - "description": "Array of songs for batch deletes" - } - } - }, - "ArtistFan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the fan's social profile" - }, - "username": { - "type": "string", - "description": "Username or handle on the platform" - }, - "avatar": { - "type": "string", - "description": "URL to the fan's avatar/profile image" - }, - "profile_url": { - "type": "string", - "description": "Full URL to the fan's profile on the platform" - }, - "region": { - "type": "string", - "description": "Geographic region or location of the fan" - }, - "bio": { - "type": "string", - "description": "Fan's biography or profile description" - }, - "followerCount": { - "type": "integer", - "description": "Number of followers the fan has" - }, - "followingCount": { - "type": "integer", - "description": "Number of accounts the fan is following" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the fan data was last updated" - } - } - }, - "ArtistFansPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of records available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of records per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "ArtistFansResponse": { - "type": "object", - "required": [ - "status", - "fans", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "fans": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ArtistFan" - }, - "description": "List of social profiles from fans across all platforms" - }, - "pagination": { - "$ref": "#/components/schemas/ArtistFansPagination", - "description": "Pagination metadata for the response" - } - } - }, - "ArtistFansErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "SegmentFan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the fan_segments record" - }, - "username": { - "type": "string", - "description": "Username or handle on the platform" - }, - "avatar": { - "type": "string", - "description": "URL to the fan's avatar/profile image" - }, - "profile_url": { - "type": "string", - "description": "Full URL to the fan's profile on the platform" - }, - "segment_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the fan's segments record" - }, - "segment_name": { - "type": "string", - "description": "Name of the segment (e.g., 'Twitter Followers')" - }, - "fan_social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the fan's socials media profile account" - }, - "region": { - "type": "string", - "description": "Geographic region or location of the fan" - }, - "bio": { - "type": "string", - "description": "Fan's biography or profile description" - }, - "follower_count": { - "type": "integer", - "description": "Number of followers the fan has" - }, - "following_count": { - "type": "integer", - "description": "Number of accounts the fan is following" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the fan data was last updated" - } - } - }, - "ArtistPost": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the post" - }, - "post_url": { - "type": "string", - "description": "Direct URL to the post on the social platform" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the post was last updated" - } - } - }, - "ArtistPostsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of posts available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of posts per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "ArtistPostsResponse": { - "type": "object", - "required": [ - "status", - "posts", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "posts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ArtistPost" - }, - "description": "List of posts from the artist across all social platforms" - }, - "pagination": { - "$ref": "#/components/schemas/ArtistPostsPagination", - "description": "Pagination metadata for the response" - } - } - }, - "ArtistPostsErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "PostComment": { - "type": "object", - "required": [ - "id", - "post_id", - "social_id", - "comment", - "commented_at", - "username", - "profile_url", - "post_url" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the comment record" - }, - "post_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the post this comment belongs to" - }, - "social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social profile that made the comment" - }, - "comment": { - "type": "string", - "description": "Text content of the comment" - }, - "commented_at": { - "type": "string", - "format": "date-time", - "description": "ISO timestamp of when the comment was posted" - }, - "username": { - "type": "string", - "description": "Username of the commenter" - }, - "avatar": { - "type": "string", - "nullable": true, - "description": "URL to the commenter's avatar image" - }, - "profile_url": { - "type": "string", - "description": "URL to the commenter's profile" - }, - "post_url": { - "type": "string", - "description": "URL to the post where the comment was made" - }, - "region": { - "type": "string", - "nullable": true, - "description": "Geographic region of the commenter" - }, - "bio": { - "type": "string", - "nullable": true, - "description": "Commenter's biography or description" - }, - "follower_count": { - "type": "integer", - "nullable": true, - "description": "Number of followers the commenter has" - }, - "following_count": { - "type": "integer", - "nullable": true, - "description": "Number of accounts the commenter follows" - } - } - }, - "PostCommentsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of comments available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of comments per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "PostCommentsResponse": { - "type": "object", - "required": [ - "status", - "comments", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "comments": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PostComment" - }, - "description": "List of comments for the specified post" - }, - "pagination": { - "$ref": "#/components/schemas/PostCommentsPagination", - "description": "Pagination metadata for the response" - } - } - }, - "PostCommentsErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "Comment": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of the comment" - }, - "post_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the associated post" - }, - "social_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the social profile who made the comment" - }, - "comment": { - "type": "string", - "description": "Comment text content" - }, - "commented_at": { - "type": "string", - "format": "date-time", - "description": "Timestamp with timezone of when the comment was made" - } - } - }, - "CommentsPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of comments available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of comments per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "CommentsResponse": { - "type": "object", - "required": [ - "status", - "comments", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "comments": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Comment" - }, - "description": "List of comments for the specified artist or post" - }, - "pagination": { - "$ref": "#/components/schemas/CommentsPagination", - "description": "Pagination metadata for the response" - } - } - }, - "CommentsErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "SegmentFansPagination": { - "type": "object", - "properties": { - "total_count": { - "type": "integer", - "description": "Total number of records available" - }, - "page": { - "type": "integer", - "description": "Current page number" - }, - "limit": { - "type": "integer", - "description": "Number of records per page" - }, - "total_pages": { - "type": "integer", - "description": "Total number of pages available" - } - } - }, - "SegmentFansResponse": { - "type": "object", - "required": [ - "status", - "fans", - "pagination" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "fans": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SegmentFan" - }, - "description": "List of social profiles from fans in the segment" - }, - "pagination": { - "$ref": "#/components/schemas/SegmentFansPagination", - "description": "Pagination metadata for the response" - } - } - }, - "SegmentFansErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "StripeSubscription": { - "type": "object", - "description": "A Stripe subscription object. For detailed information about all available properties, see the Stripe Subscription API documentation: https://docs.stripe.com/api/subscriptions/retrieve", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the subscription" - }, - "object": { - "type": "string", - "enum": [ - "subscription" - ], - "description": "String representing the object's type" - }, - "customer": { - "type": "string", - "description": "ID of the customer who owns this subscription" - }, - "status": { - "type": "string", - "enum": [ - "active", - "canceled", - "incomplete", - "incomplete_expired", - "past_due", - "trialing", - "unpaid" - ], - "description": "The status of the subscription" - }, - "currency": { - "type": "string", - "description": "Three-letter ISO currency code" - }, - "current_period_start": { - "type": "integer", - "description": "Start of the current period (Unix timestamp)" - }, - "current_period_end": { - "type": "integer", - "description": "End of the current period (Unix timestamp)" - }, - "cancel_at_period_end": { - "type": "boolean", - "description": "If true, the subscription will be canceled at the end of the current period" - }, - "created": { - "type": "integer", - "description": "Time at which the subscription was created (Unix timestamp)" - }, - "items": { - "type": "object", - "description": "List of subscription items, each with an attached price", - "properties": { - "object": { - "type": "string", - "enum": [ - "list" - ] - }, - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "object": { - "type": "string", - "enum": [ - "subscription_item" - ] - }, - "price": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "unit_amount": { - "type": "integer", - "description": "Price amount in cents" - }, - "recurring": { - "type": "object", - "properties": { - "interval": { - "type": "string", - "enum": [ - "day", - "week", - "month", - "year" - ] - }, - "interval_count": { - "type": "integer" - } - } - } - } - }, - "quantity": { - "type": "integer" - } - } - } - }, - "has_more": { - "type": "boolean" - }, - "total_count": { - "type": "integer" - } - } - }, - "latest_invoice": { - "type": "string", - "description": "ID of the most recent invoice for this subscription" - }, - "livemode": { - "type": "boolean", - "description": "Indicates if in live mode (true) or test mode (false)" - }, - "metadata": { - "type": "object", - "description": "Set of key-value pairs attached to the subscription" - } - } - }, - "SubscriptionResponse": { - "type": "object", - "required": [ - "status", - "subscription" - ], - "description": "Response for standard accounts with Stripe subscriptions", - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "subscription": { - "$ref": "#/components/schemas/StripeSubscription", - "description": "The full Stripe subscription object" - } - } - }, - "EnterpriseSubscriptionResponse": { - "type": "object", - "required": [ - "status", - "isEnterprise" - ], - "description": "Response for accounts with enterprise plans", - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "isEnterprise": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates that the account has an enterprise plan" - } - } - }, - "SubscriptionErrorResponse": { - "type": "object", - "required": [ - "status", - "error" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Status of the request" - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CreateSandboxRequest": { - "type": "object", - "description": "Request body for creating a new sandbox. All fields are optional - if no command or prompt is provided, sandbox is created without triggering a command execution task. Use prompt as a shortcut to run OpenCode with a given prompt instead of specifying command/args manually.", - "properties": { - "command": { - "type": "string", - "minLength": 1, - "description": "The command to execute in the sandbox environment. If omitted, the sandbox is created without running any command.", - "example": "ls" - }, - "args": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional arguments to pass to the command.", - "example": [ - "-la", - "/home" - ] - }, - "cwd": { - "type": "string", - "description": "Optional working directory for command execution.", - "example": "/home/user" - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "A prompt to pass to OpenCode in the sandbox. When provided, the sandbox will execute `opencode run \"\"`. Cannot be used together with command.", - "example": "create a hello world index.html" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to create the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, creates the sandbox for the API key's own account." - } - } - }, - "Sandbox": { - "type": "object", - "required": [ - "sandboxId", - "sandboxStatus", - "timeout", - "createdAt" - ], - "description": "A sandbox environment instance", - "properties": { - "sandboxId": { - "type": "string", - "description": "Unique identifier for the sandbox", - "example": "sbx_abc123def456" - }, - "sandboxStatus": { - "type": "string", - "enum": [ - "pending", - "running", - "stopping", - "stopped", - "failed" - ], - "description": "Current lifecycle state of the sandbox", - "example": "running" - }, - "timeout": { - "type": "integer", - "description": "Milliseconds remaining before the sandbox stops automatically", - "example": 300000 - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp when the sandbox was created", - "example": "2024-01-15T10:30:00.000Z" - }, - "runId": { - "type": "string", - "description": "Unique identifier for the command execution run. Only present if a command was provided when creating the sandbox. Use this with [GET /api/tasks/runs](/api-reference/tasks/runs) to check the status and retrieve results.", - "example": "run_xyz789abc123" - } - } - }, - "SandboxesResponse": { - "type": "object", - "required": [ - "status", - "sandboxes" - ], - "description": "Response containing sandbox information", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "sandboxes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Sandbox" - }, - "description": "Array of sandbox objects" - }, - "snapshot_id": { - "type": "string", - "description": "The account's saved snapshot ID used for creating new sandboxes. Null if no snapshot has been saved.", - "example": "snap_abc123def456", - "nullable": true - }, - "github_repo": { - "type": "string", - "description": "The GitHub repository URL associated with the account's sandbox environment. Used as the filesystem source when restoring sandboxes.", - "example": "https://github.com/username/repo", - "nullable": true - }, - "filetree": { - "type": "array", - "nullable": true, - "description": "The recursive file tree of the account's GitHub repository. Null if no github_repo is set or if the fetch fails.", - "items": { - "$ref": "#/components/schemas/FileTreeEntry" - } - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "SandboxErrorResponse": { - "type": "object", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string", - "description": "Error message describing what went wrong", - "example": "Failed to create sandbox" - } - } - }, - "SandboxFileResponse": { - "type": "object", - "required": [ - "status", - "content" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the operation" - }, - "content": { - "type": "string", - "description": "The raw text content of the file" - } - } - }, - "UploadSandboxFilesRequest": { - "type": "object", - "required": [ - "files" - ], - "properties": { - "path": { - "type": "string", - "description": "The target directory path within the repository to upload files to. Defaults to the repository root if omitted.", - "example": "assets/images" - }, - "files": { - "type": "array", - "items": { - "type": "object", - "required": ["url", "name"], - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The URL of the file to upload", - "example": "https://example.com/files/album-cover.png" - }, - "name": { - "type": "string", - "description": "The filename to use when committing to the repository", - "example": "album-cover.png" - } - } - }, - "description": "Array of files to upload, each with a URL and target filename" - }, - "message": { - "type": "string", - "description": "Optional commit message. Defaults to 'Upload files via API'.", - "example": "Add new album artwork" - } - } - }, - "UploadSandboxFilesResponse": { - "type": "object", - "required": [ - "status", - "uploaded" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the operation" - }, - "uploaded": { - "type": "array", - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "description": "The full path of the uploaded file in the repository" - }, - "sha": { - "type": "string", - "description": "The git SHA of the created/updated file" - } - } - }, - "description": "Array of uploaded file details" - } - } - }, - "SetupSandboxRequest": { - "type": "object", - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to set up the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, sets up the sandbox for the API key's own account." - } - } - }, - "SetupSandboxResponse": { - "type": "object", - "required": [ - "status", - "runId" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the setup operation" - }, - "runId": { - "type": "string", - "description": "The Trigger.dev run ID for the setup-sandbox background task. Use this with [GET /api/tasks/runs](/api-reference/tasks/runs) to check the status and retrieve results.", - "example": "run_abc123def456" - } - } - }, - "DeleteSandboxRequest": { - "type": "object", - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to delete the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, deletes the sandbox for the API key's own account." - } - } - }, - "DeleteSandboxResponse": { - "type": "object", - "required": [ - "status" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the delete operation" - }, - "deleted_snapshot": { - "nullable": true, - "description": "The snapshot record that was deleted. Null if no snapshot existed for the account.", - "$ref": "#/components/schemas/UpdateSnapshotResponse" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "UpdateSnapshotRequest": { - "type": "object", - "required": [], - "properties": { - "snapshotId": { - "type": "string", - "description": "The snapshot ID to set for the account. This snapshot will be used as the base environment when creating new sandboxes.", - "example": "snap_abc123def456" - }, - "github_repo": { - "type": "string", - "format": "uri", - "description": "The GitHub repository URL to associate with the account's sandbox environment. Must be a valid URL.", - "example": "https://github.com/org/repo" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to update the snapshot for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, updates the snapshot for the API key's own account." - } - } - }, - "UpdateSnapshotResponse": { - "type": "object", - "required": [ - "account_id", - "snapshot_id", - "expires_at", - "github_repo", - "created_at" - ], - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "The account ID this snapshot belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "snapshot_id": { - "type": "string", - "description": "The snapshot ID that was set for the account", - "example": "snap_abc123def456" - }, - "expires_at": { - "type": "string", - "format": "date-time", - "description": "When the snapshot expires", - "example": "2027-01-01T00:00:00.000Z" - }, - "github_repo": { - "type": "string", - "nullable": true, - "description": "The GitHub repository URL associated with the sandbox", - "example": "https://github.com/org/repo" - }, - "created_at": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "When the snapshot record was created", - "example": "2025-01-01T00:00:00.000Z" - } - } - }, - "Pulse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the pulse" - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the associated account" - }, - "active": { - "type": "boolean", - "description": "Whether the pulse is active (defaults to true)" - } - } - }, - "PulseResponse": { - "type": "object", - "required": [ - "status", - "pulse" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "pulse": { - "$ref": "#/components/schemas/Pulse", - "description": "The pulse object" - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "PulsesResponse": { - "type": "object", - "required": [ - "status", - "pulses" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "pulses": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Pulse" - }, - "description": "Array of pulse objects. Contains pulses for the authenticated account. If the account has access to organizations, all organization accounts are included." - }, - "error": { - "type": "string", - "description": "Error message (only present if status is error)" - } - } - }, - "UpdatePulseRequest": { - "type": "object", - "required": [ - "active" - ], - "properties": { - "active": { - "type": "boolean", - "description": "Whether to enable or disable the pulse", - "example": true - }, - "account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the account to update the pulse for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, updates the pulse for the API key's own account." - } - } - }, - "TaskRunResponse": { - "type": "object", - "description": "Raw Trigger.dev SDK run object. The API passes through the SDK response without field mapping. See https://trigger.dev/docs/management/runs/retrieve for the full reference. When listing runs, `output`, `error`, `payload`, and `attempts` are not included.", - "required": [ - "id", - "status", - "taskIdentifier", - "createdAt", - "updatedAt" - ], - "properties": { - "id": { - "type": "string", - "description": "The unique run identifier, prefixed with `run_`" - }, - "status": { - "type": "string", - "enum": [ - "PENDING_VERSION", - "DELAYED", - "QUEUED", - "EXECUTING", - "REATTEMPTING", - "FROZEN", - "COMPLETED", - "CANCELED", - "FAILED", - "CRASHED", - "INTERRUPTED", - "SYSTEM_FAILURE" - ], - "description": "Current run status" - }, - "taskIdentifier": { - "type": "string", - "description": "The task type identifier (e.g. 'setup-sandbox', 'run-sandbox-command')" - }, - "idempotencyKey": { - "type": "string", - "nullable": true, - "description": "Idempotency key used to deduplicate trigger requests" - }, - "version": { - "type": "string", - "description": "The worker version that executed the run" - }, - "isTest": { - "type": "boolean", - "description": "Whether this is a test run" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the run was created (ISO 8601)" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When the run was last updated (ISO 8601)" - }, - "startedAt": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "When execution started (null if not yet started)" - }, - "finishedAt": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "When the run finished (null if still running)" - }, - "delayedUntil": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "If delayed, when the run becomes eligible to execute" - }, - "ttl": { - "description": "Time-to-live. If the run is not started within this duration, it expires.", - "nullable": true - }, - "expiredAt": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "When the run expired (null if not expired)" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags associated with this run (max 10)" - }, - "metadata": { - "type": "object", - "nullable": true, - "description": "JSON metadata attached to the run" - }, - "costInCents": { - "type": "number", - "description": "Compute cost of the run in cents" - }, - "baseCostInCents": { - "type": "number", - "description": "Base invocation cost in cents" - }, - "durationMs": { - "type": "number", - "description": "Compute duration in milliseconds" - }, - "env": { - "type": "object", - "description": "Environment the run executed in", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "user": { - "type": "string", - "nullable": true - } - } - }, - "depth": { - "type": "integer", - "description": "Nesting depth for child runs" - }, - "batchId": { - "type": "string", - "nullable": true, - "description": "Batch ID if triggered as part of a batch" - }, - "triggerFunction": { - "type": "string", - "enum": [ - "trigger", - "triggerAndWait", - "batchTrigger", - "batchTriggerAndWait" - ], - "description": "The function used to trigger this run" - }, - "payload": { - "description": "Input payload for the task. Only present when retrieving by runId.", - "nullable": true - }, - "output": { - "description": "Task output data. Only present when retrieving by runId.", - "nullable": true - }, - "error": { - "type": "object", - "nullable": true, - "description": "Error details if the run failed. Only present when retrieving by runId.", - "properties": { - "message": { - "type": "string", - "description": "Human-readable error message" - }, - "name": { - "type": "string", - "description": "Error name or type" - }, - "stackTrace": { - "type": "string", - "description": "Stack trace" - } - } - }, - "attempts": { - "type": "array", - "description": "Attempt history. Only present when retrieving by runId.", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Attempt ID, prefixed with `attempt_`" - }, - "status": { - "type": "string", - "enum": [ - "PENDING", - "EXECUTING", - "PAUSED", - "COMPLETED", - "FAILED", - "CANCELED" - ] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "startedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "completedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "error": { - "type": "object", - "nullable": true, - "properties": { - "message": { - "type": "string" - }, - "name": { - "type": "string" - }, - "stackTrace": { - "type": "string" - } - } - } - } - } - }, - "schedule": { - "type": "object", - "nullable": true, - "description": "Schedule information if triggered by a schedule. Only present when retrieving by runId." - }, - "relatedRuns": { - "type": "object", - "nullable": true, - "description": "Related run references (root, parent, children). Only present when retrieving by runId." - } - } - }, - "TaskRunListResponse": { - "type": "object", - "required": [ - "status", - "runs" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Indicates the request was successful" - }, - "runs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskRunResponse" - }, - "description": "List of recent task runs for the authenticated account. Each item is a raw Trigger.dev SDK run object (same shape as TaskRunResponse, but without `output` and `error` fields)." - } - } - }, - "FileTreeEntry": { - "type": "object", - "required": [ - "path", - "type", - "sha" - ], - "description": "A single entry in a GitHub repository file tree", - "properties": { - "path": { - "type": "string", - "description": "The file or directory path relative to the repository root", - "example": "src/index.ts" - }, - "type": { - "type": "string", - "enum": [ - "blob", - "tree" - ], - "description": "The type of entry: blob for files, tree for directories" - }, - "sha": { - "type": "string", - "description": "The SHA hash of the entry", - "example": "abc123def456" - }, - "size": { - "type": "integer", - "description": "The size of the file in bytes. Only present for blob entries.", - "example": 1024 - } - } - }, - "ContentCreateRequest": { - "type": "object", - "description": "Parameters for triggering the content creation pipeline.", - "properties": { - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account to create content for. Use [GET /api/artists](/api-reference/artists/list) to find artist account IDs.", - "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" - }, - "template": { - "type": "string", - "description": "The template to use for content generation. Defines the visual style, scene, and prompt configuration. If omitted, defaults to `artist-caption-bedroom`. See [GET /api/content/templates](/api-reference/content/templates) for available options.", - "example": "artist-caption-stage", - "default": "artist-caption-bedroom" - }, - "lipsync": { - "type": "boolean", - "description": "Whether to generate video with lip-synced audio. When `true`, uses an audio-to-video model that bakes audio into the video for lip movement. When `false`, generates video from the image alone and overlays audio in post. If omitted, the template's default workflow is used.", - "example": false - }, - "caption_length": { - "type": "string", - "enum": [ - "short", - "medium", - "long" - ], - "description": "Controls the length of the generated caption text. `short` produces 1-2 lines (punchy, minimal). `medium` produces 1-2 sentences. `long` produces a paragraph (stream of consciousness style). Defaults to `short`.", - "default": "short", - "example": "short" - }, - "upscale": { - "type": "boolean", - "description": "Whether to upscale the generated image and video using fal.ai SeedVR2 for higher resolution and detail. Adds approximately 2 minutes to the pipeline. Defaults to `false`.", - "default": false, - "example": false - }, - "batch": { - "type": "integer", - "minimum": 1, - "maximum": 30, - "description": "Number of videos to generate in parallel. Each video independently selects a random reference image, song clip, and mood variation. The response always returns `runIds` as an array. Defaults to `1`.", - "default": 1, - "example": 1 - }, - "songs": { - "type": "array", - "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.", - "example": ["hiccups", "https://example.com/unreleased-track.mp3"] - }, - "images": { - "type": "array", - "items": { - "type": "string", - "format": "uri" - }, - "description": "Optional list of public image URLs to use as face guides instead of the artist's default `face-guide.png` from their GitHub repo. The first image is used as the primary face guide. Useful when the caller wants to override the default face reference.", - "example": ["https://example.com/face.png"] - } - }, - "required": [ - "artist_account_id" - ] - }, - "ContentCreateResponse": { - "type": "object", - "required": [ - "runIds", - "status", - "artist_account_id", - "template" - ], - "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", - "items": { - "type": "string" - }, - "description": "Array of run IDs. Poll each via [GET /api/tasks/runs](/api-reference/tasks/runs). For single runs this contains one element.", - "example": [ - "run_abc123def456" - ] - }, - "status": { - "type": "string", - "enum": [ - "triggered" - ], - "description": "Indicates the pipeline has been triggered" - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account the pipeline is running for", - "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" - }, - "template": { - "type": "string", - "description": "The template being used", - "example": "artist-caption-bedroom" - }, - "lipsync": { - "type": "boolean", - "description": "Whether lip-sync mode is enabled", - "example": false - }, - "failed": { - "type": "integer", - "description": "Number of triggers that failed. Only present when some triggers failed.", - "example": 0 - } - } - }, - "ContentCreateErrorResponse": { - "type": "object", - "required": [ - "error" - ], - "description": "Returned when the artist is missing required files or the template is not found. Includes actionable instructions for resolving each issue.", - "properties": { - "error": { - "type": "string", - "description": "Human-readable error summary", - "example": "Artist 'new-artist' is not ready for content creation" - }, - "ready": { - "type": "boolean", - "description": "Always `false` when this error is returned", - "example": false - }, - "missing": { - "type": "array", - "description": "List of missing files with severity and fix instructions. Only present when the artist fails validation.", - "items": { - "$ref": "#/components/schemas/ContentMissingFile" - } - }, - "available_templates": { - "type": "array", - "description": "List of valid template names. Only present when the requested template was not found.", - "items": { - "type": "string" - }, - "example": [ - "artist-caption-bedroom", - "artist-caption-outside", - "artist-caption-stage" - ] - } - } - }, - "ContentErrorResponse": { - "type": "object", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string", - "description": "Error message describing what went wrong", - "example": "Unauthorized" - } - } - }, - "ContentTemplatesResponse": { - "type": "object", - "required": [ - "templates" - ], - "description": "List of available content creation templates.", - "properties": { - "templates": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ContentTemplate" - } - } - } - }, - "ContentTemplate": { - "type": "object", - "required": [ - "name", - "description", - "defaultLipsync" - ], - "description": "A content creation template that defines the visual style and composition for generated videos.", - "properties": { - "name": { - "type": "string", - "description": "Template identifier. Pass this as the `template` field in [POST /api/content/create](/api-reference/content/create).", - "example": "artist-caption-bedroom" - }, - "description": { - "type": "string", - "description": "Human-readable description of the template's visual style", - "example": "Moody purple bedroom setting with caption overlay" - }, - "defaultLipsync": { - "type": "boolean", - "description": "Whether this template defaults to lip-sync mode when the `lipsync` flag is not explicitly set", - "example": false - } - } - }, - "ContentValidateResponse": { - "type": "object", - "required": [ - "ready", - "artist_account_id" - ], - "description": "Validation report for an artist's content creation readiness.", - "properties": { - "ready": { - "type": "boolean", - "description": "`true` if the artist has all required files and the pipeline can run. `false` if required files are missing.", - "example": true - }, - "artist_account_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the artist account that was validated", - "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" - }, - "songs": { - "type": "integer", - "description": "Number of songs found in the artist's `songs/` directory", - "example": 17 - }, - "templates": { - "type": "array", - "description": "Available templates that can be used with this artist", - "items": { - "type": "string" - }, - "example": [ - "artist-caption-bedroom", - "artist-caption-outside", - "artist-caption-stage" - ] - }, - "checks": { - "type": "object", - "description": "Per-file validation results. Only present when `ready` is `true`.", - "properties": { - "face_guide": { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - "artist_context": { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - "audience_context": { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - "era_config": { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - "pipeline_config": { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - "songs": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentValidationCheck" - }, - { - "type": "object", - "properties": { - "count": { - "type": "integer", - "description": "Number of songs found", - "example": 17 - } - } - } - ] - } - } - }, - "missing": { - "type": "array", - "description": "List of missing files with severity and fix instructions. Only present when `ready` is `false`.", - "items": { - "$ref": "#/components/schemas/ContentMissingFile" - } - } - } - }, - "ContentValidationCheck": { - "type": "object", - "required": [ - "status" - ], - "description": "Status of a single validation check.", - "properties": { - "status": { - "type": "string", - "enum": [ - "ok", - "missing", - "warning" - ], - "description": "Whether the file was found", - "example": "ok" - } - } - }, - "ContentMissingFile": { - "type": "object", - "required": [ - "file", - "severity", - "description", - "fix" - ], - "description": "A missing file that prevents or degrades content creation.", - "properties": { - "file": { - "type": "string", - "description": "Relative path of the missing file within the artist directory", - "example": "context/images/face-guide.png" - }, - "severity": { - "type": "string", - "enum": [ - "required", - "recommended" - ], - "description": "`required` means the pipeline will fail without this file. `recommended` means the pipeline will run but output quality is degraded.", - "example": "required" - }, - "description": { - "type": "string", - "description": "What this file is used for in the pipeline", - "example": "Face guide image used for AI image generation" - }, - "fix": { - "type": "string", - "description": "Actionable instructions for creating or adding the missing file", - "example": "Generate a face guide using fal-ai/nano-banana-pro/edit with 2-3 reference photos of the artist" - } - } - }, - "ContentEstimateResponse": { - "type": "object", - "required": [ - "workflows" - ], - "description": "Cost estimates based on live fal.ai pricing. When `compare` is `false`, the `workflows` array contains a single entry. When `true`, it contains all available profiles.", - "properties": { - "workflows": { - "type": "array", - "description": "One or more workflow cost breakdowns", - "items": { - "$ref": "#/components/schemas/ContentWorkflowEstimate" - } - }, - "comparison": { - "description": "Side-by-side summary. Only present when `compare` is `true` and multiple workflows are returned.", - "$ref": "#/components/schemas/ContentEstimateComparison" - }, - "batch": { - "type": "object", - "description": "Batch cost projection. Only present when `batch` > 1.", - "properties": { - "count": { - "type": "integer", - "description": "Number of videos in the batch", - "example": 30 - }, - "cheapestTotal": { - "type": "number", - "format": "float", - "description": "Total cost for the batch using the cheapest workflow", - "example": 5.4 - }, - "mostExpensiveTotal": { - "type": "number", - "format": "float", - "description": "Total cost for the batch using the most expensive workflow", - "example": 28.5 - } - } - } - } - }, - "ContentWorkflowEstimate": { - "type": "object", - "required": [ - "name", - "perVideo", - "steps" - ], - "description": "Cost breakdown for a single workflow profile.", - "properties": { - "name": { - "type": "string", - "description": "Workflow profile name", - "example": "Current (image-to-video)" - }, - "perVideo": { - "type": "number", - "format": "float", - "description": "Total estimated cost per video in USD", - "example": 0.82 - }, - "steps": { - "type": "array", - "description": "Per-step cost breakdown showing where the money goes", - "items": { - "$ref": "#/components/schemas/ContentStepEstimate" - } - }, - "costBreakdown": { - "type": "object", - "description": "Summary of the biggest cost driver", - "properties": { - "mostExpensiveStep": { - "type": "string", - "description": "Name of the step that costs the most", - "example": "Generate Video" - }, - "mostExpensivePercent": { - "type": "integer", - "description": "Percentage of total cost from the most expensive step", - "example": 68 - } - } - } - } - }, - "ContentStepEstimate": { - "type": "object", - "required": [ - "name", - "model", - "cost", - "note" - ], - "description": "Cost details for a single pipeline step.", - "properties": { - "name": { - "type": "string", - "description": "Pipeline step name", - "example": "Generate Image" - }, - "model": { - "type": "string", - "description": "The AI model or service used for this step", - "example": "fal-ai/nano-banana-pro/edit" - }, - "cost": { - "type": "number", - "format": "float", - "description": "Estimated cost for this step in USD", - "example": 0.04 - }, - "unit": { - "type": "string", - "description": "Billing unit type (e.g., `images`, `seconds`, `megapixels`). Not present for free steps.", - "example": "images" - }, - "unitPrice": { - "type": "number", - "format": "float", - "description": "Price per billing unit in USD. Not present for free steps.", - "example": 0.04 - }, - "note": { - "type": "string", - "description": "Human-readable calculation detail", - "example": "1 call" - } - } - }, - "ContentEstimateComparison": { - "type": "object", - "required": [ - "cheapest", - "cheapestPerVideo", - "mostExpensive", - "mostExpensivePerVideo", - "savingsPercent" - ], - "description": "Summary comparing the cheapest and most expensive workflow options.", - "properties": { - "cheapest": { - "type": "string", - "description": "Name of the cheapest workflow profile", - "example": "Budget (no upscale, LTX video)" - }, - "cheapestPerVideo": { - "type": "number", - "format": "float", - "description": "Cost per video for the cheapest workflow", - "example": 0.18 - }, - "mostExpensive": { - "type": "string", - "description": "Name of the most expensive workflow profile", - "example": "Current (audio-to-video)" - }, - "mostExpensivePerVideo": { - "type": "number", - "format": "float", - "description": "Cost per video for the most expensive workflow", - "example": 0.95 - }, - "savingsPercent": { - "type": "integer", - "description": "Percentage savings between the cheapest and most expensive workflows", - "example": 81 - } - } - }, - "SongAnalyzeRequest": { - "type": "object", - "description": "Provide exactly one of `preset` or `prompt`. Use `preset` for structured analysis workflows, or `prompt` for free-form questions.", - "properties": { - "preset": { - "type": "string", - "enum": [ - "catalog_metadata", - "mood_tags", - "lyric_transcription", - "mix_feedback", - "song_description", - "music_theory", - "similar_artists", - "sample_detection", - "sync_brief_match", - "audience_profile", - "content_advisory", - "playlist_pitch", - "artist_development_notes", - "full_report" - ], - "description": "Name of a curated analysis preset. Use instead of prompt for structured, optimized output. The 'full_report' preset runs all 13 presets in parallel and returns a comprehensive report. See [List Analyze Presets](/api-reference/songs/analyze-presets) for the full list of available presets.", - "example": "catalog_metadata" - }, - "prompt": { - "type": "string", - "minLength": 1, - "maxLength": 24000, - "description": "Text prompt or question about the music", - "example": "Describe the genre, tempo, and mood of this track." - }, - "audio_url": { - "type": "string", - "format": "uri", - "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": { - "type": "integer", - "minimum": 1, - "maximum": 2048, - "default": 512, - "description": "Maximum number of tokens to generate", - "example": 512 - }, - "temperature": { - "type": "number", - "minimum": 0, - "maximum": 2, - "default": 1.0, - "description": "Controls output creativity \u2014 higher values produce more varied responses", - "example": 0.7 - }, - "top_p": { - "type": "number", - "minimum": 0, - "maximum": 1, - "default": 1, - "description": "Nucleus sampling probability cutoff", - "example": 0.9 - }, - "do_sample": { - "type": "boolean", - "default": false, - "description": "Enable sampling (set true when using temperature or top_p)", - "example": false - } - } - }, - "SongAnalyzeResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Request status" - }, - "preset": { - "type": "string", - "description": "Preset used for analysis, when applicable", - "example": "catalog_metadata" - }, - "response": { - "description": "Model output for single-preset or custom-prompt analysis. May be plain text or structured JSON depending on the preset." - }, - "report": { - "type": "object", - "description": "Full report payload returned only when using the `full_report` preset" - }, - "elapsed_seconds": { - "type": "number", - "format": "float", - "description": "Inference time in seconds" - } - } - }, - "SongAnalyzeErrorResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "error" - ], - "description": "Error status" - }, - "missing_fields": { - "type": "array", - "description": "Path to the first invalid or missing field when validation fails", - "items": { - "type": "string" - } - }, - "error": { - "type": "string", - "description": "Error message describing what went wrong" - } - } - }, - "CheckAdminResponse": { - "type": "object", - "required": [ - "status", - "isAdmin" - ], - "properties": { - "status": { - "type": "string", - "enum": [ - "success" - ], - "description": "Status of the request" - }, - "isAdmin": { - "type": "boolean", - "description": "Whether the authenticated account is a Recoup admin" - } - } - }, - "AccountSandboxRow": { - "type": "object", - "required": [ - "account_id", - "total_sandboxes", - "last_created_at" - ], - "properties": { - "account_id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the account", - "example": "04e3aba9-c130-4fb8-8b92-34e95d43e66b" - }, - "total_sandboxes": { - "type": "integer", - "description": "Total number of sandboxes created for this account", - "example": 5 - }, - "last_created_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the most recently created sandbox for this account", - "example": "2026-03-10T12:00:00Z" - }, - "account_email": { - "type": "string", - "nullable": true, - "description": "The email address of the account. Null if the account has no email set.", - "example": "alice@example.com" - } - }, - "description": "" - }, - "AdminSandboxesResponse": { - "type": "object", - "required": [ - "status", - "accounts" - ], - "description": "Response containing per-account sandbox statistics for admin use", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "accounts": { - "type": "array", - "description": "List of accounts with their sandbox statistics, ordered by most recently active first", - "items": { - "$ref": "#/components/schemas/AccountSandboxRow" - } - } - } - }, - "OrgRepoRow": { - "type": "object", - "required": [ - "repo_name", - "repo_url", - "total_commits", - "latest_commit_messages", - "earliest_committed_at", - "latest_committed_at", - "account_repos" - ], - "description": "Commit statistics for a single GitHub org repository", - "properties": { - "repo_name": { - "type": "string", - "description": "Repository name", - "example": "chat" - }, - "repo_url": { - "type": "string", - "description": "Full GitHub HTML URL of the repository", - "example": "https://github.com/recoupable/chat" - }, - "total_commits": { - "type": "integer", - "description": "Total number of commits in the repository", - "example": 5696 - }, - "latest_commit_messages": { - "type": "array", - "description": "Messages from the 5 most recent commits", - "items": { - "type": "string" - }, - "example": [ - "Merge test into main", - "fix: duration stuck at 0ms for in-progress tasks" - ] - }, - "earliest_committed_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the earliest (first) commit", - "example": "2024-09-27T17:16:01Z" - }, - "latest_committed_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the most recent commit", - "example": "2026-03-10T19:57:37Z" - }, - "account_repos": { - "type": "array", - "items": { - "type": "object", - "properties": { - "account_id": { - "type": "string" - }, - "email": { - "type": "string", - "nullable": true - }, - "repo_url": { - "type": "string" - } - }, - "required": [ - "account_id", - "repo_url" - ] - }, - "description": "List of accounts using this org repo as a submodule, with account_id, email, and repo_url" - } - } - }, - "AdminEmailsResponse": { - "type": "object", - "required": [ - "status", - "emails" - ], - "description": "Response containing Resend emails sent for an account", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "emails": { - "type": "array", - "description": "List of emails sent for the account, ordered by created_at descending", - "items": { - "$ref": "#/components/schemas/PulseEmailRow" - } - } - } - }, - "PulseEmailRow": { - "type": "object", - "required": [ - "id", - "from", - "to", - "subject", - "created_at", - "last_event" - ], - "description": "A single email record from Resend (full GetEmailResponseSuccess). See [Resend API docs](https://resend.com/docs/api-reference/emails/retrieve-email) for the source of truth.", - "properties": { - "id": { - "type": "string", - "description": "The Resend email ID" - }, - "from": { - "type": "string", - "description": "Sender email address" - }, - "to": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Recipient email addresses" - }, - "cc": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "description": "CC recipient email addresses" - }, - "bcc": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "description": "BCC recipient email addresses" - }, - "reply_to": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "description": "Reply-to email addresses" - }, - "subject": { - "type": "string", - "description": "Email subject line" - }, - "html": { - "type": "string", - "nullable": true, - "description": "HTML content of the email" - }, - "text": { - "type": "string", - "nullable": true, - "description": "Plain text content of the email" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the email was created" - }, - "scheduled_at": { - "type": "string", - "format": "date-time", - "nullable": true, - "description": "Scheduled send time, if any" - }, - "last_event": { - "type": "string", - "enum": [ - "bounced", - "canceled", - "clicked", - "complained", - "delivered", - "delivery_delayed", - "failed", - "opened", - "queued", - "scheduled", - "sent" - ], - "description": "Most recent delivery event for this email" - }, - "tags": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "value" - ] - }, - "nullable": true, - "description": "Custom tags attached to the email" - } - } - }, - "AdminSandboxOrgsResponse": { - "type": "object", - "required": [ - "status", - "repos" - ], - "description": "Response containing commit statistics for all org repositories", - "properties": { - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Status of the request" - }, - "repos": { - "type": "array", - "description": "List of org repos with their commit statistics, ordered by total_commits descending", - "items": { - "$ref": "#/components/schemas/OrgRepoRow" - } - } - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" - }, - "apiKeyAuth": { - "type": "apiKey", - "in": "header", - "name": "x-api-key", - "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." - } - } - } -} diff --git a/api-reference/openapi/accounts.json b/api-reference/openapi/accounts.json new file mode 100644 index 0000000..5d9a4ac --- /dev/null +++ b/api-reference/openapi/accounts.json @@ -0,0 +1,1204 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Accounts API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/accounts/{id}": { + "get": { + "description": "Retrieve detailed account information by ID. Returns the account with associated profile info, emails, and wallet addresses.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the account", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Account retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetAccountResponse" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "get" + } + }, + "/api/accounts/id": { + "get": { + "description": "Retrieve the ID of the authenticated account associated with the provided credentials. This is useful when you have an API key or access token but do not yet know the corresponding accountId.", + "parameters": [], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Account ID retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetAccountIdResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "id" + } + }, + "/api/accounts": { + "post": { + "description": "Create a new account or retrieve an existing account by email or wallet address. If an account with the provided email or wallet already exists, returns that account. Otherwise creates a new account and initializes credits.", + "requestBody": { + "description": "Account credentials to create or lookup", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAccountRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Account created or retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountDataResponse" + } + } + } + }, + "400": { + "description": "Bad request - failed to create account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "create" + }, + "patch": { + "description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges.", + "requestBody": { + "description": "Account fields to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAccountRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Account updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountDataResponse" + } + } + } + }, + "400": { + "description": "Bad request - account not found or update failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "update" + } + }, + "/api/accounts/artists": { + "post": { + "description": "Add an artist to an account's list of associated artists. If the artist is already associated with the account, returns success without modification.", + "requestBody": { + "description": "Account and artist identifiers", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddArtistToAccountRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Artist added to account successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddArtistSuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request - account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "add-artist" + } + }, + "/api/organizations": { + "get": { + "description": "Retrieve all organizations that the authenticated account belongs to. Pass account_id to retrieve organizations for a specific account the API key has access to.", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Organizations retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOrganizationsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationsErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "organizations-list" + }, + "post": { + "description": "Create a new organization. The creator is automatically added as a member of the organization.", + "requestBody": { + "description": "Organization creation parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrganizationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Organization created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrganizationResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationsErrorResponse" + } + } + } + } + }, + "operationId": "organizations-create" + } + }, + "/api/organizations/artists": { + "post": { + "description": "Add an artist to an organization. This allows organization members to access and manage the artist. This endpoint is idempotent - calling it multiple times with the same artistId and organizationId will not create duplicate records.", + "requestBody": { + "description": "Artist-organization association parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddArtistToOrganizationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Artist added to organization successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddArtistToOrganizationResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationsErrorResponse" + } + } + } + } + }, + "operationId": "organizations-add-artist" + } + }, + "/api/workspaces": { + "post": { + "description": "Create a new workspace account. Workspaces can optionally be linked to an organization.", + "requestBody": { + "description": "Workspace creation parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWorkspaceRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Workspace created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWorkspaceResponse" + } + } + } + }, + "400": { + "description": "Bad request - validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - access denied to organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "workspaces-create" + } + }, + "/api/subscriptions": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve subscription information for an account. For accounts with enterprise plans, returns a simplified response indicating enterprise status. For standard accounts, returns the full Stripe subscription object.", + "parameters": [ + { + "name": "accountId", + "in": "query", + "description": "The unique identifier of the account to query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Subscription information retrieved successfully", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubscriptionResponse" + }, + { + "$ref": "#/components/schemas/EnterpriseSubscriptionResponse" + } + ] + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid accountId", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionErrorResponse" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionErrorResponse" + } + } + } + } + }, + "operationId": "subscriptions-get" + } + } + }, + "components": { + "schemas": { + "Account": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the account" + }, + "name": { + "type": "string", + "description": "Account display name" + }, + "image": { + "type": "string", + "nullable": true, + "description": "Profile image URL" + }, + "instruction": { + "type": "string", + "nullable": true, + "description": "Custom AI instructions for this account" + }, + "knowledges": { + "type": "array", + "nullable": true, + "items": { + "$ref": "#/components/schemas/Knowledge" + }, + "description": "Knowledge base files attached to this account" + }, + "email": { + "type": "string", + "nullable": true, + "description": "Primary email address" + }, + "wallet_address": { + "type": "string", + "nullable": true, + "description": "Connected wallet address" + } + } + }, + "AccountData": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the account" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "The account ID (same as id, for consistency)" + }, + "name": { + "type": "string", + "description": "Display name of the account" + }, + "email": { + "type": "string", + "format": "email", + "description": "Email address associated with the account" + }, + "wallet": { + "type": "string", + "description": "Wallet address associated with the account" + }, + "image": { + "type": "string", + "format": "uri", + "description": "URL of the account's profile image" + }, + "instruction": { + "type": "string", + "description": "Custom instruction or bio" + }, + "organization": { + "type": "string", + "description": "Organization name" + }, + "job_title": { + "type": "string", + "description": "Job title" + }, + "role_type": { + "type": "string", + "description": "Role type" + }, + "company_name": { + "type": "string", + "description": "Company name" + }, + "knowledges": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of knowledge areas" + } + } + }, + "AccountDataResponse": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/AccountData", + "description": "The account data" + } + } + }, + "AccountErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "AddArtistSuccessResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates the artist was successfully added" + } + } + }, + "AddArtistToAccountRequest": { + "type": "object", + "required": [ + "email", + "artistId" + ], + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the account to add the artist to" + }, + "artistId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the artist to add" + } + } + }, + "AddArtistToOrganizationRequest": { + "type": "object", + "required": [ + "artistId", + "organizationId" + ], + "properties": { + "artistId": { + "type": "string", + "format": "uuid", + "description": "The account ID of the artist to add", + "example": "artist-account-uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "The account ID of the organization", + "example": "org-account-uuid" + } + } + }, + "AddArtistToOrganizationResponse": { + "type": "object", + "required": [ + "status", + "id" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the created artist-organization link" + } + } + }, + "CreateAccountRequest": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address to associate with the account. If an account with this email exists, it will be returned." + }, + "wallet": { + "type": "string", + "description": "Wallet address to associate with the account. If an account with this wallet exists, it will be returned." + } + }, + "description": "At least one of email or wallet should be provided to identify or create an account." + }, + "CreateOrganizationRequest": { + "type": "object", + "required": [ + "name", + "accountId" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the organization to create", + "example": "My New Label" + }, + "accountId": { + "type": "string", + "format": "uuid", + "description": "The account ID of the creator", + "example": "123e4567-e89b-12d3-a456-426614174000" + } + } + }, + "CreateOrganizationResponse": { + "type": "object", + "required": [ + "status", + "organization" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "organization": { + "$ref": "#/components/schemas/CreatedOrganization", + "description": "The created organization" + } + } + }, + "CreateWorkspaceRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the workspace (defaults to \"Untitled\")" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to create the workspace for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the workspace is created for the API key's own account." + }, + "organization_id": { + "type": "string", + "format": "uuid", + "description": "Organization to link the workspace to" + } + } + }, + "CreateWorkspaceResponse": { + "type": "object", + "required": [ + "workspace" + ], + "properties": { + "workspace": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "account_id": { + "type": "string", + "format": "uuid" + }, + "isWorkspace": { + "type": "boolean" + } + } + } + } + }, + "CreatedOrganization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the new organization account" + }, + "name": { + "type": "string", + "description": "Name of the organization" + } + } + }, + "EnterpriseSubscriptionResponse": { + "type": "object", + "required": [ + "status", + "isEnterprise" + ], + "description": "Response for accounts with enterprise plans", + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "isEnterprise": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates that the account has an enterprise plan" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "GetAccountIdResponse": { + "type": "object", + "required": [ + "status", + "accountId" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "accountId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier (UUID) of the authenticated account" + } + } + }, + "GetAccountResponse": { + "type": "object", + "required": [ + "status", + "account" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "account": { + "$ref": "#/components/schemas/Account", + "description": "The account details" + } + } + }, + "GetOrganizationsResponse": { + "type": "object", + "required": [ + "status", + "organizations" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "organizations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Organization" + }, + "description": "List of organizations the account belongs to" + } + } + }, + "Knowledge": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to the knowledge file" + }, + "name": { + "type": "string", + "description": "Name of the knowledge file" + }, + "type": { + "type": "string", + "description": "MIME type of the file" + } + } + }, + "Organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the membership record" + }, + "organization_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the organization account" + }, + "organization_name": { + "type": "string", + "description": "Display name of the organization" + }, + "organization_image": { + "type": "string", + "nullable": true, + "description": "Organization logo/image URL" + } + } + }, + "OrganizationsErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "StripeSubscription": { + "type": "object", + "description": "A Stripe subscription object. For detailed information about all available properties, see the Stripe Subscription API documentation: https://docs.stripe.com/api/subscriptions/retrieve", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the subscription" + }, + "object": { + "type": "string", + "enum": [ + "subscription" + ], + "description": "String representing the object's type" + }, + "customer": { + "type": "string", + "description": "ID of the customer who owns this subscription" + }, + "status": { + "type": "string", + "enum": [ + "active", + "canceled", + "incomplete", + "incomplete_expired", + "past_due", + "trialing", + "unpaid" + ], + "description": "The status of the subscription" + }, + "currency": { + "type": "string", + "description": "Three-letter ISO currency code" + }, + "current_period_start": { + "type": "integer", + "description": "Start of the current period (Unix timestamp)" + }, + "current_period_end": { + "type": "integer", + "description": "End of the current period (Unix timestamp)" + }, + "cancel_at_period_end": { + "type": "boolean", + "description": "If true, the subscription will be canceled at the end of the current period" + }, + "created": { + "type": "integer", + "description": "Time at which the subscription was created (Unix timestamp)" + }, + "items": { + "type": "object", + "description": "List of subscription items, each with an attached price", + "properties": { + "object": { + "type": "string", + "enum": [ + "list" + ] + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string", + "enum": [ + "subscription_item" + ] + }, + "price": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "unit_amount": { + "type": "integer", + "description": "Price amount in cents" + }, + "recurring": { + "type": "object", + "properties": { + "interval": { + "type": "string", + "enum": [ + "day", + "week", + "month", + "year" + ] + }, + "interval_count": { + "type": "integer" + } + } + } + } + }, + "quantity": { + "type": "integer" + } + } + } + }, + "has_more": { + "type": "boolean" + }, + "total_count": { + "type": "integer" + } + } + }, + "latest_invoice": { + "type": "string", + "description": "ID of the most recent invoice for this subscription" + }, + "livemode": { + "type": "boolean", + "description": "Indicates if in live mode (true) or test mode (false)" + }, + "metadata": { + "type": "object", + "description": "Set of key-value pairs attached to the subscription" + } + } + }, + "SubscriptionErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "SubscriptionResponse": { + "type": "object", + "required": [ + "status", + "subscription" + ], + "description": "Response for standard accounts with Stripe subscriptions", + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "subscription": { + "$ref": "#/components/schemas/StripeSubscription", + "description": "The full Stripe subscription object" + } + } + }, + "UpdateAccountRequest": { + "type": "object", + "required": [ + "accountId" + ], + "properties": { + "accountId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the account to update" + }, + "name": { + "type": "string", + "description": "Display name for the account" + }, + "instruction": { + "type": "string", + "description": "Custom instruction or bio for the account" + }, + "organization": { + "type": "string", + "description": "Organization name associated with the account" + }, + "image": { + "type": "string", + "format": "uri", + "description": "URL of the account's profile image" + }, + "jobTitle": { + "type": "string", + "description": "Job title of the account holder" + }, + "roleType": { + "type": "string", + "description": "Role type within the organization" + }, + "companyName": { + "type": "string", + "description": "Company name associated with the account" + }, + "knowledges": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of knowledge areas or expertise" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/admins.json b/api-reference/openapi/admins.json new file mode 100644 index 0000000..dab270a --- /dev/null +++ b/api-reference/openapi/admins.json @@ -0,0 +1,1218 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Admins API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/admins": { + "get": { + "description": "Check if the authenticated account is a Recoup admin. An account is considered an admin if it is a member of the Recoup organization. No input parameters required — authentication is performed via the x-api-key or Authorization header.", + "parameters": [], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Admin status retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckAdminResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "check" + } + }, + "/api/admins/sandboxes": { + "get": { + "description": "Returns a list of all accounts and their sandbox usage statistics. Each item includes the account email, total number of sandboxes created, and the timestamp of the most recently created sandbox. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Account sandbox statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminSandboxesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "sandboxes" + } + }, + "/api/admins/sandboxes/orgs": { + "get": { + "description": "Returns commit statistics for each repository in the recoupable GitHub organization. Each item includes the repo name, URL, total commit count, latest 5 commit messages, earliest and latest commit timestamps, and the list of account repo URLs that include this org repo as a submodule. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Org repo statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminSandboxOrgsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "sandboxes-orgs" + } + }, + "/api/admins/emails": { + "get": { + "description": "Returns Resend emails including HTML content. Provide either account_id (returns all emails for an account) or email_id (returns a single email by Resend ID). Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token. Email response shape matches the [Resend Retrieve Email API](https://resend.com/docs/api-reference/emails/retrieve-email).", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "The account ID to fetch all emails for. Required if email_id is not provided.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "email_id", + "in": "query", + "description": "A Resend email ID to fetch a single email. Required if account_id is not provided.", + "required": false, + "schema": { + "type": "string" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Emails retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminEmailsResponse" + } + } + } + }, + "400": { + "description": "Bad request - must provide either account_id or email_id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "emails" + } + }, + "/api/admins/privy": { + "get": { + "description": "Returns Privy login statistics for a given time period. Results include counts for new accounts (created_at), active accounts (latest_verified_at), total Privy accounts across all time, and the full, unmodified Privy account objects. See [Privy User object documentation](https://docs.privy.io/api-reference/users/get-all) for the complete type definition. Defaults to period=all (no date filter). Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [ + { + "name": "period", + "in": "query", + "description": "Time period to filter logins. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "all", + "daily", + "weekly", + "monthly" + ], + "default": "all" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Privy login statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status", + "total", + "total_new", + "total_active", + "logins" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "total": { + "type": "integer", + "description": "Total number of accounts in Privy across all time (not filtered by period)", + "example": 42 + }, + "total_new": { + "type": "integer", + "description": "Number of accounts created (created_at) within the requested period", + "example": 15 + }, + "total_active": { + "type": "integer", + "description": "Total number of accounts matching either new or active criteria in the requested period", + "example": 30 + }, + "logins": { + "type": "array", + "description": "Full, unmodified Privy account objects. See [Privy User object docs](https://docs.privy.io/api-reference/users/get-all) for the complete type definition.", + "items": { + "type": "object" + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "privy" + } + }, + "/api/admins/coding/slack": { + "get": { + "description": "Returns a list of Slack mentions of the Recoup Coding Agent bot, pulled directly from the Slack API as the source of truth. Each entry includes the tagger's information, the prompt they sent, the timestamp, the channel, and any GitHub pull request URLs opened in response. Also returns aggregate pull request statistics. Supports optional time-period filtering. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [ + { + "name": "period", + "in": "query", + "description": "Time period to filter tags. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "all", + "daily", + "weekly", + "monthly" + ], + "default": "all" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Slack tag analytics retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status", + "total", + "total_pull_requests", + "tags_with_pull_requests", + "tags" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "total": { + "type": "integer", + "description": "Total number of times the Coding Agent was tagged in the requested period", + "example": 134 + }, + "total_pull_requests": { + "type": "integer", + "description": "Total number of pull requests opened by the Coding Agent across all tags in the requested period", + "example": 121 + }, + "tags_with_pull_requests": { + "type": "integer", + "description": "Number of tags that resulted in at least one pull request being opened", + "example": 84 + }, + "tags": { + "type": "array", + "description": "List of Slack tag events", + "items": { + "type": "object", + "required": [ + "user_id", + "user_name", + "prompt", + "timestamp", + "channel_id", + "channel_name" + ], + "properties": { + "user_id": { + "type": "string", + "description": "Slack ID of the person who tagged the agent", + "example": "U012AB3CD" + }, + "user_name": { + "type": "string", + "description": "Display name of the person who tagged the agent", + "example": "Jane Smith" + }, + "user_avatar": { + "type": [ + "string", + "null" + ], + "description": "URL of the Slack avatar", + "example": "https://avatars.slack-edge.com/..." + }, + "prompt": { + "type": "string", + "description": "The text of the message sent to the agent", + "example": "add dark mode support to the settings page" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the tag event", + "example": "2024-01-15T10:30:00.000Z" + }, + "channel_id": { + "type": "string", + "description": "Slack channel ID where the tag occurred", + "example": "C012AB3CD" + }, + "channel_name": { + "type": "string", + "description": "Human-readable name of the Slack channel", + "example": "dev-team" + }, + "pull_requests": { + "type": "array", + "description": "GitHub pull request URLs opened by the Coding Agent in response to this prompt, parsed from bot replies in the Slack thread", + "items": { + "type": "string", + "format": "uri", + "example": "https://github.com/recoupable/api/pull/42" + }, + "example": [ + "https://github.com/recoupable/api/pull/42" + ] + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "coding-agent-slack-tags" + } + }, + "/api/admins/content/slack": { + "get": { + "description": "Returns a list of Slack mentions of the Recoup Content Agent bot, pulled directly from the Slack API as the source of truth. Each entry includes the tagger's information, the prompt they sent, the timestamp, the channel, and any video link responses. Also returns aggregate video statistics for measuring tag-to-video conversion. Supports optional time-period filtering. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [ + { + "name": "period", + "in": "query", + "description": "Time period to filter tags. One of: all (no date filter), daily (last 24 hours), weekly (last 7 days), monthly (last 30 days). Defaults to all.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "all", + "daily", + "weekly", + "monthly" + ], + "default": "all" + } + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Slack tag analytics retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status", + "total", + "total_videos", + "tags_with_videos", + "tags" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "total": { + "type": "integer", + "description": "Total number of times the Content Agent was tagged in the requested period", + "example": 18 + }, + "total_videos": { + "type": "integer", + "description": "Total number of videos generated by the Content Agent across all tags in the requested period", + "example": 12 + }, + "tags_with_videos": { + "type": "integer", + "description": "Number of tags that resulted in at least one video being generated", + "example": 10 + }, + "tags": { + "type": "array", + "description": "List of Slack tag events", + "items": { + "type": "object", + "required": [ + "user_id", + "user_name", + "prompt", + "timestamp", + "channel_id", + "channel_name" + ], + "properties": { + "user_id": { + "type": "string", + "description": "Slack ID of the person who tagged the agent", + "example": "U012AB3CD" + }, + "user_name": { + "type": "string", + "description": "Display name of the person who tagged the agent", + "example": "Jane Smith" + }, + "user_avatar": { + "type": [ + "string", + "null" + ], + "description": "URL of the Slack avatar", + "example": "https://avatars.slack-edge.com/..." + }, + "prompt": { + "type": "string", + "description": "The text of the message sent to the agent", + "example": "create a highlight reel for the new single release" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the tag event", + "example": "2024-01-15T10:30:00.000Z" + }, + "channel_id": { + "type": "string", + "description": "Slack channel ID where the tag occurred", + "example": "C012AB3CD" + }, + "channel_name": { + "type": "string", + "description": "Human-readable name of the Slack channel", + "example": "content-team" + }, + "video_links": { + "type": "array", + "description": "Video URLs generated by the Content Agent in response to this prompt, parsed from bot replies in the Slack thread", + "items": { + "type": "string", + "format": "uri", + "example": "https://recoupable.com/v/abc123" + }, + "example": [ + "https://recoupable.com/v/abc123" + ] + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "content-slack-tags" + } + }, + "/api/admins/coding/pr": { + "get": { + "description": "Returns the status (open, closed, or merged) for each provided GitHub pull request URL. Accepts one or more `pull_requests` query parameters containing GitHub PR URLs. Uses the GitHub REST API to check each pull request's state. Requires the authenticated account to be a Recoup admin. Authentication via x-api-key or Authorization Bearer token.", + "parameters": [ + { + "name": "pull_requests", + "in": "query", + "description": "One or more GitHub pull request URLs to check. Repeat this parameter for each URL. Example: ?pull_requests=https://github.com/org/repo/pull/1&pull_requests=https://github.com/org/repo/pull/2", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + }, + "minItems": 1, + "maxItems": 50 + }, + "style": "form", + "explode": true + } + ], + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "PR merged status retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status", + "pull_requests" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "pull_requests": { + "type": "array", + "description": "Status for each provided pull request URL", + "items": { + "type": "object", + "required": [ + "url", + "status" + ], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The GitHub pull request URL", + "example": "https://github.com/recoupable/api/pull/42" + }, + "status": { + "type": "string", + "enum": [ + "open", + "closed", + "merged" + ], + "description": "The current status of the pull request", + "example": "merged" + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid pull_requests parameter", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - authenticated account is not a Recoup admin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountErrorResponse" + } + } + } + } + }, + "operationId": "coding-pr" + } + } + }, + "components": { + "schemas": { + "AccountErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "AccountSandboxRow": { + "type": "object", + "required": [ + "account_id", + "total_sandboxes", + "last_created_at" + ], + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the account", + "example": "04e3aba9-c130-4fb8-8b92-34e95d43e66b" + }, + "total_sandboxes": { + "type": "integer", + "description": "Total number of sandboxes created for this account", + "example": 5 + }, + "last_created_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the most recently created sandbox for this account", + "example": "2026-03-10T12:00:00Z" + }, + "account_email": { + "type": "string", + "nullable": true, + "description": "The email address of the account. Null if the account has no email set.", + "example": "alice@example.com" + } + }, + "description": "" + }, + "AdminEmailsResponse": { + "type": "object", + "required": [ + "status", + "emails" + ], + "description": "Response containing Resend emails sent for an account", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "emails": { + "type": "array", + "description": "List of emails sent for the account, ordered by created_at descending", + "items": { + "$ref": "#/components/schemas/PulseEmailRow" + } + } + } + }, + "AdminSandboxOrgsResponse": { + "type": "object", + "required": [ + "status", + "repos" + ], + "description": "Response containing commit statistics for all org repositories", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "repos": { + "type": "array", + "description": "List of org repos with their commit statistics, ordered by total_commits descending", + "items": { + "$ref": "#/components/schemas/OrgRepoRow" + } + } + } + }, + "AdminSandboxesResponse": { + "type": "object", + "required": [ + "status", + "accounts" + ], + "description": "Response containing per-account sandbox statistics for admin use", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "accounts": { + "type": "array", + "description": "List of accounts with their sandbox statistics, ordered by most recently active first", + "items": { + "$ref": "#/components/schemas/AccountSandboxRow" + } + } + } + }, + "CheckAdminResponse": { + "type": "object", + "required": [ + "status", + "isAdmin" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "isAdmin": { + "type": "boolean", + "description": "Whether the authenticated account is a Recoup admin" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "OrgRepoRow": { + "type": "object", + "required": [ + "repo_name", + "repo_url", + "total_commits", + "latest_commit_messages", + "earliest_committed_at", + "latest_committed_at", + "account_repos" + ], + "description": "Commit statistics for a single GitHub org repository", + "properties": { + "repo_name": { + "type": "string", + "description": "Repository name", + "example": "chat" + }, + "repo_url": { + "type": "string", + "description": "Full GitHub HTML URL of the repository", + "example": "https://github.com/recoupable/chat" + }, + "total_commits": { + "type": "integer", + "description": "Total number of commits in the repository", + "example": 5696 + }, + "latest_commit_messages": { + "type": "array", + "description": "Messages from the 5 most recent commits", + "items": { + "type": "string" + }, + "example": [ + "Merge test into main", + "fix: duration stuck at 0ms for in-progress tasks" + ] + }, + "earliest_committed_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the earliest (first) commit", + "example": "2024-09-27T17:16:01Z" + }, + "latest_committed_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the most recent commit", + "example": "2026-03-10T19:57:37Z" + }, + "account_repos": { + "type": "array", + "items": { + "type": "object", + "properties": { + "account_id": { + "type": "string" + }, + "email": { + "type": "string", + "nullable": true + }, + "repo_url": { + "type": "string" + } + }, + "required": [ + "account_id", + "repo_url" + ] + }, + "description": "List of accounts using this org repo as a submodule, with account_id, email, and repo_url" + } + } + }, + "PulseEmailRow": { + "type": "object", + "required": [ + "id", + "from", + "to", + "subject", + "created_at", + "last_event" + ], + "description": "A single email record from Resend (full GetEmailResponseSuccess). See [Resend API docs](https://resend.com/docs/api-reference/emails/retrieve-email) for the source of truth.", + "properties": { + "id": { + "type": "string", + "description": "The Resend email ID" + }, + "from": { + "type": "string", + "description": "Sender email address" + }, + "to": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Recipient email addresses" + }, + "cc": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "description": "CC recipient email addresses" + }, + "bcc": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "description": "BCC recipient email addresses" + }, + "reply_to": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "description": "Reply-to email addresses" + }, + "subject": { + "type": "string", + "description": "Email subject line" + }, + "html": { + "type": "string", + "nullable": true, + "description": "HTML content of the email" + }, + "text": { + "type": "string", + "nullable": true, + "description": "Plain text content of the email" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the email was created" + }, + "scheduled_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "Scheduled send time, if any" + }, + "last_event": { + "type": "string", + "enum": [ + "bounced", + "canceled", + "clicked", + "complained", + "delivered", + "delivery_delayed", + "failed", + "opened", + "queued", + "scheduled", + "sent" + ], + "description": "Most recent delivery event for this email" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + }, + "nullable": true, + "description": "Custom tags attached to the email" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/artists.json b/api-reference/openapi/artists.json new file mode 100644 index 0000000..e139cec --- /dev/null +++ b/api-reference/openapi/artists.json @@ -0,0 +1,1885 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Artists API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/artists": { + "get": { + "description": "Retrieve artists accessible to the authenticated account. The account is derived from the API key or Bearer token. When org_id is omitted, returns only the account's own artists. Pass org_id to view artists in a specific organization. Pass account_id to filter to a specific account the API key has access to.", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "Filter to a specific account's artists. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "org_id", + "in": "query", + "description": "Filter to artists in a specific organization. When omitted, returns only personal (non-organization) artists.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Artists retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistsErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - missing or invalid authentication" + }, + "403": { + "description": "Forbidden - account_id is not accessible with the provided credentials" + } + }, + "operationId": "list" + }, + "post": { + "description": "Create a new artist account. The artist can optionally be linked to an organization.", + "requestBody": { + "description": "Artist creation parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateArtistRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Artist created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateArtistResponse" + } + } + } + }, + "400": { + "description": "Bad request - validation error or invalid JSON", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateArtistError" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "create" + } + }, + "/api/artist/segments": { + "get": { + "description": "Retrieve all segments associated with an artist. This endpoint should be called before using the Segment Fans endpoint to obtain the necessary segment IDs. Supports pagination.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "The unique identifier of the artist account to fetch segments for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Segments retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSegmentsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSegmentsErrorResponse" + } + } + } + } + }, + "operationId": "segments" + } + }, + "/api/artist/socials": { + "get": { + "description": "Retrieve all social media profiles associated with an artist. This endpoint should be called before using the Social Posts endpoint to obtain the necessary social IDs.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "The unique identifier of the artist account to fetch social profiles for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Social profiles retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSocialsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSocialsErrorResponse" + } + } + } + } + }, + "operationId": "socials" + } + }, + "/api/artist/socials/scrape": { + "post": { + "description": "Trigger scrape jobs for all social profiles linked to an artist. Provide an artist_account_id, and the API will look up the artist's socials and invoke a scraping job for each social profile. Each scrape returns Apify run metadata so you can poll for status and retrieve results.", + "requestBody": { + "description": "Artist to scrape socials for", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSocialsScrapeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Scrape jobs triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSocialsScrapeResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistSocialsErrorResponse" + } + } + } + } + }, + "operationId": "socials-scrape" + } + }, + "/api/artist-profile": { + "get": { + "description": "Retrieve comprehensive profile information for an artist across all connected social media platforms, including profile details and post metrics.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "The unique identifier of the artist account to fetch profile data for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Artist profile retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistProfileResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistProfileErrorResponse" + } + } + } + } + }, + "operationId": "profile" + } + }, + "/api/segment/fans": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve all social profiles from fans within a specific segment. This endpoint should be called after obtaining segment IDs from the Artist Segments endpoint. Supports pagination for large fan lists.", + "parameters": [ + { + "name": "segment_id", + "in": "query", + "description": "The unique identifier of the segment to fetch fans for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Segment fans retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SegmentFansResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SegmentFansErrorResponse" + } + } + } + } + }, + "operationId": "segment-fans" + } + }, + "/api/fans": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve all social profiles from fans of an artist across all platforms. This endpoint aggregates fan data from all connected social media platforms. Supports pagination for large fan lists.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "The unique identifier of the artist account to fetch fans for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Artist fans retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistFansResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistFansErrorResponse" + } + } + } + } + }, + "operationId": "fans" + } + }, + "/api/posts": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve all social media posts from an artist across all platforms. This endpoint aggregates posts from all connected social media profiles for the specified artist. Supports pagination for large post collections.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "The unique identifier of the artist account to fetch posts for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Artist posts retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistPostsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArtistPostsErrorResponse" + } + } + } + } + }, + "operationId": "posts" + } + }, + "/api/post/comments": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve comments for a specific social media post. This endpoint should be called after obtaining post IDs from the Social Posts endpoint. Returns detailed information about each commenter including their profile data, follower counts, and geographic region.", + "parameters": [ + { + "name": "post_id", + "in": "query", + "description": "The unique identifier of the post to fetch comments for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Post comments retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCommentsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCommentsErrorResponse" + } + } + } + } + }, + "operationId": "post-comments" + } + }, + "/api/comments": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "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" + } + } + } + } + }, + "operationId": "comments" + } + } + }, + "components": { + "schemas": { + "ApifyRunResult": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "Unique identifier for the Apify run" + }, + "datasetId": { + "type": "string", + "description": "Unique identifier for the dataset containing scraped data" + }, + "error": { + "type": "string", + "nullable": true, + "description": "Error message if the run failed (null if successful)" + } + } + }, + "Artist": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account" + }, + "name": { + "type": "string", + "description": "Artist display name" + }, + "image": { + "type": "string", + "nullable": true, + "description": "Artist profile image URL" + }, + "pinned": { + "type": "boolean", + "description": "Whether the account has pinned this artist" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ArtistSocial" + }, + "description": "Social media profiles linked to the artist" + } + } + }, + "ArtistFan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the fan's social profile" + }, + "username": { + "type": "string", + "description": "Username or handle on the platform" + }, + "avatar": { + "type": "string", + "description": "URL to the fan's avatar/profile image" + }, + "profile_url": { + "type": "string", + "description": "Full URL to the fan's profile on the platform" + }, + "region": { + "type": "string", + "description": "Geographic region or location of the fan" + }, + "bio": { + "type": "string", + "description": "Fan's biography or profile description" + }, + "followerCount": { + "type": "integer", + "description": "Number of followers the fan has" + }, + "followingCount": { + "type": "integer", + "description": "Number of accounts the fan is following" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the fan data was last updated" + } + } + }, + "ArtistFansErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistFansPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of records available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of records per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "ArtistFansResponse": { + "type": "object", + "required": [ + "status", + "fans", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "fans": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ArtistFan" + }, + "description": "List of social profiles from fans across all platforms" + }, + "pagination": { + "$ref": "#/components/schemas/ArtistFansPagination", + "description": "Pagination metadata for the response" + } + } + }, + "ArtistPost": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the post" + }, + "post_url": { + "type": "string", + "description": "Direct URL to the post on the social platform" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the post was last updated" + } + } + }, + "ArtistPostsErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistPostsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of posts available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of posts per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "ArtistPostsResponse": { + "type": "object", + "required": [ + "status", + "posts", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "posts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ArtistPost" + }, + "description": "List of posts from the artist across all social platforms" + }, + "pagination": { + "$ref": "#/components/schemas/ArtistPostsPagination", + "description": "Pagination metadata for the response" + } + } + }, + "ArtistProfile": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the artist" + }, + "profiles": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ArtistProfileSocialProfile" + }, + "description": "List of social media profiles" + }, + "total_followers": { + "type": "integer", + "description": "Sum of followers across all platforms" + }, + "total_following": { + "type": "integer", + "description": "Sum of following across all platforms" + }, + "total_posts": { + "type": "integer", + "description": "Sum of posts across all platforms" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the data was last updated" + } + } + }, + "ArtistProfileErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistProfileResponse": { + "type": "object", + "required": [ + "status", + "profile" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "profile": { + "$ref": "#/components/schemas/ArtistProfile", + "description": "The artist's comprehensive profile information" + } + } + }, + "ArtistProfileSocialProfile": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the social profile" + }, + "username": { + "type": "string", + "description": "Username on the platform" + }, + "profile_url": { + "type": "string", + "description": "Direct URL to the profile" + }, + "avatar": { + "type": "string", + "nullable": true, + "description": "URL to the profile avatar image" + }, + "bio": { + "type": "string", + "nullable": true, + "description": "Profile biography or description" + }, + "follower_count": { + "type": "integer", + "nullable": true, + "description": "Number of followers on this platform" + }, + "following_count": { + "type": "integer", + "nullable": true, + "description": "Number of accounts followed on this platform" + }, + "post_count": { + "type": "integer", + "nullable": true, + "description": "Number of posts on this platform" + }, + "region": { + "type": "string", + "nullable": true, + "description": "Geographic region of the profile" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the profile was last updated" + } + } + }, + "ArtistSegment": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist_segments record" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist's accounts record" + }, + "segment_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the segments record" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the segment data was last updated" + }, + "segment_name": { + "type": "string", + "description": "Name of the segment (e.g., 'Twitter Followers')" + }, + "artist_name": { + "type": "string", + "description": "Name of the artist" + } + } + }, + "ArtistSegmentsErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistSegmentsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of segments available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of segments per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "ArtistSegmentsResponse": { + "type": "object", + "required": [ + "status", + "segments", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "segments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ArtistSegment" + }, + "description": "List of segment objects associated with the artist" + }, + "pagination": { + "$ref": "#/components/schemas/ArtistSegmentsPagination", + "description": "Pagination metadata for the response" + } + } + }, + "ArtistSocial": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social profile" + }, + "platform": { + "type": "string", + "description": "Social media platform (e.g., instagram, twitter, tiktok)" + }, + "username": { + "type": "string", + "description": "Username on the platform" + }, + "profile_url": { + "type": "string", + "description": "Full URL to the social media profile" + } + } + }, + "ArtistSocialsErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistSocialsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of social profiles available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of social profiles per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "ArtistSocialsResponse": { + "type": "object", + "required": [ + "status", + "socials", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SocialProfile" + }, + "description": "List of social media profiles associated with the artist" + }, + "pagination": { + "$ref": "#/components/schemas/ArtistSocialsPagination", + "description": "Pagination metadata for the response" + } + } + }, + "ArtistSocialsScrapeRequest": { + "type": "object", + "required": [ + "artist_account_id" + ], + "properties": { + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account to scrape socials for", + "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" + } + } + }, + "ArtistSocialsScrapeResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApifyRunResult" + }, + "description": "Array of Apify run results, one for each social profile scraped" + }, + "ArtistsErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ArtistsResponse": { + "type": "object", + "required": [ + "status", + "artists" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Artist" + }, + "description": "List of artist objects" + }, + "message": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "Comment": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the comment" + }, + "post_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the associated post" + }, + "social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social profile who made the comment" + }, + "comment": { + "type": "string", + "description": "Comment text content" + }, + "commented_at": { + "type": "string", + "format": "date-time", + "description": "Timestamp with timezone of when the comment was made" + } + } + }, + "CommentsErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "CommentsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of comments available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of comments per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "CommentsResponse": { + "type": "object", + "required": [ + "status", + "comments", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "comments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comment" + }, + "description": "List of comments for the specified artist or post" + }, + "pagination": { + "$ref": "#/components/schemas/CommentsPagination", + "description": "Pagination metadata for the response" + } + } + }, + "CreateArtistError": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "missing_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of missing or invalid field names" + }, + "error": { + "type": "string", + "description": "Error message describing the validation failure" + }, + "message": { + "type": "string", + "description": "Error message (for invalid JSON or other errors)" + } + } + }, + "CreateArtistRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The name of the artist to create" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to create the artist for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the artist is created for the API key's own account." + }, + "organization_id": { + "type": "string", + "format": "uuid", + "description": "Optional organization ID to link the new artist to" + } + } + }, + "CreateArtistResponse": { + "type": "object", + "required": [ + "artist" + ], + "properties": { + "artist": { + "$ref": "#/components/schemas/CreatedArtist" + } + } + }, + "CreatedArtist": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the created artist account" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account (same as id)" + }, + "name": { + "type": "string", + "description": "Name of the artist" + }, + "created_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "ISO timestamp of when the artist was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "ISO timestamp of when the artist was last updated" + }, + "image": { + "type": "string", + "nullable": true, + "description": "Artist profile image URL" + }, + "instruction": { + "type": "string", + "nullable": true, + "description": "Custom AI instruction for this artist" + }, + "knowledges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "description": "Knowledge base references for this artist" + }, + "label": { + "type": "string", + "nullable": true, + "description": "Record label name" + }, + "organization": { + "type": "string", + "nullable": true, + "description": "Organization name" + }, + "company_name": { + "type": "string", + "nullable": true, + "description": "Company name" + }, + "job_title": { + "type": "string", + "nullable": true, + "description": "Job title" + }, + "role_type": { + "type": "string", + "nullable": true, + "description": "Role type" + }, + "onboarding_status": { + "type": "string", + "nullable": true, + "description": "Onboarding status" + }, + "onboarding_data": { + "nullable": true, + "description": "Onboarding data" + }, + "account_info": { + "type": "array", + "description": "Account info records" + }, + "account_socials": { + "type": "array", + "description": "Linked social media accounts" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "PostComment": { + "type": "object", + "required": [ + "id", + "post_id", + "social_id", + "comment", + "commented_at", + "username", + "profile_url", + "post_url" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the comment record" + }, + "post_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the post this comment belongs to" + }, + "social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social profile that made the comment" + }, + "comment": { + "type": "string", + "description": "Text content of the comment" + }, + "commented_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the comment was posted" + }, + "username": { + "type": "string", + "description": "Username of the commenter" + }, + "avatar": { + "type": "string", + "nullable": true, + "description": "URL to the commenter's avatar image" + }, + "profile_url": { + "type": "string", + "description": "URL to the commenter's profile" + }, + "post_url": { + "type": "string", + "description": "URL to the post where the comment was made" + }, + "region": { + "type": "string", + "nullable": true, + "description": "Geographic region of the commenter" + }, + "bio": { + "type": "string", + "nullable": true, + "description": "Commenter's biography or description" + }, + "follower_count": { + "type": "integer", + "nullable": true, + "description": "Number of followers the commenter has" + }, + "following_count": { + "type": "integer", + "nullable": true, + "description": "Number of accounts the commenter follows" + } + } + }, + "PostCommentsErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "PostCommentsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of comments available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of comments per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "PostCommentsResponse": { + "type": "object", + "required": [ + "status", + "comments", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "comments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PostComment" + }, + "description": "List of comments for the specified post" + }, + "pagination": { + "$ref": "#/components/schemas/PostCommentsPagination", + "description": "Pagination metadata for the response" + } + } + }, + "SegmentFan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the fan_segments record" + }, + "username": { + "type": "string", + "description": "Username or handle on the platform" + }, + "avatar": { + "type": "string", + "description": "URL to the fan's avatar/profile image" + }, + "profile_url": { + "type": "string", + "description": "Full URL to the fan's profile on the platform" + }, + "segment_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the fan's segments record" + }, + "segment_name": { + "type": "string", + "description": "Name of the segment (e.g., 'Twitter Followers')" + }, + "fan_social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the fan's socials media profile account" + }, + "region": { + "type": "string", + "description": "Geographic region or location of the fan" + }, + "bio": { + "type": "string", + "description": "Fan's biography or profile description" + }, + "follower_count": { + "type": "integer", + "description": "Number of followers the fan has" + }, + "following_count": { + "type": "integer", + "description": "Number of accounts the fan is following" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the fan data was last updated" + } + } + }, + "SegmentFansErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "SegmentFansPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of records available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of records per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "SegmentFansResponse": { + "type": "object", + "required": [ + "status", + "fans", + "pagination" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "fans": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SegmentFan" + }, + "description": "List of social profiles from fans in the segment" + }, + "pagination": { + "$ref": "#/components/schemas/SegmentFansPagination", + "description": "Pagination metadata for the response" + } + } + }, + "SocialProfile": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist's account_socials record" + }, + "social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist's socials account" + }, + "username": { + "type": "string", + "description": "Username on the platform" + }, + "profile_url": { + "type": "string", + "description": "Direct URL to the profile" + }, + "avatar": { + "type": "string", + "nullable": true, + "description": "URL to the profile avatar image" + }, + "bio": { + "type": "string", + "nullable": true, + "description": "Profile biography or description" + }, + "follower_count": { + "type": "integer", + "nullable": true, + "description": "Number of followers on this platform" + }, + "following_count": { + "type": "integer", + "nullable": true, + "description": "Number of accounts followed on this platform" + }, + "region": { + "type": "string", + "nullable": true, + "description": "Geographic region of the profile" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the profile was last updated" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/chats.json b/api-reference/openapi/chats.json new file mode 100644 index 0000000..db181dc --- /dev/null +++ b/api-reference/openapi/chats.json @@ -0,0 +1,1726 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Chat API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/chats": { + "get": { + "description": "Retrieve chat rooms (conversations) for the authenticated account. If the account has access to organizations, pass account_id to filter to a specific account within those organizations. Optionally filter by an artist_account_id. The endpoint returns metadata about each room, including the topic, associated artist, and last updated timestamp.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "Optional. Filter chats to only include those for the specified artist.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "account_id", + "in": "query", + "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Chats retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatsErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "chats" + }, + "post": { + "description": "Create a new chat room. Optionally associate it with an artist and/or provide a client-generated chat ID. Pass accountId to create a chat on behalf of a specific account the API key has access to.", + "requestBody": { + "description": "Chat creation parameters", + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chat created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatResponse" + } + } + } + }, + "400": { + "description": "Bad request - failed to create chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - API key does not have access to the specified accountId", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatErrorResponse" + } + } + } + } + }, + "operationId": "create" + }, + "patch": { + "description": "Update a chat room's topic (display name). The chatId is required; the topic field will be updated. Topic must be between 3 and 50 characters.", + "requestBody": { + "description": "Chat fields to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateChatRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chat updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateChatResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters or validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateChatErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - API key does not have access to this chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - chat room does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateChatErrorResponse" + } + } + } + } + }, + "operationId": "update" + }, + "delete": { + "description": "Delete a chat room by ID. This operation also removes related room records (memory emails, memories, room-report links, and segment-room links) before deleting the room itself.", + "requestBody": { + "description": "Chat deletion parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChatRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chat deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChatResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters or validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChatErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - API key does not have access to this chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - chat room does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChatErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - failed to delete chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChatErrorResponse" + } + } + } + } + }, + "operationId": "delete" + } + }, + "/api/chats/{id}/artist": { + "get": { + "description": "Retrieve the artist associated with a specific chat room. Returns 404 if the chat does not exist or is not accessible by the authenticated caller.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the chat room.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Chat artist resolved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatArtistResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid chat id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatArtistErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - chat does not exist or is not accessible", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatArtistErrorResponse" + } + } + } + } + }, + "operationId": "artist" + } + }, + "/api/chats/{id}/segment": { + "get": { + "description": "Retrieve the segment associated with a specific chat room. Returns 404 if the chat does not exist or is not accessible by the authenticated caller.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the chat room.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Chat segment resolved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatSegmentResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid chat id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatSegmentErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - chat does not exist or is not accessible", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatSegmentErrorResponse" + } + } + } + } + }, + "operationId": "segment" + } + }, + "/api/chats/{id}/messages": { + "get": { + "description": "Retrieve all messages (memories) for a specific chat room in chronological order.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the chat room.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Messages retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatMessagesResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid chat id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatMessagesErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - caller does not have access to this chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - chat does not exist or is not accessible", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatMessagesErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - failed to retrieve messages", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatMessagesErrorResponse" + } + } + } + } + }, + "operationId": "messages" + } + }, + "/api/chats/{id}/messages/copy": { + "post": { + "description": "Copy all messages from the source chat (`id` path param) to a target chat (`targetChatId` in request body). By default, existing target messages are cleared before copy.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The source chat room UUID.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Copy target options", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Messages copied successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid payload or chat identifiers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - caller lacks access to source or target chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" + } + } + } + }, + "404": { + "description": "Not found - source or target chat does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - failed to copy messages", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyChatMessagesErrorResponse" + } + } + } + } + }, + "operationId": "messages-copy" + } + }, + "/api/chats/{id}/messages/trailing": { + "delete": { + "description": "Delete all messages in a chat from a given message onward (inclusive), identified by `from_message_id`.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier (UUID) of the chat room.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "from_message_id", + "in": "query", + "description": "The message UUID from which trailing messages should be deleted (inclusive).", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Trailing messages deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid or missing query/path parameters or message does not belong to chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - access denied to this chat", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" + } + } + } + }, + "404": { + "description": "Not found - chat or message does not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - failed to delete trailing messages", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTrailingChatMessagesErrorResponse" + } + } + } + } + }, + "operationId": "messages-trailing-delete" + } + }, + "/api/chat/generate": { + "post": { + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "description": "Generate AI-powered text responses using the Recoup chat system. This endpoint processes chat requests and returns generated text along with metadata about the generation process.", + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "description": "Chat generation request", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatGenerateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chat generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatGenerateResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatGenerateErrorResponse" + } + } + } + } + }, + "operationId": "generate" + } + }, + "/api/chat": { + "post": { + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "description": "Stream AI-powered chat responses using the Recoup chat system. This endpoint mirrors the request payload of the Chat Generate API but returns a streaming response compatible with the Vercel AI SDK `createUIMessageStreamResponse`. The stream emits UI message parts encoded as data chunks that can be parsed with `createUIMessageStreamParser`.", + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "description": "Chat stream request", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatStreamRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Streaming response with UI message parts. Events include: message-start (assistant begins message), message-delta (incremental updates), message-end (assistant finishes message), error (stream error), and metadata (usage data).", + "content": { + "text/event-stream": { + "schema": { + "type": "string", + "description": "Server-Sent Events stream containing UI message parts" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatStreamErrorResponse" + } + } + } + } + }, + "operationId": "stream" + } + }, + "/api/chats/compact": { + "post": { + "description": "Compact one or more chat conversations into summarized versions. This reduces the size of chat history while preserving key information. Optionally provide a prompt to control what information gets preserved in the compacted summary.", + "requestBody": { + "description": "Chat compaction parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompactChatsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chats compacted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompactChatsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not found - one or more chat IDs do not exist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "compact" + } + } + }, + "components": { + "schemas": { + "ChatGenerateErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ChatGenerateRequest": { + "type": "object", + "description": "Request body for chat generation. Exactly one of 'prompt' or 'messages' must be provided.", + "properties": { + "prompt": { + "type": "string", + "description": "Single text prompt for the assistant. Required if 'messages' is not provided." + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UIMessage" + }, + "description": "Array of UIMessage objects for context. Required if 'prompt' is not provided." + }, + "artistId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the artist (optional)" + }, + "model": { + "type": "string", + "description": "The AI model to use for text generation (optional)", + "example": "openai/gpt-5-mini" + }, + "excludeTools": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of tool names to exclude from execution", + "example": [ + "create_scheduled_actions" + ] + }, + "roomId": { + "type": "string", + "format": "uuid", + "description": "UUID of the chat room. If not provided, one will be generated automatically." + }, + "topic": { + "type": "string", + "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). Only applies when creating a new room - ignored if room already exists. To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." + } + } + }, + "ChatGenerateResponse": { + "type": "object", + "description": "Response from the chat generation endpoint", + "properties": { + "text": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentPart" + }, + "description": "Array of content parts from the AI model response" + }, + "reasoningText": { + "type": "string", + "nullable": true, + "description": "Optional reasoning or explanation for the response" + }, + "sources": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Optional array of sources used for the response" + }, + "finishReason": { + "type": "string", + "description": "The reason why the generation finished", + "example": "stop" + }, + "usage": { + "$ref": "#/components/schemas/ChatGenerateUsage", + "description": "Token usage information" + }, + "response": { + "$ref": "#/components/schemas/ChatGenerateResponseMeta", + "description": "Additional response metadata" + } + } + }, + "ChatGenerateResponseMeta": { + "type": "object", + "description": "Additional response metadata", + "properties": { + "messages": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Response messages" + }, + "headers": { + "type": "object", + "description": "Response headers" + }, + "body": { + "type": "object", + "description": "Response body" + } + } + }, + "ChatGenerateUsage": { + "type": "object", + "description": "Token usage information with detailed breakdown", + "properties": { + "inputTokens": { + "type": "integer", + "description": "Number of input tokens processed" + }, + "outputTokens": { + "type": "integer", + "description": "Number of output tokens generated" + }, + "totalTokens": { + "type": "integer", + "description": "Total tokens used (input + output)" + }, + "reasoningTokens": { + "type": "integer", + "description": "Number of reasoning tokens used" + }, + "cachedInputTokens": { + "type": "integer", + "description": "Number of cached input tokens" + } + } + }, + "ChatMessage": { + "type": "object", + "required": [ + "id", + "room_id", + "content", + "updated_at" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the memory message" + }, + "room_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the parent chat room" + }, + "content": { + "type": "object", + "description": "Structured message payload stored for the memory" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of the memory update" + } + } + }, + "ChatRoom": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the chat room" + }, + "account_id": { + "type": "string", + "format": "uuid", + "nullable": true, + "description": "UUID of the associated account (can be null if not set)" + }, + "topic": { + "type": "string", + "nullable": true, + "description": "Optional topic or description of the room (null if not provided)" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of the last update to the room" + }, + "artist_id": { + "type": "string", + "format": "uuid", + "nullable": true, + "description": "UUID of the associated artist account (null when not applicable)" + } + } + }, + "ChatStreamErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ChatStreamRequest": { + "type": "object", + "description": "Request body for chat streaming. Exactly one of 'prompt' or 'messages' must be provided.", + "properties": { + "prompt": { + "type": "string", + "description": "Single text prompt for the assistant. Required if 'messages' is not provided." + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UIMessage" + }, + "description": "Array of UIMessage objects for context. Required if 'prompt' is not provided." + }, + "artistId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the artist (optional)" + }, + "model": { + "type": "string", + "description": "The AI model to use for text generation (optional)", + "example": "openai/gpt-5-mini" + }, + "excludeTools": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of tool names to exclude from execution", + "example": [ + "create_scheduled_actions" + ] + }, + "roomId": { + "type": "string", + "format": "uuid", + "description": "UUID of the chat room. If not provided, one will be generated automatically." + }, + "topic": { + "type": "string", + "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). Only applies when creating a new room - ignored if room already exists. To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." + } + } + }, + "CompactChatsRequest": { + "type": "object", + "required": [ + "chatId" + ], + "properties": { + "chatId": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Array of chat IDs to compact" + }, + "prompt": { + "type": "string", + "description": "Optional prompt to control what information gets preserved in the compacted summary" + } + } + }, + "CompactChatsResponse": { + "type": "object", + "required": [ + "chats" + ], + "properties": { + "chats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompactedChat" + }, + "description": "Array of compacted chat results" + } + } + }, + "CompactedChat": { + "type": "object", + "required": [ + "chatId", + "compacted" + ], + "properties": { + "chatId": { + "type": "string", + "format": "uuid", + "description": "The ID of the chat that was compacted" + }, + "compacted": { + "type": "string", + "description": "The compacted summary text of the chat" + } + } + }, + "ContentPart": { + "type": "object", + "description": "A part of the response content. See https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text#content for details.", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "tool-call", + "tool-result" + ], + "description": "The type of content part" + }, + "text": { + "type": "string", + "description": "The text content (present when type is 'text')" + } + } + }, + "CopyChatMessagesErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong." + } + } + }, + "CopyChatMessagesRequest": { + "type": "object", + "required": [ + "targetChatId" + ], + "properties": { + "targetChatId": { + "type": "string", + "format": "uuid", + "description": "Target chat room UUID to receive the copied messages." + }, + "clearExisting": { + "type": "boolean", + "default": true, + "description": "When true, existing messages in the target chat are deleted before copy." + } + } + }, + "CopyChatMessagesResponse": { + "type": "object", + "required": [ + "status", + "source_chat_id", + "target_chat_id", + "copied_count", + "cleared_existing" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "source_chat_id": { + "type": "string", + "format": "uuid", + "description": "Source chat room UUID." + }, + "target_chat_id": { + "type": "string", + "format": "uuid", + "description": "Target chat room UUID." + }, + "copied_count": { + "type": "integer", + "description": "Number of messages copied from source to target." + }, + "cleared_existing": { + "type": "boolean", + "description": "Whether existing target messages were deleted before copy." + } + } + }, + "CreateChatErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "CreateChatRequest": { + "type": "object", + "properties": { + "artistId": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account the chat is associated with" + }, + "chatId": { + "type": "string", + "format": "uuid", + "description": "UUID for the new chat (client-generated). If not provided, one will be generated automatically." + }, + "accountId": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to create the chat for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, the chat is created for the API key's own account." + }, + "topic": { + "type": "string", + "description": "Topic name for the new chat room (e.g., 'Pulse Feb 2'). To edit the topic of an existing room, use [PATCH /api/chats](/api-reference/chat/update)." + } + } + }, + "CreateChatResponse": { + "type": "object", + "required": [ + "status", + "chat" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "chat": { + "$ref": "#/components/schemas/ChatRoom", + "description": "The created chat room object" + } + } + }, + "DeleteChatErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong." + } + } + }, + "DeleteChatRequest": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier (UUID) of the chat room to delete." + } + } + }, + "DeleteChatResponse": { + "type": "object", + "required": [ + "status", + "id", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The UUID of the deleted chat room." + }, + "message": { + "type": "string", + "description": "Success message describing the deletion result." + } + } + }, + "DeleteTrailingChatMessagesErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong." + }, + "missing_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of missing or invalid parameter fields (when validation fails)." + } + } + }, + "DeleteTrailingChatMessagesResponse": { + "type": "object", + "required": [ + "status", + "chat_id", + "from_message_id" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "chat_id": { + "type": "string", + "format": "uuid", + "description": "The chat UUID where deletion was applied." + }, + "from_message_id": { + "type": "string", + "format": "uuid", + "description": "The message UUID used as the trailing deletion boundary." + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "GetChatArtistErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "GetChatArtistResponse": { + "type": "object", + "required": [ + "status", + "room_id", + "artist_id", + "artist_exists" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "room_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the chat room" + }, + "artist_id": { + "type": "string", + "format": "uuid", + "nullable": true, + "description": "UUID of the artist account associated with the chat, or null when no artist is linked" + }, + "artist_exists": { + "type": "boolean", + "description": "Whether an artist is linked to the chat room" + } + } + }, + "GetChatMessagesErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "GetChatMessagesResponse": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatMessage" + }, + "description": "Chronologically ordered list of messages for the chat" + } + } + }, + "GetChatSegmentErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "GetChatSegmentResponse": { + "type": "object", + "required": [ + "status", + "room_id", + "segment_id", + "segment_exists" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "room_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the chat room" + }, + "segment_id": { + "type": "string", + "format": "uuid", + "nullable": true, + "description": "UUID of the segment associated with the chat, or null when no segment is linked" + }, + "segment_exists": { + "type": "boolean", + "description": "Whether a segment is linked to the chat room" + } + } + }, + "GetChatsErrorResponse": { + "type": "object", + "required": [ + "status", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "GetChatsResponse": { + "type": "object", + "required": [ + "status", + "chats" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "chats": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatRoom" + }, + "description": "Array of chat room objects" + } + } + }, + "UIMessage": { + "type": "object", + "description": "A message in the chat conversation. See https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message for details.", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the message" + }, + "role": { + "type": "string", + "enum": [ + "user", + "assistant", + "system" + ], + "description": "The role of the message sender" + }, + "content": { + "type": "string", + "description": "The text content of the message" + } + } + }, + "UpdateChatErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "UpdateChatRequest": { + "type": "object", + "required": [ + "chatId", + "topic" + ], + "properties": { + "chatId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier (UUID) of the chat room to update" + }, + "topic": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "description": "The new display name for the chat room. Must be between 3 and 50 characters." + } + } + }, + "UpdateChatResponse": { + "type": "object", + "required": [ + "status", + "chat" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the request" + }, + "chat": { + "$ref": "#/components/schemas/ChatRoom", + "description": "The updated chat room object" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/content.json b/api-reference/openapi/content.json new file mode 100644 index 0000000..c9cbe17 --- /dev/null +++ b/api-reference/openapi/content.json @@ -0,0 +1,2505 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Content API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/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). Authentication is handled via the x-api-key header.", + "requestBody": { + "description": "Content creation parameters including the target artist and optional template/workflow settings", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentCreateRequest" + } + } + } + }, + "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.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentCreateResponse" + } + } + } + }, + "400": { + "description": "Validation failed — missing artist identifier, artist is missing required files, or template not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentCreateErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + }, + "404": { + "description": "Artist not found — the provided artist_account_id does not match any artist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + } + }, + "operationId": "create" + } + }, + "/api/content/templates": { + "get": { + "description": "List all available content creation templates. Templates define the visual style, scene composition, and default workflow settings for generated videos. Each template includes reference images, style guides, caption rules, and prompt configurations.", + "responses": { + "200": { + "description": "Templates retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentTemplatesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + } + }, + "operationId": "templates" + } + }, + "/api/content/validate": { + "get": { + "description": "Check whether an artist has all the required files to run the content creation pipeline. Returns a structured report of each required and recommended file with its status. Required files must be present or the pipeline will fail. Recommended files improve output quality but are not strictly necessary. Provide `artist_account_id` as a query parameter.", + "parameters": [ + { + "name": "artist_account_id", + "in": "query", + "description": "UUID of the artist account to validate. Use [GET /api/artists](/api-reference/artists/list) to find artist account IDs.", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" + } + } + ], + "responses": { + "200": { + "description": "Validation completed. Check the `ready` field to determine if the artist can run the pipeline.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentValidateResponse" + } + } + } + }, + "400": { + "description": "Bad request — artist_account_id is required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + }, + "404": { + "description": "Artist not found — the provided artist_account_id does not match any artist", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + } + }, + "operationId": "validate" + } + }, + "/api/content/estimate": { + "get": { + "description": "Estimate the cost of running the content creation pipeline. Fetches live pricing from fal.ai and calculates per-step and per-video costs. 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.", + "parameters": [ + { + "name": "lipsync", + "in": "query", + "description": "Which workflow to estimate. `false` for image-to-video, `true` for audio-to-video. If omitted, estimates the default image-to-video workflow.", + "required": false, + "schema": { + "type": "boolean", + "example": false + } + }, + { + "name": "batch", + "in": "query", + "description": "Number of videos to project costs for. Use this to answer questions like \"how much would 30 videos cost?\"", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "example": 1 + } + }, + { + "name": "compare", + "in": "query", + "description": "When `true`, returns estimates for all available workflow profiles (premium, budget, mid) for side-by-side comparison.", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "example": false + } + } + ], + "responses": { + "200": { + "description": "Cost estimate calculated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentEstimateResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentErrorResponse" + } + } + } + } + }, + "operationId": "estimate" + } + }, + "/api/songs": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve songs from the database with optional filtering by ISRC (International Standard Recording Code) or artist account. This endpoint joins the songs table with song_artists and accounts tables to provide comprehensive song information.", + "parameters": [ + { + "name": "isrc", + "in": "query", + "description": "International Standard Recording Code to filter by specific song", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "artist_account_id", + "in": "query", + "description": "Artist account ID to filter songs by artist", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Songs retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongsErrorResponse" + } + } + } + }, + "404": { + "description": "No songs found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongsErrorResponse" + } + } + } + } + }, + "operationId": "songs" + }, + "post": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Bulk create or fetch songs by ISRC. For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used.", + "requestBody": { + "description": "Array of songs to create or fetch", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSongsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Songs created or fetched successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongsErrorResponse" + } + } + } + } + }, + "operationId": "songs-create" + } + }, + "/api/catalogs": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve catalogs associated with a specific account. The endpoint joins account_catalogs with catalogs to return catalog metadata for the specified account.", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "The unique identifier of the account to query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Catalogs retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid account_id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsErrorResponse" + } + } + } + }, + "404": { + "description": "Account not found or no catalogs found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsErrorResponse" + } + } + } + } + }, + "operationId": "catalogs" + }, + "post": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Create new catalogs or link existing catalogs to an account. If catalog_id is provided, links the existing catalog. If name is provided without catalog_id, creates a new catalog. If both are provided, catalog_id takes priority.", + "requestBody": { + "description": "Array of catalogs to create or link", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCatalogsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Catalogs created or linked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters or catalog_id not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsErrorResponse" + } + } + } + } + }, + "operationId": "catalogs-create" + }, + "delete": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Unlink catalogs from an account. If no other accounts are linked to a catalog after removal, the catalog is automatically deleted (cascading to catalog_songs). Otherwise, only the account-catalog relationship is removed.", + "requestBody": { + "description": "Array of catalog-account pairs to remove", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteCatalogsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Catalogs unlinked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing catalog_id or account_id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogsErrorResponse" + } + } + } + } + }, + "operationId": "catalogs-delete" + } + }, + "/api/catalogs/songs": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve songs within a specific catalog with pagination support. This endpoint joins catalog_songs with songs, song_artists, and accounts to provide comprehensive song information for a given catalog.", + "parameters": [ + { + "name": "catalog_id", + "in": "query", + "description": "The unique identifier of the catalog to query songs for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "artistName", + "in": "query", + "description": "Optional. Filters songs to only include those with matching artist name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "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 songs per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Catalog songs retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid catalog_id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsErrorResponse" + } + } + } + }, + "404": { + "description": "Catalog not found or no songs in catalog", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsErrorResponse" + } + } + } + } + }, + "operationId": "catalog-songs" + }, + "post": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Batch add songs to a catalog by ISRC. For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used.", + "requestBody": { + "description": "Array of songs to add to catalog", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddCatalogSongsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Songs added to catalog successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required fields", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsErrorResponse" + } + } + } + } + }, + "operationId": "catalog-songs-add" + }, + "delete": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Batch remove songs from a catalog by ISRC. Deletes the relationship in catalog_songs for each catalog_id and ISRC pair.", + "requestBody": { + "description": "Array of songs to remove from catalog", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteCatalogSongsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Songs removed from catalog successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing catalog_id or isrc", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CatalogSongsErrorResponse" + } + } + } + } + }, + "operationId": "catalog-songs-delete" + } + }, + "/api/songs/analyze/presets": { + "get": { + "description": "Lists all available music analysis presets. Each preset is a curated prompt with optimized generation parameters for a specific use case (e.g. catalog metadata enrichment, sync licensing analysis, audience profiling). Requires authentication via API key or Bearer token.", + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Presets listed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ] + }, + "presets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Preset identifier to pass in the analyze request" + }, + "label": { + "type": "string", + "description": "Human-readable preset name" + }, + "description": { + "type": "string", + "description": "What this preset does" + }, + "requiresAudio": { + "type": "boolean", + "description": "Whether this preset needs an audio_url" + }, + "responseFormat": { + "type": "string", + "enum": [ + "json", + "text" + ], + "description": "Expected response format" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key / Bearer token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeErrorResponse" + } + } + } + } + }, + "operationId": "analyze-presets" + } + }, + "/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.", + "security": [ + { + "apiKeyAuth": [] + }, + { + "bearerAuth": [] + } + ], + "requestBody": { + "description": "Music analysis request", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Music analysis completed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeResponse" + } + } + } + }, + "400": { + "description": "Bad request — missing or invalid fields", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized — invalid or missing API key / Bearer token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeErrorResponse" + } + } + } + }, + "500": { + "description": "Server error — upstream model unavailable or inference failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SongAnalyzeErrorResponse" + } + } + } + } + }, + "operationId": "analyze" + } + }, + "/api/image/generate": { + "get": { + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "description": "Generate high-quality images using AI models. Images are automatically stored on Arweave and include In Process moment metadata for provenance and ownership tracking.", + "parameters": [ + { + "name": "prompt", + "in": "query", + "description": "Text description of the image you want to generate", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "account_id", + "in": "query", + "description": "The unique identifier of the account generating the image", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Image generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageGenerationResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters or invalid input", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImageGenerationErrorResponse" + } + } + } + } + }, + "operationId": "image-generation" + } + }, + "/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.", + "requestBody": { + "description": "Audio transcription request", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Audio transcribed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required fields or invalid audio URL", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioErrorResponse" + } + } + } + }, + "413": { + "description": "Audio file exceeds the 25MB limit", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioErrorResponse" + } + } + } + }, + "429": { + "description": "Rate limit exceeded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - OpenAI API key not configured", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranscribeAudioErrorResponse" + } + } + } + } + }, + "operationId": "transcribe-audio" + } + }, + "/api/content-agent/{platform}": { + "post": { + "description": "Webhook endpoint for the Recoup Content Agent Slack bot. Receives @mention events from Slack and triggers content generation for the mentioned artist. The bot parses the mention text for ` [template] [batch=N] [lipsync]`, validates the artist, calls POST /api/content/create, and starts a background polling task that reports results back to the Slack thread.\n\nFor Slack, also handles `url_verification` challenges during app setup.", + "parameters": [ + { + "name": "platform", + "in": "path", + "description": "Chat platform identifier. Currently supports `slack`.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "slack" + ] + } + } + ], + "requestBody": { + "description": "Slack Events API payload (app_mention event or url_verification challenge)", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Slack Events API envelope — the shape depends on the event type" + } + } + } + }, + "responses": { + "200": { + "description": "Event processed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ok": { + "type": "boolean" + } + } + } + } + } + }, + "404": { + "description": "Unknown platform" + } + }, + "operationId": "content-agent-webhook" + } + }, + "/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.", + "requestBody": { + "description": "Content generation results from the polling task", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "threadId", + "status" + ], + "properties": { + "threadId": { + "type": "string", + "description": "Chat SDK thread identifier for the originating Slack thread" + }, + "status": { + "type": "string", + "enum": [ + "completed", + "failed", + "timeout" + ], + "description": "Overall status of the content generation batch" + }, + "results": { + "type": "array", + "description": "Per-run results", + "items": { + "type": "object", + "required": [ + "runId", + "status" + ], + "properties": { + "runId": { + "type": "string", + "description": "Trigger.dev run ID" + }, + "status": { + "type": "string", + "enum": [ + "completed", + "failed", + "timeout" + ] + }, + "videoUrl": { + "type": "string", + "description": "URL of the generated video (when completed)" + }, + "captionText": { + "type": "string", + "description": "Generated caption text (when completed)" + }, + "error": { + "type": "string", + "description": "Error message (when failed)" + } + } + } + }, + "message": { + "type": "string", + "description": "Optional human-readable message" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Callback processed and results posted to Slack", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "ok" + } + } + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Missing or invalid callback secret" + } + }, + "security": [ + { + "callbackSecret": [] + } + ], + "operationId": "content-agent-callback" + } + } + }, + "components": { + "schemas": { + "AddCatalogSongInput": { + "type": "object", + "required": [ + "catalog_id", + "isrc" + ], + "properties": { + "catalog_id": { + "type": "string", + "format": "uuid", + "description": "Catalog ID to which the song will be added" + }, + "isrc": { + "type": "string", + "description": "Song ISRC to associate to the catalog" + }, + "name": { + "type": "string", + "description": "Optional. Applied only if internal search cannot find valid info for ISRC" + }, + "album": { + "type": "string", + "description": "Optional. Applied only if internal search cannot find valid info for ISRC" + }, + "notes": { + "type": "string", + "description": "Optional. Applied only if internal search cannot find valid info for ISRC" + }, + "artists": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional array of artist names. Applied only if internal search lacks info" + } + } + }, + "AddCatalogSongsRequest": { + "type": "object", + "required": [ + "songs" + ], + "properties": { + "songs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AddCatalogSongInput" + }, + "description": "Array of songs for batch updates" + } + } + }, + "ArweaveTransaction": { + "type": "object", + "description": "Arweave transaction object for the stored image", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the Arweave transaction" + }, + "last_tx": { + "type": "string", + "description": "Last transaction reference" + }, + "owner": { + "type": "string", + "description": "Owner address of the transaction" + }, + "tags": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Tags associated with the transaction" + }, + "target": { + "type": "string", + "description": "Target address (empty for data transactions)" + }, + "quantity": { + "type": "string", + "description": "Amount transferred (typically '0' for data transactions)" + }, + "data": { + "type": "string", + "description": "Transaction data (may be empty in response)" + }, + "reward": { + "type": "string", + "description": "Mining reward for the transaction" + }, + "signature": { + "type": "string", + "description": "Transaction signature" + }, + "format": { + "type": "integer", + "description": "Transaction format version" + } + } + }, + "Catalog": { + "type": "object", + "description": "A catalog with its metadata", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the catalog" + }, + "name": { + "type": "string", + "description": "Name of the catalog" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the catalog was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the catalog was last updated" + } + } + }, + "CatalogSong": { + "type": "object", + "description": "A song within a catalog with its metadata and associated artists", + "properties": { + "catalog_id": { + "type": "string", + "format": "uuid", + "description": "Catalog ID this song entry is associated with" + }, + "isrc": { + "type": "string", + "description": "International Standard Recording Code (primary key)" + }, + "name": { + "type": "string", + "description": "Name of the song" + }, + "album": { + "type": "string", + "description": "Name of the album the song belongs to" + }, + "lyrics": { + "type": "string", + "description": "Full lyrics of the song" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the song data was last updated" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SongArtist" + }, + "description": "Array of artist objects associated with this song" + } + } + }, + "CatalogSongsErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "CatalogSongsPagination": { + "type": "object", + "description": "Pagination metadata for catalog songs response", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of songs in the catalog" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of songs per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "CatalogSongsResponse": { + "type": "object", + "description": "Response containing catalog songs data with pagination", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "songs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CatalogSong" + }, + "description": "Array of song objects with artist information" + }, + "pagination": { + "$ref": "#/components/schemas/CatalogSongsPagination", + "description": "Pagination metadata for the response" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is 'error')" + } + } + }, + "CatalogsErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "CatalogsResponse": { + "type": "object", + "description": "Response containing catalogs data", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "catalogs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Catalog" + }, + "description": "Array of catalog objects" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is 'error')" + } + } + }, + "ContentCreateErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "description": "Returned when the artist is missing required files or the template is not found. Includes actionable instructions for resolving each issue.", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error summary", + "example": "Artist 'new-artist' is not ready for content creation" + }, + "ready": { + "type": "boolean", + "description": "Always `false` when this error is returned", + "example": false + }, + "missing": { + "type": "array", + "description": "List of missing files with severity and fix instructions. Only present when the artist fails validation.", + "items": { + "$ref": "#/components/schemas/ContentMissingFile" + } + }, + "available_templates": { + "type": "array", + "description": "List of valid template names. Only present when the requested template was not found.", + "items": { + "type": "string" + }, + "example": [ + "artist-caption-bedroom", + "artist-caption-outside", + "artist-caption-stage" + ] + } + } + }, + "ContentCreateRequest": { + "type": "object", + "description": "Parameters for triggering the content creation pipeline.", + "properties": { + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account to create content for. Use [GET /api/artists](/api-reference/artists/list) to find artist account IDs.", + "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" + }, + "template": { + "type": "string", + "description": "The template to use for content generation. Defines the visual style, scene, and prompt configuration. If omitted, defaults to `artist-caption-bedroom`. See [GET /api/content/templates](/api-reference/content/templates) for available options.", + "example": "artist-caption-stage", + "default": "artist-caption-bedroom" + }, + "lipsync": { + "type": "boolean", + "description": "Whether to generate video with lip-synced audio. When `true`, uses an audio-to-video model that bakes audio into the video for lip movement. When `false`, generates video from the image alone and overlays audio in post. If omitted, the template's default workflow is used.", + "example": false + }, + "caption_length": { + "type": "string", + "enum": [ + "short", + "medium", + "long" + ], + "description": "Controls the length of the generated caption text. `short` produces 1-2 lines (punchy, minimal). `medium` produces 1-2 sentences. `long` produces a paragraph (stream of consciousness style). Defaults to `short`.", + "default": "short", + "example": "short" + }, + "upscale": { + "type": "boolean", + "description": "Whether to upscale the generated image and video using fal.ai SeedVR2 for higher resolution and detail. Adds approximately 2 minutes to the pipeline. Defaults to `false`.", + "default": false, + "example": false + }, + "batch": { + "type": "integer", + "minimum": 1, + "maximum": 30, + "description": "Number of videos to generate in parallel. Each video independently selects a random reference image, song clip, and mood variation. The response always returns `runIds` as an array. Defaults to `1`.", + "default": 1, + "example": 1 + }, + "songs": { + "type": "array", + "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.", + "example": [ + "hiccups", + "https://example.com/unreleased-track.mp3" + ] + }, + "images": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + }, + "description": "Optional list of public image URLs to use as face guides instead of the artist's default `face-guide.png` from their GitHub repo. The first image is used as the primary face guide. Useful when the caller wants to override the default face reference.", + "example": [ + "https://example.com/face.png" + ] + } + }, + "required": [ + "artist_account_id" + ] + }, + "ContentCreateResponse": { + "type": "object", + "required": [ + "runIds", + "status", + "artist_account_id", + "template" + ], + "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.", + "properties": { + "runIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of run IDs. Poll each via [GET /api/tasks/runs](/api-reference/tasks/runs). For single runs this contains one element.", + "example": [ + "run_abc123def456" + ] + }, + "status": { + "type": "string", + "enum": [ + "triggered" + ], + "description": "Indicates the pipeline has been triggered" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account the pipeline is running for", + "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" + }, + "template": { + "type": "string", + "description": "The template being used", + "example": "artist-caption-bedroom" + }, + "lipsync": { + "type": "boolean", + "description": "Whether lip-sync mode is enabled", + "example": false + }, + "failed": { + "type": "integer", + "description": "Number of triggers that failed. Only present when some triggers failed.", + "example": 0 + } + } + }, + "ContentErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "description": "Error message describing what went wrong", + "example": "Unauthorized" + } + } + }, + "ContentEstimateComparison": { + "type": "object", + "required": [ + "cheapest", + "cheapestPerVideo", + "mostExpensive", + "mostExpensivePerVideo", + "savingsPercent" + ], + "description": "Summary comparing the cheapest and most expensive workflow options.", + "properties": { + "cheapest": { + "type": "string", + "description": "Name of the cheapest workflow profile", + "example": "Budget (no upscale, LTX video)" + }, + "cheapestPerVideo": { + "type": "number", + "format": "float", + "description": "Cost per video for the cheapest workflow", + "example": 0.18 + }, + "mostExpensive": { + "type": "string", + "description": "Name of the most expensive workflow profile", + "example": "Current (audio-to-video)" + }, + "mostExpensivePerVideo": { + "type": "number", + "format": "float", + "description": "Cost per video for the most expensive workflow", + "example": 0.95 + }, + "savingsPercent": { + "type": "integer", + "description": "Percentage savings between the cheapest and most expensive workflows", + "example": 81 + } + } + }, + "ContentEstimateResponse": { + "type": "object", + "required": [ + "workflows" + ], + "description": "Cost estimates based on live fal.ai pricing. When `compare` is `false`, the `workflows` array contains a single entry. When `true`, it contains all available profiles.", + "properties": { + "workflows": { + "type": "array", + "description": "One or more workflow cost breakdowns", + "items": { + "$ref": "#/components/schemas/ContentWorkflowEstimate" + } + }, + "comparison": { + "description": "Side-by-side summary. Only present when `compare` is `true` and multiple workflows are returned.", + "$ref": "#/components/schemas/ContentEstimateComparison" + }, + "batch": { + "type": "object", + "description": "Batch cost projection. Only present when `batch` > 1.", + "properties": { + "count": { + "type": "integer", + "description": "Number of videos in the batch", + "example": 30 + }, + "cheapestTotal": { + "type": "number", + "format": "float", + "description": "Total cost for the batch using the cheapest workflow", + "example": 5.4 + }, + "mostExpensiveTotal": { + "type": "number", + "format": "float", + "description": "Total cost for the batch using the most expensive workflow", + "example": 28.5 + } + } + } + } + }, + "ContentMissingFile": { + "type": "object", + "required": [ + "file", + "severity", + "description", + "fix" + ], + "description": "A missing file that prevents or degrades content creation.", + "properties": { + "file": { + "type": "string", + "description": "Relative path of the missing file within the artist directory", + "example": "context/images/face-guide.png" + }, + "severity": { + "type": "string", + "enum": [ + "required", + "recommended" + ], + "description": "`required` means the pipeline will fail without this file. `recommended` means the pipeline will run but output quality is degraded.", + "example": "required" + }, + "description": { + "type": "string", + "description": "What this file is used for in the pipeline", + "example": "Face guide image used for AI image generation" + }, + "fix": { + "type": "string", + "description": "Actionable instructions for creating or adding the missing file", + "example": "Generate a face guide using fal-ai/nano-banana-pro/edit with 2-3 reference photos of the artist" + } + } + }, + "ContentStepEstimate": { + "type": "object", + "required": [ + "name", + "model", + "cost", + "note" + ], + "description": "Cost details for a single pipeline step.", + "properties": { + "name": { + "type": "string", + "description": "Pipeline step name", + "example": "Generate Image" + }, + "model": { + "type": "string", + "description": "The AI model or service used for this step", + "example": "fal-ai/nano-banana-pro/edit" + }, + "cost": { + "type": "number", + "format": "float", + "description": "Estimated cost for this step in USD", + "example": 0.04 + }, + "unit": { + "type": "string", + "description": "Billing unit type (e.g., `images`, `seconds`, `megapixels`). Not present for free steps.", + "example": "images" + }, + "unitPrice": { + "type": "number", + "format": "float", + "description": "Price per billing unit in USD. Not present for free steps.", + "example": 0.04 + }, + "note": { + "type": "string", + "description": "Human-readable calculation detail", + "example": "1 call" + } + } + }, + "ContentTemplate": { + "type": "object", + "required": [ + "name", + "description", + "defaultLipsync" + ], + "description": "A content creation template that defines the visual style and composition for generated videos.", + "properties": { + "name": { + "type": "string", + "description": "Template identifier. Pass this as the `template` field in [POST /api/content/create](/api-reference/content/create).", + "example": "artist-caption-bedroom" + }, + "description": { + "type": "string", + "description": "Human-readable description of the template's visual style", + "example": "Moody purple bedroom setting with caption overlay" + }, + "defaultLipsync": { + "type": "boolean", + "description": "Whether this template defaults to lip-sync mode when the `lipsync` flag is not explicitly set", + "example": false + } + } + }, + "ContentTemplatesResponse": { + "type": "object", + "required": [ + "templates" + ], + "description": "List of available content creation templates.", + "properties": { + "templates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentTemplate" + } + } + } + }, + "ContentValidateResponse": { + "type": "object", + "required": [ + "ready", + "artist_account_id" + ], + "description": "Validation report for an artist's content creation readiness.", + "properties": { + "ready": { + "type": "boolean", + "description": "`true` if the artist has all required files and the pipeline can run. `false` if required files are missing.", + "example": true + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the artist account that was validated", + "example": "1873859c-dd37-4e9a-9bac-80d3558527a9" + }, + "songs": { + "type": "integer", + "description": "Number of songs found in the artist's `songs/` directory", + "example": 17 + }, + "templates": { + "type": "array", + "description": "Available templates that can be used with this artist", + "items": { + "type": "string" + }, + "example": [ + "artist-caption-bedroom", + "artist-caption-outside", + "artist-caption-stage" + ] + }, + "checks": { + "type": "object", + "description": "Per-file validation results. Only present when `ready` is `true`.", + "properties": { + "face_guide": { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + "artist_context": { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + "audience_context": { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + "era_config": { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + "pipeline_config": { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + "songs": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentValidationCheck" + }, + { + "type": "object", + "properties": { + "count": { + "type": "integer", + "description": "Number of songs found", + "example": 17 + } + } + } + ] + } + } + }, + "missing": { + "type": "array", + "description": "List of missing files with severity and fix instructions. Only present when `ready` is `false`.", + "items": { + "$ref": "#/components/schemas/ContentMissingFile" + } + } + } + }, + "ContentValidationCheck": { + "type": "object", + "required": [ + "status" + ], + "description": "Status of a single validation check.", + "properties": { + "status": { + "type": "string", + "enum": [ + "ok", + "missing", + "warning" + ], + "description": "Whether the file was found", + "example": "ok" + } + } + }, + "ContentWorkflowEstimate": { + "type": "object", + "required": [ + "name", + "perVideo", + "steps" + ], + "description": "Cost breakdown for a single workflow profile.", + "properties": { + "name": { + "type": "string", + "description": "Workflow profile name", + "example": "Current (image-to-video)" + }, + "perVideo": { + "type": "number", + "format": "float", + "description": "Total estimated cost per video in USD", + "example": 0.82 + }, + "steps": { + "type": "array", + "description": "Per-step cost breakdown showing where the money goes", + "items": { + "$ref": "#/components/schemas/ContentStepEstimate" + } + }, + "costBreakdown": { + "type": "object", + "description": "Summary of the biggest cost driver", + "properties": { + "mostExpensiveStep": { + "type": "string", + "description": "Name of the step that costs the most", + "example": "Generate Video" + }, + "mostExpensivePercent": { + "type": "integer", + "description": "Percentage of total cost from the most expensive step", + "example": 68 + } + } + } + } + }, + "CreateCatalogInput": { + "type": "object", + "required": [ + "account_id" + ], + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "The account to associate the catalog with" + }, + "name": { + "type": "string", + "description": "Catalog name to create if catalog_id is omitted" + }, + "catalog_id": { + "type": "string", + "format": "uuid", + "description": "Existing catalog ID to link to the account" + } + } + }, + "CreateCatalogsRequest": { + "type": "object", + "required": [ + "catalogs" + ], + "properties": { + "catalogs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateCatalogInput" + }, + "description": "Array of catalog inputs for bulk create/link operations" + } + } + }, + "CreateSongInput": { + "type": "object", + "required": [ + "isrc" + ], + "properties": { + "isrc": { + "type": "string", + "description": "International Standard Recording Code of the song to create or fetch" + }, + "name": { + "type": "string", + "description": "Optional. Song name, applied only if internal search cannot find valid info" + }, + "album": { + "type": "string", + "description": "Optional. Album name, applied only if internal search cannot find valid info" + }, + "notes": { + "type": "string", + "description": "Optional. Notes for the song, applied only if internal search cannot find valid info" + }, + "artists": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional array of artist names, applied only if internal search cannot find valid info" + } + } + }, + "CreateSongsRequest": { + "type": "object", + "required": [ + "songs" + ], + "properties": { + "songs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateSongInput" + }, + "description": "Array of song inputs for bulk create/fetch" + } + } + }, + "DeleteCatalogInput": { + "type": "object", + "required": [ + "catalog_id", + "account_id" + ], + "properties": { + "catalog_id": { + "type": "string", + "format": "uuid", + "description": "Catalog ID to remove" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Account ID whose relationship will be removed" + } + } + }, + "DeleteCatalogSongInput": { + "type": "object", + "required": [ + "catalog_id", + "isrc" + ], + "properties": { + "catalog_id": { + "type": "string", + "format": "uuid", + "description": "Catalog ID from which the song will be removed" + }, + "isrc": { + "type": "string", + "description": "Song ISRC to remove from the catalog" + } + } + }, + "DeleteCatalogSongsRequest": { + "type": "object", + "required": [ + "songs" + ], + "properties": { + "songs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeleteCatalogSongInput" + }, + "description": "Array of songs for batch deletes" + } + } + }, + "DeleteCatalogsRequest": { + "type": "object", + "required": [ + "catalogs" + ], + "properties": { + "catalogs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeleteCatalogInput" + }, + "description": "Array of catalog-account pairs to remove" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "GeneratedImage": { + "type": "object", + "description": "A generated image file from the AI model", + "properties": { + "base64": { + "type": "string", + "description": "Image file as a base64 encoded string" + }, + "uint8Array": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "Image file as a Uint8Array (represented as array of numbers in JSON)" + }, + "mediaType": { + "type": "string", + "description": "The IANA media type of the file (e.g., 'image/png', 'image/jpeg')" + } + } + }, + "ImageGenerationErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "ImageGenerationResponse": { + "type": "object", + "description": "Response from the image generation endpoint, extending Experimental_GenerateImageResult from the AI SDK", + "properties": { + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeneratedImage" + }, + "description": "Array of generated image objects" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of warning messages, if any" + }, + "responses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageResponseMeta" + }, + "description": "Array of response metadata from the AI provider" + }, + "providerMetadata": { + "$ref": "#/components/schemas/ImageProviderMetadata" + }, + "usage": { + "$ref": "#/components/schemas/ImageUsage" + }, + "imageUrl": { + "type": "string", + "description": "Permanent Arweave URL where the image is stored" + }, + "arweaveResult": { + "$ref": "#/components/schemas/ArweaveTransaction" + }, + "moment": { + "$ref": "#/components/schemas/InProcessMoment" + } + } + }, + "ImageProviderMetadata": { + "type": "object", + "description": "Metadata from the AI provider about the generation", + "properties": { + "model": { + "type": "string", + "description": "The AI model used for generation (e.g., 'dall-e-3', 'gpt-image-1')" + }, + "size": { + "type": "string", + "description": "The size of the generated image (e.g., '1024x1024')" + } + } + }, + "ImageResponseMeta": { + "type": "object", + "description": "Response metadata from the AI provider", + "properties": { + "finishReason": { + "type": "string", + "description": "Reason the generation finished (e.g., 'stop')" + } + } + }, + "ImageUsage": { + "type": "object", + "description": "Token usage information for the image generation", + "properties": { + "promptTokens": { + "type": "integer", + "description": "Number of tokens used in the prompt" + }, + "completionTokens": { + "type": "integer", + "description": "Number of tokens used in the completion (typically 0 for image generation)" + }, + "totalTokens": { + "type": "integer", + "description": "Total tokens used" + } + } + }, + "InProcessMoment": { + "type": "object", + "description": "In Process moment metadata for provenance and ownership tracking", + "properties": { + "contractAddress": { + "type": "string", + "description": "Smart contract address for the moment" + }, + "tokenId": { + "type": "string", + "description": "Token ID of the minted moment" + }, + "hash": { + "type": "string", + "description": "Transaction hash of the moment mint" + }, + "chainId": { + "type": "integer", + "description": "Chain ID (e.g., 8453 for Base)" + } + } + }, + "Song": { + "type": "object", + "description": "A song with its metadata and associated artists", + "properties": { + "isrc": { + "type": "string", + "description": "International Standard Recording Code (primary key)" + }, + "name": { + "type": "string", + "description": "Name of the song" + }, + "album": { + "type": "string", + "description": "Name of the album the song belongs to" + }, + "notes": { + "type": "string", + "description": "Notes for the song" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the song data was last updated" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SongArtist" + }, + "description": "Array of artist objects associated with this song" + } + } + }, + "SongAnalyzeErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Error status" + }, + "missing_fields": { + "type": "array", + "description": "Path to the first invalid or missing field when validation fails", + "items": { + "type": "string" + } + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "SongAnalyzeRequest": { + "type": "object", + "description": "Provide exactly one of `preset` or `prompt`. Use `preset` for structured analysis workflows, or `prompt` for free-form questions.", + "properties": { + "preset": { + "type": "string", + "enum": [ + "catalog_metadata", + "mood_tags", + "lyric_transcription", + "mix_feedback", + "song_description", + "music_theory", + "similar_artists", + "sample_detection", + "sync_brief_match", + "audience_profile", + "content_advisory", + "playlist_pitch", + "artist_development_notes", + "full_report" + ], + "description": "Name of a curated analysis preset. Use instead of prompt for structured, optimized output. The 'full_report' preset runs all 13 presets in parallel and returns a comprehensive report. See [List Analyze Presets](/api-reference/songs/analyze-presets) for the full list of available presets.", + "example": "catalog_metadata" + }, + "prompt": { + "type": "string", + "minLength": 1, + "maxLength": 24000, + "description": "Text prompt or question about the music", + "example": "Describe the genre, tempo, and mood of this track." + }, + "audio_url": { + "type": "string", + "format": "uri", + "description": "Public URL to an audio file (MP3, WAV, or FLAC — up to 20 minutes)", + "example": "https://example.com/song.mp3" + }, + "max_new_tokens": { + "type": "integer", + "minimum": 1, + "maximum": 2048, + "default": 512, + "description": "Maximum number of tokens to generate", + "example": 512 + }, + "temperature": { + "type": "number", + "minimum": 0, + "maximum": 2, + "default": 1, + "description": "Controls output creativity — higher values produce more varied responses", + "example": 0.7 + }, + "top_p": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 1, + "description": "Nucleus sampling probability cutoff", + "example": 0.9 + }, + "do_sample": { + "type": "boolean", + "default": false, + "description": "Enable sampling (set true when using temperature or top_p)", + "example": false + } + } + }, + "SongAnalyzeResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Request status" + }, + "preset": { + "type": "string", + "description": "Preset used for analysis, when applicable", + "example": "catalog_metadata" + }, + "response": { + "description": "Model output for single-preset or custom-prompt analysis. May be plain text or structured JSON depending on the preset." + }, + "report": { + "type": "object", + "description": "Full report payload returned only when using the `full_report` preset" + }, + "elapsed_seconds": { + "type": "number", + "format": "float", + "description": "Inference time in seconds" + } + } + }, + "SongArtist": { + "type": "object", + "description": "Artist associated with a song", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the artist account" + }, + "name": { + "type": "string", + "nullable": true, + "description": "Name of the artist (can be null)" + }, + "timestamp": { + "type": "integer", + "nullable": true, + "description": "Timestamp associated with the artist account (can be null)" + } + } + }, + "SongsErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "SongsResponse": { + "type": "object", + "description": "Response containing songs data", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "songs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Song" + }, + "description": "Array of song objects with artist information" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is 'error')" + } + } + }, + "TranscribeAudioErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "TranscribeAudioRequest": { + "type": "object", + "required": [ + "audio_url", + "account_id", + "artist_account_id" + ], + "properties": { + "audio_url": { + "type": "string", + "description": "Public URL to the audio file (mp3, wav, m4a, webm)", + "example": "https://example.com/song.mp3" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Owner account ID for file storage", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "Artist account ID for file storage", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "title": { + "type": "string", + "description": "Optional title for the audio and transcription files", + "example": "My Song" + }, + "include_timestamps": { + "type": "boolean", + "description": "Whether to include timestamps in the markdown transcript", + "default": false + } + } + }, + "TranscribeAudioResponse": { + "type": "object", + "required": [ + "success", + "audioFile", + "transcriptFile", + "text" + ], + "properties": { + "success": { + "type": "boolean", + "description": "Whether the transcription was successful" + }, + "audioFile": { + "$ref": "#/components/schemas/TranscribeFileInfo", + "description": "Information about the saved audio file" + }, + "transcriptFile": { + "$ref": "#/components/schemas/TranscribeFileInfo", + "description": "Information about the saved transcript file" + }, + "text": { + "type": "string", + "description": "The full transcription text" + }, + "language": { + "type": "string", + "description": "Detected language code (e.g., 'en', 'es', 'fr')" + } + } + }, + "TranscribeFileInfo": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the file record in the database" + }, + "fileName": { + "type": "string", + "description": "Name of the saved file" + }, + "storageKey": { + "type": "string", + "description": "Storage path in Supabase Storage" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/general.json b/api-reference/openapi/general.json new file mode 100644 index 0000000..cb49275 --- /dev/null +++ b/api-reference/openapi/general.json @@ -0,0 +1,369 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup General API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/pulses": { + "get": { + "description": "Retrieve pulse information for the authenticated account. If the account has access to organizations, pass account_id to filter to a specific account within those organizations.", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "active", + "in": "query", + "description": "Filter by active status. Set to 'true' to return only active pulses, 'false' for inactive pulses. If not provided, returns all pulses regardless of active status.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + } + } + ], + "responses": { + "200": { + "description": "Pulses retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PulsesResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "pulses-list" + }, + "patch": { + "description": "Update the pulse settings for an account. Use this to enable or disable the pulse. Returns an array of pulses for consistency with the GET endpoint.", + "requestBody": { + "description": "Pulse fields to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePulseRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Pulse updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PulsesResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "pulses-update" + } + }, + "/api/notifications": { + "post": { + "description": "Send a notification email to the authenticated account's email address via the Resend API. Emails are sent from `Agent by Recoup `. The recipient is automatically resolved from the API key or Bearer token. Supports plain text (rendered as Markdown) or raw HTML bodies, optional CC recipients, custom headers, and an optional room_id to include a chat link in the email footer.", + "requestBody": { + "description": "Notification email payload", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNotificationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Notification sent successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationResponse" + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Authentication required", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "502": { + "description": "Email delivery failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "notifications-create" + } + } + }, + "components": { + "schemas": { + "CreateNotificationRequest": { + "type": "object", + "required": [ + "subject" + ], + "properties": { + "cc": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "description": "Optional CC email addresses", + "example": [ + "cc@example.com" + ] + }, + "subject": { + "type": "string", + "description": "Email subject line", + "example": "Weekly Pulse Report" + }, + "text": { + "type": "string", + "description": "Plain text or Markdown body. Rendered as HTML via Markdown if no `html` is provided.", + "example": "# Pulse Report\n\nHere's your weekly summary." + }, + "html": { + "type": "string", + "description": "Raw HTML body. Takes precedence over `text` when both are provided.", + "example": "

Pulse Report

Here's your weekly summary.

" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional custom email headers" + }, + "room_id": { + "type": "string", + "description": "Room ID to include a chat link in the email footer" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to send the notification for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, sends the notification for the API key's own account." + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "NotificationResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the notification was sent successfully", + "example": true + }, + "message": { + "type": "string", + "description": "Human-readable result message", + "example": "Email sent successfully from Agent by Recoup to user@example.com." + }, + "id": { + "type": "string", + "description": "Resend email ID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + } + } + }, + "Pulse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the pulse" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the associated account" + }, + "active": { + "type": "boolean", + "description": "Whether the pulse is active (defaults to true)" + } + } + }, + "PulsesResponse": { + "type": "object", + "required": [ + "status", + "pulses" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "pulses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pulse" + }, + "description": "Array of pulse objects. Contains pulses for the authenticated account. If the account has access to organizations, all organization accounts are included." + }, + "error": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "UpdatePulseRequest": { + "type": "object", + "required": [ + "active" + ], + "properties": { + "active": { + "type": "boolean", + "description": "Whether to enable or disable the pulse", + "example": true + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to update the pulse for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, updates the pulse for the API key's own account." + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/sandboxes.json b/api-reference/openapi/sandboxes.json new file mode 100644 index 0000000..ea0dcfa --- /dev/null +++ b/api-reference/openapi/sandboxes.json @@ -0,0 +1,879 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Sandboxes API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/sandboxes": { + "get": { + "description": "List all sandboxes associated with the authenticated account and their current statuses. Returns sandbox details including lifecycle state, timeout remaining, and creation timestamp. Pass account_id to retrieve sandboxes for a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "parameters": [ + { + "name": "sandbox_id", + "in": "query", + "required": false, + "description": "Filter by a specific sandbox ID. When provided, returns only the sandbox matching this ID. Must be a sandbox that your account or organization is an admin of.", + "schema": { + "type": "string", + "example": "sbx_abc123def456" + } + }, + { + "name": "account_id", + "in": "query", + "description": "Filter to a specific account. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Sandboxes retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxesResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to filter by an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "list" + }, + "post": { + "description": "Create a new ephemeral sandbox environment. Optionally executes a command or an OpenCode prompt if provided. Sandboxes are isolated Linux microVMs that can be used to evaluate account-generated code, run AI agent output safely, or execute reproducible tasks. The sandbox will automatically stop after the timeout period. If no command or prompt is provided, the sandbox is created without triggering any background task. Use the prompt parameter as a shortcut to run `opencode run \"\"` in the sandbox. Pass account_id to create a sandbox for a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "requestBody": { + "description": "Optional command execution parameters. If command and prompt are both omitted, sandbox is created without running any command. Use prompt as a shortcut for running OpenCode.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSandboxRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Sandbox created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxesResponse" + } + } + } + }, + "400": { + "description": "Bad request - failed to create sandbox", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "create" + }, + "patch": { + "description": "Set a custom snapshot ID for an account. By default, updates the key owner's account. Pass account_id to target a specific account the API key has access to. This allows accounts to use a specific sandbox snapshot when creating new sandboxes, enabling reproducible environments with pre-configured tools, dependencies, and files.", + "requestBody": { + "description": "Snapshot configuration parameters", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSnapshotRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Snapshot ID updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSnapshotResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid snapshot ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "snapshot" + }, + "delete": { + "description": "Delete a sandbox environment for the authenticated account. This permanently deletes the associated GitHub repository and removes the account's snapshot record from the database. By default, deletes the sandbox for the key owner's account. Pass account_id to target a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "requestBody": { + "description": "Optional account targeting parameters", + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteSandboxRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Sandbox deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteSandboxResponse" + } + } + } + }, + "400": { + "description": "Bad request - failed to delete sandbox", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not a member of the organization or account tried to use an account_id they don't have access to", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "delete" + } + }, + "/api/sandboxes/setup": { + "post": { + "description": "Triggers the setup-sandbox background task to create a personal sandbox, provision a GitHub repo, take a snapshot, and shut down. By default, sets up the sandbox for the key owner's account. Pass account_id to target a specific account the API key has access to. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "requestBody": { + "description": "Optional account targeting parameters", + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupSandboxRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Setup task triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupSandboxResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid account_id format", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "setup" + } + }, + "/api/sandboxes/file": { + "get": { + "description": "Retrieve the raw contents of a file from the authenticated account's sandbox GitHub repository. Resolves the github_repo from the [account's snapshot](/api-reference/sandboxes/list), then fetches the file at the specified path from the repository's main branch. Authentication is handled via the x-api-key header or Authorization Bearer token.", + "parameters": [ + { + "name": "path", + "in": "query", + "required": true, + "description": "The file path within the repository (e.g. \"src/index.ts\" or \"README.md\").", + "schema": { + "type": "string", + "example": "src/index.ts" + } + } + ], + "responses": { + "200": { + "description": "File contents retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxFileResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid path parameter", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account does not have access", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "404": { + "description": "Not found - no snapshot, no github_repo, or file not found in repository", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "file" + } + }, + "/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.", + "requestBody": { + "description": "JSON body containing file URLs and target path", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadSandboxFilesRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Files uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadSandboxFilesResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing files or invalid path", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden - account does not have access", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + }, + "404": { + "description": "Not found - no snapshot or no github_repo configured", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxErrorResponse" + } + } + } + } + }, + "operationId": "upload" + } + } + }, + "components": { + "schemas": { + "CreateSandboxRequest": { + "type": "object", + "description": "Request body for creating a new sandbox. All fields are optional - if no command or prompt is provided, sandbox is created without triggering a command execution task. Use prompt as a shortcut to run OpenCode with a given prompt instead of specifying command/args manually.", + "properties": { + "command": { + "type": "string", + "minLength": 1, + "description": "The command to execute in the sandbox environment. If omitted, the sandbox is created without running any command.", + "example": "ls" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional arguments to pass to the command.", + "example": [ + "-la", + "/home" + ] + }, + "cwd": { + "type": "string", + "description": "Optional working directory for command execution.", + "example": "/home/user" + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "A prompt to pass to OpenCode in the sandbox. When provided, the sandbox will execute `opencode run \"\"`. Cannot be used together with command.", + "example": "create a hello world index.html" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to create the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, creates the sandbox for the API key's own account." + } + } + }, + "DeleteSandboxRequest": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to delete the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, deletes the sandbox for the API key's own account." + } + } + }, + "DeleteSandboxResponse": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the delete operation" + }, + "deleted_snapshot": { + "nullable": true, + "description": "The snapshot record that was deleted. Null if no snapshot existed for the account.", + "$ref": "#/components/schemas/UpdateSnapshotResponse" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "FileTreeEntry": { + "type": "object", + "required": [ + "path", + "type", + "sha" + ], + "description": "A single entry in a GitHub repository file tree", + "properties": { + "path": { + "type": "string", + "description": "The file or directory path relative to the repository root", + "example": "src/index.ts" + }, + "type": { + "type": "string", + "enum": [ + "blob", + "tree" + ], + "description": "The type of entry: blob for files, tree for directories" + }, + "sha": { + "type": "string", + "description": "The SHA hash of the entry", + "example": "abc123def456" + }, + "size": { + "type": "integer", + "description": "The size of the file in bytes. Only present for blob entries.", + "example": 1024 + } + } + }, + "Sandbox": { + "type": "object", + "required": [ + "sandboxId", + "sandboxStatus", + "timeout", + "createdAt" + ], + "description": "A sandbox environment instance", + "properties": { + "sandboxId": { + "type": "string", + "description": "Unique identifier for the sandbox", + "example": "sbx_abc123def456" + }, + "sandboxStatus": { + "type": "string", + "enum": [ + "pending", + "running", + "stopping", + "stopped", + "failed" + ], + "description": "Current lifecycle state of the sandbox", + "example": "running" + }, + "timeout": { + "type": "integer", + "description": "Milliseconds remaining before the sandbox stops automatically", + "example": 300000 + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the sandbox was created", + "example": "2024-01-15T10:30:00.000Z" + }, + "runId": { + "type": "string", + "description": "Unique identifier for the command execution run. Only present if a command was provided when creating the sandbox. Use this with [GET /api/tasks/runs](/api-reference/tasks/runs) to check the status and retrieve results.", + "example": "run_xyz789abc123" + } + } + }, + "SandboxErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "description": "Error message describing what went wrong", + "example": "Failed to create sandbox" + } + } + }, + "SandboxFileResponse": { + "type": "object", + "required": [ + "status", + "content" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the operation" + }, + "content": { + "type": "string", + "description": "The raw text content of the file" + } + } + }, + "SandboxesResponse": { + "type": "object", + "required": [ + "status", + "sandboxes" + ], + "description": "Response containing sandbox information", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "sandboxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Sandbox" + }, + "description": "Array of sandbox objects" + }, + "snapshot_id": { + "type": "string", + "description": "The account's saved snapshot ID used for creating new sandboxes. Null if no snapshot has been saved.", + "example": "snap_abc123def456", + "nullable": true + }, + "github_repo": { + "type": "string", + "description": "The GitHub repository URL associated with the account's sandbox environment. Used as the filesystem source when restoring sandboxes.", + "example": "https://github.com/username/repo", + "nullable": true + }, + "filetree": { + "type": "array", + "nullable": true, + "description": "The recursive file tree of the account's GitHub repository. Null if no github_repo is set or if the fetch fails.", + "items": { + "$ref": "#/components/schemas/FileTreeEntry" + } + }, + "error": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "SetupSandboxRequest": { + "type": "object", + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to set up the sandbox for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, sets up the sandbox for the API key's own account." + } + } + }, + "SetupSandboxResponse": { + "type": "object", + "required": [ + "status", + "runId" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the setup operation" + }, + "runId": { + "type": "string", + "description": "The Trigger.dev run ID for the setup-sandbox background task. Use this with [GET /api/tasks/runs](/api-reference/tasks/runs) to check the status and retrieve results.", + "example": "run_abc123def456" + } + } + }, + "UpdateSnapshotRequest": { + "type": "object", + "required": [], + "properties": { + "snapshotId": { + "type": "string", + "description": "The snapshot ID to set for the account. This snapshot will be used as the base environment when creating new sandboxes.", + "example": "snap_abc123def456" + }, + "github_repo": { + "type": "string", + "format": "uri", + "description": "The GitHub repository URL to associate with the account's sandbox environment. Must be a valid URL.", + "example": "https://github.com/org/repo" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the account to update the snapshot for. Only applicable when the authenticated account has access to multiple accounts via organization membership. If not provided, updates the snapshot for the API key's own account." + } + } + }, + "UpdateSnapshotResponse": { + "type": "object", + "required": [ + "account_id", + "snapshot_id", + "expires_at", + "github_repo", + "created_at" + ], + "properties": { + "account_id": { + "type": "string", + "format": "uuid", + "description": "The account ID this snapshot belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "snapshot_id": { + "type": "string", + "description": "The snapshot ID that was set for the account", + "example": "snap_abc123def456" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "description": "When the snapshot expires", + "example": "2027-01-01T00:00:00.000Z" + }, + "github_repo": { + "type": "string", + "nullable": true, + "description": "The GitHub repository URL associated with the sandbox", + "example": "https://github.com/org/repo" + }, + "created_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the snapshot record was created", + "example": "2025-01-01T00:00:00.000Z" + } + } + }, + "UploadSandboxFilesRequest": { + "type": "object", + "required": [ + "files" + ], + "properties": { + "path": { + "type": "string", + "description": "The target directory path within the repository to upload files to. Defaults to the repository root if omitted.", + "example": "assets/images" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "required": [ + "url", + "name" + ], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The URL of the file to upload", + "example": "https://example.com/files/album-cover.png" + }, + "name": { + "type": "string", + "description": "The filename to use when committing to the repository", + "example": "album-cover.png" + } + } + }, + "description": "Array of files to upload, each with a URL and target filename" + }, + "message": { + "type": "string", + "description": "Optional commit message. Defaults to 'Upload files via API'.", + "example": "Add new album artwork" + } + } + }, + "UploadSandboxFilesResponse": { + "type": "object", + "required": [ + "status", + "uploaded" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Status of the operation" + }, + "uploaded": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "The full path of the uploaded file in the repository" + }, + "sha": { + "type": "string", + "description": "The git SHA of the created/updated file" + } + } + }, + "description": "Array of uploaded file details" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/social.json b/api-reference/openapi/social.json new file mode 100644 index 0000000..4d6663e --- /dev/null +++ b/api-reference/openapi/social.json @@ -0,0 +1,2212 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Social API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/spotify/search": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Search for artists, albums, tracks, and playlists using the Spotify API. This endpoint is a proxy to the official Spotify Search API.", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "The search query keywords and optional field filters", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "A comma-separated list of item types to search across: album, artist, playlist, track, show, episode, audiobook", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "market", + "in": "query", + "description": "An ISO 3166-1 alpha-2 country code or 'from_token'", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of results to return (default: 20, min: 1, max: 50)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "minimum": 1, + "maximum": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "The index of the first result to return (default: 0, max: 10000)", + "required": false, + "schema": { + "type": "integer", + "default": 0, + "maximum": 10000 + } + } + ], + "responses": { + "200": { + "description": "Search results retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifySearchResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyErrorResponse" + } + } + } + } + }, + "operationId": "spotify-search" + } + }, + "/api/spotify/artist/": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Get Spotify catalog information for a single artist identified by their unique Spotify ID.", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The Spotify ID of the artist", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Artist retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyGetArtistResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyErrorResponse" + } + } + } + } + }, + "operationId": "spotify-artist" + } + }, + "/api/spotify/artist/albums": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Get Spotify catalog information about an artist's albums.", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The Spotify ID of the artist", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "include_groups", + "in": "query", + "description": "A comma-separated list of keywords to filter the response. Valid values are: album, single, appears_on, compilation", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "market", + "in": "query", + "description": "An ISO 3166-1 alpha-2 country code. If specified, only content available in that market will be returned", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of items to return (default: 20, min: 1, max: 50)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "minimum": 1, + "maximum": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "The index of the first item to return (default: 0)", + "required": false, + "schema": { + "type": "integer", + "default": 0 + } + } + ], + "responses": { + "200": { + "description": "Artist albums retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyArtistAlbumsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyErrorResponse" + } + } + } + } + }, + "operationId": "spotify-artist-albums" + } + }, + "/api/spotify/artist/topTracks": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Get an artist's top tracks by country.", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The Spotify ID of the artist", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "market", + "in": "query", + "description": "An ISO 3166-1 alpha-2 country code. If provided, only tracks available in that market are returned", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Artist top tracks retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyArtistTopTracksResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyErrorResponse" + } + } + } + } + }, + "operationId": "spotify-artist-top-tracks" + } + }, + "/api/spotify/album": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Get Spotify catalog information for a single album.", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The Spotify ID of the album", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "market", + "in": "query", + "description": "An ISO 3166-1 alpha-2 country code. If provided, only content available in that market is returned", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Album retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyAlbum" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpotifyErrorResponse" + } + } + } + } + }, + "operationId": "spotify-album" + } + }, + "/api/instagram/comments": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Fetch Instagram comments for multiple post URLs using Apify's Instagram Comment Scraper. The actual comment data will be available in the Apify dataset after the run completes.", + "parameters": [ + { + "name": "postUrls", + "in": "query", + "description": "Array of Instagram post URLs to fetch comments for", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "style": "form", + "explode": true + }, + { + "name": "resultsLimit", + "in": "query", + "description": "Maximum number of comments to fetch (default: 10000)", + "required": false, + "schema": { + "type": "integer", + "default": 10000 + } + }, + { + "name": "isNewestComments", + "in": "query", + "description": "Whether to fetch newest comments first. Set to true for newest first, false for oldest first, or omit for platform default sorting", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Apify scraper run started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApifyRunResult" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstagramErrorResponse" + } + } + } + } + }, + "operationId": "instagram-comments" + } + }, + "/api/instagram/profiles": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Fetch Instagram profile information for multiple handles using Apify's Instagram Profile Scraper. The actual profile data will be available in the Apify dataset after the run completes.", + "parameters": [ + { + "name": "handles", + "in": "query", + "description": "Array of Instagram handles to fetch profiles for", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "style": "form", + "explode": true + } + ], + "responses": { + "200": { + "description": "Apify scraper run started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApifyRunResult" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstagramErrorResponse" + } + } + } + } + }, + "operationId": "instagram-profiles" + } + }, + "/api/x/search": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Search for tweets using the Twitter Search API, powered by agent-twitter-client (no Twitter API key required). Supports various search modes including Top, Latest, Photos, Videos, and Users.", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "The search query. Any Twitter-compatible query format can be used (e.g., '#nodejs', 'from:username', etc.)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "maxTweets", + "in": "query", + "description": "The maximum number of tweets to return", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "searchMode", + "in": "query", + "description": "The category filter to apply to the search", + "required": false, + "schema": { + "type": "string", + "enum": [ + "Top", + "Latest", + "Photos", + "Videos", + "Users" + ], + "default": "Latest" + } + } + ], + "responses": { + "200": { + "description": "Tweets retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TwitterSearchResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TwitterErrorResponse" + } + } + } + } + }, + "operationId": "x-search" + } + }, + "/api/x/trends": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve the current trending topics from Twitter using the getTrends method from agent-twitter-client (no Twitter API key required).", + "responses": { + "200": { + "description": "Trends retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TwitterTrendsResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TwitterErrorResponse" + } + } + } + } + }, + "operationId": "x-trends" + } + }, + "/api/social/scrape": { + "post": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Trigger a social profile scraping job for a given social_id. Use the Get Artist Socials endpoint first to retrieve the social_id values. The response returns Apify run metadata for polling status and retrieving results via the Apify Scraper Results API.", + "requestBody": { + "description": "Social profile to scrape", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SocialScrapeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Scrape job triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApifyRunResult" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SocialErrorResponse" + } + } + } + } + }, + "operationId": "scrape" + } + }, + "/api/social/posts": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "description": "Retrieve all social media posts from a specific social profile. Call the Artist Socials endpoint first to obtain social IDs.", + "parameters": [ + { + "name": "social_id", + "in": "query", + "description": "The unique identifier (UUID) of the social profile to fetch posts for", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "latestFirst", + "in": "query", + "description": "Sort posts by most recent first (default: true)", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "page", + "in": "query", + "description": "The page number to retrieve (default: 1)", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "The number of records per page (default: 20, max: 100)", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100 + } + } + ], + "responses": { + "200": { + "description": "Posts retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SocialPostsResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing required parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SocialErrorResponse" + } + } + } + } + }, + "operationId": "posts" + } + }, + "/api/apify/scraper": { + "get": { + "servers": [ + { + "url": "https://api.recoupable.com" + } + ], + "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.", + "parameters": [ + { + "name": "runId", + "in": "query", + "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.", + "required": true, + "schema": { + "type": "string" + }, + "example": "abc123xyz" + } + ], + "responses": { + "200": { + "description": "Scraper run status retrieved successfully. Returns status info for in-progress runs, or status info plus data for completed runs.", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ApifyScraperInProgressResponse" + }, + { + "$ref": "#/components/schemas/ApifyScraperCompletedResponse" + } + ] + } + } + } + }, + "400": { + "description": "Bad request - missing required runId parameter", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApifyScraperErrorResponse" + } + } + } + }, + "500": { + "description": "Server error - failed to fetch run status from Apify", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApifyScraperErrorResponse" + } + } + } + } + }, + "operationId": "apify-scraper" + } + }, + "/api/connectors": { + "get": { + "description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.", + "parameters": [ + { + "name": "account_id", + "in": "query", + "description": "Optional account ID to get connectors for a different account (e.g., an artist, workspace, or organization). The authenticated account must have access to the specified account. Omit to get your own account's connectors.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Connectors retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectorsResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid account_id format", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - no access to the specified account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "connectors-list" + }, + "delete": { + "description": "Disconnect a connected account from a third-party service. This revokes the OAuth connection and removes stored credentials.", + "requestBody": { + "description": "Connection to disconnect", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisconnectConnectorRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Connector disconnected successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisconnectConnectorResponse" + } + } + } + }, + "400": { + "description": "Bad request - missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - no access to the specified account or connection", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "connectors-disconnect" + }, + "post": { + "description": "Generate an OAuth authorization URL for connecting a third-party service. Redirect to the returned URL to complete the OAuth flow.", + "requestBody": { + "description": "Authorization request details", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorizeConnectorRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Authorization URL generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorizeConnectorResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid connector or parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - no access to the specified account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "connectors-authorize" + } + } + }, + "components": { + "schemas": { + "ApifyRunResult": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "description": "Unique identifier for the Apify run" + }, + "datasetId": { + "type": "string", + "description": "Unique identifier for the dataset containing scraped data" + }, + "error": { + "type": "string", + "nullable": true, + "description": "Error message if the run failed (null if successful)" + } + } + }, + "ApifyScraperCompletedResponse": { + "type": "object", + "required": [ + "status", + "datasetId", + "data" + ], + "description": "Response when the Apify run has completed successfully", + "properties": { + "status": { + "type": "string", + "description": "Final status of the Apify run (typically 'SUCCEEDED')", + "example": "SUCCEEDED" + }, + "datasetId": { + "type": "string", + "description": "ID of the dataset containing the results", + "example": "def456uvw" + }, + "data": { + "type": "array", + "items": { + "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.)", + "example": [ + { + "id": "123456789", + "username": "example_user", + "fullName": "Example User", + "biography": "This is a sample biography", + "followersCount": 1000, + "followsCount": 500, + "profilePicUrl": "https://example.com/profile.jpg" + } + ] + } + } + }, + "ApifyScraperErrorResponse": { + "type": "object", + "required": [ + "status", + "message" + ], + "description": "Error response from the Apify scraper results endpoint", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status indicating an error occurred" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong", + "example": "runId is required" + } + } + }, + "ApifyScraperInProgressResponse": { + "type": "object", + "required": [ + "status", + "datasetId" + ], + "description": "Response when the Apify run is still in progress", + "properties": { + "status": { + "type": "string", + "description": "Current status of the Apify run (e.g., 'RUNNING', 'READY')", + "example": "RUNNING" + }, + "datasetId": { + "type": "string", + "description": "ID of the dataset that will contain the results when the run completes", + "example": "def456uvw" + } + } + }, + "AuthorizeConnectorRequest": { + "type": "object", + "required": [ + "connector" + ], + "properties": { + "connector": { + "type": "string", + "description": "The connector slug to authorize (e.g., 'googlesheets', 'tiktok')" + }, + "callback_url": { + "type": "string", + "format": "uri", + "description": "Optional custom callback URL after OAuth completion" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Optional account ID to connect a service for a different account (e.g., an artist, workspace, or organization). Use this when connecting an artist's TikTok or other service. The authenticated account must have access. Omit to connect for your own account." + } + } + }, + "AuthorizeConnectorResponse": { + "type": "object", + "required": [ + "success", + "data" + ], + "properties": { + "success": { + "type": "boolean" + }, + "data": { + "type": "object", + "required": [ + "connector", + "redirectUrl" + ], + "properties": { + "connector": { + "type": "string", + "description": "The connector slug being authorized" + }, + "redirectUrl": { + "type": "string", + "format": "uri", + "description": "URL to redirect to for OAuth authorization" + } + } + } + } + }, + "ConnectorInfo": { + "type": "object", + "required": [ + "slug", + "name", + "isConnected" + ], + "properties": { + "slug": { + "type": "string", + "description": "Unique identifier for the connector (e.g., 'googlesheets', 'tiktok')" + }, + "name": { + "type": "string", + "description": "Human-readable name of the connector" + }, + "isConnected": { + "type": "boolean", + "description": "Whether the connector is currently connected" + }, + "connectedAccountId": { + "type": "string", + "description": "The connected account ID (only present when isConnected is true)" + } + } + }, + "ConnectorsResponse": { + "type": "object", + "required": [ + "success", + "connectors" + ], + "properties": { + "success": { + "type": "boolean" + }, + "connectors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConnectorInfo" + }, + "description": "List of available connectors with connection status" + } + } + }, + "DisconnectConnectorRequest": { + "type": "object", + "required": [ + "connected_account_id" + ], + "properties": { + "connected_account_id": { + "type": "string", + "description": "The connected account ID to disconnect (from ConnectorInfo.connectedAccountId)" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Optional account ID when disconnecting a connection that belongs to a different account (e.g., an artist). Required when the connection was created for another account rather than your own. The authenticated account must have access." + } + } + }, + "DisconnectConnectorResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string", + "description": "Status message" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "InstagramErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message describing what went wrong" + } + } + }, + "SocialErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message" + } + } + }, + "SocialPost": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social's social_posts record" + }, + "post_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social's posts record" + }, + "social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social's socials record" + }, + "post_url": { + "type": "string", + "description": "Direct URL to the post on the platform" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO timestamp of when the post data was last updated" + } + } + }, + "SocialPostsPagination": { + "type": "object", + "properties": { + "total_count": { + "type": "integer", + "description": "Total number of posts available" + }, + "page": { + "type": "integer", + "description": "Current page number" + }, + "limit": { + "type": "integer", + "description": "Number of posts per page" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages available" + } + } + }, + "SocialPostsResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "posts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SocialPost" + }, + "description": "List of social media posts" + }, + "pagination": { + "$ref": "#/components/schemas/SocialPostsPagination" + } + } + }, + "SocialScrapeRequest": { + "type": "object", + "required": [ + "social_id" + ], + "properties": { + "social_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the social profile to scrape. Obtain this from the Get Artist Socials API." + } + } + }, + "SpotifyAlbum": { + "type": "object", + "properties": { + "album_type": { + "type": "string", + "enum": [ + "album", + "single", + "compilation" + ], + "description": "The type of the album" + }, + "total_tracks": { + "type": "integer", + "description": "The number of tracks in the album" + }, + "available_markets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Markets in which the album is available" + }, + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "href": { + "type": "string", + "description": "A link to the Web API endpoint providing full details" + }, + "id": { + "type": "string", + "description": "The Spotify ID for the album" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyImage" + }, + "description": "The cover art for the album in various sizes" + }, + "name": { + "type": "string", + "description": "The name of the album" + }, + "release_date": { + "type": "string", + "description": "The date the album was first released" + }, + "release_date_precision": { + "type": "string", + "enum": [ + "year", + "month", + "day" + ], + "description": "The precision with which release_date value is known" + }, + "restrictions": { + "type": "object", + "properties": { + "reason": { + "type": "string" + } + }, + "description": "Included when a content restriction is applied" + }, + "type": { + "type": "string", + "enum": [ + "album" + ], + "description": "The object type, always 'album'" + }, + "uri": { + "type": "string", + "description": "The Spotify URI for the album" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedArtist" + }, + "description": "The artists of the album" + }, + "tracks": { + "$ref": "#/components/schemas/SpotifyAlbumTracks", + "description": "The tracks of the album" + }, + "copyrights": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyCopyright" + }, + "description": "Copyright statements of the album" + }, + "external_ids": { + "type": "object", + "properties": { + "isrc": { + "type": "string" + }, + "ean": { + "type": "string" + }, + "upc": { + "type": "string" + } + }, + "description": "Known external IDs for the album" + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated. Always empty." + }, + "label": { + "type": "string", + "description": "The label associated with the album" + }, + "popularity": { + "type": "integer", + "description": "Popularity of the album (0-100)" + } + } + }, + "SpotifyAlbumTracks": { + "type": "object", + "properties": { + "href": { + "type": "string", + "description": "A link to the Web API endpoint" + }, + "limit": { + "type": "integer", + "description": "The maximum number of items in the response" + }, + "next": { + "type": "string", + "nullable": true, + "description": "URL to the next page of items" + }, + "offset": { + "type": "integer", + "description": "The offset of the items returned" + }, + "previous": { + "type": "string", + "nullable": true, + "description": "URL to the previous page" + }, + "total": { + "type": "integer", + "description": "Total number of items available" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedTrack" + }, + "description": "Array of simplified track objects" + } + } + }, + "SpotifyArtistAlbumsResponse": { + "type": "object", + "properties": { + "href": { + "type": "string", + "description": "A link to the Web API endpoint returning the full result" + }, + "limit": { + "type": "integer", + "description": "The maximum number of items in the response" + }, + "next": { + "type": "string", + "nullable": true, + "description": "URL to the next page of items" + }, + "offset": { + "type": "integer", + "description": "The offset of the items returned" + }, + "previous": { + "type": "string", + "nullable": true, + "description": "URL to the previous page of items" + }, + "total": { + "type": "integer", + "description": "The total number of items available" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedAlbum" + }, + "description": "Array of simplified album objects" + } + } + }, + "SpotifyArtistObject": { + "type": "object", + "properties": { + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "followers": { + "$ref": "#/components/schemas/SpotifyFollowers" + }, + "genres": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of the genres the artist is associated with" + }, + "href": { + "type": "string", + "description": "A link to the Web API endpoint providing full details" + }, + "id": { + "type": "string", + "description": "The Spotify ID for the artist" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyImage" + }, + "description": "Images of the artist in various sizes" + }, + "name": { + "type": "string", + "description": "The name of the artist" + }, + "popularity": { + "type": "integer", + "description": "The popularity of the artist (0-100)" + }, + "type": { + "type": "string", + "enum": [ + "artist" + ], + "description": "The object type, always 'artist'" + }, + "uri": { + "type": "string", + "description": "The Spotify URI for the artist" + } + } + }, + "SpotifyArtistTopTracksResponse": { + "type": "object", + "properties": { + "tracks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyTrack" + }, + "description": "Array of track objects" + } + } + }, + "SpotifyArtistsPaginated": { + "type": "object", + "properties": { + "href": { + "type": "string", + "description": "A link to the Web API endpoint returning the full result" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyArtistObject" + }, + "description": "List of artist objects" + }, + "limit": { + "type": "integer", + "description": "The maximum number of items in the response" + }, + "next": { + "type": "string", + "nullable": true, + "description": "URL to the next page of items" + }, + "offset": { + "type": "integer", + "description": "The offset of the items returned" + }, + "previous": { + "type": "string", + "nullable": true, + "description": "URL to the previous page of items" + }, + "total": { + "type": "integer", + "description": "The total number of items available" + } + } + }, + "SpotifyCopyright": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "The copyright text" + }, + "type": { + "type": "string", + "description": "The type of copyright" + } + } + }, + "SpotifyErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "status": { + "type": "integer", + "description": "HTTP status code" + }, + "message": { + "type": "string", + "description": "Error message" + } + }, + "description": "Error details" + } + } + }, + "SpotifyExternalUrls": { + "type": "object", + "properties": { + "spotify": { + "type": "string", + "description": "The Spotify URL for the object" + } + } + }, + "SpotifyFollowers": { + "type": "object", + "properties": { + "href": { + "type": "string", + "nullable": true, + "description": "This will always be set to null" + }, + "total": { + "type": "integer", + "description": "The total number of followers" + } + } + }, + "SpotifyGetArtistResponse": { + "type": "object", + "properties": { + "artist": { + "$ref": "#/components/schemas/SpotifyArtistObject", + "nullable": true, + "description": "The Spotify artist object (null if error)" + }, + "error": { + "type": "object", + "nullable": true, + "description": "Error object if request failed (null if successful)" + } + } + }, + "SpotifyImage": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The source URL of the image" + }, + "height": { + "type": "integer", + "nullable": true, + "description": "The image height in pixels" + }, + "width": { + "type": "integer", + "nullable": true, + "description": "The image width in pixels" + } + } + }, + "SpotifySearchResponse": { + "type": "object", + "properties": { + "artists": { + "$ref": "#/components/schemas/SpotifyArtistsPaginated", + "description": "Search results for artists (if type includes artist)" + }, + "albums": { + "type": "object", + "description": "Search results for albums (if type includes album)" + }, + "tracks": { + "type": "object", + "description": "Search results for tracks (if type includes track)" + }, + "playlists": { + "type": "object", + "description": "Search results for playlists (if type includes playlist)" + } + } + }, + "SpotifySimplifiedAlbum": { + "type": "object", + "properties": { + "album_type": { + "type": "string", + "enum": [ + "album", + "single", + "compilation" + ], + "description": "The type of the album" + }, + "total_tracks": { + "type": "integer", + "description": "The number of tracks in the album" + }, + "available_markets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Markets in which the album is available" + }, + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "href": { + "type": "string", + "description": "A link to the Web API endpoint providing full details" + }, + "id": { + "type": "string", + "description": "The Spotify ID for the album" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifyImage" + }, + "description": "The cover art for the album in various sizes" + }, + "name": { + "type": "string", + "description": "The name of the album" + }, + "release_date": { + "type": "string", + "description": "The date the album was first released" + }, + "release_date_precision": { + "type": "string", + "enum": [ + "year", + "month", + "day" + ], + "description": "The precision with which release_date value is known" + }, + "restrictions": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "The reason for the restriction" + } + }, + "description": "Included when a content restriction is applied" + }, + "type": { + "type": "string", + "enum": [ + "album" + ], + "description": "The object type, always 'album'" + }, + "uri": { + "type": "string", + "description": "The Spotify URI for the album" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedArtist" + }, + "description": "The artists of the album" + }, + "album_group": { + "type": "string", + "enum": [ + "album", + "single", + "compilation", + "appears_on" + ], + "description": "The field to distinguish albums by various groups" + } + } + }, + "SpotifySimplifiedArtist": { + "type": "object", + "properties": { + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "href": { + "type": "string", + "description": "A link to the Web API endpoint providing full details" + }, + "id": { + "type": "string", + "description": "The Spotify ID for the artist" + }, + "name": { + "type": "string", + "description": "The name of the artist" + }, + "type": { + "type": "string", + "enum": [ + "artist" + ], + "description": "The object type, always 'artist'" + }, + "uri": { + "type": "string", + "description": "The Spotify URI for the artist" + } + } + }, + "SpotifySimplifiedTrack": { + "type": "object", + "properties": { + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedArtist" + }, + "description": "The artists who performed the track" + }, + "available_markets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Markets in which the track is available" + }, + "disc_number": { + "type": "integer", + "description": "Disc number the track is on" + }, + "duration_ms": { + "type": "integer", + "description": "Track length in milliseconds" + }, + "explicit": { + "type": "boolean", + "description": "Whether the track has explicit lyrics" + }, + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "href": { + "type": "string", + "description": "Link to the Web API endpoint" + }, + "id": { + "type": "string", + "description": "Spotify ID for the track" + }, + "is_playable": { + "type": "boolean", + "description": "If true, the track is playable" + }, + "linked_from": { + "type": "object", + "description": "Track relinking info" + }, + "restrictions": { + "type": "object", + "properties": { + "reason": { + "type": "string" + } + } + }, + "name": { + "type": "string", + "description": "Track name" + }, + "preview_url": { + "type": "string", + "nullable": true, + "description": "URL to a 30 second preview" + }, + "track_number": { + "type": "integer", + "description": "Track number on the album" + }, + "type": { + "type": "string", + "enum": [ + "track" + ] + }, + "uri": { + "type": "string", + "description": "Spotify URI for the track" + }, + "is_local": { + "type": "boolean", + "description": "Whether from a local file" + } + } + }, + "SpotifyTrack": { + "type": "object", + "properties": { + "album": { + "$ref": "#/components/schemas/SpotifySimplifiedAlbum", + "description": "The album the track appears on" + }, + "artists": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpotifySimplifiedArtist" + }, + "description": "Artists who performed the track" + }, + "available_markets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Markets in which the track is available" + }, + "disc_number": { + "type": "integer", + "description": "Disc number the track is on" + }, + "duration_ms": { + "type": "integer", + "description": "Track length in milliseconds" + }, + "explicit": { + "type": "boolean", + "description": "Whether the track has explicit lyrics" + }, + "external_ids": { + "type": "object", + "properties": { + "isrc": { + "type": "string", + "description": "International Standard Recording Code" + }, + "ean": { + "type": "string", + "description": "International Article Number" + }, + "upc": { + "type": "string", + "description": "Universal Product Code" + } + }, + "description": "Known external IDs for the track" + }, + "external_urls": { + "$ref": "#/components/schemas/SpotifyExternalUrls" + }, + "href": { + "type": "string", + "description": "Link to the Web API endpoint with full details" + }, + "id": { + "type": "string", + "description": "Spotify ID for the track" + }, + "is_playable": { + "type": "boolean", + "description": "If true, the track is playable in the given market" + }, + "linked_from": { + "type": "object", + "description": "Information about the originally requested track when track relinking is applied" + }, + "restrictions": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "The reason for the restriction" + } + }, + "description": "Content restriction information" + }, + "name": { + "type": "string", + "description": "Track name" + }, + "popularity": { + "type": "integer", + "description": "Popularity score (0-100)" + }, + "preview_url": { + "type": "string", + "nullable": true, + "description": "URL to a 30 second preview, if available" + }, + "track_number": { + "type": "integer", + "description": "Track number on the album" + }, + "type": { + "type": "string", + "enum": [ + "track" + ], + "description": "The object type, always 'track'" + }, + "uri": { + "type": "string", + "description": "The Spotify URI for the track" + }, + "is_local": { + "type": "boolean", + "description": "Whether the track is from a local file" + } + } + }, + "Tweet": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Tweet ID" + }, + "text": { + "type": "string", + "description": "Tweet text content" + }, + "username": { + "type": "string", + "description": "Username of the tweet author" + }, + "timestamp": { + "type": "integer", + "description": "Unix timestamp (ms) of when the tweet was posted" + }, + "createdAt": { + "type": "string", + "description": "ISO timestamp of when the tweet was posted" + }, + "isReply": { + "type": "boolean", + "description": "Whether the tweet is a reply" + }, + "isRetweet": { + "type": "boolean", + "description": "Whether the tweet is a retweet" + }, + "likes": { + "type": "integer", + "description": "Number of likes" + }, + "retweetCount": { + "type": "integer", + "description": "Number of retweets" + }, + "replies": { + "type": "integer", + "description": "Number of replies" + }, + "photos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TwitterPhoto" + }, + "description": "Array of photo objects" + }, + "videos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TwitterVideo" + }, + "description": "Array of video objects" + }, + "urls": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of URLs included in the tweet" + }, + "permanentUrl": { + "type": "string", + "description": "Permanent URL to the tweet" + }, + "quotedStatusId": { + "type": "string", + "description": "ID of the quoted tweet (if applicable)" + }, + "inReplyToStatusId": { + "type": "string", + "description": "ID of the tweet this is replying to (if applicable)" + }, + "hashtags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of hashtags in the tweet" + } + } + }, + "TwitterErrorResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "error" + ], + "description": "Status of the request" + }, + "message": { + "type": "string", + "description": "Error message" + } + } + }, + "TwitterPhoto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Photo ID" + }, + "url": { + "type": "string", + "description": "URL of the photo" + } + } + }, + "TwitterSearchResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Status of the request", + "enum": [ + "success", + "error" + ] + }, + "tweets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Tweet" + }, + "description": "List of tweet objects" + } + } + }, + "TwitterTrendsResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Status of the request", + "enum": [ + "success", + "error" + ] + }, + "trends": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of current trending topics on Twitter" + } + } + }, + "TwitterVideo": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Video ID" + }, + "preview": { + "type": "string", + "description": "URL of the video preview image" + }, + "url": { + "type": "string", + "description": "URL of the video" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/openapi/tasks.json b/api-reference/openapi/tasks.json new file mode 100644 index 0000000..554d849 --- /dev/null +++ b/api-reference/openapi/tasks.json @@ -0,0 +1,778 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Recoup Tasks API", + "description": "API documentation for the Recoup platform - an AI agent platform for the music industry", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://recoup-api.vercel.app" + } + ], + "security": [ + { + "apiKeyAuth": [] + } + ], + "paths": { + "/api/tasks": { + "get": { + "description": "Retrieve scheduled tasks. The response includes recent_runs (last 5 runs) and upcoming (next scheduled run times) sourced directly from the Trigger.dev API. Supports filtering by id, account_id, or artist_account_id.", + "parameters": [ + { + "name": "id", + "in": "query", + "description": "Filter by task ID (UUID). Returns a single task matching the provided ID.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "account_id", + "in": "query", + "description": "Filter tasks to only include those for the specified account.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "artist_account_id", + "in": "query", + "description": "Filter tasks to only include those for the specified artist account.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Tasks retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TasksResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "get" + }, + "post": { + "description": "Create a new scheduled task. All fields are required. The response shape matches the GET endpoint (an array containing the created task).", + "requestBody": { + "description": "Task to create", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTaskRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Task created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TasksResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "create" + }, + "patch": { + "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).", + "requestBody": { + "description": "Task fields to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTaskRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Task updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TasksResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "update" + }, + "delete": { + "description": "Delete an existing scheduled task by its ID. Returns the status of the delete operation.", + "requestBody": { + "description": "Task to delete", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTaskRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Task deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTaskResponse" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "delete" + } + }, + "/api/tasks/runs": { + "get": { + "description": "Returns an array of task runs. When runId is provided, the array contains that single run. When omitted, returns recent runs for the authenticated account. Use account_id to query runs for a specific account within your organizations.", + "parameters": [ + { + "name": "runId", + "in": "query", + "description": "The unique identifier of a specific task run to retrieve. If omitted, returns a list of recent runs for the authenticated account.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of runs to return when listing (ignored when runId is provided). Default 20, max 100.", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "account_id", + "in": "query", + "description": "Filter runs by account ID. When provided, returns runs tagged with account:. Only applicable when the authenticated account has access to multiple accounts via organization membership.", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Task runs retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskRunListResponse" + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden - account_id is not accessible with the provided credentials", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Task run not found (only when runId is provided)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + }, + "operationId": "runs" + } + } + }, + "components": { + "schemas": { + "CreateTaskRequest": { + "type": "object", + "required": [ + "title", + "prompt", + "schedule", + "account_id", + "artist_account_id" + ], + "properties": { + "title": { + "type": "string", + "description": "Descriptive title of the task", + "example": "Weekly Genre Pulse Check" + }, + "prompt": { + "type": "string", + "description": "Instruction/prompt executed by the task", + "example": "Execute this weekly genre analysis workflow and email a summary to the team." + }, + "schedule": { + "type": "string", + "description": "Cron expression defining when the task runs (e.g., '0 9 * * 4' for Thursdays at 9 AM)", + "example": "0 9 * * 4" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the associated account", + "example": "848cd58d-700f-4b38-ab4c-d9f52a1b2c3d" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the associated artist account", + "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" + } + } + }, + "DeleteTaskRequest": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the task to delete", + "example": "aade2bce-55c7-468e-a606-c4e76fb2ea2a" + } + } + }, + "DeleteTaskResponse": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the delete operation" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "Task": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the task" + }, + "title": { + "type": "string", + "description": "Descriptive title or name of the task" + }, + "prompt": { + "type": "string", + "description": "Detailed instruction or prompt for task execution" + }, + "schedule": { + "type": "string", + "description": "Cron expression defining when the task should execute (e.g., '0 10 * * *')" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the associated account" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the associated artist account" + }, + "enabled": { + "type": "boolean", + "nullable": true, + "description": "Whether the task is enabled. Defaults to true." + }, + "trigger_schedule_id": { + "type": "string", + "nullable": true, + "description": "Identifier for the trigger schedule associated with this task" + }, + "recent_runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskRunResponse" + }, + "description": "Last 5 runs for this task, sourced from the Trigger.dev API." + }, + "upcoming": { + "type": "array", + "items": { + "type": "string", + "format": "date-time" + }, + "description": "Next scheduled run times, sourced from the latest Trigger.dev run payload." + } + } + }, + "TaskRunListResponse": { + "type": "object", + "required": [ + "status", + "runs" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success" + ], + "description": "Indicates the request was successful" + }, + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaskRunResponse" + }, + "description": "List of recent task runs for the authenticated account. Each item is a raw Trigger.dev SDK run object (same shape as TaskRunResponse, but without `output` and `error` fields)." + } + } + }, + "TaskRunResponse": { + "type": "object", + "description": "Raw Trigger.dev SDK run object. The API passes through the SDK response without field mapping. See https://trigger.dev/docs/management/runs/retrieve for the full reference. When listing runs, `output`, `error`, `payload`, and `attempts` are not included.", + "required": [ + "id", + "status", + "taskIdentifier", + "createdAt", + "updatedAt" + ], + "properties": { + "id": { + "type": "string", + "description": "The unique run identifier, prefixed with `run_`" + }, + "status": { + "type": "string", + "enum": [ + "PENDING_VERSION", + "DELAYED", + "QUEUED", + "EXECUTING", + "REATTEMPTING", + "FROZEN", + "COMPLETED", + "CANCELED", + "FAILED", + "CRASHED", + "INTERRUPTED", + "SYSTEM_FAILURE" + ], + "description": "Current run status" + }, + "taskIdentifier": { + "type": "string", + "description": "The task type identifier (e.g. 'setup-sandbox', 'run-sandbox-command')" + }, + "idempotencyKey": { + "type": "string", + "nullable": true, + "description": "Idempotency key used to deduplicate trigger requests" + }, + "version": { + "type": "string", + "description": "The worker version that executed the run" + }, + "isTest": { + "type": "boolean", + "description": "Whether this is a test run" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the run was created (ISO 8601)" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the run was last updated (ISO 8601)" + }, + "startedAt": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When execution started (null if not yet started)" + }, + "finishedAt": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the run finished (null if still running)" + }, + "delayedUntil": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "If delayed, when the run becomes eligible to execute" + }, + "ttl": { + "description": "Time-to-live. If the run is not started within this duration, it expires.", + "nullable": true + }, + "expiredAt": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the run expired (null if not expired)" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags associated with this run (max 10)" + }, + "metadata": { + "type": "object", + "nullable": true, + "description": "JSON metadata attached to the run" + }, + "costInCents": { + "type": "number", + "description": "Compute cost of the run in cents" + }, + "baseCostInCents": { + "type": "number", + "description": "Base invocation cost in cents" + }, + "durationMs": { + "type": "number", + "description": "Compute duration in milliseconds" + }, + "env": { + "type": "object", + "description": "Environment the run executed in", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "user": { + "type": "string", + "nullable": true + } + } + }, + "depth": { + "type": "integer", + "description": "Nesting depth for child runs" + }, + "batchId": { + "type": "string", + "nullable": true, + "description": "Batch ID if triggered as part of a batch" + }, + "triggerFunction": { + "type": "string", + "enum": [ + "trigger", + "triggerAndWait", + "batchTrigger", + "batchTriggerAndWait" + ], + "description": "The function used to trigger this run" + }, + "payload": { + "description": "Input payload for the task. Only present when retrieving by runId.", + "nullable": true + }, + "output": { + "description": "Task output data. Only present when retrieving by runId.", + "nullable": true + }, + "error": { + "type": "object", + "nullable": true, + "description": "Error details if the run failed. Only present when retrieving by runId.", + "properties": { + "message": { + "type": "string", + "description": "Human-readable error message" + }, + "name": { + "type": "string", + "description": "Error name or type" + }, + "stackTrace": { + "type": "string", + "description": "Stack trace" + } + } + }, + "attempts": { + "type": "array", + "description": "Attempt history. Only present when retrieving by runId.", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Attempt ID, prefixed with `attempt_`" + }, + "status": { + "type": "string", + "enum": [ + "PENDING", + "EXECUTING", + "PAUSED", + "COMPLETED", + "FAILED", + "CANCELED" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "startedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "error": { + "type": "object", + "nullable": true, + "properties": { + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "stackTrace": { + "type": "string" + } + } + } + } + } + }, + "schedule": { + "type": "object", + "nullable": true, + "description": "Schedule information if triggered by a schedule. Only present when retrieving by runId." + }, + "relatedRuns": { + "type": "object", + "nullable": true, + "description": "Related run references (root, parent, children). Only present when retrieving by runId." + } + } + }, + "TasksResponse": { + "type": "object", + "required": [ + "status", + "tasks" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Status of the request" + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Task" + }, + "description": "Array of task objects" + }, + "error": { + "type": "string", + "description": "Error message (only present if status is error)" + } + } + }, + "UpdateTaskRequest": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the task to update", + "example": "aade2bce-55c7-468e-a606-c4e76fb2ea2a" + }, + "title": { + "type": "string", + "description": "New descriptive title of the task", + "example": "Weekly Genre Pulse Check (Updated)" + }, + "prompt": { + "type": "string", + "description": "New instruction/prompt executed by the task", + "example": "Execute this weekly genre analysis workflow and email a summary to the team." + }, + "schedule": { + "type": "string", + "description": "New cron expression defining when the task runs", + "example": "0 10 * * 4" + }, + "account_id": { + "type": "string", + "format": "uuid", + "description": "New UUID of the associated account", + "example": "848cd58d-700f-4b38-ab4c-d9f52a1b2c3d" + }, + "artist_account_id": { + "type": "string", + "format": "uuid", + "description": "New UUID of the associated artist account", + "example": "1873859c-dd37-4e9a-9bac-80d35a1b2c3d" + }, + "enabled": { + "type": "boolean", + "nullable": true, + "description": "Whether the task is enabled. Can be true, false, or null.", + "example": true + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "Your Recoup API key. [Learn more](/quickstart#api-keys)." + } + } + } +} diff --git a/api-reference/organizations/add-artist.mdx b/api-reference/organizations/add-artist.mdx deleted file mode 100644 index ec3d671..0000000 --- a/api-reference/organizations/add-artist.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add Artist to Organization -openapi: POST /api/organizations/artists ---- diff --git a/api-reference/organizations/create.mdx b/api-reference/organizations/create.mdx deleted file mode 100644 index 18677eb..0000000 --- a/api-reference/organizations/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Create Organization -openapi: POST /api/organizations ---- diff --git a/api-reference/organizations/list.mdx b/api-reference/organizations/list.mdx deleted file mode 100644 index 2e6bb53..0000000 --- a/api-reference/organizations/list.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Organizations -openapi: GET /api/organizations ---- diff --git a/api-reference/post/comments.mdx b/api-reference/post/comments.mdx deleted file mode 100644 index 9c77d09..0000000 --- a/api-reference/post/comments.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Post Comments -openapi: GET /api/post/comments ---- diff --git a/api-reference/posts/get.mdx b/api-reference/posts/get.mdx deleted file mode 100644 index 4bfee8e..0000000 --- a/api-reference/posts/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Artist Posts -openapi: GET /api/posts ---- diff --git a/api-reference/pulses/list.mdx b/api-reference/pulses/list.mdx deleted file mode 100644 index b08d254..0000000 --- a/api-reference/pulses/list.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Pulses' -openapi: 'GET /api/pulses' ---- diff --git a/api-reference/pulses/update.mdx b/api-reference/pulses/update.mdx deleted file mode 100644 index e909536..0000000 --- a/api-reference/pulses/update.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Pulse' -openapi: 'PATCH /api/pulses' ---- diff --git a/api-reference/sandboxes/create.mdx b/api-reference/sandboxes/create.mdx deleted file mode 100644 index b0a01e6..0000000 --- a/api-reference/sandboxes/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Sandbox' -openapi: 'POST /api/sandboxes' ---- diff --git a/api-reference/sandboxes/delete.mdx b/api-reference/sandboxes/delete.mdx deleted file mode 100644 index 075d05e..0000000 --- a/api-reference/sandboxes/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Sandbox' -openapi: 'DELETE /api/sandboxes' ---- diff --git a/api-reference/sandboxes/file.mdx b/api-reference/sandboxes/file.mdx deleted file mode 100644 index de8a7ee..0000000 --- a/api-reference/sandboxes/file.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get File Contents' -openapi: 'GET /api/sandboxes/file' ---- diff --git a/api-reference/sandboxes/list.mdx b/api-reference/sandboxes/list.mdx deleted file mode 100644 index 66a9cba..0000000 --- a/api-reference/sandboxes/list.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Sandboxes' -openapi: 'GET /api/sandboxes' ---- diff --git a/api-reference/sandboxes/setup.mdx b/api-reference/sandboxes/setup.mdx deleted file mode 100644 index 4922c80..0000000 --- a/api-reference/sandboxes/setup.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Setup Sandbox' -openapi: 'POST /api/sandboxes/setup' ---- diff --git a/api-reference/sandboxes/snapshot.mdx b/api-reference/sandboxes/snapshot.mdx deleted file mode 100644 index 97f9a87..0000000 --- a/api-reference/sandboxes/snapshot.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Snapshot' -openapi: 'PATCH /api/sandboxes' ---- diff --git a/api-reference/sandboxes/upload.mdx b/api-reference/sandboxes/upload.mdx deleted file mode 100644 index bc6990a..0000000 --- a/api-reference/sandboxes/upload.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Upload Files' -openapi: 'POST /api/sandboxes/files' ---- diff --git a/api-reference/segment/fans.mdx b/api-reference/segment/fans.mdx deleted file mode 100644 index 55cc9c5..0000000 --- a/api-reference/segment/fans.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Get Segment Fans -openapi: GET /api/segment/fans ---- diff --git a/api-reference/social/posts.mdx b/api-reference/social/posts.mdx deleted file mode 100644 index b73e743..0000000 --- a/api-reference/social/posts.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Social Posts' -openapi: 'GET /api/social/posts' ---- diff --git a/api-reference/social/scrape.mdx b/api-reference/social/scrape.mdx deleted file mode 100644 index a2236c2..0000000 --- a/api-reference/social/scrape.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Social Scrape' -openapi: 'POST /api/social/scrape' ---- diff --git a/api-reference/songs/analyze-presets.mdx b/api-reference/songs/analyze-presets.mdx deleted file mode 100644 index fd24fb2..0000000 --- a/api-reference/songs/analyze-presets.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Analyze Presets' -openapi: 'GET /api/songs/analyze/presets' ---- diff --git a/api-reference/songs/analyze.mdx b/api-reference/songs/analyze.mdx deleted file mode 100644 index 2905518..0000000 --- a/api-reference/songs/analyze.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Analyze Songs' -openapi: 'POST /api/songs/analyze' ---- diff --git a/api-reference/songs/catalog-songs-add.mdx b/api-reference/songs/catalog-songs-add.mdx deleted file mode 100644 index 6b6f4b5..0000000 --- a/api-reference/songs/catalog-songs-add.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Add Catalog Songs -openapi: post /api/catalogs/songs ---- - - - For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used. - diff --git a/api-reference/songs/catalog-songs-delete.mdx b/api-reference/songs/catalog-songs-delete.mdx deleted file mode 100644 index 932c6fc..0000000 --- a/api-reference/songs/catalog-songs-delete.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Remove Catalog Songs -openapi: delete /api/catalogs/songs ---- - - - This endpoint removes the relationship in `catalog_songs` for each `catalog_id` and ISRC pair. The song data itself is not deleted. - diff --git a/api-reference/songs/catalog-songs.mdx b/api-reference/songs/catalog-songs.mdx deleted file mode 100644 index 5c2b76d..0000000 --- a/api-reference/songs/catalog-songs.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Get Catalog Songs -openapi: get /api/catalogs/songs ---- - - - This endpoint supports pagination. The Catalog Songs API also supports POST for adding songs and DELETE for removing songs. See the [Add Catalog Songs](/api-reference/songs/catalog-songs-add) and [Remove Catalog Songs](/api-reference/songs/catalog-songs-delete) endpoints. - diff --git a/api-reference/songs/catalogs-create.mdx b/api-reference/songs/catalogs-create.mdx deleted file mode 100644 index b0d690a..0000000 --- a/api-reference/songs/catalogs-create.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Create Catalogs -openapi: post /api/catalogs ---- - - - If `catalog_id` is provided, the existing catalog is linked to the account. If `name` is provided without `catalog_id`, a new catalog is created. If both are provided, `catalog_id` takes priority. - diff --git a/api-reference/songs/catalogs-delete.mdx b/api-reference/songs/catalogs-delete.mdx deleted file mode 100644 index 9754706..0000000 --- a/api-reference/songs/catalogs-delete.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Delete Catalogs -openapi: delete /api/catalogs ---- - - - When unlinking a catalog from an account, if no other accounts remain linked to the catalog, the catalog is automatically deleted (cascading to catalog_songs). Otherwise, only the account-catalog relationship is removed. - diff --git a/api-reference/songs/catalogs.mdx b/api-reference/songs/catalogs.mdx deleted file mode 100644 index 357d672..0000000 --- a/api-reference/songs/catalogs.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Get Catalogs -openapi: get /api/catalogs ---- - - - The Catalogs API also supports POST for creating/linking catalogs and DELETE for unlinking catalogs. See the [Create Catalogs](/api-reference/songs/catalogs-create) and [Delete Catalogs](/api-reference/songs/catalogs-delete) endpoints. - diff --git a/api-reference/songs/create.mdx b/api-reference/songs/create.mdx deleted file mode 100644 index 58ce3ff..0000000 --- a/api-reference/songs/create.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Create Songs -openapi: post /api/songs ---- - - - This endpoint performs bulk create/fetch operations. For each song, the API attempts to look up metadata via internal search. If no data is found, optional fallback fields (name, album, notes, artists) are used. - diff --git a/api-reference/songs/songs.mdx b/api-reference/songs/songs.mdx deleted file mode 100644 index 207cf9a..0000000 --- a/api-reference/songs/songs.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Get Songs -openapi: get /api/songs ---- - - - The Songs API also supports POST requests for bulk create/fetch operations. See the [Create Songs](/api-reference/songs/create) endpoint. - diff --git a/api-reference/spotify/album.mdx b/api-reference/spotify/album.mdx deleted file mode 100644 index a3be57d..0000000 --- a/api-reference/spotify/album.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Album' -openapi: 'GET /api/spotify/album' ---- diff --git a/api-reference/spotify/artist-albums.mdx b/api-reference/spotify/artist-albums.mdx deleted file mode 100644 index 9dcfb8d..0000000 --- a/api-reference/spotify/artist-albums.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Artist Albums' -openapi: 'GET /api/spotify/artist/albums' ---- diff --git a/api-reference/spotify/artist-top-tracks.mdx b/api-reference/spotify/artist-top-tracks.mdx deleted file mode 100644 index 426b7af..0000000 --- a/api-reference/spotify/artist-top-tracks.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Artist Top Tracks' -openapi: 'GET /api/spotify/artist/topTracks' ---- diff --git a/api-reference/spotify/artist.mdx b/api-reference/spotify/artist.mdx deleted file mode 100644 index de4204c..0000000 --- a/api-reference/spotify/artist.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Artist' -openapi: 'GET /api/spotify/artist/' ---- diff --git a/api-reference/spotify/search.mdx b/api-reference/spotify/search.mdx deleted file mode 100644 index aea2441..0000000 --- a/api-reference/spotify/search.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Search' -openapi: 'GET /api/spotify/search' ---- diff --git a/api-reference/subscriptions/get.mdx b/api-reference/subscriptions/get.mdx deleted file mode 100644 index d513375..0000000 --- a/api-reference/subscriptions/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Subscriptions' -openapi: 'GET /api/subscriptions' ---- diff --git a/api-reference/tasks/create.mdx b/api-reference/tasks/create.mdx deleted file mode 100644 index 99a6e51..0000000 --- a/api-reference/tasks/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Task' -openapi: 'POST /api/tasks' ---- diff --git a/api-reference/tasks/delete.mdx b/api-reference/tasks/delete.mdx deleted file mode 100644 index 7a34680..0000000 --- a/api-reference/tasks/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Task' -openapi: 'DELETE /api/tasks' ---- diff --git a/api-reference/tasks/get.mdx b/api-reference/tasks/get.mdx deleted file mode 100644 index facff38..0000000 --- a/api-reference/tasks/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Tasks' -openapi: 'GET /api/tasks' ---- diff --git a/api-reference/tasks/runs.mdx b/api-reference/tasks/runs.mdx deleted file mode 100644 index 6b5b120..0000000 --- a/api-reference/tasks/runs.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Task Runs' -openapi: 'GET /api/tasks/runs' ---- diff --git a/api-reference/tasks/update.mdx b/api-reference/tasks/update.mdx deleted file mode 100644 index a6b1a01..0000000 --- a/api-reference/tasks/update.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Task' -openapi: 'PATCH /api/tasks' ---- diff --git a/api-reference/transcribe/audio.mdx b/api-reference/transcribe/audio.mdx deleted file mode 100644 index 88fd6a0..0000000 --- a/api-reference/transcribe/audio.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Transcribe Audio' -openapi: 'POST /api/transcribe' ---- diff --git a/api-reference/workspaces/create.mdx b/api-reference/workspaces/create.mdx deleted file mode 100644 index 1c12f63..0000000 --- a/api-reference/workspaces/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Create Workspace -openapi: POST /api/workspaces ---- diff --git a/api-reference/x/search.mdx b/api-reference/x/search.mdx deleted file mode 100644 index f361d8c..0000000 --- a/api-reference/x/search.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Search Tweets' -openapi: 'GET /api/x/search' ---- diff --git a/api-reference/x/trends.mdx b/api-reference/x/trends.mdx deleted file mode 100644 index 07497b7..0000000 --- a/api-reference/x/trends.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Trends' -openapi: 'GET /api/x/trends' ---- diff --git a/docs.json b/docs.json index 5a49eac..9712894 100644 --- a/docs.json +++ b/docs.json @@ -44,227 +44,66 @@ }, { "group": "Chat", - "pages": [ - "api-reference/chat/chats", - "api-reference/chat/artist", - "api-reference/chat/segment", - "api-reference/chat/messages", - "api-reference/chat/messages-copy", - "api-reference/chat/messages-trailing-delete", - "api-reference/chat/create", - "api-reference/chat/update", - "api-reference/chat/delete", - "api-reference/chat/generate", - "api-reference/chat/stream", - "api-reference/chat/compact" - ] - }, - { - "group": "Pulses", - "pages": [ - "api-reference/pulses/list", - "api-reference/pulses/update" - ] + "openapi": { + "source": "api-reference/openapi/chats.json", + "directory": "api-reference/chat" + } }, { "group": "Tasks", - "pages": [ - "api-reference/tasks/get", - "api-reference/tasks/create", - "api-reference/tasks/update", - "api-reference/tasks/delete", - "api-reference/tasks/runs" - ] + "openapi": { + "source": "api-reference/openapi/tasks.json", + "directory": "api-reference/tasks" + } }, { "group": "Accounts", - "pages": [ - "api-reference/accounts/get", - "api-reference/accounts/id", - "api-reference/accounts/create", - "api-reference/accounts/update", - "api-reference/accounts/add-artist" - ] + "openapi": { + "source": "api-reference/openapi/accounts.json", + "directory": "api-reference/accounts" + } }, { "group": "Admins", - "pages": [ - "api-reference/admins/check", - "api-reference/admins/sandboxes", - "api-reference/admins/sandboxes-orgs", - "api-reference/admins/emails", - "api-reference/admins/privy", - "api-reference/admins/coding-agent-slack-tags", - "api-reference/admins/coding-pr", - "api-reference/admins/content-slack-tags" - ] + "openapi": { + "source": "api-reference/openapi/admins.json", + "directory": "api-reference/admins" + } }, { "group": "Artists", - "pages": [ - "api-reference/artists/list", - "api-reference/artists/create", - "api-reference/artist/segments", - "api-reference/artist/socials", - "api-reference/artist/socials-scrape", - "api-reference/artist/profile" - ] - }, - { - "group": "Segment", - "pages": [ - "api-reference/segment/fans" - ] - }, - { - "group": "Fans", - "pages": [ - "api-reference/fans/get" - ] - }, - { - "group": "Posts", - "pages": [ - "api-reference/posts/get" - ] - }, - { - "group": "Post", - "pages": [ - "api-reference/post/comments" - ] - }, - { - "group": "Comments", - "pages": [ - "api-reference/comments/get" - ] - }, - { - "group": "Organizations", - "pages": [ - "api-reference/organizations/list", - "api-reference/organizations/create", - "api-reference/organizations/add-artist" - ] - }, - { - "group": "Workspaces", - "pages": [ - "api-reference/workspaces/create" - ] - }, - { - "group": "Spotify", - "pages": [ - "api-reference/spotify/search", - "api-reference/spotify/artist", - "api-reference/spotify/artist-albums", - "api-reference/spotify/artist-top-tracks", - "api-reference/spotify/album" - ] - }, - { - "group": "Instagram", - "pages": [ - "api-reference/instagram/comments", - "api-reference/instagram/profiles" - ] - }, - { - "group": "X (Twitter)", - "pages": [ - "api-reference/x/search", - "api-reference/x/trends" - ] + "openapi": { + "source": "api-reference/openapi/artists.json", + "directory": "api-reference/artists" + } }, { "group": "Social", - "pages": [ - "api-reference/social/scrape", - "api-reference/social/posts" - ] - }, - { - "group": "Image", - "pages": [ - "api-reference/image/generation" - ] - }, - { - "group": "Transcribe", - "pages": [ - "api-reference/transcribe/audio" - ] - }, - { - "group": "Songs & Catalogs", - "pages": [ - "api-reference/songs/songs", - "api-reference/songs/create", - "api-reference/songs/analyze", - "api-reference/songs/analyze-presets", - "api-reference/songs/catalogs", - "api-reference/songs/catalogs-create", - "api-reference/songs/catalogs-delete", - "api-reference/songs/catalog-songs", - "api-reference/songs/catalog-songs-add", - "api-reference/songs/catalog-songs-delete" - ] - }, - { - "group": "Subscriptions", - "pages": [ - "api-reference/subscriptions/get" - ] - }, - { - "group": "Notifications", - "pages": [ - "api-reference/notifications/create" - ] + "openapi": { + "source": "api-reference/openapi/social.json", + "directory": "api-reference/social" + } }, { - "group": "Apify", - "pages": [ - "api-reference/apify/scraper" - ] + "group": "Content", + "openapi": { + "source": "api-reference/openapi/content.json", + "directory": "api-reference/content" + } }, { "group": "Sandboxes", - "pages": [ - "api-reference/sandboxes/list", - "api-reference/sandboxes/create", - "api-reference/sandboxes/snapshot", - "api-reference/sandboxes/delete", - "api-reference/sandboxes/setup", - "api-reference/sandboxes/file", - "api-reference/sandboxes/upload" - ] + "openapi": { + "source": "api-reference/openapi/sandboxes.json", + "directory": "api-reference/sandboxes" + } }, { - "group": "Connectors", - "pages": [ - "api-reference/connectors/list", - "api-reference/connectors/authorize", - "api-reference/connectors/disconnect" - ] - }, - { - "group": "Content", - "pages": [ - "api-reference/content/create", - "api-reference/content/templates", - "api-reference/content/validate", - "api-reference/content/estimate" - ] - }, - { - "group": "Content Agent", - "pages": [ - "api-reference/content-agent/webhook", - "api-reference/content-agent/callback" - ] + "group": "General", + "openapi": { + "source": "api-reference/openapi/general.json", + "directory": "api-reference/general" + } } ] }