ViralCat

Schedule and publish social posts across platforms, with drafts, media uploads and analytics.

Should I use this

Quality & Safety

A
Description quality
100%
Schema completeness
90%
Naming quality
91%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~5,528Tokens (tool definitions)
~1.8 KBTypical response size
Significant attention impact (4.32% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "viral-cat": {
      "url": "https://viral-cat.com/api/mcp/mcp"
    }
  }
}

Remote endpoints

https://viral-cat.com/api/mcp/mcpstreamable-http

What it can do

Tool inventory

Tools (21)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟡list_brands(limit, include_samples)

List brands (content profiles), newest first, with per-brand post counts (posted/scheduled) and the next scheduled date. Use to see which brands exist and how active each is. Excludes archived brands. Returns `total` (all active brands) next to `count` (rows returned): when `truncated` is true the roster was cut off by `limit`, so raise it (max 50) before concluding a brand does not exist.

Input Schema

{
  "type": "object",
  "properties": {
    "limit": {
      "default": 20,
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡get_brand_details(brand_id, include_samples)

Full content profile for one brand: description, taglines, hashtags, CTA/website URL, niche (category/subcategory), content type, target platforms, and active discount. Use this to write on-brand captions BEFORE calling create_draft or schedule_post. Read-only; returns no secrets.

Input Schema

{
  "type": "object",
  "properties": {
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "required": [
    "brand_id"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_posts(status, platform, limit, include_samples)

List posts across all platforms, newest scheduled first. Each row is one publication on one platform. Filter by status (draft|scheduled|posting|posted|failed|cancelled) and/or platform (youtube|tiktok|instagram|...). Returns caption, brand name, permalink, error message when present, and publishWarning for posts that succeeded with an anomaly (e.g. published without media).

Input Schema

{
  "type": "object",
  "properties": {
    "status": {
      "type": "string",
      "enum": [
        "draft",
        "scheduled",
        "posting",
        "posted",
        "failed",
        "cancelled"
      ]
    },
    "platform": {
      "description": "Filter to a single platform, e.g. youtube or tiktok",
      "type": "string",
      "maxLength": 20
    },
    "limit": {
      "default": 20,
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_pipeline_summary(include_samples)

High-level snapshot of the posting pipeline: active brand count, a status breakdown (how many scheduled/posted/failed/etc.), a per-platform breakdown, how many posts are due in the next 7 days, and the next scheduled date. Use for 'how's the pipeline?' style questions.

Input Schema

{
  "type": "object",
  "properties": {
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_connections(include_samples)

List connected platform accounts (channels) and their health: platform, account username, connected flag, posting-enabled flag, and token expiry. Use to check which platforms are wired up and whether any connection has expired. Never returns access or refresh tokens.

Input Schema

{
  "type": "object",
  "properties": {
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡post_performance(brand_id, platform, days, include_samples)

Publish-outcome metrics over a rolling window (default 30 days): posted/failed/cancelled totals, success rate, per-platform breakdown, and the most recent published posts with permalinks plus their latest stored engagement snapshot (views/likes/comments/shares; available for youtube/tiktok/twitter/threads). Snapshots are stored, not live: call refresh_post_metrics first if the numbers must be current. Optionally scope by brand_id and/or platform.

Input Schema

{
  "type": "object",
  "properties": {
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "platform": {
      "type": "string",
      "maxLength": 20
    },
    "days": {
      "default": 30,
      "type": "integer",
      "minimum": 1,
      "maximum": 365
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡content_queue(limit, include_samples)

The forward content pipeline: drafts awaiting approval first, then scheduled posts in publish order. Use to review what is queued before it goes out, and to find draft ids for schedule_post.

Input Schema

{
  "type": "object",
  "properties": {
    "limit": {
      "default": 50,
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡campaign_summary(brand_id, include_samples)

Per-brand campaign rollup (brands are ViralCat's campaign unit): posted/scheduled/failed/draft counts, platforms used, next scheduled date, last posted date, and auto-post settings. Optionally scope to one brand_id.

Input Schema

{
  "type": "object",
  "properties": {
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢diagnose_failures(days, platform, include_samples)

Group failed posts by platform + normalized failure reason: counts, date range, affected brands, a sample raw error, a recoverable flag (retry_failed_posts can re-queue it) and a concrete suggested fix per group. Answers "what is broken and why" in one call. Read-only.

Input Schema

{
  "type": "object",
  "properties": {
    "days": {
      "default": 60,
      "description": "Rolling window of failed posts to analyze",
      "type": "integer",
      "minimum": 1,
      "maximum": 365
    },
    "platform": {
      "description": "Scope to a single platform, e.g. pinterest",
      "type": "string",
      "maxLength": 20
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡preflight_check(post_id, limit, include_samples)

READ-ONLY: validate a post BEFORE it is scheduled or published, so a problem is caught up front instead of discovered as a failure afterwards. Checks the exact things that produced the failed-post backlog: incompatible media for the platform (e.g. video to Pinterest), a disconnected or unrefreshable platform token (LinkedIn has no refresh token on this API tier and needs a manual browser reconnect roughly every 60 days — that's an expected state, not a bug), Facebook posting to an account with no Page (impossible via the Graph API), content referencing an already-passed date/season/promo code, and X/Twitter free-tier monthly write-cap headroom. Pass post_id to check one existing post; omit it to scan the forward queue (draft + scheduled, soonest first) and return only posts that have at least one issue.

Input Schema

{
  "type": "object",
  "properties": {
    "post_id": {
      "description": "Check one existing post (id from list_posts or content_queue). Omit to scan the whole upcoming queue instead.",
      "type": "integer",
      "minimum": -9007199254740991,
      "maximum": 9007199254740991
    },
    "limit": {
      "default": 20,
      "description": "Queue-scan mode only: how many upcoming posts to check.",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "include_samples": {
      "default": false,
      "description": "Include sample users (email contains \"sample\"). Default: real data only.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_draft(brand_id, platform, caption, scheduled_date, skip_hashtags, ...)

WRITE (safe): create a DRAFT post for a brand. Drafts are never picked up by the publisher, so nothing goes live; a human approves in the dashboard or promotes it later with schedule_post. scheduled_date is a proposed slot (default: 7 days out).

Input Schema

{
  "type": "object",
  "properties": {
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "platform": {
      "type": "string",
      "maxLength": 20,
      "description": "Target platform, e.g. youtube, tiktok, instagram"
    },
    "caption": {
      "description": "Post body. Omit to inherit the brand's taglines.",
      "type": "string",
      "maxLength": 2200
    },
    "scheduled_date": {
      "description": "Proposed ISO 8601 slot, e.g. 2026-07-15T09:00:00Z",
      "type": "string"
    },
    "skip_hashtags": {
      "description": "true = publish the caption as-is with NO brand hashtags appended; false = always append them. Omit to auto-detect: long hand-authored captions (>280 chars, no '#') skip hashtags. The result's hashtagsSkipped shows the decision.",
      "type": "boolean"
    },
    "reply_text": {
      "description": "Follow-up reply posted under the main post. On X this is where a link belongs: a URL in the post body costs up to 94% of the reach (near-total on a non-Premium account), while the same URL one reply down costs nothing. Omit to reply with the brand's CTA url; pass an empty string for no reply at all. Ignored by every platform except X.",
      "type": "string",
      "maxLength": 2200
    }
  },
  "required": [
    "brand_id",
    "platform"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡schedule_post(post_id, brand_id, platform, caption, scheduled_date, ...)

WRITE (gated): queue a post for FUTURE publishing, at least 15 minutes out (immediate posting is not available over MCP). Either pass post_id to promote an existing draft, or brand_id + platform to create a new scheduled post. The publishing cron sends it at the scheduled time.

Input Schema

{
  "type": "object",
  "properties": {
    "post_id": {
      "description": "Draft post id to promote (from content_queue)",
      "type": "integer",
      "minimum": -9007199254740991,
      "maximum": 9007199254740991
    },
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "platform": {
      "type": "string",
      "maxLength": 20
    },
    "caption": {
      "type": "string",
      "maxLength": 2200
    },
    "scheduled_date": {
      "type": "string",
      "description": "ISO 8601, at least 15 minutes in the future"
    },
    "skip_hashtags": {
      "description": "true = publish the caption as-is with NO brand hashtags appended; false = always append them. Omit to auto-detect: long hand-authored captions (>280 chars, no '#') skip hashtags. When promoting a draft without a new caption, omitting this keeps the draft's existing setting.",
      "type": "boolean"
    },
    "reply_text": {
      "description": "Follow-up reply posted under the main post. On X this is where a link belongs: a URL in the post body costs up to 94% of the reach (near-total on a non-Premium account), while the same URL one reply down costs nothing. Omit to reply with the brand's CTA url; pass an empty string for no reply at all. Ignored by every platform except X.",
      "type": "string",
      "maxLength": 2200
    }
  },
  "required": [
    "scheduled_date"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴cancel_post(post_id, scheduled_date)

WRITE (safe): cancel a queued post, or move it to a new slot. Omit scheduled_date to CANCEL (status -> cancelled; the publisher ignores it). Pass scheduled_date to RESCHEDULE to that time instead (ISO 8601, at least 15 minutes out; a draft keeps its draft status). Works on draft or scheduled posts (cancel or reschedule); also works on FAILED posts but cancel-only (omit scheduled_date) — this is the way to clear a dead failed-post backlog, since failed has no other exit. Posts already posting/posted/cancelled are immutable. Get post ids from content_queue, list_posts or diagnose_failures.

Input Schema

{
  "type": "object",
  "properties": {
    "post_id": {
      "type": "integer",
      "minimum": -9007199254740991,
      "maximum": 9007199254740991,
      "description": "Post id to cancel or reschedule (from content_queue)"
    },
    "scheduled_date": {
      "description": "Omit to cancel. Provide to reschedule: ISO 8601, at least 15 minutes in the future",
      "type": "string"
    }
  },
  "required": [
    "post_id"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡retry_failed_posts(dry_run, platform, reasons, limit, start_at, ...)

WRITE (gated): bulk re-queue recoverable failed posts (default reason classes: token_expired, missed_window, platform_transient_error, drive_media_missing). dry_run DEFAULTS TO TRUE and only returns the plan; pass dry_run=false to actually reschedule. Retries are staggered per platform (spacing_minutes apart) and capped at limit, so a bulk retry cannot dogpile a platform API. Posts that would structurally fail again (archived brand, incompatible media, Facebook with no Page) are skipped with the reason. Use diagnose_failures first to see what is recoverable.

Input Schema

{
  "type": "object",
  "properties": {
    "dry_run": {
      "default": true,
      "description": "true = plan only, change nothing (the default)",
      "type": "boolean"
    },
    "platform": {
      "description": "Scope to a single platform",
      "type": "string",
      "maxLength": 20
    },
    "reasons": {
      "description": "Failure reason classes to retry. Default: token_expired, missed_window, platform_transient_error, drive_media_missing. Non-retryable classes are rejected.",
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 40
      }
    },
    "limit": {
      "default": 20,
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "start_at": {
      "description": "ISO 8601 start of the retry window, at least 15 minutes out. Default: ~20 minutes from now.",
      "type": "string"
    },
    "spacing_minutes": {
      "default": 30,
      "description": "Gap between retries on the same platform",
      "type": "integer",
      "minimum": 5,
      "maximum": 240
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴reschedule_post(post_id, scheduled_date)

WRITE (gated): move ONE post to a new future slot (ISO 8601, at least 15 minutes out). Unlike cancel_post this also accepts FAILED posts: a failed post is re-queued (status -> scheduled, error cleared). Draft and scheduled posts keep their status. Refuses posts that would structurally fail again (archived brand, incompatible media, Facebook with no Page).

Input Schema

{
  "type": "object",
  "properties": {
    "post_id": {
      "type": "integer",
      "minimum": -9007199254740991,
      "maximum": 9007199254740991,
      "description": "Post id (from list_posts, content_queue or diagnose_failures)"
    },
    "scheduled_date": {
      "type": "string",
      "description": "New slot, ISO 8601, at least 15 minutes in the future"
    }
  },
  "required": [
    "post_id",
    "scheduled_date"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡refresh_post_metrics(include_samples)

WRITE (gated): fetch current engagement (views/likes/comments/shares) for already-published posts and store today's snapshot, then read it back with post_performance. This is the only way to update the numbers without opening the dashboard Stats tab. Supported platforms: youtube, tiktok, twitter, threads; LinkedIn and the rest expose no engagement API. A 60-minute cooldown applies per account and protects X's free-tier read quota, so a call inside it returns skipped:true and changes nothing. Publishes nothing and reaches no audience.

Input Schema

{
  "type": "object",
  "properties": {
    "include_samples": {
      "default": false,
      "description": "Include sample users. Default false: real accounts only, matching every read tool.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡reconnect_platform(platform)

WRITE (safe): attempt a server-side token refresh for a platform whose access token has lapsed, updating the stored connection's token/expiry. Works without a browser when a refresh token is on file (twitter/youtube/google_drive self-heal this way); returns needsManualReauth + a dashboard link when the platform genuinely requires a manual browser reconnect (e.g. threads). Cannot publish or touch content, only refreshes credentials; safe to retry. Never exposes tokens.

Input Schema

{
  "type": "object",
  "properties": {
    "platform": {
      "type": "string",
      "maxLength": 20,
      "description": "Platform to reconnect, e.g. twitter, youtube, google_drive"
    }
  },
  "required": [
    "platform"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡upload_media(source_url, file_name, brand, kind, folder_id)

WRITE (gated): fetch a public media URL and store it in the connected Google Drive, returning the Drive fileId to pass to create_draft or schedule_post. This uploads to YOUR OWN Drive; it publishes nothing and reaches no audience. Accepts video, image or audio up to 100MB. With brand, files land in the folder the generator actually reads for that media type: Viral-Cat/_Res/{brand}/Imgs for an image, Vids for a video, Music for audio. Without brand it defaults to the Viral-Cat folder, and folder_id overrides both.

Input Schema

{
  "type": "object",
  "properties": {
    "source_url": {
      "type": "string",
      "format": "uri",
      "description": "Public https URL of the media to store, e.g. a rendered Short. Must be reachable without auth."
    },
    "file_name": {
      "description": "Name to save as. Omit to take it from the URL.",
      "type": "string",
      "maxLength": 200
    },
    "brand": {
      "description": "Brand whose _Res/{brand} folder should receive the file. Ignored when folder_id is given.",
      "type": "string",
      "maxLength": 200
    },
    "kind": {
      "description": "Which brand folder receives the file: Vids, Imgs or Music. Omit to route by media type, which is almost always right.",
      "type": "string",
      "enum": [
        "video",
        "image",
        "music"
      ]
    },
    "folder_id": {
      "description": "Destination Drive folder id, overriding brand. Omit to use the Viral-Cat folder.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "source_url"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_media_upload(file_name, mime_type, size_bytes, brand, kind, ...)

WRITE (gated): open a Google Drive upload session for media you hold locally, so a clip rendered on your own machine never has to be published publicly just so ViralCat can fetch it back. Returns an uploadUrl - PUT the bytes to it yourself (no auth header) and Drive stores the file; the response Location/id is the fileId for create_draft or schedule_post. When brand is given the file lands in the folder the generator actually reads for that media type: Viral-Cat/_Res/{brand}/Imgs for an image, Vids for a video, Music for audio. Without brand it defaults to the Viral-Cat folder. Video, image or audio up to 100MB. Publishes nothing and reaches no audience.

Input Schema

{
  "type": "object",
  "properties": {
    "file_name": {
      "type": "string",
      "maxLength": 200,
      "description": "Name to save as in Drive, e.g. \"ducktax-short.mp4\"."
    },
    "mime_type": {
      "type": "string",
      "maxLength": 100,
      "description": "Media type of the file, e.g. \"video/mp4\"."
    },
    "size_bytes": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Exact byte length of the file. Drive rejects a mismatch."
    },
    "brand": {
      "description": "Brand whose _Res/{brand} folder should receive the file. Ignored when folder_id is given.",
      "type": "string",
      "maxLength": 200
    },
    "kind": {
      "description": "Which brand folder receives the file: Vids, Imgs or Music. Omit to route by media type, which is almost always right.",
      "type": "string",
      "enum": [
        "video",
        "image",
        "music"
      ]
    },
    "folder_id": {
      "description": "Destination Drive folder id, overriding brand.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "file_name",
    "mime_type",
    "size_bytes"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_brand(name, description, hashtags, cta_url, website_url, ...)

WRITE (gated): create a brand (content profile) so create_draft and schedule_post have something to target. Every other write here needs a brand_id, so an agent had no way to set one up. Returns the brand_id and the Drive folder the publisher will read its media from (Viral-Cat/_Res/{name}/Vids). Publishes nothing and reaches no audience.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "Brand name. Also names its Drive media folder, so keep it filesystem-friendly."
    },
    "description": {
      "type": "string",
      "maxLength": 1000
    },
    "hashtags": {
      "description": "Brand hashtags appended to captions unless skip_hashtags is set.",
      "maxItems": 30,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 100
      }
    },
    "cta_url": {
      "description": "Link included in posts.",
      "type": "string",
      "maxLength": 500
    },
    "website_url": {
      "type": "string",
      "maxLength": 500
    },
    "content_type": {
      "description": "What the publisher should expect to find for this brand.",
      "type": "string",
      "enum": [
        "video",
        "image"
      ]
    }
  },
  "required": [
    "name"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡update_brand(brand_id, description, taglines, hashtags, cta_url, ...)

WRITE (gated): correct a brand's content profile: description, taglines, hashtags, CTA and website links, content type, and the auto-post switch. This is the repair path for a brand carrying wrong copy, which otherwise makes every caption for it wrong, and the off switch for a brand whose generator is posting against your content rules. Only the fields you pass change; the rest keep their stored values. Cannot rename a brand (the name also names its Drive media folder) and cannot touch posting frequency/day or discount settings. Queues nothing and publishes nothing itself.

Input Schema

{
  "type": "object",
  "properties": {
    "brand_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "description": {
      "description": "What the product actually is. The generator writes captions from this, so a wrong description makes every post wrong.",
      "type": "string",
      "maxLength": 1000
    },
    "taglines": {
      "description": "Short lines the publisher rotates through when a post has no caption of its own.",
      "maxItems": 30,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 500
      }
    },
    "hashtags": {
      "description": "Brand hashtags appended to captions unless skip_hashtags is set.",
      "maxItems": 30,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 100
      }
    },
    "cta_url": {
      "description": "Link included in posts. Pass an empty string to clear it.",
      "type": "string",
      "maxLength": 500
    },
    "website_url": {
      "type": "string",
      "maxLength": 500
    },
    "content_type": {
      "description": "What the publisher should expect to find for this brand.",
      "type": "string",
      "enum": [
        "video",
        "image"
      ]
    },
    "auto_post_enabled": {
      "description": "false = stop the content generator booking posts for this brand from its next cycle; true = let it resume. This is the only way to stop a brand auto-posting without opening the dashboard. Already-scheduled posts are NOT withdrawn by this: cancel those with cancel_post.",
      "type": "boolean"
    }
  },
  "required": [
    "brand_id"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded21 tools
auth requiredversion not recorded—
auth requiredversion not recorded—