{ "openapi": "3.1.0", "info": { "title": "Fandom API", "version": "1.0.0", "description": "Campaigns, targeting, audiences, data stores, brands and Audience Exploration. The same operations are available as MCP tools at /mcp." }, "servers": [ { "url": "https://www.fandom.ai/api/v1" } ], "security": [ { "bearerAuth": [] } ], "tags": [ { "name": "Workspace", "description": "What's in the workspace." }, { "name": "Campaigns", "description": "Campaigns, as the app's Marketing section shows them." }, { "name": "Targeting", "description": "Keywords, segments, topics and websites for each audience on a campaign." }, { "name": "Google Ads", "description": "Connected accounts, performance, and creating campaigns in Google Ads." }, { "name": "Audiences", "description": "Saved audiences you can attach to campaigns." }, { "name": "Data stores", "description": "YouTube channels and videos, with their comments, that audiences are built from." }, { "name": "Brands", "description": "Brands that campaigns belong to." }, { "name": "Audience Exploration", "description": "Who an audience is on YouTube: the channels they watch and how they group." } ], "paths": { "/workspace": { "get": { "operationId": "get_workspace", "tags": [ "Workspace" ], "summary": "Get the workspace", "description": "The workspace this key belongs to: counts and the most recent campaigns. A good first call.\n\nScope: `campaigns:read`.", "parameters": [], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "slug": { "type": "string" }, "counts": { "type": "object", "properties": { "campaigns": { "type": "number" }, "audiences": { "type": "number" }, "dataStores": { "type": "number" }, "brands": { "type": "number" } }, "required": [ "campaigns", "audiences", "dataStores", "brands" ], "additionalProperties": false }, "recentCampaigns": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } }, "required": [ "slug", "counts", "recentCampaigns" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/search": { "get": { "operationId": "search_workspace", "tags": [ "Workspace" ], "summary": "Search the workspace", "description": "Find campaigns, audiences, data stores and brands by name in one call.\n\nScope: `campaigns:read`.", "parameters": [ { "name": "q", "in": "query", "required": true, "description": "Text to look for in names.", "schema": { "type": "string", "minLength": 1, "maxLength": 200 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "campaigns": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "additionalProperties": false } }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "additionalProperties": false } }, "dataStores": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "additionalProperties": false } }, "brands": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "additionalProperties": false } } }, "required": [ "campaigns", "audiences", "dataStores", "brands" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/campaigns": { "get": { "operationId": "list_campaigns", "tags": [ "Campaigns" ], "summary": "List campaigns", "description": "Newest first.\n\nScope: `campaigns:read`.", "parameters": [ { "name": "search", "in": "query", "required": false, "description": "Only items whose name contains this text.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 200 } ] } }, { "name": "limit", "in": "query", "required": false, "description": "How many to return, 1–100. Default 25.", "schema": { "anyOf": [ { "not": {} }, { "type": "integer", "minimum": 1, "maximum": 100 } ] } }, { "name": "cursor", "in": "query", "required": false, "description": "The `nextCursor` from the previous page.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 64 } ] } }, { "name": "brandId", "in": "query", "required": false, "description": "Only this brand's campaigns.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Brand id." } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } }, "nextCursor": { "type": [ "string", "null" ], "description": "Pass as `cursor` to get the next page. Null on the last page." } }, "required": [ "data", "nextCursor" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "post": { "operationId": "create_campaign", "tags": [ "Campaigns" ], "summary": "Create a campaign", "description": "Creates the campaign exactly as the app's New campaign form does. Audiences you pass are attached and start generating targeting right away. Nothing is sent to Google Ads.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "campaignType": { "type": "string", "enum": [ "SEARCH", "DEMAND_GEN", "VIDEO", "DISPLAY" ], "description": "Google Ads campaign type." }, "objective": { "type": "string", "maxLength": 4000, "description": "What the campaign should achieve and for whom. Drives targeting." }, "brandId": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Fills the brand's name, website and description into the campaign." }, "audienceIds": { "type": "array", "items": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Audience id." }, "maxItems": 25 }, "googleAdsCustomerId": { "type": "string", "pattern": "^\\d{3}-?\\d{3}-?\\d{4}$", "description": "A connected Google Ads account to create it in later. See List Google Ads accounts." }, "budget": { "type": "number", "exclusiveMinimum": 0, "maximum": 10000000, "description": "Daily budget." }, "biddingStrategy": { "type": "string", "enum": [ "MAXIMIZE_CONVERSIONS", "MAXIMIZE_CONVERSION_VALUE", "TARGET_CPA", "TARGET_ROAS", "TARGET_CPC", "TARGET_SPEND", "MANUAL_CPC" ], "description": "Google Ads bidding strategy." }, "industry": { "type": "string", "maxLength": 120 }, "language": { "type": "string", "maxLength": 20, "description": "Language code. Default `en`." }, "locations": { "type": "array", "items": { "type": "string", "maxLength": 80 }, "maxItems": 20, "description": "Country or region codes, e.g. `[\"US\"]`. Default `[\"US\"]`." }, "successMetrics": { "type": "array", "items": { "type": "string", "maxLength": 200 }, "maxItems": 20 } }, "required": [ "name", "campaignType" ], "additionalProperties": false }, "example": { "name": "Spring launch", "campaignType": "DEMAND_GEN", "objective": "Reach parents who buy building toys for kids 6–12", "budget": 50 } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "403": { "$ref": "#/components/responses/Forbidden" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/campaigns/{campaignId}": { "get": { "operationId": "get_campaign", "tags": [ "Campaigns" ], "summary": "Get a campaign", "description": "One campaign, with its audiences and Google Ads link.\n\nScope: `campaigns:read`.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "patch": { "operationId": "update_campaign", "tags": [ "Campaigns" ], "summary": "Update a campaign", "description": "Send only the fields to change. Google Ads settings are saved in Fandom; a campaign already in Google Ads picks them up on its next sync from the app.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "objective": { "type": "string", "maxLength": 4000, "description": "What the campaign should achieve and for whom. Drives targeting." }, "brandId": { "anyOf": [ { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Brand id." }, { "type": "null" } ], "description": "Null removes the brand." }, "industry": { "type": "string", "maxLength": 120 }, "language": { "type": "string", "maxLength": 20, "description": "Language code. Default `en`." }, "locations": { "type": "array", "items": { "type": "string", "maxLength": 80 }, "maxItems": 20, "description": "Country or region codes, e.g. `[\"US\"]`. Default `[\"US\"]`." }, "successMetrics": { "type": "array", "items": { "type": "string", "maxLength": 200 }, "maxItems": 20 }, "campaignType": { "type": "string", "enum": [ "SEARCH", "DEMAND_GEN", "VIDEO", "DISPLAY" ], "description": "Google Ads campaign type." }, "budget": { "anyOf": [ { "type": "number", "exclusiveMinimum": 0, "maximum": 10000000 }, { "type": "null" } ] }, "budgetType": { "type": "string", "enum": [ "daily", "total" ] }, "endDate": { "anyOf": [ { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, { "type": "null" } ], "description": "YYYY-MM-DD. Required for a total budget." }, "biddingStrategy": { "anyOf": [ { "type": "string", "enum": [ "MAXIMIZE_CONVERSIONS", "MAXIMIZE_CONVERSION_VALUE", "TARGET_CPA", "TARGET_ROAS", "TARGET_CPC", "TARGET_SPEND", "MANUAL_CPC" ], "description": "Google Ads bidding strategy." }, { "type": "null" } ], "description": "Google Ads bidding strategy." }, "targetCpa": { "anyOf": [ { "type": "number", "exclusiveMinimum": 0, "maximum": 1000000 }, { "type": "null" } ] }, "targetRoas": { "anyOf": [ { "type": "number", "exclusiveMinimum": 0, "maximum": 1000 }, { "type": "null" } ] } }, "additionalProperties": false }, "example": { "name": "Spring launch (US and Canada)", "budget": 75, "locations": [ "US", "CA" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "delete": { "operationId": "delete_campaign", "tags": [ "Campaigns" ], "summary": "Delete a campaign", "description": "Removes it from Fandom. A linked Google Ads campaign is not touched.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "const": true } }, "required": [ "id", "deleted" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/campaigns/{campaignId}/audiences": { "post": { "operationId": "add_campaign_audience", "tags": [ "Campaigns" ], "summary": "Add an audience to a campaign", "description": "Attaches a saved audience and, by default, starts generating its targeting.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "audienceId": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Audience id." }, "generateTargeting": { "type": "boolean", "description": "Start generating targeting now. Default true." } }, "required": [ "audienceId" ], "additionalProperties": false }, "example": { "audienceId": "6524f0c1e4b0a1b2c3d4e5f6" } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/campaigns/{campaignId}/targeting": { "get": { "operationId": "get_campaign_targeting", "tags": [ "Targeting" ], "summary": "Get targeting", "description": "Each audience's keywords, segments, topics and websites. Everything listed is in the campaign's targeting and goes to Google Ads on the next sync.\n\nScope: `campaigns:read`.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "campaignId": { "type": "string" }, "campaignType": { "type": [ "string", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The audience's slot on the campaign." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ] }, "status": { "type": "string", "enum": [ "not_generated", "generating", "ready", "error" ], "description": "Generation takes 30–90 seconds." }, "error": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "items": { "type": "array", "items": { "type": "object", "properties": { "section": { "type": "string" }, "label": { "type": "string", "description": "The section's name in the app." }, "text": { "type": "string" }, "matchType": { "type": [ "string", "null" ], "description": "Keywords only: BROAD, PHRASE or EXACT." }, "source": { "type": "string", "description": "`generated`, `manual`, `rfp`, `imported`…" } }, "required": [ "section", "label", "text", "matchType", "source" ], "additionalProperties": false } } }, "required": [ "id", "name", "audienceId", "status", "error", "updatedAt", "items" ], "additionalProperties": false } } }, "required": [ "campaignId", "campaignType", "audiences" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "patch": { "operationId": "edit_campaign_targeting", "tags": [ "Targeting" ], "summary": "Add or remove targeting", "description": "The app's Add and Delete for one audience. Removed terms come out of Google Ads on the next sync. Not allowed while the audience is generating.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "audienceId": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The audience slot (the `id` in Get targeting)." }, "add": { "type": "array", "items": { "type": "object", "properties": { "section": { "type": "string", "enum": [ "keywords", "negativeKeywords", "caaWebsites", "websites", "adCategories", "adAffinities", "adInMarketAffinities", "adLifeEvents", "adDetailedDemographics", "adDemographics", "cia", "caaApps" ], "description": "`keywords`, `negativeKeywords`, `caaWebsites` (websites), `adCategories` (topics), `adAffinities`, `adInMarketAffinities`, `adLifeEvents`, `adDetailedDemographics`, `adDemographics`, `cia` (custom intent) or `caaApps`. Which apply depends on the campaign type." }, "text": { "type": "string", "minLength": 1, "maxLength": 500 }, "matchType": { "type": "string", "enum": [ "BROAD", "PHRASE", "EXACT" ], "description": "Keywords only." } }, "required": [ "section", "text" ], "additionalProperties": false }, "maxItems": 200 }, "remove": { "type": "array", "items": { "type": "object", "properties": { "section": { "type": "string", "enum": [ "keywords", "negativeKeywords", "caaWebsites", "websites", "adCategories", "adAffinities", "adInMarketAffinities", "adLifeEvents", "adDetailedDemographics", "adDemographics", "cia", "caaApps" ], "description": "`keywords`, `negativeKeywords`, `caaWebsites` (websites), `adCategories` (topics), `adAffinities`, `adInMarketAffinities`, `adLifeEvents`, `adDetailedDemographics`, `adDemographics`, `cia` (custom intent) or `caaApps`. Which apply depends on the campaign type." }, "text": { "type": "string", "minLength": 1, "maxLength": 500 } }, "required": [ "section", "text" ], "additionalProperties": false }, "maxItems": 200 } }, "required": [ "audienceId" ], "additionalProperties": false }, "example": { "audienceId": "aud-ent-6524f0c1e4b0a1b2c3d4e5f6", "add": [ { "section": "keywords", "text": "building sets for kids", "matchType": "PHRASE" } ], "remove": [ { "section": "adAffinities", "text": "Travel" } ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "added": { "type": "number" }, "updated": { "type": "number" }, "removed": { "type": "number" }, "audience": { "type": "object", "properties": { "id": { "type": "string", "description": "The audience's slot on the campaign." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ] }, "status": { "type": "string", "enum": [ "not_generated", "generating", "ready", "error" ], "description": "Generation takes 30–90 seconds." }, "error": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "items": { "type": "array", "items": { "type": "object", "properties": { "section": { "type": "string" }, "label": { "type": "string", "description": "The section's name in the app." }, "text": { "type": "string" }, "matchType": { "type": [ "string", "null" ], "description": "Keywords only: BROAD, PHRASE or EXACT." }, "source": { "type": "string", "description": "`generated`, `manual`, `rfp`, `imported`…" } }, "required": [ "section", "label", "text", "matchType", "source" ], "additionalProperties": false } } }, "required": [ "id", "name", "audienceId", "status", "error", "updatedAt", "items" ], "additionalProperties": false } }, "required": [ "added", "updated", "removed", "audience" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/campaigns/{campaignId}/targeting/generate": { "post": { "operationId": "generate_campaign_targeting", "tags": [ "Targeting" ], "summary": "Generate targeting", "description": "Starts generating in the background. With no `audienceIds`, generates every audience that has none yet; naming an audience regenerates it. Audiences need data stores. Poll Get targeting until `ready`.\n\nScope: `campaigns:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "audienceIds": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 25, "description": "Audience slots on the campaign (the `id` in Get targeting)." } }, "additionalProperties": false }, "example": { "audienceIds": [ "aud-ent-6524f0c1e4b0a1b2c3d4e5f6" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "campaignId": { "type": "string" }, "campaignType": { "type": [ "string", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The audience's slot on the campaign." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ] }, "status": { "type": "string", "enum": [ "not_generated", "generating", "ready", "error" ], "description": "Generation takes 30–90 seconds." }, "error": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "items": { "type": "array", "items": { "type": "object", "properties": { "section": { "type": "string" }, "label": { "type": "string", "description": "The section's name in the app." }, "text": { "type": "string" }, "matchType": { "type": [ "string", "null" ], "description": "Keywords only: BROAD, PHRASE or EXACT." }, "source": { "type": "string", "description": "`generated`, `manual`, `rfp`, `imported`…" } }, "required": [ "section", "label", "text", "matchType", "source" ], "additionalProperties": false } } }, "required": [ "id", "name", "audienceId", "status", "error", "updatedAt", "items" ], "additionalProperties": false } }, "started": { "type": "array", "items": { "type": "string" } }, "skipped": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "reason": { "type": "string" } }, "required": [ "id", "reason" ], "additionalProperties": false } } }, "required": [ "campaignId", "campaignType", "audiences", "started", "skipped" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/google-ads/accounts": { "get": { "operationId": "list_google_ads_accounts", "tags": [ "Google Ads" ], "summary": "List Google Ads accounts", "description": "The workspace's connected Google Ads accounts.\n\nScope: `google-ads:read`.", "parameters": [], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "customerId": { "type": "string" }, "name": { "type": "string" }, "currency": { "type": [ "string", "null" ] }, "timeZone": { "type": [ "string", "null" ] }, "isManager": { "type": "boolean" }, "canCreateCampaigns": { "type": "boolean", "description": "False for manager accounts: create in one of their client accounts." } }, "required": [ "customerId", "name", "currency", "timeZone", "isManager", "canCreateCampaigns" ], "additionalProperties": false } }, "nextCursor": { "type": [ "string", "null" ], "description": "Pass as `cursor` to get the next page. Null on the last page." } }, "required": [ "data", "nextCursor" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" }, "502": { "$ref": "#/components/responses/UpstreamError" } } } }, "/google-ads/performance": { "get": { "operationId": "get_google_ads_performance", "tags": [ "Google Ads" ], "summary": "Get performance", "description": "Impressions, clicks, cost and conversions for the Fandom campaigns in one account.\n\nScope: `google-ads:read`.", "parameters": [ { "name": "customerId", "in": "query", "required": true, "description": "Google Ads customer id, with or without dashes.", "schema": { "type": "string", "pattern": "^\\d{3}-?\\d{3}-?\\d{4}$" } }, { "name": "dateRange", "in": "query", "required": false, "description": "Default LAST_30_DAYS.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "enum": [ "LAST_7_DAYS", "LAST_14_DAYS", "LAST_30_DAYS", "LAST_90_DAYS" ] } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "customerId": { "type": "string" }, "dateRange": { "type": "object", "properties": { "preset": { "type": "string" }, "startDate": { "type": "string" }, "endDate": { "type": "string" } }, "required": [ "preset", "startDate", "endDate" ], "additionalProperties": false }, "campaigns": { "type": "array", "items": { "type": "object", "properties": { "campaignId": { "type": "string", "description": "Fandom campaign id." }, "name": { "type": "string" }, "googleAdsCampaignId": { "type": [ "string", "null" ] }, "campaignType": { "type": [ "string", "null" ] }, "status": { "type": "string", "description": "Google's status, `NOT_LINKED` or `NO_DATA`." }, "impressions": { "type": "number" }, "clicks": { "type": "number" }, "cost": { "type": "number", "description": "In the account's currency." }, "conversions": { "type": "number" }, "ctr": { "type": "number", "description": "Click-through rate, in percent." }, "cpc": { "type": "number" }, "costPerConversion": { "type": "number" }, "roas": { "type": "number" } }, "required": [ "campaignId", "name", "googleAdsCampaignId", "campaignType", "status", "impressions", "clicks", "cost", "conversions", "ctr", "cpc", "costPerConversion", "roas" ], "additionalProperties": false } }, "daily": { "type": "array", "items": { "type": "object", "properties": { "date": { "type": "string" }, "impressions": { "type": "number" }, "clicks": { "type": "number" }, "cost": { "type": "number" }, "conversions": { "type": "number" } }, "required": [ "date", "impressions", "clicks", "cost", "conversions" ], "additionalProperties": false } } }, "required": [ "customerId", "dateRange", "campaigns", "daily" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" }, "502": { "$ref": "#/components/responses/UpstreamError" } } } }, "/campaigns/{campaignId}/google-ads": { "post": { "operationId": "create_google_ads_campaign", "tags": [ "Google Ads" ], "summary": "Create in Google Ads", "description": "Creates the campaign in Google Ads, paused, exactly as the campaign page does. Nothing spends until someone turns it on in Google Ads. Targeting goes over when the app syncs.\n\nScope: `google-ads:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "campaignId", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "customerId": { "type": "string", "pattern": "^\\d{3}-?\\d{3}-?\\d{4}$", "description": "The account to create it in. Defaults to the campaign's account." } }, "additionalProperties": false }, "example": { "customerId": "1234567890" } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "description": "`draft`, `loading` (collecting data), `ready` or `error`." }, "objective": { "type": "string" }, "brandId": { "type": [ "string", "null" ] }, "brand": { "type": "object", "properties": { "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" } }, "required": [ "name", "website", "description" ], "additionalProperties": false }, "industry": { "type": "string" }, "language": { "type": "string" }, "locations": { "type": "array", "items": { "type": "string" } }, "successMetrics": { "type": "array", "items": { "type": "string" } }, "campaignType": { "type": [ "string", "null" ] }, "budget": { "type": [ "number", "null" ], "description": "In the account's currency." }, "budgetType": { "anyOf": [ { "type": "string", "enum": [ "daily", "total" ] }, { "type": "null" } ] }, "endDate": { "type": [ "string", "null" ] }, "biddingStrategy": { "type": [ "string", "null" ] }, "targetCpa": { "type": [ "number", "null" ] }, "targetRoas": { "type": [ "number", "null" ] }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "This audience's slot on the campaign. Stable; use it for targeting." }, "name": { "type": "string" }, "audienceId": { "type": [ "string", "null" ], "description": "The saved audience, or null for the campaign's own primary audience." }, "dataStoreIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "audienceId", "dataStoreIds" ], "additionalProperties": false } }, "googleAds": { "type": "object", "properties": { "customerId": { "type": [ "string", "null" ] }, "accountName": { "type": [ "string", "null" ] }, "campaignId": { "type": [ "string", "null" ], "description": "Set once the campaign exists in Google Ads." }, "status": { "type": [ "string", "null" ] } }, "required": [ "customerId", "accountName", "campaignId", "status" ], "additionalProperties": false }, "url": { "type": "string", "description": "Opens the campaign in Fandom." }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "status", "objective", "brandId", "brand", "industry", "language", "locations", "successMetrics", "campaignType", "budget", "budgetType", "endDate", "biddingStrategy", "targetCpa", "targetRoas", "audiences", "googleAds", "url", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" }, "502": { "$ref": "#/components/responses/UpstreamError" } } } }, "/audiences": { "get": { "operationId": "list_audiences", "tags": [ "Audiences" ], "summary": "List audiences", "description": "Saved audiences, newest first.\n\nScope: `audiences:read`.", "parameters": [ { "name": "search", "in": "query", "required": false, "description": "Only items whose name contains this text.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 200 } ] } }, { "name": "limit", "in": "query", "required": false, "description": "How many to return, 1–100. Default 25.", "schema": { "anyOf": [ { "not": {} }, { "type": "integer", "minimum": 1, "maximum": 100 } ] } }, { "name": "cursor", "in": "query", "required": false, "description": "The `nextCursor` from the previous page.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 64 } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "kind": { "type": "string", "description": "`custom`, `rfp` (from a brief) or `preset`." }, "keywords": { "type": "array", "items": { "type": "string" } }, "topics": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "array", "items": { "type": "string" } }, "dataStoreIds": { "type": "array", "items": { "type": "string" } }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "kind", "keywords", "topics", "tags", "dataStoreIds", "createdAt", "updatedAt" ], "additionalProperties": false } }, "nextCursor": { "type": [ "string", "null" ], "description": "Pass as `cursor` to get the next page. Null on the last page." } }, "required": [ "data", "nextCursor" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "post": { "operationId": "create_audience", "tags": [ "Audiences" ], "summary": "Create an audience", "description": "Names must be unique in the workspace. Link data stores so targeting has real data behind it.\n\nScope: `audiences:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "description": { "type": "string", "maxLength": 4000, "description": "Who these people are, in plain words. Drives targeting." }, "keywords": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 200 }, "topics": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 }, "tags": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 100 }, "maxItems": 50 }, "dataStoreIds": { "type": "array", "items": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Data store id." }, "maxItems": 25, "description": "Data stores this audience is built from." } }, "required": [ "name" ], "additionalProperties": false }, "example": { "name": "Parents of young builders", "description": "Parents buying building sets for kids 6–12", "keywords": [ "building sets", "stem toys" ], "dataStoreIds": [ "6524f0c1e4b0a1b2c3d4e5f6" ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "kind": { "type": "string", "description": "`custom`, `rfp` (from a brief) or `preset`." }, "keywords": { "type": "array", "items": { "type": "string" } }, "topics": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "array", "items": { "type": "string" } }, "dataStoreIds": { "type": "array", "items": { "type": "string" } }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "kind", "keywords", "topics", "tags", "dataStoreIds", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/audiences/{audienceId}": { "get": { "operationId": "get_audience", "tags": [ "Audiences" ], "summary": "Get an audience", "description": "One saved audience.\n\nScope: `audiences:read`.", "parameters": [ { "name": "audienceId", "in": "path", "required": true, "description": "Audience id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "kind": { "type": "string", "description": "`custom`, `rfp` (from a brief) or `preset`." }, "keywords": { "type": "array", "items": { "type": "string" } }, "topics": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "array", "items": { "type": "string" } }, "dataStoreIds": { "type": "array", "items": { "type": "string" } }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "kind", "keywords", "topics", "tags", "dataStoreIds", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "patch": { "operationId": "update_audience", "tags": [ "Audiences" ], "summary": "Update an audience", "description": "Send only the fields to change. Lists replace the stored list. Campaigns keep the copy they attached.\n\nScope: `audiences:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "audienceId", "in": "path", "required": true, "description": "Audience id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "description": { "type": "string", "maxLength": 4000, "description": "Who these people are, in plain words. Drives targeting." }, "keywords": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 200 }, "topics": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 200 }, "maxItems": 100 }, "tags": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 100 }, "maxItems": 50 }, "dataStoreIds": { "type": "array", "items": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Data store id." }, "maxItems": 25, "description": "Data stores this audience is built from." } }, "additionalProperties": false }, "example": { "description": "Parents and grandparents buying building sets", "tags": [ "toys" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "kind": { "type": "string", "description": "`custom`, `rfp` (from a brief) or `preset`." }, "keywords": { "type": "array", "items": { "type": "string" } }, "topics": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "array", "items": { "type": "string" } }, "dataStoreIds": { "type": "array", "items": { "type": "string" } }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "kind", "keywords", "topics", "tags", "dataStoreIds", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "delete": { "operationId": "delete_audience", "tags": [ "Audiences" ], "summary": "Delete an audience", "description": "Removes it from the workspace. Campaigns that use it keep their copy.\n\nScope: `audiences:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "audienceId", "in": "path", "required": true, "description": "Audience id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "const": true } }, "required": [ "id", "deleted" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/data-stores": { "get": { "operationId": "list_data_stores", "tags": [ "Data stores" ], "summary": "List data stores", "description": "The workspace's data stores, newest first.\n\nScope: `datasets:read`.", "parameters": [ { "name": "search", "in": "query", "required": false, "description": "Only items whose name contains this text.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 200 } ] } }, { "name": "limit", "in": "query", "required": false, "description": "How many to return, 1–100. Default 25.", "schema": { "anyOf": [ { "not": {} }, { "type": "integer", "minimum": 1, "maximum": 100 } ] } }, { "name": "cursor", "in": "query", "required": false, "description": "The `nextCursor` from the previous page.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 64 } ] } }, { "name": "includeLibrary", "in": "query", "required": false, "description": "Also list Fandom's shared library stores. Default false.", "schema": { "anyOf": [ { "not": {} }, { "type": "boolean" } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string", "description": "`collecting`, `ready` or `error`. Collection usually takes minutes." }, "error": { "type": [ "string", "null" ] }, "scope": { "type": "string", "enum": [ "workspace", "private", "library" ], "description": "`library` stores are shared by Fandom and read-only." }, "channelCount": { "type": "number" }, "videoCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "readyAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "status", "error", "scope", "channelCount", "videoCount", "createdAt", "updatedAt", "readyAt" ], "additionalProperties": false } }, "nextCursor": { "type": [ "string", "null" ], "description": "Pass as `cursor` to get the next page. Null on the last page." } }, "required": [ "data", "nextCursor" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "post": { "operationId": "create_data_store", "tags": [ "Data stores" ], "summary": "Create a data store", "description": "Collects YouTube channels and videos, with their comments, in the background. Starts as `collecting`; poll Get a data store until `ready`.\n\nScope: `datasets:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "sources": { "type": "array", "items": { "type": "object", "properties": { "url": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "A YouTube channel or video URL." }, "type": { "type": "string", "enum": [ "channel", "video" ], "description": "Detected from the URL when left out." }, "videosPerChannel": { "type": "integer", "minimum": 1, "maximum": 50, "description": "Recent videos to read per channel. Default 10." } }, "required": [ "url" ], "additionalProperties": false }, "minItems": 1, "maxItems": 100 }, "private": { "type": "boolean", "description": "Only visible to the key's creator. Default false." } }, "required": [ "name", "sources" ], "additionalProperties": false }, "example": { "name": "Building toy channels", "sources": [ { "url": "https://www.youtube.com/@LEGO", "videosPerChannel": 10 }, { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" } ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string", "description": "`collecting`, `ready` or `error`. Collection usually takes minutes." }, "error": { "type": [ "string", "null" ] }, "scope": { "type": "string", "enum": [ "workspace", "private", "library" ], "description": "`library` stores are shared by Fandom and read-only." }, "channelCount": { "type": "number" }, "videoCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "readyAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "status", "error", "scope", "channelCount", "videoCount", "createdAt", "updatedAt", "readyAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/data-stores/{dataStoreId}": { "get": { "operationId": "get_data_store", "tags": [ "Data stores" ], "summary": "Get a data store", "description": "Check `status` to see when collection is done.\n\nScope: `datasets:read`.", "parameters": [ { "name": "dataStoreId", "in": "path", "required": true, "description": "Data store id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string", "description": "`collecting`, `ready` or `error`. Collection usually takes minutes." }, "error": { "type": [ "string", "null" ] }, "scope": { "type": "string", "enum": [ "workspace", "private", "library" ], "description": "`library` stores are shared by Fandom and read-only." }, "channelCount": { "type": "number" }, "videoCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "readyAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "status", "error", "scope", "channelCount", "videoCount", "createdAt", "updatedAt", "readyAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "patch": { "operationId": "update_data_store", "tags": [ "Data stores" ], "summary": "Rename a data store", "description": "Library stores can't be changed.\n\nScope: `datasets:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "dataStoreId", "in": "path", "required": true, "description": "Data store id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 } }, "required": [ "name" ], "additionalProperties": false }, "example": { "name": "Building toy channels (US)" } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "status": { "type": "string", "description": "`collecting`, `ready` or `error`. Collection usually takes minutes." }, "error": { "type": [ "string", "null" ] }, "scope": { "type": "string", "enum": [ "workspace", "private", "library" ], "description": "`library` stores are shared by Fandom and read-only." }, "channelCount": { "type": "number" }, "videoCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] }, "readyAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "description", "status", "error", "scope", "channelCount", "videoCount", "createdAt", "updatedAt", "readyAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "delete": { "operationId": "delete_data_store", "tags": [ "Data stores" ], "summary": "Delete a data store", "description": "Removes it from the workspace. Library stores can't be deleted.\n\nScope: `datasets:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "dataStoreId", "in": "path", "required": true, "description": "Data store id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "const": true } }, "required": [ "id", "deleted" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/brands": { "get": { "operationId": "list_brands", "tags": [ "Brands" ], "summary": "List brands", "description": "Newest first.\n\nScope: `brands:read`.", "parameters": [ { "name": "search", "in": "query", "required": false, "description": "Only items whose name contains this text.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 200 } ] } }, { "name": "limit", "in": "query", "required": false, "description": "How many to return, 1–100. Default 25.", "schema": { "anyOf": [ { "not": {} }, { "type": "integer", "minimum": 1, "maximum": 100 } ] } }, { "name": "cursor", "in": "query", "required": false, "description": "The `nextCursor` from the previous page.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 64 } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" }, "logoUrl": { "type": "string" }, "campaignCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "website", "description", "logoUrl", "campaignCount", "createdAt", "updatedAt" ], "additionalProperties": false } }, "nextCursor": { "type": [ "string", "null" ], "description": "Pass as `cursor` to get the next page. Null on the last page." } }, "required": [ "data", "nextCursor" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "post": { "operationId": "create_brand", "tags": [ "Brands" ], "summary": "Create a brand", "description": "Campaigns created with this brand inherit its name, website and description.\n\nScope: `brands:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "website": { "type": "string", "maxLength": 500 }, "description": { "type": "string", "maxLength": 2000 }, "logoUrl": { "type": "string", "maxLength": 1000, "description": "An https image URL." } }, "required": [ "name" ], "additionalProperties": false }, "example": { "name": "Brickworks", "website": "brickworks.example", "description": "Building toys for kids 6–12" } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" }, "logoUrl": { "type": "string" }, "campaignCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "website", "description", "logoUrl", "campaignCount", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/brands/{brandId}": { "get": { "operationId": "get_brand", "tags": [ "Brands" ], "summary": "Get a brand", "description": "One brand and how many campaigns use it.\n\nScope: `brands:read`.", "parameters": [ { "name": "brandId", "in": "path", "required": true, "description": "Brand id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" }, "logoUrl": { "type": "string" }, "campaignCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "website", "description", "logoUrl", "campaignCount", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "patch": { "operationId": "update_brand", "tags": [ "Brands" ], "summary": "Update a brand", "description": "Send only the fields to change. Existing campaigns keep the brand details they were created with.\n\nScope: `brands:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "brandId", "in": "path", "required": true, "description": "Brand id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 160 }, "website": { "type": "string", "maxLength": 500 }, "description": { "type": "string", "maxLength": 2000 }, "logoUrl": { "type": "string", "maxLength": 1000, "description": "An https image URL." } }, "additionalProperties": false }, "example": { "description": "Building toys and kits for kids 6–12" } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "website": { "type": "string" }, "description": { "type": "string" }, "logoUrl": { "type": "string" }, "campaignCount": { "type": "number" }, "createdAt": { "type": [ "string", "null" ] }, "updatedAt": { "type": [ "string", "null" ] } }, "required": [ "id", "name", "website", "description", "logoUrl", "campaignCount", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } }, "delete": { "operationId": "delete_brand", "tags": [ "Brands" ], "summary": "Delete a brand", "description": "Removes it from the workspace. Its campaigns stay.\n\nScope: `brands:write`.\n\nSend an `Idempotency-Key` header to make retries safe.", "parameters": [ { "name": "brandId", "in": "path", "required": true, "description": "Brand id.", "schema": { "type": "string", "pattern": "^[a-f0-9]{24}$" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Any unique string. Repeating a request with the same key returns the first result instead of doing it twice.", "schema": { "type": "string", "maxLength": 200 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "const": true } }, "required": [ "id", "deleted" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/exploration/search": { "get": { "operationId": "search_exploration", "tags": [ "Audience Exploration" ], "summary": "Search YouTube audiences", "description": "Find a starting point for a map: channels by name, channels whose audiences talk about your words, topics, and saved audiences. Leave q out to see what the workspace can start from: its campaigns, audiences and brands.\n\nScope: `exploration:read`.", "parameters": [ { "name": "q", "in": "query", "required": false, "description": "A channel name, @handle, YouTube URL or a few words about an audience.", "schema": { "anyOf": [ { "not": {} }, { "type": "string", "maxLength": 200 } ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "query": { "type": "string" }, "startFrom": { "type": "object", "properties": { "campaigns": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "brandName": { "type": "string" } }, "required": [ "id", "name", "brandName" ], "additionalProperties": false } }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "preset": { "type": "boolean" }, "channels": { "type": "number" } }, "required": [ "id", "name", "preset", "channels" ], "additionalProperties": false } }, "brands": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" } }, "required": [ "id", "name", "description" ], "additionalProperties": false } } }, "required": [ "campaigns", "audiences", "brands" ], "additionalProperties": false, "description": "What the workspace can start from. Only when no search words were given." }, "channels": { "type": "array", "items": { "type": "object", "properties": { "channelId": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": [ "string", "null" ] }, "imageUrl": { "type": "string" }, "subscribers": { "type": "number" } }, "required": [ "channelId", "title", "handle", "imageUrl", "subscribers" ], "additionalProperties": false }, "description": "Channels matching by name." }, "similar": { "type": "array", "items": { "type": "object", "properties": { "channelId": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": [ "string", "null" ] }, "imageUrl": { "type": "string" }, "subscribers": { "type": "number" } }, "required": [ "channelId", "title", "handle", "imageUrl", "subscribers" ], "additionalProperties": false }, "description": "Channels whose audiences talk about this, by meaning." }, "topics": { "type": "array", "items": { "type": "object", "properties": { "topic": { "type": "string" }, "kind": { "type": "string", "enum": [ "conversation", "content" ] }, "channels": { "type": "number" } }, "required": [ "topic", "kind", "channels" ], "additionalProperties": false } }, "audiences": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "preset": { "type": "boolean" }, "channels": { "type": "number" } }, "required": [ "id", "name", "preset", "channels" ], "additionalProperties": false } } }, "required": [ "query", "channels", "similar", "topics", "audiences" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/exploration/map": { "post": { "operationId": "build_exploration_map", "tags": [ "Audience Exploration" ], "summary": "Map an audience", "description": "The channels an audience also watches, grouped by shared commenters, with people counts. Built from real YouTube comment data; takes a few seconds the first time. Size 160 is the app's Expand map.\n\nScope: `exploration:read`.", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "sources": { "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "channel" }, "channelId": { "type": "string", "pattern": "^UC[A-Za-z0-9_-]{22}$", "description": "YouTube channel id, e.g. `UCX6OQ3DkcsbYNE6H8uQQuVA`." } }, "required": [ "type", "channelId" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "query" }, "query": { "type": "string", "minLength": 2, "maxLength": 200, "description": "Describe the audience in plain words." } }, "required": [ "type", "query" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "brand" }, "brandId": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Brand id." } }, "required": [ "type", "brandId" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "audience" }, "audienceId": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Audience id." }, "preset": { "type": "boolean", "description": "One of Fandom's own audiences, as search_exploration says. Worked out when you leave it out." } }, "required": [ "type", "audienceId" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "channels" }, "channelIds": { "type": "array", "items": { "type": "string", "pattern": "^UC[A-Za-z0-9_-]{22}$", "description": "YouTube channel id, e.g. `UCX6OQ3DkcsbYNE6H8uQQuVA`." }, "minItems": 1, "maxItems": 16, "description": "A group of channels, mapped as one audience." }, "label": { "type": "string", "minLength": 1, "maxLength": 80, "description": "What to call the group." }, "of": { "type": "array", "items": { "type": "string", "maxLength": 80 }, "maxItems": 4, "description": "What the group was taken from, outermost first, as a group's `expand` says." } }, "required": [ "type", "channelIds", "label" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "topic" }, "topic": { "type": "string", "minLength": 2, "maxLength": 80, "description": "A topic from search_exploration." }, "kind": { "type": "string", "enum": [ "conversation", "content" ], "description": "What viewers talk about, or what channels publish." } }, "required": [ "type", "topic", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "campaign" }, "campaignId": { "type": "string", "pattern": "^[a-f0-9]{24}$", "description": "Campaign id." } }, "required": [ "type", "campaignId" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "link" }, "url": { "type": "string", "minLength": 4, "maxLength": 500, "description": "A YouTube channel or video link, an @handle, or a website." } }, "required": [ "type", "url" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "inclusion_list" }, "listId": { "type": "string", "minLength": 1, "maxLength": 64, "description": "A finished inclusion list: its top channels are mapped." } }, "required": [ "type", "listId" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "project" }, "projectId": { "type": "string", "minLength": 1, "maxLength": 64, "description": "A project: its most relevant channels are mapped." }, "selection": { "type": "string", "maxLength": 200, "description": "Part of its map: a cluster number or name." }, "channelIds": { "type": "array", "items": { "type": "string", "pattern": "^UC[A-Za-z0-9_-]{22}$", "description": "YouTube channel id, e.g. `UCX6OQ3DkcsbYNE6H8uQQuVA`." }, "maxItems": 16, "description": "Or exactly these channels of it." } }, "required": [ "type", "projectId" ], "additionalProperties": false } ] }, "minItems": 1, "maxItems": 8, "description": "What to map. Combine up to 8." }, "size": { "type": "integer", "minimum": 40, "maximum": 160, "description": "Most channels on the map. Default 110." } }, "required": [ "sources" ], "additionalProperties": false }, "example": { "sources": [ { "type": "channel", "channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA" } ], "size": 110 } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" }, "url": { "type": "string", "description": "This map in the app." }, "builtAt": { "type": "string" }, "canExpand": { "type": "boolean", "description": "A bigger map of the same sources may hold more channels: ask for size 160." }, "notes": { "type": "array", "items": { "type": "string" }, "description": "Coverage caveats worth showing to people." }, "audience": { "anyOf": [ { "type": "object", "properties": { "corePeople": { "type": "number" }, "totalPeople": { "type": "number" }, "totalComments": { "type": "number" } }, "required": [ "corePeople", "totalPeople", "totalComments" ], "additionalProperties": false }, { "type": "null" } ], "description": "People counts. Null when they could not be measured in time." }, "groups": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "number" }, "name": { "type": "string" }, "kind": { "type": "string", "enum": [ "core", "adjacent", "unconnected" ], "description": "`core` is the audience you asked about; `adjacent` groups share its commenters." }, "description": { "type": "string", "description": "Who these people are." }, "themes": { "type": "array", "items": { "type": "string" } }, "relevance": { "type": [ "number", "null" ] }, "channelIds": { "type": "array", "items": { "type": "string" } }, "expand": { "type": "object", "properties": { "type": { "type": "string", "const": "channels" }, "channelIds": { "type": "array", "items": { "type": "string" } }, "label": { "type": "string" } }, "required": [ "type", "channelIds", "label" ], "additionalProperties": false, "description": "A source for build_exploration_map: this group as its own map." }, "people": { "type": [ "number", "null" ], "description": "Distinct commenters (sampled, then scaled)." }, "reach": { "type": [ "number", "null" ], "description": "Share of the core audience found here, 0–1." }, "concentration": { "type": [ "number", "null" ], "description": "Share of these people who are in the core audience, 0–1." }, "fanDensity": { "type": [ "number", "null" ], "description": "How many times more common the core audience is here than among everyone we see on YouTube (1.3 = 30% more). Null for the core itself." } }, "required": [ "id", "name", "kind", "description", "themes", "relevance", "channelIds", "expand", "people", "reach", "concentration", "fanDensity" ], "additionalProperties": false } }, "channels": { "type": "array", "items": { "type": "object", "properties": { "channelId": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": [ "string", "null" ] }, "imageUrl": { "type": "string" }, "subscribers": { "type": "number" }, "country": { "type": [ "string", "null" ] }, "groupId": { "type": "number" }, "seed": { "type": "boolean", "description": "One of the channels the map was built from." }, "relevance": { "type": [ "number", "null" ] }, "sharedCommenters": { "type": "number" }, "audienceThemes": { "type": "array", "items": { "type": "string" } }, "contentThemes": { "type": "array", "items": { "type": "string" } }, "people": { "type": [ "number", "null" ], "description": "Distinct commenters (sampled, then scaled)." }, "reach": { "type": [ "number", "null" ], "description": "Share of the core audience found here, 0–1." }, "concentration": { "type": [ "number", "null" ], "description": "Share of these people who are in the core audience, 0–1." }, "fanDensity": { "type": [ "number", "null" ], "description": "How many times more common the core audience is here than among everyone we see on YouTube (1.3 = 30% more). Null for the core itself." } }, "required": [ "channelId", "title", "handle", "imageUrl", "subscribers", "country", "groupId", "seed", "relevance", "sharedCommenters", "audienceThemes", "contentThemes", "people", "reach", "concentration", "fanDensity" ], "additionalProperties": false } } }, "required": [ "title", "url", "builtAt", "canExpand", "notes", "audience", "groups", "channels" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/RateLimited" } } } }, "/exploration/channels/{channelId}": { "get": { "operationId": "get_exploration_channel", "tags": [ "Audience Exploration" ], "summary": "Get a YouTube channel", "description": "What a channel makes, its topics and its latest videos.\n\nScope: `exploration:read`.", "parameters": [ { "name": "channelId", "in": "path", "required": true, "description": "YouTube channel id, e.g. `UCX6OQ3DkcsbYNE6H8uQQuVA`.", "schema": { "type": "string", "pattern": "^UC[A-Za-z0-9_-]{22}$" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "properties": { "channelId": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": [ "string", "null" ] }, "imageUrl": { "type": "string" }, "subscribers": { "type": "number" }, "country": { "type": [ "string", "null" ] }, "topics": { "type": "array", "items": { "type": "string" }, "description": "YouTube's own topic categories." }, "contentThemes": { "type": "array", "items": { "type": "string" }, "description": "What the channel makes." }, "recentTitles": { "type": "array", "items": { "type": "string" } } }, "required": [ "channelId", "title", "handle", "imageUrl", "subscribers", "country", "topics", "contentThemes", "recentTitles" ], "additionalProperties": false } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } } } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "An API key from Settings → API access, starting with `fnd_`." } }, "schemas": { "Error": { "type": "object", "required": [ "error" ], "properties": { "error": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "string", "description": "Stable, machine-readable.", "examples": [ "not_found" ] }, "message": { "type": "string", "description": "Plain-language explanation." }, "requestId": { "type": "string", "description": "Quote this when asking for help." } } } } } }, "responses": { "BadRequest": { "description": "The request is missing something or has a bad value. The message says what.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "Unauthorized": { "description": "No API key, or the key is wrong or revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "PaymentRequired": { "description": "The workspace's plan doesn't include this.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "Forbidden": { "description": "The key doesn't have the scope, or isn't allowed this campaign or account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "NotFound": { "description": "Nothing with that id in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "Conflict": { "description": "The current state doesn't allow this (for example, it's already done or still generating).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "RateLimited": { "description": "More than 120 requests in a minute. Wait and retry.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "UpstreamError": { "description": "Google Ads didn't answer as expected. The message says whether anything changed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }