{"openapi":"3.0.3","info":{"version":"1.0.0","title":"CodivUpload API Reference","description":"Publish content to 11 social media platforms with a single API call.\n\n## Authentication\n\nAll API requests require a Bearer token in the `Authorization` header:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\n### Getting your API Key\n\n1. Log in to [CodivUpload Dashboard](https://app.codivupload.com)\n2. Go to **API Keys** from the sidebar menu\n3. Click **Create API Key** and copy the key\n4. Use the key in the `Authorization` header as shown above\n\n> **Important:** API keys are shown only once at creation. Store them securely. If lost, revoke and create a new one.\n\n> **Plan requirement:** API key access requires **Starter plan** or above. Free plan users can only use the dashboard UI.\n\n### Quick Test\n\n```bash\ncurl -X GET https://api.codivupload.com/v1/agency/profiles \\\n  -H \"Authorization: Bearer YOUR_API_KEY\"\n```\n\nA successful response returns your profiles:\n\n```json\n{\n  \"success\": true,\n  \"profiles\": [\n    {\n      \"id\": \"550e8400-...\",\n      \"profile_name\": \"my_brand\",\n      \"social_accounts\": { \"youtube\": true, \"instagram\": true, \"tiktok\": false }\n    }\n  ]\n}\n```\n\n### Error Responses\n\n| Status | Meaning | Example |\n|---|---|---|\n| `401` | Missing or invalid API key | `{ \"error\": \"Missing or invalid Authorization header\" }` |\n| `403` | Plan tier insufficient — API keys require Starter plan or above | `{ \"error\": \"This feature requires the Starter plan or above.\", \"required_tier\": \"starter\", \"current_tier\": \"free\", \"upgrade_url\": \"/dashboard/subscription\" }` |\n\n---"},"servers":[{"url":"https://api.codivupload.com/v1","description":"Production API"},{"url":"http://localhost:3000/api/v1","description":"Local Development"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"Pass your API key as a Bearer token in the Authorization header: `Authorization: Bearer YOUR_API_KEY`. Generate API keys from your CodivUpload Dashboard → API Keys menu."}},"schemas":{},"parameters":{}},"paths":{"/agency/profiles":{"get":{"tags":["Profiles"],"summary":"List Profiles","description":"Retrieve all profiles mapped to the authenticated workspace.\n\n**Authorization rules:**\n- All workspace members (owner and members) can list all profiles in their workspace.\n- Use the `created_by` field to identify which user created each profile.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"A list of Profiles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"profiles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The unique UUID of the profile"},"workspace_id":{"type":"string","format":"uuid","description":"The UUID of the workspace this profile belongs to"},"profile_name":{"type":"string","description":"The display name of the profile"},"username":{"type":"string","description":"The system username mapping"},"created_by":{"type":"string","nullable":true,"format":"uuid","description":"UUID of the user who created this profile. Null for legacy profiles."},"created_at":{"type":"string","format":"date-time","description":"Profile creation timestamp"},"social_accounts":{"type":"object","additionalProperties":{"type":"boolean"},"description":"Key-value map of active platform connections","example":{"youtube":true,"tiktok":false}}},"required":["id","workspace_id","profile_name","username","created_by","created_at"]}}},"required":["success","profiles"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}}}},"post":{"tags":["Profiles"],"summary":"Create Profile","description":"Creates a new media management profile in the workspace.\n\n**Authorization rules:**\n- **Owner**: Can create profiles freely within the workspace.\n- **Member**: Can create profiles — the profile is automatically linked to the creator.\n- Members can only update/delete profiles they created. Owners can manage all profiles.\n\nThe `created_by` field is set automatically from the authenticated user.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","minLength":3,"description":"Desired username for the new profile","example":"creative_studio_xyz"}},"required":["username"]}}}},"responses":{"201":{"description":"Profile created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"profile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"profile_name":{"type":"string"},"workspace_id":{"type":"string","format":"uuid"},"created_at":{"type":"string"}},"required":["id","username","workspace_id","created_at"]}},"required":["success","profile"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Profile limit exceeded for current plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"example":{"error":"Profile limit reached. Upgrade your plan to create more profiles."}}}}},"409":{"description":"Profile with this username already exists","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Resource already exists","example":{"error":"A profile with the provided username already exists"}}}}}}}},"/agency/profiles/{id}":{"delete":{"tags":["Profiles"],"summary":"Delete Profile","description":"Permanently deletes a profile and all its associated media assets via cascading deletion.\n\n**Authorization rules:**\n- **Owner**: Can delete any profile in the workspace.\n- **Member**: Can only delete profiles they created (`created_by` must match the authenticated user).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The UUID of the profile to immediately delete"},"required":true,"description":"The UUID of the profile to immediately delete","name":"id","in":"path"}],"responses":{"200":{"description":"Profile deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Not allowed — members can only delete profiles they created","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Insufficient permissions for this action","example":{"error":"You can only modify profiles you created. Workspace owners can modify all profiles."}}}}},"404":{"description":"Profile not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Resource not found","example":{"error":"Profile not found"}}}}}}}},"/agency/media":{"post":{"tags":["Media"],"summary":"Create Media Asset","description":"Registers a new media asset. Can accept a single object or an array of objects for bulk insertion.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Display title of the media asset"},"profile_id":{"type":"string","format":"uuid","description":"Profile UUID this media belongs to"},"source_type":{"type":"string","default":"url","description":"Asset origin type"},"public_url":{"type":"string","format":"uri","description":"Accessible CDN or origin URL"},"duration":{"type":"number","description":"Duration in seconds (video/audio)"},"size":{"type":"number","description":"Filesize in bytes"}},"required":["title","profile_id","public_url"]},{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Display title of the media asset"},"profile_id":{"type":"string","format":"uuid","description":"Profile UUID this media belongs to"},"source_type":{"type":"string","default":"url","description":"Asset origin type"},"public_url":{"type":"string","format":"uri","description":"Accessible CDN or origin URL"},"duration":{"type":"number","description":"Duration in seconds (video/audio)"},"size":{"type":"number","description":"Filesize in bytes"}},"required":["title","profile_id","public_url"]}}]}}}},"responses":{"201":{"description":"Media Registered","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"count":{"type":"number"}},"required":["message","count"]}}}}}},"get":{"tags":["Media"],"summary":"List Media Assets","description":"Fetch all media assets mapped to the authenticated workspace workspace. Pass ?profile_id to filter by a specific profile.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Filter by specific Profile UUID"},"required":false,"description":"Filter by specific Profile UUID","name":"profile_id","in":"query"}],"responses":{"200":{"description":"A list of Media Assets","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Display title of the media asset"},"profile_id":{"type":"string","format":"uuid","description":"Profile UUID this media belongs to"},"source_type":{"type":"string","default":"url","description":"Asset origin type"},"public_url":{"type":"string","format":"uri","description":"Accessible CDN or origin URL"},"duration":{"type":"number","description":"Duration in seconds (video/audio)"},"size":{"type":"number","description":"Filesize in bytes"},"id":{"type":"string","format":"uuid","description":"Unique database identifier"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"status":{"type":"string","nullable":true,"description":"Processing status"},"workspace_id":{"type":"string","format":"uuid","description":"Owning workspace"}},"required":["title","profile_id","public_url","id","created_at"]}}}}}}}},"/agency/media/{id}":{"get":{"tags":["Media"],"summary":"Get Media Details","description":"Retrieve a single media asset by its UUID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The UUID of the media asset"},"required":true,"description":"The UUID of the media asset","name":"id","in":"path"}],"responses":{"200":{"description":"Media Asset Details","content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Display title of the media asset"},"profile_id":{"type":"string","format":"uuid","description":"Profile UUID this media belongs to"},"source_type":{"type":"string","default":"url","description":"Asset origin type"},"public_url":{"type":"string","format":"uri","description":"Accessible CDN or origin URL"},"duration":{"type":"number","description":"Duration in seconds (video/audio)"},"size":{"type":"number","description":"Filesize in bytes"},"id":{"type":"string","format":"uuid","description":"Unique database identifier"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"status":{"type":"string","nullable":true,"description":"Processing status"},"workspace_id":{"type":"string","format":"uuid","description":"Owning workspace"}},"required":["title","profile_id","public_url","id","created_at"]}}}}}},"delete":{"tags":["Media"],"summary":"Delete Media Asset","description":"Auto-generated structure for /agency/media/{id}","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","default":"OK"}}}}}}}}},"/agency/playlists":{"post":{"tags":["Playlists"],"summary":"Create Playlist","description":"Creates a new media playlist and optionally initializes it with specific assets.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Name of the playlist"},"profile_id":{"type":"string","format":"uuid","description":"Profile UUID this playlist belongs to"},"loop_enabled":{"type":"boolean","default":true,"description":"Enable 24/7 continuous looping"},"media_asset_ids":{"type":"array","items":{"type":"string","format":"uuid"},"default":[],"description":"Array of initially bound media asset UUIDs"}},"required":["name","profile_id"]}}}},"responses":{"201":{"description":"Playlist created","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"playlist":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique database identifier"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"name":{"type":"string","description":"Name of the playlist"},"profile_id":{"type":"string","format":"uuid","description":"Owning Profile UUID"},"loop_enabled":{"type":"boolean","description":"Loop status"},"workspace_id":{"type":"string","format":"uuid","description":"Owning workspace"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"media_asset_id":{"type":"string","format":"uuid"},"sort_order":{"type":"number"}},"required":["id","media_asset_id","sort_order"]},"description":"Ordered list of attached media assets"}},"required":["id","created_at","name","profile_id","loop_enabled"]}},"required":["message","playlist"]}}}}}},"get":{"tags":["Playlists"],"summary":"List Playlists","description":"Fetch all playlists mapped to the authenticated workspace. Pass ?profile_id to filter by a specific profile.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Filter by specific Profile UUID"},"required":false,"description":"Filter by specific Profile UUID","name":"profile_id","in":"query"}],"responses":{"200":{"description":"A list of Playlists","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique database identifier"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"name":{"type":"string","description":"Name of the playlist"},"profile_id":{"type":"string","format":"uuid","description":"Owning Profile UUID"},"loop_enabled":{"type":"boolean","description":"Loop status"},"workspace_id":{"type":"string","format":"uuid","description":"Owning workspace"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"media_asset_id":{"type":"string","format":"uuid"},"sort_order":{"type":"number"}},"required":["id","media_asset_id","sort_order"]},"description":"Ordered list of attached media assets"}},"required":["id","created_at","name","profile_id","loop_enabled"]}}}}}}}},"/agency/playlists/{id}":{"get":{"tags":["Playlists"],"summary":"Get Playlist Details","description":"Retrieve a single playlist and its nested media items by UUID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The UUID of the playlist"},"required":true,"description":"The UUID of the playlist","name":"id","in":"path"}],"responses":{"200":{"description":"Playlist Details","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique database identifier"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"name":{"type":"string","description":"Name of the playlist"},"profile_id":{"type":"string","format":"uuid","description":"Owning Profile UUID"},"loop_enabled":{"type":"boolean","description":"Loop status"},"workspace_id":{"type":"string","format":"uuid","description":"Owning workspace"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"media_asset_id":{"type":"string","format":"uuid"},"sort_order":{"type":"number"}},"required":["id","media_asset_id","sort_order"]},"description":"Ordered list of attached media assets"}},"required":["id","created_at","name","profile_id","loop_enabled"]}}}}}}},"/ai/generate":{"post":{"tags":["AI"],"summary":"Generate AI-powered social media content","description":"Generate captions, hashtags, repurpose content, or improve existing text using AI. Returns per-platform optimized content respecting each platform's character limits and culture. Usage is metered per plan (Free: 10/mo, Starter: 50/mo, Pro: 200/mo, Business: 1000/mo, Enterprise: unlimited).","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["caption","hashtags","repurpose","improve"],"description":"Generation type. caption: generate from topic, hashtags: hashtag-only generation, repurpose: adapt text for platforms, improve: enhance existing text"},"topic":{"type":"string","maxLength":500,"description":"Topic or subject for caption/hashtag generation (required for caption and hashtags types)"},"text":{"type":"string","maxLength":3000,"description":"Existing text to repurpose or improve (required for repurpose and improve types)"},"platforms":{"type":"array","items":{"type":"string","enum":["instagram","x","youtube","facebook","linkedin","tiktok","threads","pinterest","bluesky"]},"maxItems":5,"description":"Target platforms. Each platform gets an individually optimized caption respecting its character limits and culture. Default: [\"instagram\"]"},"tone":{"type":"string","enum":["casual","professional","funny","inspirational","genz","formal","friendly","poetic"],"description":"Tone of the generated content. Default: casual"},"language":{"type":"string","description":"Output language code (en, tr, ar, es, fr, de, pt, ja, ko, zh). Default: en"},"hashtag_count":{"type":"number","minimum":0,"maximum":30,"description":"Number of hashtags for hashtag-only generation. Default: 15"},"context":{"type":"string","maxLength":500,"description":"Additional context to guide generation (e.g. \"targeting small business owners\")"}},"required":["type"]}}}},"responses":{"200":{"description":"AI-generated content","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Generation type used"},"platforms":{"type":"array","items":{"type":"string"},"description":"Platforms content was generated for"},"tone":{"type":"string","description":"Tone applied"},"language":{"type":"string","description":"Language used"},"result":{"type":"object","additionalProperties":{"type":"object","properties":{"caption":{"type":"string","description":"Generated caption text"},"hashtags":{"type":"string","description":"Generated hashtags"}},"required":["caption","hashtags"]},"description":"Per-platform generated content. Keys are platform names."}},"required":["type","platforms","tone","language","result"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"]}}}},"429":{"description":"AI generation limit reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"]}}}}}}},"/integrations/youtube/broadcasts":{"get":{"operationId":"listYouTubeBroadcasts","tags":["YouTube Live"],"summary":"List Broadcasts","description":"Retrieves all YouTube Live Broadcast sessions for the authenticated workspace. Results are ordered by creation date descending.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Filter by Social Account ID"},"required":false,"description":"Filter by Social Account ID","name":"account_id","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Filter by Profile ID"},"required":false,"description":"Filter by Profile ID","name":"profile_id","in":"query"},{"schema":{"type":"string","enum":["pending","starting","live","completed","failed","stopped"],"description":"Filter by broadcast status"},"required":false,"description":"Filter by broadcast status","name":"status","in":"query"},{"schema":{"type":"string","description":"Max records (Default: 50)","example":"50"},"required":false,"description":"Max records (Default: 50)","name":"limit","in":"query"}],"responses":{"200":{"description":"List of broadcasts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"broadcasts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"rtmp_url":{"type":"string","nullable":true,"format":"uri"},"stream_key":{"type":"string","nullable":true},"youtube_broadcast_id":{"type":"string","nullable":true},"playlist_id":{"type":"string","nullable":true},"created_at":{"type":"string"},"started_at":{"type":"string","nullable":true},"ended_at":{"type":"string","nullable":true},"social_account_id":{"type":"string","format":"uuid"},"profile_id":{"type":"string","format":"uuid"}},"required":["id","title","description","status","rtmp_url","stream_key","youtube_broadcast_id","playlist_id","created_at","started_at","ended_at","social_account_id","profile_id"]}}},"required":["success","broadcasts"]}}}}}},"post":{"operationId":"createYouTubeBroadcast","tags":["YouTube Live"],"summary":"Create Broadcast","description":"Initializes a new Live Broadcast on YouTube and binds an active stream key.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_name":{"type":"string","description":"The exact name of the profile (e.g., Codivion TR) authoring the broadcast (White Label identifier)","example":"Codivion TR"},"title":{"type":"string","minLength":5,"maxLength":100,"description":"Title of the YouTube broadcast","example":"My 24/7 Lo-Fi Radio Stream"},"description":{"type":"string","maxLength":5000,"description":"Video description text","example":"Chill beats to relax/study to."},"privacyStatus":{"type":"string","enum":["public","unlisted","private"],"default":"public","description":"Privacy level of the stream","example":"public"},"start_time":{"type":"string","format":"date-time","description":"Scheduled ISO-8601 start time. If omitted, defaults to immediate execution (+1m).","example":"2026-12-31T23:59:59Z"},"playlist_id":{"type":"string","format":"uuid","description":"UUID of the CodivUpload playlist to loop","example":"123e4567-e89b-12d3-a456-426614174000"},"is_loop":{"type":"boolean","description":"Indicates if the stream should loop indefinitely","example":true}},"required":["profile_name","title"]}}}},"responses":{"200":{"description":"Broadcast initialized","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"session_id":{"type":"string","format":"uuid"},"broadcast_id":{"type":"string"},"rtmp_url":{"type":"string","format":"uri"}},"required":["status","broadcast_id"]}}}}}}},"/integrations/youtube/broadcasts/{id}/stop":{"post":{"tags":["YouTube Live"],"summary":"Stop Broadcast","description":"Signals the remote OVH Stream Worker to halt and transitions the YouTube session state.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The UUID of the Live Session"},"required":true,"description":"The UUID of the Live Session","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"delete_broadcast":{"type":"boolean","default":false,"description":"If true, hard deletes the broadcast. If false, transitions it to complete."}}}}}},"responses":{"200":{"description":"Stop signal success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"}},"required":["status","message"]}}}}}}},"/integrations/youtube/playlists":{"get":{"tags":["YouTube"],"summary":"List YouTube playlists","description":"Returns the authenticated user's YouTube playlists. Use the returned `playlist_id` as `youtube_playlist_id` when creating a post to add the video to a playlist.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Profile name","example":"my-brand"},"required":true,"description":"Profile name","name":"profile_name","in":"query"}],"responses":{"200":{"description":"List of YouTube playlists","content":{"application/json":{"schema":{"type":"object","properties":{"playlists":{"type":"array","items":{"type":"object","properties":{"playlist_id":{"type":"string","description":"YouTube playlist ID"},"title":{"type":"string","description":"Playlist title"},"description":{"type":"string","description":"Playlist description"},"privacy":{"type":"string","description":"Privacy status"},"item_count":{"type":"number","description":"Number of videos"},"thumbnail":{"type":"string","nullable":true,"description":"Thumbnail URL"}},"required":["playlist_id","title","description","privacy","item_count","thumbnail"]}},"total":{"type":"number"}},"required":["playlists","total"]}}}}}},"post":{"tags":["YouTube"],"summary":"Create YouTube playlist","description":"Creates a new YouTube playlist on the authenticated user's channel. Costs 50 API units.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"profile_name":{"type":"string","description":"Profile name"},"title":{"type":"string","description":"Playlist title"},"description":{"type":"string","description":"Playlist description"},"privacy":{"type":"string","enum":["public","unlisted","private"],"description":"Privacy status (default: public)"}},"required":["profile_name","title"]}}}},"responses":{"201":{"description":"Playlist created","content":{"application/json":{"schema":{"type":"object","properties":{"playlist":{"type":"object","properties":{"playlist_id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"privacy":{"type":"string"}},"required":["playlist_id","title","description","privacy"]},"success":{"type":"boolean","enum":[true]}},"required":["playlist","success"]}}}}}}},"/integrations/youtube/categories":{"get":{"tags":["YouTube"],"summary":"List YouTube video categories","description":"Returns assignable YouTube video categories for a region. Use the returned `category_id` as `youtube_category_id` when creating a post.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"ISO 3166-1 region code (default: US)","example":"US"},"required":false,"description":"ISO 3166-1 region code (default: US)","name":"region","in":"query"}],"responses":{"200":{"description":"List of video categories","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"category_id":{"type":"string","description":"YouTube category ID","example":"22"},"title":{"type":"string","description":"Category name","example":"People & Blogs"}},"required":["category_id","title"]}},"total":{"type":"number"}},"required":["categories","total"]}}}}}}},"/integrations/youtube/languages":{"get":{"tags":["YouTube"],"summary":"List YouTube languages","description":"Returns YouTube supported languages (i18nLanguages). Use the returned `code` as `youtube_default_language` or `youtube_caption_language`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Profile name"},"required":true,"description":"Profile name","name":"profile_name","in":"query"},{"schema":{"type":"string","description":"Display language (default: en)","example":"en"},"required":false,"description":"Display language (default: en)","name":"hl","in":"query"}],"responses":{"200":{"description":"List of languages","content":{"application/json":{"schema":{"type":"object","properties":{"languages":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}},"required":["code","name"]}},"total":{"type":"number"}},"required":["languages","total"]}}}}}}},"/integrations/youtube/regions":{"get":{"tags":["YouTube"],"summary":"List YouTube regions","description":"Returns YouTube supported regions/countries (i18nRegions). Use the returned `code` as values in `youtube_allowed_countries` or `youtube_blocked_countries`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Profile name"},"required":true,"description":"Profile name","name":"profile_name","in":"query"},{"schema":{"type":"string","description":"Display language (default: en)","example":"en"},"required":false,"description":"Display language (default: en)","name":"hl","in":"query"}],"responses":{"200":{"description":"List of regions","content":{"application/json":{"schema":{"type":"object","properties":{"regions":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}},"required":["code","name"]}},"total":{"type":"number"}},"required":["regions","total"]}}}}}}},"/posts":{"post":{"operationId":"createPost","tags":["Posts"],"summary":"Create Post","description":"Publish content to multiple social media platforms with a single API call.\n\nUse the `post_type` field to select the content type: **text**, **image**, **video**, or **document**. Each type shows the available fields and which platforms support it.\n\n## Scheduling\n- Omit `scheduled_date` to publish **immediately**.\n- Provide a future date (ISO-8601 UTC) to **schedule** the post. The system automatically publishes it at the specified time. Max 365 days ahead.\n\n## Platform Support\n\n| Platform  | Text | Image | Video | Document |\n|-----------|------|-------|-------|----------|\n| X/Twitter | ✓    | ✓ (4) | ✓     | —        |\n| YouTube   | —    | —     | ✓     | —        |\n| Instagram | —    | ✓ (10)| ✓     | —        |\n| Facebook  | ✓    | ✓     | ✓     | —        |\n| LinkedIn  | ✓    | ✓ (9) | ✓     | ✓        |\n| TikTok    | —    | ✓ (35)| ✓     | —        |\n| Threads   | ✓    | ✓ (10)| ✓     | —        |\n| Pinterest | —    | ✓ (1) | ✓     | —        |\n| Google Business | ✓ | ✓ (1) | ✓  | —        |\n| Bluesky   | ✓    | ✓ (4) | —     | —        |\n| Snapchat  | —    | ✓ (1) | ✓     | —        |\n\n*(Numbers in parentheses = max images per post)*\n\n## Common Parameters (All Post Types)\n\n| Parameter | Type | Required | Description |\n|---|---|---|---|\n| `post_type` | enum | Yes | `text`, `image`, `video`, or `document` |\n| `profile_name` | string | Yes | Target profile name in your workspace |\n| `platforms` | string[] | Yes | Target platforms to publish to |\n| `media_urls` | string[] | Conditional | Public URLs of media files (from CDN Upload or external). Required for image/video/document. Use `/v1/upload-media` to upload files first. |\n| `title` | string | No | Post title / video title / pin title |\n| `description` | string | Conditional | Post caption / body text. Required for text posts. |\n| `scheduled_date` | datetime | No | ISO-8601 UTC. Omit for immediate publishing. Cannot be used with `add_to_queue`. |\n| `add_to_queue` | boolean | No | Auto-schedule to next available queue slot. **Requires Starter plan.** Configure slots in Settings → Queue. Cannot be used with `scheduled_date`. |\n| `schedule_best_time` | boolean | No | Auto-schedule to the best posting time based on your last 90 days of analytics data. The system finds the optimal hour and day of week with highest engagement, then schedules the post for the next occurrence. Cannot be used with `scheduled_date` or `add_to_queue`. |\n| `first_comment` | string | No | Auto-posted comment after publishing (Instagram, YouTube) |\n| `auto_truncate` | boolean | No | Trim media arrays exceeding platform limits (default: false) |\n\n## Platform-Specific Parameters\n\nEach post type schema includes platform-specific override fields. These are only applied when the corresponding platform is in your `platforms` array.\n\n### YouTube (video)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `youtube_media_urls` | url[] | — | **Override media** for YouTube. Replaces shared `media_urls`. Upload via `/v1/upload-media` first. |\n| `youtube_type` | enum | video | `video` = regular, `shorts` = YouTube Shorts (vertical, <60 sec). Or include #Shorts in title. Thumbnails not for Shorts. |\n| `youtube_category_id` | enum | 22 | Video category (1=Film, 10=Music, 20=Gaming, 22=People&Blogs, 27=Education, 28=Sci&Tech) |\n| `youtube_tags` | string[] | [] | SEO tags (max 500 chars total) |\n| `youtube_privacy_status` | enum | public | public / unlisted / private |\n| `youtube_thumbnail_url` | url | — | Custom thumbnail image. JPG/PNG/GIF/BMP, max 2 MB. Upload via `/v1/upload-media` or provide URL. Not for Shorts. |\n| `youtube_self_declared_made_for_kids` | bool | false | COPPA: content made for children |\n| `youtube_contains_synthetic_media` | bool | false | AI-generated content flag |\n| `youtube_has_paid_product_placement` | bool | false | FTC: paid sponsorship disclosure |\n| `youtube_license` | enum | youtube | youtube or creativeCommon |\n| `youtube_embeddable` | bool | true | Allow embedding on other websites |\n| `youtube_public_stats_viewable` | bool | true | Show view/like counts publicly |\n| `youtube_default_language` | string | — | Video language (BCP-47: en, tr, es) |\n| `youtube_default_audio_language` | string | — | Audio language (BCP-47: en-US, tr-TR) |\n| `youtube_allowed_countries` | string[] | — | ISO 3166-1 codes where video is viewable |\n| `youtube_blocked_countries` | string[] | — | ISO 3166-1 codes where video is blocked |\n| `youtube_recording_date` | datetime | — | Original recording date (ISO 8601) |\n| `youtube_caption_url` | url | — | SRT subtitle file URL. Costs 400 API units. Upload via `/v1/upload-media` or provide URL. |\n| `youtube_caption_language` | string | en | BCP-47 language code for the caption file (en, tr, es, ar) |\n| `youtube_playlist_id` | string | — | Add video to a YouTube playlist after upload (50 units). Use [`GET /v1/integrations/youtube/playlists`](#tag/youtube/GET/integrations/youtube/playlists) to list playlists. |\n\n> **YouTube-specific endpoints:** Manage playlists via [`GET /v1/integrations/youtube/playlists`](#tag/youtube/GET/integrations/youtube/playlists) (list) and [`POST /v1/integrations/youtube/playlists`](#tag/youtube/POST/integrations/youtube/playlists) (create). Get video categories via [`GET /v1/integrations/youtube/categories`](#tag/youtube/GET/integrations/youtube/categories).\n\n### TikTok (video & image)\n\n*Image posts are automatically published as TikTok Photo Mode (photo carousel).*\n\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `tiktok_media_urls` | url[] | — | **Override media** for TikTok. Replaces shared `media_urls`. |\n| `tiktok_privacy_level` | string | — | **Required.** Privacy from `GET /v1/integrations/tiktok/creator-info`: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY. Legacy: public / friends / private. |\n| `tiktok_allow_comment` | bool | false | Allow comments. Check `GET /v1/integrations/tiktok/creator-info` — may be disabled in account settings. |\n| `tiktok_allow_duet` | bool | false | Allow duet (video only). Check creator_info — may be disabled in account settings. |\n| `tiktok_allow_stitch` | bool | false | Allow stitch (video only). Check creator_info — may be disabled in account settings. |\n| `tiktok_brand_content_toggle` | bool | false | Branded content: promoting another brand. Labels as \"Paid partnership.\" Cannot use SELF_ONLY privacy. |\n| `tiktok_brand_organic_toggle` | bool | false | Your brand: promoting yourself. Labels as \"Promotional content.\" |\n| `tiktok_is_aigc` | bool | false | AI-generated content flag (video only) |\n| `tiktok_auto_add_music` | bool | false | Auto background music (image/photo mode only) |\n| `tiktok_post_mode` | enum | DIRECT_POST | `DIRECT_POST` = publish immediately. `MEDIA_UPLOAD` = send to TikTok inbox/drafts (no metadata, add details in TikTok app). |\n| `tiktok_disable_comment` | bool | — | *(Legacy)* Prefer `tiktok_allow_comment`. |\n| `tiktok_disable_duet` | bool | — | *(Legacy)* Prefer `tiktok_allow_duet`. |\n| `tiktok_disable_stitch` | bool | — | *(Legacy)* Prefer `tiktok_allow_stitch`. |\n\n### Instagram (video & image)\n\n*Videos default to Reels. Multiple images auto-carousel.*\n\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `instagram_media_urls` | url[] | — | **Override media** for Instagram. Replaces shared `media_urls`. |\n| `instagram_media_type` | enum | REELS | REELS (default) or STORIES. Video posts only. |\n| `instagram_share_to_feed` | bool | true | Share reel to main feed (video only) |\n| `instagram_collaborators` | string | — | Comma-separated collaborator usernames |\n| `instagram_cover_url` | url | — | Custom cover image for Reels. Upload via `/v1/upload-media` or provide URL. |\n| `instagram_user_tags` | string | — | Comma-separated @usernames (image only) |\n| `instagram_location_id` | string | — | Instagram location ID |\n| `instagram_alt_text` | string | — | Alt text for image accessibility (max 1000 chars, image only) |\n\n### Facebook (video & image)\n\n*Videos default to regular video. Use `facebook_media_type: \"REELS\"` for Reels.*\n\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `facebook_media_urls` | url[] | — | **Override media** for Facebook. Replaces shared `media_urls`. |\n| `facebook_media_type` | enum | VIDEO | VIDEO (regular) or REELS (Facebook Reels). Video only. |\n\n### Pinterest (video & image)\n\n> **Required step:** Before posting to Pinterest, retrieve your board IDs:\n> `GET /v1/integrations/pinterest/boards?profile_name={name}`\n> Pins cannot be created without a `pinterest_board_id`.\n\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `pinterest_media_urls` | url[] | — | **Override media** for Pinterest. Replaces shared `media_urls`. |\n| `pinterest_board_id` | string | — | **Required.** Target board ID. First call [`GET /v1/integrations/pinterest/boards`](#tag/pinterest/GET/integrations/pinterest/boards) to list your boards. |\n| `pinterest_link` | url | — | Destination URL when pin is clicked |\n| `pinterest_alt_text` | string | — | Alt text for accessibility (image only) |\n\n### Threads (all types)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `threads_topic_tag` | string | — | Topic tag, 1-50 chars, no periods or ampersands |\n\n### X / Twitter (all types)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `x_reply_settings` | enum | — | Who can reply: `following` (accounts you follow) or `mentionedUsers` (mentioned only). Omit for everyone. |\n| `x_alt_text` | string | — | Alt text for image accessibility (max 1000 chars, image only) |\n\n### LinkedIn (all types)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `linkedin_page_id` | string | — | Post as company page (Organization ID) |\n| `linkedin_visibility` | enum | PUBLIC | PUBLIC or CONNECTIONS |\n\n### Bluesky (text, image & video)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `bluesky_alt_text` | string | — | Alt text for image accessibility (max 1000 chars, image only) |\n\n### Google Business Profile (text, image & video)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `gbp_location_id` | string | — | Location ID from your Google Business Profile |\n| `gbp_topic_type` | enum | STANDARD | `STANDARD` = general update, `EVENT` = event announcement, `OFFER` = promotional offer |\n| `gbp_cta_type` | enum | — | Call-to-action button: `BOOK`, `ORDER`, `SHOP`, `LEARN_MORE`, `SIGN_UP`, `CALL` |\n| `gbp_cta_url` | url | — | Destination URL for the CTA button |\n| `gbp_event_title` | string | — | Title for EVENT or OFFER posts |\n| `gbp_event_start_date` | string | — | Event/offer start date (ISO 8601) |\n| `gbp_event_end_date` | string | — | Event/offer end date (ISO 8601) |\n| `gbp_event_start_time` | string | — | Event start time (HH:MM, 24h format) |\n| `gbp_event_end_time` | string | — | Event end time (HH:MM, 24h format) |\n| `gbp_coupon_code` | string | — | Coupon/promo code for OFFER posts |\n| `gbp_redeem_url` | url | — | URL where customers can redeem the offer |\n| `gbp_terms` | string | — | Terms and conditions for OFFER posts |\n| `gbp_media_urls` | url[] | — | **Override media** for Google Business. Replaces shared `media_urls`. |\n\n### Snapchat (image & video)\n| Parameter | Type | Default | Description |\n|---|---|---|---|\n| `snapchat_media_urls` | url[] | — | **Override media** for Snapchat. Replaces shared `media_urls`. |\n| `snapchat_post_type` | enum | story | `story` = 24h disappearing, `spotlight` = public Spotlight feed, `saved_story` = permanent on profile |\n| `snapchat_description` | string | — | Short description for Spotlight or Saved Story (max 160 chars) |\n| `snapchat_saved_story_title` | string | — | Title for Saved Stories (max 45 chars, required for saved_story type) |\n| `snapchat_locale` | string | — | Content locale (e.g. en_US, fr_FR) |\n| `snapchat_skip_save_to_profile` | bool | false | Skip saving Story content to public profile |\n\n## Per-Platform Media Override\n\nBy default, all platforms receive the same `media_urls`. To send **different media to specific platforms**, use per-platform media override fields:\n\n| Parameter | Post Types | Description |\n|---|---|---|\n| `youtube_media_urls` | video | Override media for YouTube only |\n| `instagram_media_urls` | image, video | Override media for Instagram only |\n| `tiktok_media_urls` | image, video | Override media for TikTok only |\n| `facebook_media_urls` | image, video | Override media for Facebook only |\n| `pinterest_media_urls` | image, video | Override media for Pinterest only |\n| `gbp_media_urls` | image, video | Override media for Google Business only |\n| `snapchat_media_urls` | image, video | Override media for Snapchat only |\n\nWhen a `{platform}_media_urls` is provided, it replaces `media_urls` for that specific platform. Other platforms continue using the shared `media_urls`.\n\n**Example:** Post the same text but different video to YouTube and TikTok:\n```json\n{\n  \"post_type\": \"video\",\n  \"media_urls\": [\"https://cdn.codivupload.com/.../horizontal.mp4\"],\n  \"youtube_media_urls\": [\"https://cdn.codivupload.com/.../horizontal.mp4\"],\n  \"tiktok_media_urls\": [\"https://cdn.codivupload.com/.../vertical.mp4\"],\n  \"platforms\": [\"youtube\", \"tiktok\"]\n}\n```\n\n## Auto-Truncate\nSet `auto_truncate: true` to automatically trim media arrays when they exceed a platform's limit (e.g., sending 8 images when X allows only 4). If false, the request returns a 400 error.\n\n## Character Limits\n\nText is validated against platform-specific limits unless `auto_truncate: true` is set.\n\n| Platform | Post | Title | Comment | Alt Text |\n|---|---|---|---|---|\n| X (Twitter) | 280 | — | — | 1,000 |\n| YouTube | 5,000 | 100 | — | — |\n| Instagram | 2,200 | — | 2,196 | 1,000 |\n| Facebook | 63,206 | 255 | — | — |\n| LinkedIn | 3,000 | 400 | 1,250 | — |\n| TikTok | 2,200 | — | — | — |\n| Threads | 500 | — | — | — |\n| Pinterest | 500 | 100 | — | 500 |\n| Bluesky | 300 | — | — | 1,000 |\n| Google Business | 1,500 | 58 | — | — |\n| Snapchat | 160 | 45 | — | — |\n\n## Media Limits\n\n| Platform | Max File Size | Max Duration | Max Images | Formats |\n|---|---|---|---|---|\n| YouTube | 256 GB | 12 hours | — | MP4, MOV, AVI, WMV, FLV, WebM |\n| TikTok | 4 GB | 10 min | 35 (photo) | MP4, MOV, WebM |\n| Instagram | 300 MB | 15 min | 10 | JPG, PNG, MP4, MOV |\n| Facebook | 1 GB | 240 min | 10 | JPG, PNG, GIF, WebP, MP4, MOV |\n| LinkedIn | 5 GB | 10 min | 9 | JPG, PNG, GIF, MP4 |\n| X (Twitter) | 1 GB | 4 hours | 4 | JPG, PNG, GIF, WebP, MP4, MOV |\n| Threads | 1 GB | 5 min | 10 | JPG, PNG, MP4, MOV |\n| Pinterest | 1 GB | 15 min | 5 | JPG, PNG, GIF, WebP, MP4 |\n| Bluesky | 100 MB | 60 sec | 4 | JPG, PNG, GIF, WebP, MP4 |\n| Google Business | 25 MB | 30 sec | 1 | JPG, PNG, MP4 |\n| Snapchat | 1 GB | 300 sec | 1 | JPG, PNG, MP4 |\n\n## Daily Post Limits\n\nLimits are enforced per connected social account (not per user) within a 24-hour rolling window.\n\n| Platform | Daily Limit (per account) |\n|---|---|\n| Instagram | 50 |\n| TikTok | 15 |\n| LinkedIn | 150 |\n| YouTube | 10 |\n| Facebook | 25 |\n| X (Twitter) | 50 |\n| Threads | 50 |\n| Pinterest | 20 |\n| Bluesky | 50 |\n| Google Business | 25 |\n| Snapchat | 25 |\n\nWhen a daily limit is reached, the API returns a `429` error with details:\n```json\n{\n  \"success\": false,\n  \"error\": \"Post verification failed\",\n  \"violations\": [{\n    \"platform\": \"instagram\",\n    \"type\": \"hard_cap\",\n    \"message\": \"Daily cap reached for instagram: 50/50 in last 24h\",\n    \"used_last_24h\": 50,\n    \"cap\": 50\n  }]\n}\n```\n\n## Rate Limits\nIf a platform temporarily blocks publishing (rate limit), the post is automatically retried within a few minutes. You don't need to resend the request.\n\n## Queue System (Starter plan and above)\n\nInstead of specifying a `scheduled_date`, you can use `add_to_queue: true` to auto-schedule to the next available time slot.\nQueue endpoints require **Starter plan or above**. Free plan users receive a `403` response with `required_tier: \"starter\"`.\n\n- Configure slots (e.g., 9:00, 12:00, 17:00) via `POST /api/v1/queue/settings`\n- Preview upcoming slots: `GET /api/v1/queue/preview?profile_name=xxx`\n- Find next slot: `GET /api/v1/queue/next-slot?profile_name=xxx`\n- Default slots: 9:00 AM, 12:00 PM, 5:00 PM UTC, every day, 1 post per slot\n\n## YouTube API Quota\n\nEach YouTube API operation consumes quota units from the project (10,000 units/day default):\n\n| Operation | Unit Cost |\n|---|---|\n| Video upload (`videos.insert`) | 100 |\n| Custom thumbnail (`thumbnails.set`) | 50 |\n| Country restrictions (`videos.update`) | 50 |\n| First comment (`commentThreads.insert`) | 50 |\n| Caption/subtitle upload (`captions.insert`) | 400 |\n\nTypical video upload with thumbnail = 150 units ≈ 66 videos/day.\nUsers can provide their own Google Cloud credentials for a dedicated 10,000 unit quota.\n\n## Content Validation\n\nPosts are validated before publishing:\n- **Character limits** — enforced per platform (returns 400 if exceeded, unless `auto_truncate: true`)\n- **Banned hashtags** — Instagram/Threads/Facebook posts are checked against a list of hashtags known to cause shadow bans. Returns 400 with `violations` array.\n- **Duplicate content** — Similar content posted within 48 hours triggers a warning (non-blocking).\n- **Media format** — Unsupported file formats are rejected at upload time.\n\n---\n\n## Usage Examples\n\n> **Tip:** Use the **Example** dropdown in the request panel to load ready-to-use templates for each platform. Each example shows only the fields relevant to that scenario.\n\n### Simple text post\n```json\n{\n  \"post_type\": \"text\",\n  \"profile_name\": \"my_brand\",\n  \"platforms\": [\"x\", \"threads\", \"bluesky\"],\n  \"description\": \"Exciting news! Our new feature is live. Check it out!\"\n}\n```\n\n### YouTube video (common fields only — defaults handle the rest)\n```json\n{\n  \"post_type\": \"video\",\n  \"profile_name\": \"my_brand\",\n  \"platforms\": [\"youtube\"],\n  \"media_urls\": [\"https://cdn.codivupload.com/.../video.mp4\"],\n  \"title\": \"Product Launch 2026\",\n  \"description\": \"Full walkthrough of our new features.\",\n  \"youtube_privacy_status\": \"public\",\n  \"youtube_tags\": [\"product\", \"launch\", \"tech\"],\n  \"youtube_thumbnail_url\": \"https://cdn.codivupload.com/.../thumb.jpg\",\n  \"youtube_category_id\": \"28\"\n}\n```\n*Other YouTube fields like `youtube_license`, `youtube_embeddable`, `youtube_default_language` etc. use sensible defaults. Add them only when you need to override.*\n\n### Multi-platform video with per-platform media override\n```json\n{\n  \"post_type\": \"video\",\n  \"profile_name\": \"my_brand\",\n  \"platforms\": [\"youtube\", \"tiktok\", \"instagram\"],\n  \"media_urls\": [\"https://cdn.codivupload.com/.../horizontal.mp4\"],\n  \"tiktok_media_urls\": [\"https://cdn.codivupload.com/.../vertical.mp4\"],\n  \"instagram_media_urls\": [\"https://cdn.codivupload.com/.../square.mp4\"],\n  \"title\": \"Day in my life\",\n  \"description\": \"Follow along for a day at the office!\",\n  \"youtube_privacy_status\": \"public\",\n  \"youtube_tags\": [\"vlog\", \"day-in-my-life\"],\n  \"tiktok_privacy_level\": \"PUBLIC_TO_EVERYONE\",\n  \"tiktok_post_mode\": \"DIRECT_POST\",\n  \"instagram_media_type\": \"REELS\",\n  \"instagram_share_to_feed\": true\n}\n```\n*YouTube receives `media_urls` (horizontal). TikTok receives `tiktok_media_urls` (vertical). Instagram receives `instagram_media_urls` (square). Each platform also gets its own override fields — fields for other platforms are ignored.*\n\n### TikTok draft mode (send to inbox)\n```json\n{\n  \"post_type\": \"video\",\n  \"profile_name\": \"my_brand\",\n  \"platforms\": [\"tiktok\"],\n  \"media_urls\": [\"https://cdn.codivupload.com/.../clip.mp4\"],\n  \"tiktok_post_mode\": \"MEDIA_UPLOAD\"\n}\n```\n*In MEDIA_UPLOAD mode, no metadata (title, privacy, interactions) is sent. Add details in the TikTok app before publishing.*\n\n### Scheduled post\n```json\n{\n  \"post_type\": \"text\",\n  \"profile_name\": \"my_brand\",\n  \"platforms\": [\"linkedin\", \"x\"],\n  \"description\": \"We are hiring! Senior engineers wanted. DM us.\",\n  \"scheduled_date\": \"2026-04-15T09:00:00Z\",\n  \"linkedin_visibility\": \"PUBLIC\",\n  \"x_reply_settings\": \"following\"\n}\n```","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"profile_name":{"type":"string","minLength":1,"description":"The display name of your target profile. Must match an existing profile in your workspace.","example":"Codivion TR"},"platforms":{"type":"array","items":{"type":"string","enum":["x","youtube","instagram","facebook","linkedin","tiktok","threads","pinterest","bluesky","google_business","snapchat"],"description":"Platform identifier"},"minItems":1,"description":"Target platforms to publish to. Each platform must have a connected social account for the selected profile.","example":["youtube","instagram","x"]},"auto_truncate":{"type":"boolean","default":false,"description":"Automatically trim media arrays that exceed a platform's limit (e.g., X allows max 4 images). If false, returns 400 error instead."},"scheduled_date":{"type":"string","format":"date-time","description":"Schedule for later publishing (ISO-8601 UTC). If omitted, the post is published immediately. Max 365 days in the future.","example":"2026-04-01T14:30:00Z"},"schedule_best_time":{"type":"boolean","description":"Auto-schedule to the best posting time based on your last 90 days of analytics. Finds the optimal hour and day of week, schedules for the next occurrence. Cannot be used with scheduled_date or add_to_queue."},"title":{"type":"string","description":"Post title. Used as video title on YouTube, pin title on Pinterest, and prepended to caption on other platforms.","example":"New Product Launch"},"description":{"type":"string","minLength":1,"description":"Your post text (required). Character limits by platform:\n• X/Twitter — 280 characters\n• Bluesky — 300 characters\n• Threads — 500 characters\n• LinkedIn — 3,000 characters\n• Facebook — 63,206 characters","example":"Exciting news! We just launched our new scheduling feature. #SocialMedia #Automation"},"first_comment":{"type":"string","description":"Automatically post a comment after publishing. Supported on Instagram and YouTube.","example":"Link in bio!"},"post_type":{"type":"string","enum":["text"],"description":"Set to \"text\" for text-only posts (no media)."},"threads_topic_tag":{"type":"string","maxLength":50,"description":"Threads only — Topic tag (1-50 chars, no periods or ampersands). Ignored if threads is not in platforms."},"x_reply_settings":{"type":"string","enum":["following","mentionedUsers"],"description":"X only — Who can reply: following or mentionedUsers. Omit for everyone. Ignored if x is not in platforms."},"linkedin_page_id":{"type":"string","description":"LinkedIn only — Post as company page (Organization ID). Ignored if linkedin is not in platforms."},"linkedin_visibility":{"type":"string","enum":["PUBLIC","CONNECTIONS"],"description":"LinkedIn only — PUBLIC or CONNECTIONS. Ignored if linkedin is not in platforms."},"gbp_location_id":{"type":"string","description":"Google Business only — Location ID from your Business Profile. Ignored if gbp is not in platforms."},"gbp_topic_type":{"type":"string","enum":["STANDARD","EVENT","OFFER"],"description":"Google Business only — Post type: STANDARD = general update, EVENT = event announcement, OFFER = promotional offer. Ignored if gbp is not in platforms.","example":"STANDARD"},"gbp_cta_type":{"type":"string","enum":["BOOK","ORDER","SHOP","LEARN_MORE","SIGN_UP","CALL"],"description":"Google Business only — Call-to-action button type. Ignored if gbp is not in platforms.","example":"LEARN_MORE"},"gbp_cta_url":{"type":"string","format":"uri","description":"Google Business only — Destination URL for the call-to-action button. Ignored if gbp is not in platforms."},"gbp_event_title":{"type":"string","description":"Google Business only — Title for EVENT or OFFER posts. Ignored if gbp is not in platforms."},"gbp_event_start_date":{"type":"string","description":"Google Business only — Event/offer start date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-15"},"gbp_event_end_date":{"type":"string","description":"Google Business only — Event/offer end date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-30"},"gbp_event_start_time":{"type":"string","description":"Google Business only — Event start time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"09:00"},"gbp_event_end_time":{"type":"string","description":"Google Business only — Event end time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"17:00"},"gbp_coupon_code":{"type":"string","description":"Google Business only — Coupon/promo code for OFFER posts. Ignored if gbp is not in platforms."},"gbp_redeem_url":{"type":"string","format":"uri","description":"Google Business only — URL where customers can redeem the offer. Ignored if gbp is not in platforms."},"gbp_terms":{"type":"string","description":"Google Business only — Terms and conditions for OFFER posts. Ignored if gbp is not in platforms."},"snapchat_post_type":{"type":"string","enum":["story","spotlight","saved_story"],"description":"Snapchat only — Content type: story = 24h disappearing, spotlight = public Spotlight feed, saved_story = permanent on profile. Ignored if snapchat is not in platforms.","example":"spotlight"},"snapchat_description":{"type":"string","maxLength":160,"description":"Snapchat only — Short description for Spotlight or Saved Story (max 160 chars). Ignored if snapchat is not in platforms."},"snapchat_locale":{"type":"string","description":"Snapchat only — Content locale (e.g. en_US, fr_FR). Ignored if snapchat is not in platforms."},"snapchat_skip_save_to_profile":{"type":"boolean","description":"Snapchat only — Skip saving Story content to your public profile. Ignored if snapchat is not in platforms."},"snapchat_saved_story_title":{"type":"string","maxLength":45,"description":"Snapchat only — Title for Saved Stories (max 45 chars, required for saved_story type). Ignored if snapchat is not in platforms."}},"required":["profile_name","platforms","description","post_type"],"title":"Text Post","description":"Text-only post without media. Supported on: X, Facebook, LinkedIn, Threads, Bluesky, Google Business, Snapchat."},{"type":"object","properties":{"profile_name":{"type":"string","minLength":1,"description":"The display name of your target profile. Must match an existing profile in your workspace.","example":"Codivion TR"},"platforms":{"type":"array","items":{"type":"string","enum":["x","youtube","instagram","facebook","linkedin","tiktok","threads","pinterest","bluesky","google_business","snapchat"],"description":"Platform identifier"},"minItems":1,"description":"Target platforms to publish to. Each platform must have a connected social account for the selected profile.","example":["youtube","instagram","x"]},"auto_truncate":{"type":"boolean","default":false,"description":"Automatically trim media arrays that exceed a platform's limit (e.g., X allows max 4 images). If false, returns 400 error instead."},"scheduled_date":{"type":"string","format":"date-time","description":"Schedule for later publishing (ISO-8601 UTC). If omitted, the post is published immediately. Max 365 days in the future.","example":"2026-04-01T14:30:00Z"},"schedule_best_time":{"type":"boolean","description":"Auto-schedule to the best posting time based on your last 90 days of analytics. Finds the optimal hour and day of week, schedules for the next occurrence. Cannot be used with scheduled_date or add_to_queue."},"title":{"type":"string","description":"Post title. Used as video title on YouTube, pin title on Pinterest, and prepended to caption on other platforms.","example":"New Product Launch"},"description":{"type":"string","description":"Post caption / body text. The main text content shown on all platforms.","example":"Check out our latest feature! Now available for everyone."},"first_comment":{"type":"string","description":"Automatically post a comment after publishing. Supported on Instagram and YouTube.","example":"Link in bio!"},"post_type":{"type":"string","enum":["image"],"description":"Set to \"image\" for image posts."},"media_urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"description":"One or more public image URLs. Maximum images per platform:\n• X/Twitter — 4 images\n• Instagram — 10 images (auto-carousel when >1)\n• TikTok — 35 images (photo mode)\n• Threads — 10 images (auto-carousel when >1)\n• LinkedIn — 9 images\n• Bluesky — 4 images\n• Pinterest — 1 image per pin\n• Facebook — no limit (multi-photo post)\n\nSupported formats: JPEG, PNG, WebP, GIF.","example":["https://cdn.example.com/photo1.jpg","https://cdn.example.com/photo2.jpg"]},"instagram_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Instagram — replaces shared media_urls. Ignored if instagram is not in platforms."},"tiktok_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for TikTok — replaces shared media_urls. Ignored if tiktok is not in platforms."},"facebook_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Facebook — replaces shared media_urls. Ignored if facebook is not in platforms."},"pinterest_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Pinterest — replaces shared media_urls. Ignored if pinterest is not in platforms."},"gbp_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Google Business — replaces shared media_urls. Ignored if gbp is not in platforms."},"snapchat_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Snapchat — replaces shared media_urls. Ignored if snapchat is not in platforms."},"instagram_collaborators":{"type":"string","description":"Instagram only — Comma-separated collaborator usernames. Ignored if instagram is not in platforms."},"instagram_user_tags":{"type":"string","description":"Instagram only — Comma-separated @usernames to tag. Ignored if instagram is not in platforms."},"instagram_location_id":{"type":"string","description":"Instagram only — Location ID for the post. Ignored if instagram is not in platforms."},"instagram_alt_text":{"type":"string","maxLength":1000,"description":"Instagram only — Alt text for image accessibility (max 1000 chars). Ignored if instagram is not in platforms."},"tiktok_privacy_level":{"type":"string","description":"TikTok only — Privacy level from creator_info API: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, or SELF_ONLY. Use GET /v1/integrations/tiktok/creator-info to get available options for the creator. Legacy values (public, friends, private) are also accepted. Ignored if tiktok is not in platforms.","example":"PUBLIC_TO_EVERYONE"},"tiktok_allow_comment":{"type":"boolean","description":"TikTok only — Allow comments. Default: false (disabled). Check creator_info for account-level setting. Ignored if tiktok is not in platforms."},"tiktok_disable_comment":{"type":"boolean","description":"TikTok only — (Legacy) Disable comments. Prefer tiktok_allow_comment instead. Ignored if tiktok is not in platforms."},"tiktok_brand_content_toggle":{"type":"boolean","description":"TikTok only — Branded content: promoting another brand or third party. Labels as \"Paid partnership.\" Cannot use SELF_ONLY privacy. Ignored if tiktok is not in platforms."},"tiktok_brand_organic_toggle":{"type":"boolean","description":"TikTok only — Your brand: promoting yourself or own business. Labels as \"Promotional content.\" Ignored if tiktok is not in platforms."},"tiktok_auto_add_music":{"type":"boolean","description":"TikTok only — Automatically add background music to photo slideshow. Ignored if tiktok is not in platforms."},"pinterest_board_id":{"type":"string","description":"Pinterest only — Target board ID (required for Pinterest). Use GET /v1/integrations/pinterest/boards to list boards. Ignored if pinterest is not in platforms."},"pinterest_link":{"type":"string","format":"uri","description":"Pinterest only — Destination URL when pin is clicked. Ignored if pinterest is not in platforms."},"pinterest_alt_text":{"type":"string","description":"Pinterest only — Alt text for accessibility. Ignored if pinterest is not in platforms."},"threads_topic_tag":{"type":"string","maxLength":50,"description":"Threads only — Topic tag (1-50 chars, no periods or ampersands). Ignored if threads is not in platforms."},"x_reply_settings":{"type":"string","enum":["following","mentionedUsers"],"description":"X only — Who can reply: following or mentionedUsers. Omit for everyone. Ignored if x is not in platforms."},"x_alt_text":{"type":"string","maxLength":1000,"description":"X only — Alt text for image accessibility (max 1000 chars). Ignored if x is not in platforms."},"bluesky_alt_text":{"type":"string","maxLength":1000,"description":"Bluesky only — Alt text for image accessibility (max 1000 chars). Ignored if bluesky is not in platforms."},"linkedin_page_id":{"type":"string","description":"LinkedIn only — Post as company page (Organization ID). Ignored if linkedin is not in platforms."},"linkedin_visibility":{"type":"string","enum":["PUBLIC","CONNECTIONS"],"description":"LinkedIn only — PUBLIC or CONNECTIONS. Ignored if linkedin is not in platforms."},"gbp_location_id":{"type":"string","description":"Google Business only — Location ID from your Business Profile. Ignored if gbp is not in platforms."},"gbp_topic_type":{"type":"string","enum":["STANDARD","EVENT","OFFER"],"description":"Google Business only — Post type: STANDARD = general update, EVENT = event announcement, OFFER = promotional offer. Ignored if gbp is not in platforms.","example":"STANDARD"},"gbp_cta_type":{"type":"string","enum":["BOOK","ORDER","SHOP","LEARN_MORE","SIGN_UP","CALL"],"description":"Google Business only — Call-to-action button type. Ignored if gbp is not in platforms.","example":"LEARN_MORE"},"gbp_cta_url":{"type":"string","format":"uri","description":"Google Business only — Destination URL for the call-to-action button. Ignored if gbp is not in platforms."},"gbp_event_title":{"type":"string","description":"Google Business only — Title for EVENT or OFFER posts. Ignored if gbp is not in platforms."},"gbp_event_start_date":{"type":"string","description":"Google Business only — Event/offer start date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-15"},"gbp_event_end_date":{"type":"string","description":"Google Business only — Event/offer end date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-30"},"gbp_event_start_time":{"type":"string","description":"Google Business only — Event start time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"09:00"},"gbp_event_end_time":{"type":"string","description":"Google Business only — Event end time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"17:00"},"gbp_coupon_code":{"type":"string","description":"Google Business only — Coupon/promo code for OFFER posts. Ignored if gbp is not in platforms."},"gbp_redeem_url":{"type":"string","format":"uri","description":"Google Business only — URL where customers can redeem the offer. Ignored if gbp is not in platforms."},"gbp_terms":{"type":"string","description":"Google Business only — Terms and conditions for OFFER posts. Ignored if gbp is not in platforms."},"snapchat_post_type":{"type":"string","enum":["story","spotlight","saved_story"],"description":"Snapchat only — Content type: story = 24h disappearing, spotlight = public Spotlight feed, saved_story = permanent on profile. Ignored if snapchat is not in platforms.","example":"spotlight"},"snapchat_description":{"type":"string","maxLength":160,"description":"Snapchat only — Short description for Spotlight or Saved Story (max 160 chars). Ignored if snapchat is not in platforms."},"snapchat_locale":{"type":"string","description":"Snapchat only — Content locale (e.g. en_US, fr_FR). Ignored if snapchat is not in platforms."},"snapchat_skip_save_to_profile":{"type":"boolean","description":"Snapchat only — Skip saving Story content to your public profile. Ignored if snapchat is not in platforms."},"snapchat_saved_story_title":{"type":"string","maxLength":45,"description":"Snapchat only — Title for Saved Stories (max 45 chars, required for saved_story type). Ignored if snapchat is not in platforms."}},"required":["profile_name","platforms","post_type","media_urls"],"title":"Image Post","description":"Single or multi-image post. Supported on: X, Instagram, Facebook, LinkedIn, TikTok (photo mode), Threads, Pinterest, Bluesky, Google Business, Snapchat."},{"type":"object","properties":{"profile_name":{"type":"string","minLength":1,"description":"The display name of your target profile. Must match an existing profile in your workspace.","example":"Codivion TR"},"platforms":{"type":"array","items":{"type":"string","enum":["x","youtube","instagram","facebook","linkedin","tiktok","threads","pinterest","bluesky","google_business","snapchat"],"description":"Platform identifier"},"minItems":1,"description":"Target platforms to publish to. Each platform must have a connected social account for the selected profile.","example":["youtube","instagram","x"]},"auto_truncate":{"type":"boolean","default":false,"description":"Automatically trim media arrays that exceed a platform's limit (e.g., X allows max 4 images). If false, returns 400 error instead."},"scheduled_date":{"type":"string","format":"date-time","description":"Schedule for later publishing (ISO-8601 UTC). If omitted, the post is published immediately. Max 365 days in the future.","example":"2026-04-01T14:30:00Z"},"schedule_best_time":{"type":"boolean","description":"Auto-schedule to the best posting time based on your last 90 days of analytics. Finds the optimal hour and day of week, schedules for the next occurrence. Cannot be used with scheduled_date or add_to_queue."},"title":{"type":"string","description":"Post title. Used as video title on YouTube, pin title on Pinterest, and prepended to caption on other platforms.","example":"New Product Launch"},"description":{"type":"string","description":"Post caption / body text. The main text content shown on all platforms.","example":"Check out our latest feature! Now available for everyone."},"first_comment":{"type":"string","description":"Automatically post a comment after publishing. Supported on Instagram and YouTube.","example":"Link in bio!"},"post_type":{"type":"string","enum":["video"],"description":"Set to \"video\" for video posts."},"media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Exactly one public video URL. Supported formats: MP4, MOV, WebM.\n\nMaximum duration per platform:\n• YouTube — 12 hours (add #Shorts to title for YouTube Shorts)\n• Facebook — 240 minutes\n• Pinterest — 15 minutes\n• LinkedIn — 10 minutes\n• TikTok — 10 minutes\n• Threads — 5 minutes\n• Instagram Reels — 90 seconds (recommended)\n• X/Twitter — 2 min 20 sec","example":["https://cdn.example.com/video.mp4"]},"youtube_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for YouTube — replaces shared media_urls. Ignored if youtube is not in platforms."},"instagram_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Instagram — replaces shared media_urls. Ignored if instagram is not in platforms."},"tiktok_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for TikTok — replaces shared media_urls. Ignored if tiktok is not in platforms."},"facebook_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Facebook — replaces shared media_urls. Ignored if facebook is not in platforms."},"pinterest_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Pinterest — replaces shared media_urls. Ignored if pinterest is not in platforms."},"gbp_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Google Business — replaces shared media_urls. Ignored if gbp is not in platforms."},"snapchat_media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Override media for Snapchat — replaces shared media_urls. Ignored if snapchat is not in platforms."},"youtube_type":{"type":"string","enum":["video","shorts"],"description":"YouTube only — Regular video or Shorts. Shorts = vertical video under 60 sec. Thumbnails not supported for Shorts. Ignored if youtube is not in platforms."},"youtube_category_id":{"type":"string","enum":["1","2","10","15","17","20","22","23","24","25","26","27","28"],"description":"YouTube only — Video category. Ignored if youtube is not in platforms.\n1 = Film & Animation, 2 = Autos & Vehicles, 10 = Music, 15 = Pets & Animals,\n17 = Sports, 20 = Gaming, 22 = People & Blogs (default), 23 = Comedy,\n24 = Entertainment, 25 = News & Politics, 26 = Howto & Style,\n27 = Education, 28 = Science & Technology","example":"22"},"youtube_tags":{"type":"array","items":{"type":"string"},"description":"YouTube only — SEO tags. Max 500 characters total. Ignored if youtube is not in platforms.","example":["automation","social media"]},"youtube_privacy_status":{"type":"string","enum":["public","unlisted","private"],"description":"YouTube only — Video privacy (default: public). Ignored if youtube is not in platforms."},"youtube_thumbnail_url":{"type":"string","format":"uri","description":"YouTube only — Custom thumbnail URL. JPG/PNG/GIF/BMP, max 2 MB. Not supported for Shorts. Ignored if youtube is not in platforms."},"youtube_self_declared_made_for_kids":{"type":"boolean","description":"YouTube only — COPPA compliance: mark if content is made for children. Ignored if youtube is not in platforms."},"youtube_contains_synthetic_media":{"type":"boolean","description":"YouTube only — Mark if video contains AI-generated content. Ignored if youtube is not in platforms."},"youtube_has_paid_product_placement":{"type":"boolean","description":"YouTube only — FTC disclosure: contains paid sponsorship or product placement. Ignored if youtube is not in platforms."},"youtube_license":{"type":"string","enum":["youtube","creativeCommon"],"description":"YouTube only — License type (default: standard YouTube license). Ignored if youtube is not in platforms."},"youtube_embeddable":{"type":"boolean","description":"YouTube only — Allow embedding on other websites (default: true). Ignored if youtube is not in platforms."},"youtube_public_stats_viewable":{"type":"boolean","description":"YouTube only — Show view/like counts publicly (default: true). Ignored if youtube is not in platforms."},"youtube_default_language":{"type":"string","description":"YouTube only — Video language as BCP-47 code (e.g. \"en\", \"tr\", \"es\"). Ignored if youtube is not in platforms."},"youtube_default_audio_language":{"type":"string","description":"YouTube only — Audio language as BCP-47 code (e.g. \"en-US\", \"tr-TR\"). Ignored if youtube is not in platforms."},"youtube_allowed_countries":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}],"description":"YouTube only — ISO 3166-1 country codes where the video is viewable. Array or comma-separated string. Ignored if youtube is not in platforms.","example":["US","TR","DE"]},"youtube_blocked_countries":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}],"description":"YouTube only — ISO 3166-1 country codes where the video is blocked. Array or comma-separated string. Ignored if youtube is not in platforms."},"youtube_recording_date":{"type":"string","description":"YouTube only — Original recording date (ISO 8601). Ignored if youtube is not in platforms.","example":"2026-03-27T00:00:00Z"},"tiktok_privacy_level":{"type":"string","description":"TikTok only — Privacy level from creator_info API: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, or SELF_ONLY. Use GET /v1/integrations/tiktok/creator-info to get available options for the creator. Legacy values (public, friends, private) are also accepted. Ignored if tiktok is not in platforms.","example":"PUBLIC_TO_EVERYONE"},"tiktok_allow_comment":{"type":"boolean","description":"TikTok only — Allow comments on this video. Default: false (disabled). Check creator_info for account-level setting. Ignored if tiktok is not in platforms."},"tiktok_allow_duet":{"type":"boolean","description":"TikTok only — Allow duet for this video. Default: false (disabled). Check creator_info for account-level setting. Ignored if tiktok is not in platforms."},"tiktok_allow_stitch":{"type":"boolean","description":"TikTok only — Allow stitch for this video. Default: false (disabled). Check creator_info for account-level setting. Ignored if tiktok is not in platforms."},"tiktok_disable_duet":{"type":"boolean","description":"TikTok only — (Legacy) Disable duet. Prefer tiktok_allow_duet instead. Ignored if tiktok is not in platforms."},"tiktok_disable_comment":{"type":"boolean","description":"TikTok only — (Legacy) Disable comments. Prefer tiktok_allow_comment instead. Ignored if tiktok is not in platforms."},"tiktok_disable_stitch":{"type":"boolean","description":"TikTok only — (Legacy) Disable stitch. Prefer tiktok_allow_stitch instead. Ignored if tiktok is not in platforms."},"tiktok_brand_content_toggle":{"type":"boolean","description":"TikTok only — Branded content: promoting another brand or third party. Labels as \"Paid partnership.\" Cannot use SELF_ONLY privacy. Ignored if tiktok is not in platforms."},"tiktok_brand_organic_toggle":{"type":"boolean","description":"TikTok only — Your brand: promoting yourself or own business. Labels as \"Promotional content.\" Ignored if tiktok is not in platforms."},"tiktok_is_aigc":{"type":"boolean","description":"TikTok only — Mark if content is AI-generated. Ignored if tiktok is not in platforms."},"tiktok_post_mode":{"type":"string","enum":["DIRECT_POST","MEDIA_UPLOAD"],"description":"TikTok only — DIRECT_POST = publish immediately (default). MEDIA_UPLOAD = send to TikTok inbox/drafts — no metadata sent, add details in TikTok app before publishing. Ignored if tiktok is not in platforms."},"instagram_media_type":{"type":"string","enum":["REELS","STORIES"],"description":"Instagram only — Publish as Reels (default) or Stories. Ignored if instagram is not in platforms."},"instagram_share_to_feed":{"type":"boolean","description":"Instagram only — Share the reel to your main feed (default: true). Ignored if instagram is not in platforms."},"instagram_collaborators":{"type":"string","description":"Instagram only — Comma-separated collaborator usernames. Ignored if instagram is not in platforms."},"instagram_cover_url":{"type":"string","format":"uri","description":"Instagram only — Custom cover image URL for Reels. Ignored if instagram is not in platforms."},"instagram_location_id":{"type":"string","description":"Instagram only — Location ID for the post. Ignored if instagram is not in platforms."},"instagram_alt_text":{"type":"string","maxLength":1000,"description":"Instagram only — Alt text for accessibility (max 1000 chars). Ignored if instagram is not in platforms."},"x_reply_settings":{"type":"string","enum":["following","mentionedUsers"],"description":"X only — Who can reply: following or mentionedUsers. Omit for everyone. Ignored if x is not in platforms."},"x_alt_text":{"type":"string","maxLength":1000,"description":"X only — Alt text for video accessibility (max 1000 chars). Ignored if x is not in platforms."},"bluesky_alt_text":{"type":"string","maxLength":1000,"description":"Bluesky only — Alt text for accessibility (max 1000 chars). Ignored if bluesky is not in platforms."},"facebook_media_type":{"type":"string","enum":["REELS","VIDEO"],"description":"Facebook only — Publish as Reels or regular Video (default: VIDEO). Ignored if facebook is not in platforms."},"pinterest_board_id":{"type":"string","description":"Pinterest only — Target board ID (required for Pinterest). Use GET /v1/integrations/pinterest/boards to list boards. Ignored if pinterest is not in platforms."},"pinterest_link":{"type":"string","format":"uri","description":"Pinterest only — Destination URL when pin is clicked. Ignored if pinterest is not in platforms."},"pinterest_alt_text":{"type":"string","description":"Pinterest only — Alt text for accessibility. Ignored if pinterest is not in platforms."},"threads_topic_tag":{"type":"string","maxLength":50,"description":"Threads only — Topic tag (1-50 chars, no periods or ampersands). Ignored if threads is not in platforms."},"linkedin_page_id":{"type":"string","description":"LinkedIn only — Post as company page (Organization ID). Ignored if linkedin is not in platforms."},"linkedin_visibility":{"type":"string","enum":["PUBLIC","CONNECTIONS"],"description":"LinkedIn only — PUBLIC or CONNECTIONS. Ignored if linkedin is not in platforms."},"gbp_location_id":{"type":"string","description":"Google Business: Location ID from your Business Profile"},"gbp_topic_type":{"type":"string","enum":["STANDARD","EVENT","OFFER"],"description":"Google Business only — Post type: STANDARD = general update, EVENT = event announcement, OFFER = promotional offer. Ignored if gbp is not in platforms.","example":"STANDARD"},"gbp_cta_type":{"type":"string","enum":["BOOK","ORDER","SHOP","LEARN_MORE","SIGN_UP","CALL"],"description":"Google Business only — Call-to-action button type. Ignored if gbp is not in platforms.","example":"LEARN_MORE"},"gbp_cta_url":{"type":"string","format":"uri","description":"Google Business only — Destination URL for the call-to-action button. Ignored if gbp is not in platforms."},"gbp_event_title":{"type":"string","description":"Google Business only — Title for EVENT or OFFER posts. Ignored if gbp is not in platforms."},"gbp_event_start_date":{"type":"string","description":"Google Business only — Event/offer start date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-15"},"gbp_event_end_date":{"type":"string","description":"Google Business only — Event/offer end date (ISO 8601). Ignored if gbp is not in platforms.","example":"2026-04-30"},"gbp_event_start_time":{"type":"string","description":"Google Business only — Event start time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"09:00"},"gbp_event_end_time":{"type":"string","description":"Google Business only — Event end time (HH:MM, 24h format). Ignored if gbp is not in platforms.","example":"17:00"},"gbp_coupon_code":{"type":"string","description":"Google Business only — Coupon/promo code for OFFER posts. Ignored if gbp is not in platforms."},"gbp_redeem_url":{"type":"string","format":"uri","description":"Google Business only — URL where customers can redeem the offer. Ignored if gbp is not in platforms."},"gbp_terms":{"type":"string","description":"Google Business only — Terms and conditions for OFFER posts. Ignored if gbp is not in platforms."},"snapchat_post_type":{"type":"string","enum":["story","spotlight","saved_story"],"description":"Snapchat only — Content type: story = 24h disappearing, spotlight = public Spotlight feed, saved_story = permanent on profile. Ignored if snapchat is not in platforms.","example":"spotlight"},"snapchat_description":{"type":"string","maxLength":160,"description":"Snapchat only — Short description for Spotlight or Saved Story (max 160 chars). Ignored if snapchat is not in platforms."},"snapchat_locale":{"type":"string","description":"Snapchat only — Content locale (e.g. en_US, fr_FR). Ignored if snapchat is not in platforms."},"snapchat_skip_save_to_profile":{"type":"boolean","description":"Snapchat only — Skip saving Story content to your public profile. Ignored if snapchat is not in platforms."},"snapchat_saved_story_title":{"type":"string","maxLength":45,"description":"Snapchat only — Title for Saved Stories (max 45 chars, required for saved_story type). Ignored if snapchat is not in platforms."}},"required":["profile_name","platforms","post_type","media_urls"],"title":"Video Post","description":"Video post with a single video URL. Supported on: X, YouTube, Instagram, Facebook, LinkedIn, TikTok, Threads, Pinterest, Google Business, Snapchat.\n\n## Platform-Specific Parameters\n\n### Text Overrides (all platforms)\nEach platform accepts an optional text override that replaces the shared `title`/`description` for that specific platform. If omitted, the shared fields are used.\n\n| Parameter | Max | Description |\n|---|---|---|\n| `x_text` | 280 | Override text for X (Twitter) |\n| `youtube_title` | 100 | Override title for YouTube |\n| `youtube_text` | 5000 | Override description for YouTube |\n| `instagram_text` | 2200 | Override caption for Instagram |\n| `facebook_text` | 63206 | Override text for Facebook |\n| `linkedin_text` | 3000 | Override text for LinkedIn |\n| `tiktok_text` | 2200 | Override caption for TikTok |\n| `threads_text` | 500 | Override text for Threads |\n| `pinterest_text` | 500 | Override description for Pinterest |\n| `bluesky_text` | 300 | Override text for Bluesky |\n| `gbp_text` | 1500 | Override text for Google Business Profile |\n\n### YouTube\n| Parameter | Description |\n|---|---|\n| `youtube_category_id` | Video category (default: 22 = People & Blogs) |\n| `youtube_tags` | SEO tags array (max 500 chars total) |\n| `youtube_privacy_status` | public / unlisted / private |\n| `youtube_thumbnail_url` | Custom thumbnail (JPG/PNG, max 2 MB, not for Shorts) |\n| `youtube_self_declared_made_for_kids` | COPPA: content made for children |\n| `youtube_contains_synthetic_media` | AI-generated content flag |\n| `youtube_has_paid_product_placement` | FTC: paid sponsorship disclosure |\n| `youtube_license` | youtube (default) or creativeCommon |\n| `youtube_embeddable` | Allow embedding (default: true) |\n| `youtube_public_stats_viewable` | Show stats publicly (default: true) |\n| `youtube_default_language` | Video language (BCP-47: en, tr) |\n| `youtube_default_audio_language` | Audio language (BCP-47: en-US) |\n| `youtube_allowed_countries` | ISO country codes where video is viewable |\n| `youtube_blocked_countries` | ISO country codes where video is blocked |\n| `youtube_recording_date` | Original recording date (ISO 8601) |\n| `youtube_playlist_id` | Add video to a playlist (50 units). List playlists: `GET /v1/integrations/youtube/playlists` |\n\n### TikTok\n| Parameter | Description |\n|---|---|\n| `tiktok_privacy_level` | Dynamic from creator_info: PUBLIC_TO_EVERYONE / MUTUAL_FOLLOW_FRIENDS / FOLLOWER_OF_CREATOR / SELF_ONLY. Use `GET /v1/integrations/tiktok/creator-info` to get available options. Legacy: public / friends / private also accepted. |\n| `tiktok_allow_comment` | Allow comments (default: false). Check creator_info — may be disabled in account settings. |\n| `tiktok_allow_duet` | Allow duet (default: false, video only). Check creator_info — may be disabled in account settings. |\n| `tiktok_allow_stitch` | Allow stitch (default: false, video only). Check creator_info — may be disabled in account settings. |\n| `tiktok_brand_content_toggle` | Branded content: promoting another brand. Labels as \"Paid partnership\" |\n| `tiktok_brand_organic_toggle` | Your brand: promoting yourself. Labels as \"Promotional content\" |\n| `tiktok_is_aigc` | AI-generated content flag |\n\n### Instagram\n| Parameter | Description |\n|---|---|\n| `instagram_media_type` | REELS (default) or STORIES |\n| `instagram_share_to_feed` | Share reel to main feed (default: true) |\n| `instagram_collaborators` | Comma-separated collaborator usernames |\n| `instagram_cover_url` | Custom cover image URL for Reels |\n| `instagram_location_id` | Location ID for the post |\n\n### Pinterest\n\n> **Required:** Before creating a Pinterest post, you must first retrieve your board IDs using\n> [`GET /v1/integrations/pinterest/boards`](#tag/pinterest/GET/integrations/pinterest/boards).\n> Pass the desired `board_id` as `pinterest_board_id` — pins cannot be created without a target board.\n\n| Parameter | Description |\n|---|---|\n| `pinterest_board_id` | **Required.** Target board ID. Use [GET /v1/integrations/pinterest/boards](#tag/pinterest/GET/integrations/pinterest/boards) to list your boards |\n| `pinterest_link` | Destination URL when pin is clicked |\n| `pinterest_alt_text` | Alt text for accessibility |\n\n### Threads\n| Parameter | Description |\n|---|---|\n| `threads_topic_tag` | Topic tag (1-50 chars) |\n\n### LinkedIn\n| Parameter | Description |\n|---|---|\n| `linkedin_page_id` | Post as company page (Organization ID) |\n| `linkedin_visibility` | PUBLIC (default) or CONNECTIONS |\n\n### Google Business Profile (text, image & video)\n| Parameter | Description |\n|---|---|\n| `gbp_location_id` | Location ID from your Business Profile |\n| `gbp_topic_type` | STANDARD / EVENT / OFFER |\n| `gbp_cta_type` | Call-to-action button: BOOK / ORDER / SHOP / LEARN_MORE / SIGN_UP / CALL |\n| `gbp_cta_url` | Destination URL for the CTA button |\n| `gbp_event_title` | Title for EVENT or OFFER posts |\n| `gbp_event_start_date` | Event/offer start date (ISO 8601) |\n| `gbp_event_end_date` | Event/offer end date (ISO 8601) |\n| `gbp_event_start_time` | Event start time (HH:MM, 24h) |\n| `gbp_event_end_time` | Event end time (HH:MM, 24h) |\n| `gbp_coupon_code` | Coupon/promo code (OFFER only) |\n| `gbp_redeem_url` | URL to redeem the offer (OFFER only) |\n| `gbp_terms` | Terms and conditions (OFFER only) |\n\n### Snapchat (image & video)\n| Parameter | Description |\n|---|---|\n| `snapchat_post_type` | story (24h) / spotlight (public feed) / saved_story (permanent) |\n| `snapchat_description` | Short description (max 160 chars) |\n| `snapchat_saved_story_title` | Title for Saved Stories (max 45 chars) |\n| `snapchat_locale` | Content locale (e.g. en_US) |\n| `snapchat_skip_save_to_profile` | Skip saving Story to public profile |"},{"type":"object","properties":{"profile_name":{"type":"string","minLength":1,"description":"The display name of your target profile. Must match an existing profile in your workspace.","example":"Codivion TR"},"platforms":{"type":"array","items":{"type":"string","enum":["x","youtube","instagram","facebook","linkedin","tiktok","threads","pinterest","bluesky","google_business","snapchat"],"description":"Platform identifier"},"minItems":1,"description":"Target platforms to publish to. Each platform must have a connected social account for the selected profile.","example":["youtube","instagram","x"]},"auto_truncate":{"type":"boolean","default":false,"description":"Automatically trim media arrays that exceed a platform's limit (e.g., X allows max 4 images). If false, returns 400 error instead."},"scheduled_date":{"type":"string","format":"date-time","description":"Schedule for later publishing (ISO-8601 UTC). If omitted, the post is published immediately. Max 365 days in the future.","example":"2026-04-01T14:30:00Z"},"schedule_best_time":{"type":"boolean","description":"Auto-schedule to the best posting time based on your last 90 days of analytics. Finds the optimal hour and day of week, schedules for the next occurrence. Cannot be used with scheduled_date or add_to_queue."},"title":{"type":"string","description":"Post title. Used as video title on YouTube, pin title on Pinterest, and prepended to caption on other platforms.","example":"New Product Launch"},"description":{"type":"string","description":"Post caption / body text. The main text content shown on all platforms.","example":"Check out our latest feature! Now available for everyone."},"first_comment":{"type":"string","description":"Automatically post a comment after publishing. Supported on Instagram and YouTube.","example":"Link in bio!"},"post_type":{"type":"string","enum":["document"],"description":"Set to \"document\" for document posts (PDF)."},"media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Single public document URL (PDF). LinkedIn displays it as a swipeable carousel viewer. Max 100 MB, 300 pages.","example":["https://cdn.example.com/whitepaper.pdf"]},"linkedin_page_id":{"type":"string","description":"LinkedIn: Post as company page (Organization ID)"},"linkedin_visibility":{"type":"string","enum":["PUBLIC","CONNECTIONS"],"description":"LinkedIn: PUBLIC or CONNECTIONS"}},"required":["profile_name","platforms","post_type","media_urls"],"title":"Document Post","description":"Document (PDF) post. Currently supported on LinkedIn only.\n\n**LinkedIn** — Uploaded as a native document post with a swipeable carousel viewer.\n- `title` — post headline\n- `description` — commentary text above the document\n- `linkedin_page_id` — post as company page (from common parameters)\n- `linkedin_visibility` — PUBLIC or CONNECTIONS\n\nSupported formats: PDF. Max size: 100 MB, 300 pages."}]},"examples":{"simple_text":{"summary":"Simple Text Post","description":"Text post to multiple text-friendly platforms. No media needed.","value":{"post_type":"text","profile_name":"my_brand","platforms":["x","threads","bluesky"],"description":"Exciting news! Our new feature is live. Check it out!"}},"instagram_carousel":{"summary":"Instagram Carousel","description":"Multiple images auto-carousel on Instagram.","value":{"post_type":"image","profile_name":"my_brand","platforms":["instagram"],"media_urls":["https://cdn.codivupload.com/.../photo1.jpg","https://cdn.codivupload.com/.../photo2.jpg","https://cdn.codivupload.com/.../photo3.jpg"],"description":"Behind the scenes from our latest shoot 📸","instagram_alt_text":"Team working on new product designs"}},"youtube_video":{"summary":"YouTube Video","description":"Standard YouTube video with title, tags, thumbnail, and privacy. Other YouTube fields use defaults.","value":{"post_type":"video","profile_name":"my_brand","platforms":["youtube"],"media_urls":["https://cdn.codivupload.com/.../video.mp4"],"title":"Product Launch 2026","description":"Full walkthrough of our new features.","youtube_privacy_status":"public","youtube_tags":["product","launch","tech"],"youtube_thumbnail_url":"https://cdn.codivupload.com/.../thumb.jpg","youtube_category_id":"28"}},"youtube_shorts":{"summary":"YouTube Shorts","description":"Short vertical video (≤60 sec). Custom thumbnails not supported for Shorts.","value":{"post_type":"video","profile_name":"my_brand","platforms":["youtube"],"media_urls":["https://cdn.codivupload.com/.../vertical_short.mp4"],"title":"Quick tip #shorts","description":"60 second productivity hack you need to know!","youtube_type":"shorts","youtube_privacy_status":"public","youtube_self_declared_made_for_kids":false}},"tiktok_video":{"summary":"TikTok Video","description":"Direct publish to TikTok. Use GET /v1/integrations/tiktok/creator-info first to get available privacy_level_options and interaction settings for the creator.","value":{"post_type":"video","profile_name":"my_brand","platforms":["tiktok"],"media_urls":["https://cdn.codivupload.com/.../vertical.mp4"],"description":"60 second productivity hack","tiktok_privacy_level":"PUBLIC_TO_EVERYONE","tiktok_allow_comment":true,"tiktok_allow_duet":true,"tiktok_allow_stitch":true}},"tiktok_draft":{"summary":"TikTok Draft (Inbox)","description":"Send video to TikTok inbox/drafts. No metadata is sent — add title and details in the TikTok app before publishing.","value":{"post_type":"video","profile_name":"my_brand","platforms":["tiktok"],"media_urls":["https://cdn.codivupload.com/.../clip.mp4"],"tiktok_post_mode":"MEDIA_UPLOAD"}},"instagram_reel":{"summary":"Instagram Reel","description":"Video published as Instagram Reel with optional cover image and collaborators.","value":{"post_type":"video","profile_name":"my_brand","platforms":["instagram"],"media_urls":["https://cdn.codivupload.com/.../reel.mp4"],"description":"Watch till the end! 🎬","instagram_media_type":"REELS","instagram_share_to_feed":true,"instagram_cover_url":"https://cdn.codivupload.com/.../cover.jpg"}},"pinterest_pin":{"summary":"Pinterest Pin","description":"Image pin with board, click-through link, and alt text. Board ID is required — use GET /v1/integrations/pinterest/boards first.","value":{"post_type":"image","profile_name":"my_brand","platforms":["pinterest"],"media_urls":["https://cdn.codivupload.com/.../design.png"],"title":"Spring Collection 2026","description":"Fresh designs for the new season ✨","pinterest_board_id":"board_abc123","pinterest_link":"https://mybrand.com/spring-collection","pinterest_alt_text":"Colorful spring clothing designs on a white background"}},"multi_platform_override":{"summary":"Multi-Platform (different media per platform)","description":"Same text, different video per platform. YouTube gets the shared horizontal video, TikTok gets a vertical version, Instagram gets a square version. Each platform also gets its own relevant overrides.","value":{"post_type":"video","profile_name":"my_brand","platforms":["youtube","tiktok","instagram"],"media_urls":["https://cdn.codivupload.com/.../horizontal.mp4"],"tiktok_media_urls":["https://cdn.codivupload.com/.../vertical.mp4"],"instagram_media_urls":["https://cdn.codivupload.com/.../square.mp4"],"title":"Day in my life","description":"Follow along for a day at the office!","youtube_privacy_status":"public","youtube_tags":["vlog","day-in-my-life"],"tiktok_privacy_level":"PUBLIC_TO_EVERYONE","tiktok_post_mode":"DIRECT_POST","instagram_media_type":"REELS","instagram_share_to_feed":true}},"scheduled_post":{"summary":"Scheduled Post","description":"Schedule a post for a future date. The system automatically publishes at the specified time.","value":{"post_type":"text","profile_name":"my_brand","platforms":["linkedin","x"],"description":"We are hiring! Senior engineers wanted. DM us.","scheduled_date":"2026-04-15T09:00:00Z","linkedin_visibility":"PUBLIC","x_reply_settings":"following"}},"queue_post":{"summary":"Queue Auto-Slot","description":"Auto-schedule to the next available queue slot. Requires Starter plan. Configure slots via POST /v1/queue/settings.","value":{"post_type":"image","profile_name":"my_brand","platforms":["instagram","facebook","pinterest"],"media_urls":["https://cdn.codivupload.com/.../design.png"],"description":"Fresh designs for the new collection ✨","add_to_queue":true,"pinterest_board_id":"board_abc123","pinterest_link":"https://mybrand.com/collection"}},"gbp_offer":{"summary":"Google Business — Offer Post","description":"Promotional offer on Google Business Profile with coupon code and CTA button.","value":{"post_type":"text","profile_name":"my_brand","platforms":["gbp"],"description":"Spring sale! 20% off all services this month.","gbp_topic_type":"OFFER","gbp_event_title":"Spring Sale — 20% Off","gbp_event_start_date":"2026-04-01","gbp_event_end_date":"2026-04-30","gbp_coupon_code":"SPRING20","gbp_cta_type":"SHOP","gbp_cta_url":"https://mybrand.com/spring-sale","gbp_redeem_url":"https://mybrand.com/redeem"}},"youtube_advanced":{"summary":"YouTube Video — Advanced Options","description":"YouTube video with captions, playlist, country restrictions, language, and compliance flags.","value":{"post_type":"video","profile_name":"my_brand","platforms":["youtube"],"media_urls":["https://cdn.codivupload.com/.../tutorial.mp4"],"title":"Complete API Tutorial — Getting Started","description":"Learn how to use the CodivUpload API from scratch. Chapters below ⬇️","youtube_privacy_status":"public","youtube_category_id":"27","youtube_tags":["api","tutorial","automation"],"youtube_thumbnail_url":"https://cdn.codivupload.com/.../thumb.jpg","youtube_default_language":"en","youtube_default_audio_language":"en-US","youtube_caption_url":"https://cdn.codivupload.com/.../captions.srt","youtube_caption_language":"en","youtube_playlist_id":"PLxxxxxxxx","youtube_license":"youtube","youtube_embeddable":true,"youtube_self_declared_made_for_kids":false,"youtube_contains_synthetic_media":false,"first_comment":"Chapters: 0:00 Intro, 1:30 Setup, 5:00 First Request"}},"snapchat_spotlight":{"summary":"Snapchat Spotlight","description":"Video published to Snapchat Spotlight (public feed).","value":{"post_type":"video","profile_name":"my_brand","platforms":["snapchat"],"media_urls":["https://cdn.codivupload.com/.../snap_video.mp4"],"snapchat_post_type":"spotlight","snapchat_description":"Quick behind the scenes look 👀"}}}}}},"responses":{"200":{"description":"Post published immediately","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Post successfully queued for immediate delivery."},"post_id":{"type":"string","format":"uuid","description":"Unique ID of the created post","example":"550e8400-e29b-41d4-a716-446655440000"},"destinations_count":{"type":"number","description":"Number of platforms the post was sent to","example":3},"received_type":{"type":"string","description":"The post type that was processed","example":"video"},"is_immediate":{"type":"boolean","description":"True if published immediately, false if scheduled","example":true}},"required":["message","post_id","destinations_count","received_type","is_immediate"]}}}},"202":{"description":"Post scheduled for later","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Post successfully queued for immediate delivery."},"post_id":{"type":"string","format":"uuid","description":"Unique ID of the created post","example":"550e8400-e29b-41d4-a716-446655440000"},"destinations_count":{"type":"number","description":"Number of platforms the post was sent to","example":3},"received_type":{"type":"string","description":"The post type that was processed","example":"video"},"is_immediate":{"type":"boolean","description":"True if published immediately, false if scheduled","example":true}},"required":["message","post_id","destinations_count","received_type","is_immediate"]}}}},"400":{"description":"Validation error: unsupported platform, character limit exceeded, invalid media format","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Post type 'document' is not supported by: x"},"details":{"nullable":true,"description":"Detailed validation errors (if applicable)"}},"required":["error"]}}}},"401":{"description":"Invalid or missing API key"},"403":{"description":"Plan tier insufficient (Free users cannot use API keys) or monthly post quota exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Feature requires a higher plan"},"required_tier":{"type":"string","enum":["starter","pro","business","enterprise"],"description":"Minimum plan needed"},"current_tier":{"type":"string","description":"Current workspace plan"},"upgrade_url":{"type":"string","description":"Dashboard URL to upgrade"}},"required":["error","required_tier","current_tier","upgrade_url"],"description":"Plan tier insufficient for this feature","example":{"error":"This feature requires the Starter plan or above.","required_tier":"starter","current_tier":"free","upgrade_url":"/dashboard/subscription"}}}}},"404":{"description":"Profile not found in workspace"},"429":{"description":"Daily platform limit exceeded — includes violations array with per-platform details"}}},"get":{"operationId":"listPosts","tags":["Posts"],"summary":"List Posts","description":"Retrieve all posts for your workspace with optional filters. Results include destination statuses per platform.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["draft","scheduled","publishing","completed","partially_failed","failed"],"description":"Filter by post status"},"required":false,"description":"Filter by post status","name":"status","in":"query"},{"schema":{"type":"string","description":"Filter by profile name"},"required":false,"description":"Filter by profile name","name":"profile_name","in":"query"},{"schema":{"type":"string","description":"Results per page (max 100, default 20)","example":"20"},"required":false,"description":"Results per page (max 100, default 20)","name":"limit","in":"query"},{"schema":{"type":"string","description":"Pagination offset (default 0)","example":"0"},"required":false,"description":"Pagination offset (default 0)","name":"offset","in":"query"}],"responses":{"200":{"description":"Post list","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"post_type":{"type":"string"},"status":{"type":"string"},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"media_urls":{"type":"array","nullable":true,"items":{"type":"string"}},"scheduled_date":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"post_destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string"},"status":{"type":"string"},"external_job_id":{"type":"string","nullable":true,"description":"Platform-specific post ID"},"post_url":{"type":"string","nullable":true,"description":"Direct URL to the published post on the platform","example":"https://youtube.com/watch?v=abc123"},"error_message":{"type":"string","nullable":true}},"required":["id","platform","status","external_job_id","post_url","error_message"]}}},"required":["id","post_type","status","title","description","media_urls","scheduled_date","created_at","updated_at","post_destinations"]}},"total":{"type":"number","example":42},"limit":{"type":"number","example":20},"offset":{"type":"number","example":0}},"required":["posts","total","limit","offset"]}}}},"401":{"description":"Invalid API key"}}}},"/upload-media":{"post":{"operationId":"uploadMedia","tags":["CDN Upload"],"summary":"Upload Media to CDN","description":"Upload a file to the CodivUpload CDN (Cloudflare R2). Returns a public URL that can be used in the `media_urls` field when creating a post.\n\n## Two Upload Methods\n\n### 1. File Upload (multipart/form-data)\nSend the file directly as form data. Best for UI file pickers and drag-drop uploads.\n\n```\ncurl -X POST /v1/upload-media \\\n  -H \"Authorization: Bearer YOUR_TOKEN\" \\\n  -F \"file=@photo.jpg\" \\\n  -F \"profile_name=WhiskeyBlues\"\n```\n\n### 2. URL Upload (application/json)\nProvide a public URL and we fetch + store it on CDN. Best for external integrations.\n\n```json\n{\n  \"url\": \"https://example.com/image.jpg\",\n  \"profile_name\": \"WhiskeyBlues\",\n  \"type\": \"image\"\n}\n```\n\n## Parameters\n\n| Parameter | Type | Required | Description |\n|---|---|---|---|\n| `file` | binary | Yes* | File to upload (multipart mode) |\n| `url` | string | Yes* | Public URL to fetch (JSON mode) |\n| `profile_name` | string | Yes | Target profile name in your workspace |\n| `type` | string | No | Force file type: image, video, document. Auto-detected if omitted. |\n\n*One of `file` or `url` is required.\n\n## Supported Formats\n- **Images:** JPG, PNG, WebP, GIF, BMP\n- **Videos:** MP4, MOV, WebM, AVI, MKV\n- **Documents:** PDF, DOC, DOCX, PPT, PPTX\n\n## Limits\n- Max file size depends on your plan\n- Large files (>64 MB) are automatically uploaded in parallel chunks for reliability\n- URL fetch timeout: 2 minutes\n\n## CDN Storage\n- Files are stored on the CodivUpload CDN (Cloudflare R2)\n- Path: `{workspace}/{profile}/{upload_id}/original.{ext}`\n- Files expire after 30 days if not linked to a post\n- After post is published, files remain for 30 days (platforms copy the media)","security":[{"bearerAuth":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"nullable":true,"description":"File to upload (binary)"},"profile_name":{"type":"string","description":"Target profile name","example":"WhiskeyBlues"},"type":{"type":"string","enum":["image","video","document"],"description":"File type (auto-detected if omitted)"}},"required":["profile_name"]}},"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Public URL to fetch and upload","example":"https://example.com/photo.jpg"},"profile_name":{"type":"string","description":"Target profile name","example":"WhiskeyBlues"},"type":{"type":"string","enum":["image","video","document"],"description":"File type (auto-detected if omitted)"}},"required":["url","profile_name"]}}}},"responses":{"200":{"description":"File uploaded successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"url":{"type":"string","format":"uri","description":"Public CDN URL of the uploaded file","example":"https://cdn.codivupload.com/ws_123/prof_456/upl_789/original.jpg"},"upload_id":{"type":"string","format":"uuid","description":"Unique upload identifier"},"file_type":{"type":"string","enum":["image","video","document"],"description":"Detected file type"},"file_size":{"type":"number","description":"File size in bytes","example":245760},"file_name":{"type":"string","description":"Original file name","example":"photo.jpg"}},"required":["success","url","upload_id","file_type","file_size","file_name"]}}}},"400":{"description":"Missing file/URL or invalid profile"},"401":{"description":"Invalid or missing authentication"},"404":{"description":"Profile not found in workspace"},"500":{"description":"Upload failed (R2 error)"}}}},"/posts/{id}":{"get":{"operationId":"getPost","tags":["Posts"],"summary":"Get Post Details","description":"Retrieve a single post with all platform destination statuses. Use the `post_id` from the create response to check publishing progress.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Post ID"},"required":true,"description":"Post ID","name":"id","in":"path"}],"responses":{"200":{"description":"Post details","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"post_type":{"type":"string"},"status":{"type":"string"},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"media_urls":{"type":"array","nullable":true,"items":{"type":"string"}},"scheduled_date":{"type":"string","nullable":true},"first_comment":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","post_type","status","title","description","media_urls","scheduled_date","first_comment","created_at","updated_at"]},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string"},"status":{"type":"string"},"external_job_id":{"type":"string","nullable":true},"post_url":{"type":"string","nullable":true,"description":"Direct URL to the published post on the platform"},"error_message":{"type":"string","nullable":true},"override_data":{"nullable":true},"created_at":{"type":"string"}},"required":["id","platform","status","external_job_id","post_url","error_message","created_at"]}}},"required":["post","destinations"]}}}},"401":{"description":"Invalid API key"},"404":{"description":"Post not found"}}},"patch":{"operationId":"updatePost","tags":["Posts"],"summary":"Update Post","description":"Update a post that has not been published yet.\n\n**Only `draft` and `scheduled` posts can be updated.** Posts that are currently publishing, completed, or failed cannot be modified.\n\nFor scheduled posts, `scheduled_date` cannot be removed — if you want to publish immediately, delete this post and create a new one without a date.\n\nTo change target platforms, delete the post and create a new one.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Post ID"},"required":true,"description":"Post ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"New title"},"description":{"type":"string","description":"New caption/body text"},"media_urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"Replace media URLs"},"scheduled_date":{"type":"string","nullable":true,"format":"date-time","description":"New scheduled date (ISO-8601). Cannot be removed from scheduled posts."},"first_comment":{"type":"string","nullable":true,"description":"New first comment text"}},"title":"UpdatePostBody"}}}},"responses":{"200":{"description":"Post updated","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"post":{"nullable":true}},"required":["message"]}}}},"400":{"description":"Post cannot be updated (wrong status or validation error)"},"401":{"description":"Invalid API key"},"404":{"description":"Post not found"}}},"delete":{"operationId":"deletePost","tags":["Posts"],"summary":"Delete Post","description":"Delete a post and all its platform destinations.\n\n**Deletable statuses:** `draft`, `scheduled`, `publishing` (if not yet published), `failed`.\n\n**Cannot delete:** `completed` or `partially_failed` posts — these have already been published to at least one platform.\n\nIf the post is in the publishing queue, it will be automatically removed from the queue before deletion.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Post ID"},"required":true,"description":"Post ID","name":"id","in":"path"}],"responses":{"200":{"description":"Post deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"post_id":{"type":"string","format":"uuid"}},"required":["message","post_id"]}}}},"401":{"description":"Invalid API key"},"404":{"description":"Post not found"},"409":{"description":"Post already published — cannot delete"}}}},"/integrations/pinterest/boards":{"get":{"tags":["Pinterest"],"summary":"List Pinterest boards","description":"Returns the authenticated user's Pinterest boards for board selection when creating pins. Requires an active Pinterest connection for the specified profile.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Profile name to look up Pinterest connection","example":"my-brand"},"required":false,"description":"Profile name to look up Pinterest connection","name":"profile_name","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Profile UUID (alternative to profile_name)"},"required":false,"description":"Profile UUID (alternative to profile_name)","name":"profile_id","in":"query"}],"responses":{"200":{"description":"List of Pinterest boards","content":{"application/json":{"schema":{"type":"object","properties":{"boards":{"type":"array","items":{"type":"object","properties":{"board_id":{"type":"string","description":"Pinterest board ID","example":"729090695864053352"},"name":{"type":"string","description":"Board name","example":"Travel Inspiration"},"description":{"type":"string","description":"Board description"},"privacy":{"type":"string","description":"Board privacy setting","example":"PUBLIC"}},"required":["board_id","name","description","privacy"]}},"total":{"type":"number","description":"Total number of boards"}},"required":["boards","total"]}}}},"404":{"description":"No active Pinterest connection found for this profile"},"502":{"description":"Failed to fetch boards from Pinterest API"}}}},"/integrations/tiktok/creator-info":{"get":{"tags":["TikTok"],"summary":"Get TikTok creator posting constraints","description":"Returns the creator's dynamic posting constraints from TikTok. **Must be called before creating a TikTok post** to get available privacy levels, interaction settings, and video duration limits.\n\nThe response determines:\n- **`privacy_level_options`**: Which privacy levels the creator can use (varies per account)\n- **`comment_disabled` / `duet_disabled` / `stitch_disabled`**: Whether these features are disabled in the creator's TikTok settings\n- **`max_video_post_duration_sec`**: Maximum allowed video duration\n\nRate limit: 20 requests per minute per TikTok user.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Profile name with an active TikTok connection","example":"my-brand"},"required":true,"description":"Profile name with an active TikTok connection","name":"profile_name","in":"query"}],"responses":{"200":{"description":"Creator posting constraints","content":{"application/json":{"schema":{"type":"object","properties":{"creator_avatar_url":{"type":"string","nullable":true,"description":"Creator avatar URL"},"creator_username":{"type":"string","nullable":true,"description":"TikTok username","example":"myuser"},"creator_nickname":{"type":"string","nullable":true,"description":"Display name","example":"My Brand"},"privacy_level_options":{"type":"array","items":{"type":"string"},"description":"Available privacy levels for this creator","example":["PUBLIC_TO_EVERYONE","MUTUAL_FOLLOW_FRIENDS","FOLLOWER_OF_CREATOR","SELF_ONLY"]},"comment_disabled":{"type":"boolean","description":"Whether comments are disabled in creator settings"},"duet_disabled":{"type":"boolean","description":"Whether duets are disabled in creator settings"},"stitch_disabled":{"type":"boolean","description":"Whether stitches are disabled in creator settings"},"max_video_post_duration_sec":{"type":"number","description":"Maximum video duration in seconds","example":600}},"required":["creator_avatar_url","creator_username","creator_nickname","privacy_level_options","comment_disabled","duet_disabled","stitch_disabled","max_video_post_duration_sec"]}}}},"401":{"description":"TikTok token expired — reconnect the account"},"404":{"description":"No active TikTok connection for this profile"},"429":{"description":"TikTok rate limit exceeded (20 req/min per user)"}}}},"/webhooks":{"get":{"operationId":"listWebhooks","tags":["Webhooks"],"summary":"List Webhook Endpoints","description":"Returns all webhook endpoints configured for the authenticated workspace.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of webhook endpoints","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique webhook endpoint ID"},"url":{"type":"string","format":"uri","description":"HTTPS URL that receives webhook POST requests","example":"https://yourapp.com/webhooks/codivupload"},"events":{"type":"array","items":{"type":"string","enum":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Webhook event type. Your endpoint will only receive events it is subscribed to."},"description":"Events this endpoint is subscribed to","example":["post.success","post.failed"]},"is_active":{"type":"boolean","description":"Whether this endpoint is currently active","example":true},"description":{"type":"string","nullable":true,"description":"Optional human-readable label","example":"Production post notifications"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"updated_at":{"type":"string","nullable":true,"format":"date-time","description":"Last update timestamp"}},"required":["id","url","events","is_active","description","created_at","updated_at"]}}},"required":["success","webhooks"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Requires Business plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Feature requires a higher plan"},"required_tier":{"type":"string","enum":["starter","pro","business","enterprise"],"description":"Minimum plan needed"},"current_tier":{"type":"string","description":"Current workspace plan"},"upgrade_url":{"type":"string","description":"Dashboard URL to upgrade"}},"required":["error","required_tier","current_tier","upgrade_url"],"description":"Plan tier insufficient for this feature","example":{"error":"This feature requires the Starter plan or above.","required_tier":"starter","current_tier":"free","upgrade_url":"/dashboard/subscription"}}}}}}},"post":{"operationId":"createWebhook","tags":["Webhooks"],"summary":"Create Webhook Endpoint","description":"Create a new webhook endpoint. Maximum 5 endpoints per workspace.\n\nA signing secret (`whsec_...`) is returned **only once** in the creation response. Store it securely — it is used to verify webhook signatures.\n\n## Supported Events\n\n| Event | Trigger |\n|---|---|\n| `post.success` | A post was successfully published to a platform |\n| `post.failed` | A post failed to publish to a platform |\n| `post.scheduled` | A post was created with a future `scheduled_date` |\n| `post.deleted` | A scheduled or draft post was deleted |\n| `profile.connected` | A new social account was connected via OAuth |\n| `profile.disconnected` | A social account connection was revoked |\n\n## Webhook Delivery\n\nWhen an event fires, CodivUpload sends a `POST` request to your URL with:\n\n**Headers:**\n| Header | Description |\n|---|---|\n| `Content-Type` | `application/json` |\n| `X-Webhook-Event` | Event type (e.g. `post.success`) |\n| `X-Webhook-Signature` | HMAC-SHA256 hex digest of the request body, signed with your secret |\n\n**Body:**\n```json\n{\n  \"event\": \"post.success\",\n  \"timestamp\": \"2026-04-08T14:30:00.000Z\",\n  \"workspace_id\": \"ws_abc123\",\n  \"data\": {\n    \"post_id\": \"550e8400-...\",\n    \"destination_id\": \"660e8400-...\",\n    \"platform\": \"instagram\",\n    \"post_url\": \"https://www.instagram.com/p/ABC123/\"\n  }\n}\n```\n\n## Verifying Signatures\n\nTo verify that a webhook came from CodivUpload, compute the HMAC-SHA256 of the raw request body using your signing secret and compare it with the `X-Webhook-Signature` header:\n\n```javascript\nconst crypto = require(\"crypto\");\n\nfunction verifyWebhook(body, signature, secret) {\n  const expected = crypto\n    .createHmac(\"sha256\", secret)\n    .update(body)\n    .digest(\"hex\");\n  return crypto.timingSafeEqual(\n    Buffer.from(signature),\n    Buffer.from(expected)\n  );\n}\n```\n\n```python\nimport hmac, hashlib\n\ndef verify_webhook(body: bytes, signature: str, secret: str) -> bool:\n    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()\n    return hmac.compare_digest(signature, expected)\n```\n\n## Delivery Behavior\n\n- Timeout: 10 seconds per delivery attempt\n- All deliveries are logged (success and failure)\n- Webhooks are fire-and-forget — they do not block post publishing\n- Failed deliveries do not automatically retry (check delivery logs in Dashboard)","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"HTTPS URL to receive webhook events. Must start with https://.","example":"https://yourapp.com/webhooks/codivupload"},"events":{"type":"array","items":{"type":"string","enum":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Webhook event type. Your endpoint will only receive events it is subscribed to."},"minItems":1,"description":"One or more event types to subscribe to","example":["post.success","post.failed"]},"description":{"type":"string","description":"Optional label for this webhook","example":"Slack notification relay"}},"required":["url","events"]},"examples":{"post_events":{"summary":"Subscribe to post events","value":{"url":"https://yourapp.com/webhooks/codivupload","events":["post.success","post.failed"],"description":"Notify Slack on post results"}},"all_events":{"summary":"Subscribe to all events","value":{"url":"https://yourapp.com/webhooks/codivupload","events":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Full event stream"}}}}}},"responses":{"201":{"description":"Webhook created. The `secret` field is only returned once — store it securely.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique webhook endpoint ID"},"url":{"type":"string","format":"uri","description":"HTTPS URL that receives webhook POST requests","example":"https://yourapp.com/webhooks/codivupload"},"events":{"type":"array","items":{"type":"string","enum":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Webhook event type. Your endpoint will only receive events it is subscribed to."},"description":"Events this endpoint is subscribed to","example":["post.success","post.failed"]},"is_active":{"type":"boolean","description":"Whether this endpoint is currently active","example":true},"description":{"type":"string","nullable":true,"description":"Optional human-readable label","example":"Production post notifications"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"updated_at":{"type":"string","nullable":true,"format":"date-time","description":"Last update timestamp"},"secret":{"type":"string","description":"Signing secret (whsec_...). Shown only once at creation.","example":"whsec_a1b2c3d4e5f6..."}},"required":["id","url","events","is_active","description","created_at","updated_at","secret"]}},"required":["success","webhook"]}}}},"400":{"description":"Validation error or maximum 5 webhooks reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Requires Business plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Feature requires a higher plan"},"required_tier":{"type":"string","enum":["starter","pro","business","enterprise"],"description":"Minimum plan needed"},"current_tier":{"type":"string","description":"Current workspace plan"},"upgrade_url":{"type":"string","description":"Dashboard URL to upgrade"}},"required":["error","required_tier","current_tier","upgrade_url"],"description":"Plan tier insufficient for this feature","example":{"error":"This feature requires the Starter plan or above.","required_tier":"starter","current_tier":"free","upgrade_url":"/dashboard/subscription"}}}}}}}},"/webhooks/{id}":{"patch":{"operationId":"updateWebhook","tags":["Webhooks"],"summary":"Update Webhook Endpoint","description":"Update a webhook endpoint's URL, events, active status, or description. Only provided fields are updated.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook endpoint ID"},"required":true,"description":"Webhook endpoint ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"New HTTPS URL"},"events":{"type":"array","items":{"type":"string","enum":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Webhook event type. Your endpoint will only receive events it is subscribed to."},"description":"Updated event subscriptions"},"is_active":{"type":"boolean","description":"Enable or disable this endpoint"},"description":{"type":"string","nullable":true,"description":"Update the label"}}},"examples":{"toggle_active":{"summary":"Disable a webhook","value":{"is_active":false}},"update_events":{"summary":"Change subscribed events","value":{"events":["post.success","post.failed","post.scheduled"]}}}}}},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique webhook endpoint ID"},"url":{"type":"string","format":"uri","description":"HTTPS URL that receives webhook POST requests","example":"https://yourapp.com/webhooks/codivupload"},"events":{"type":"array","items":{"type":"string","enum":["post.success","post.failed","post.scheduled","post.deleted","profile.connected","profile.disconnected"],"description":"Webhook event type. Your endpoint will only receive events it is subscribed to."},"description":"Events this endpoint is subscribed to","example":["post.success","post.failed"]},"is_active":{"type":"boolean","description":"Whether this endpoint is currently active","example":true},"description":{"type":"string","nullable":true,"description":"Optional human-readable label","example":"Production post notifications"},"created_at":{"type":"string","format":"date-time","description":"Creation timestamp"},"updated_at":{"type":"string","nullable":true,"format":"date-time","description":"Last update timestamp"}},"required":["id","url","events","is_active","description","created_at","updated_at"]}},"required":["success","webhook"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Requires Business plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Feature requires a higher plan"},"required_tier":{"type":"string","enum":["starter","pro","business","enterprise"],"description":"Minimum plan needed"},"current_tier":{"type":"string","description":"Current workspace plan"},"upgrade_url":{"type":"string","description":"Dashboard URL to upgrade"}},"required":["error","required_tier","current_tier","upgrade_url"],"description":"Plan tier insufficient for this feature","example":{"error":"This feature requires the Starter plan or above.","required_tier":"starter","current_tier":"free","upgrade_url":"/dashboard/subscription"}}}}},"404":{"description":"Webhook not found"}}},"delete":{"operationId":"deleteWebhook","tags":["Webhooks"],"summary":"Delete Webhook Endpoint","description":"Permanently delete a webhook endpoint. All delivery logs for this endpoint are also removed.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Webhook endpoint ID"},"required":true,"description":"Webhook endpoint ID","name":"id","in":"path"}],"responses":{"200":{"description":"Webhook deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message"}},"required":["error"],"description":"Missing or invalid Authorization header","example":{"error":"Missing or invalid Authorization header"}}}}},"403":{"description":"Requires Business plan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Feature requires a higher plan"},"required_tier":{"type":"string","enum":["starter","pro","business","enterprise"],"description":"Minimum plan needed"},"current_tier":{"type":"string","description":"Current workspace plan"},"upgrade_url":{"type":"string","description":"Dashboard URL to upgrade"}},"required":["error","required_tier","current_tier","upgrade_url"],"description":"Plan tier insufficient for this feature","example":{"error":"This feature requires the Starter plan or above.","required_tier":"starter","current_tier":"free","upgrade_url":"/dashboard/subscription"}}}}},"404":{"description":"Webhook not found"}}}}}}