Skip to content
UGC API

Social media automation with Grok and UGC API

Grok is good at what's happening right now, which makes it a natural fit for trend-driven content. Give a Grok model one tool that schedules posts through UGC API, and it can turn today's trend into tonight's TikTok, Reel and Short.

Updated

How Grok connects

At the time of writing, the Grok consumer app doesn't let you add your own MCP servers, so the path is the xAI API. It's compatible with the OpenAI SDKs (base URL https://api.x.ai/v1) and supports function calling: you describe a tool, the model asks to call it, your code runs it. Any Grok model with tool calling works. Check xAI's docs too: if they offer remote MCP tools for your account, you can point them at https://ugcapi.dev/mcp, though our MCP endpoint needs an OAuth sign-in, which suits interactive use better than a backend.

For a backend job, the REST API with an API key is simpler. Create a key in the dashboard and keep it on your server.

The tool

One tool is enough: schedule a post. Your code adds the options you don't want the model to choose, like TikTok privacy and the AI-content label.

python
import json, os, requests
from openai import OpenAI

grok = OpenAI(api_key=os.environ["XAI_API_KEY"], base_url="https://api.x.ai/v1")
UGC_KEY = os.environ["UGCAPI_KEY"]          # ugc_live_...
ALLOWED = {"acc_tt_main", "acc_ig_main", "acc_yt_main"}

tools = [{
  "type": "function",
  "function": {
    "name": "schedule_post",
    "description": "Schedule one short video to the brand's social accounts via UGC API.",
    "parameters": {
      "type": "object",
      "required": ["accounts", "video_url", "caption", "scheduled_at"],
      "properties": {
        "accounts": {"type": "array", "items": {"type": "string", "enum": sorted(ALLOWED)}},
        "video_url": {"type": "string"},
        "caption": {"type": "string"},
        "scheduled_at": {"type": "string", "description": "ISO 8601, at least 1 hour from now"}
      }
    }
  }
}]

def schedule_post(accounts, video_url, caption, scheduled_at):
    if not set(accounts) <= ALLOWED:
        return {"error": "account not allowed"}
    r = requests.post("https://ugcapi.dev/v1/posts",
        headers={"Authorization": f"Bearer {UGC_KEY}"},
        json={"accounts": accounts, "format": "video", "media": [video_url],
              "caption": caption, "scheduled_at": scheduled_at,
              "options": {"tiktok": {"privacy": "PUBLIC_TO_EVERYONE", "ai_generated": True},
                          "youtube": {"title": caption[:90]}}})
    return r.json()
python
messages = [
  {"role": "system", "content": "You run social posting for a desk accessories brand. "
     "Pick from today's finished videos, write a caption that fits a current trend, "
     "and schedule at most 3 posts for this evening. Never post the same video twice."},
  {"role": "user", "content": "Finished videos: " + json.dumps(todays_videos)},
]
resp = grok.chat.completions.create(model=GROK_MODEL, messages=messages, tools=tools)
for call in resp.choices[0].message.tool_calls or []:
    result = schedule_post(**json.loads(call.function.arguments))
    print(result.get("id"), result.get("status") or result)

In a full loop you append each tool result to messages and call the model again so it can react to errors. Keep GROK_MODEL in config; xAI updates its model names.

A trend-jacking workflow

  1. Your generator (or your editors) produce a pool of finished videos with a short description each, stored at public URLs.
  2. Every afternoon, a job asks Grok: what's trending in our niche today, and which of these videos fits it best? Grok writes the caption with the trend's wording.
  3. Grok calls schedule_post for the evening slots. Posts are scheduled at least an hour ahead, so someone can review upcoming posts with GET /v1/posts?sort=scheduled_at and cancel with DELETE /v1/posts/:id (refunded).
  4. Webhooks report post.published with each public URL, or post.failed with the reason.
  5. Next day, the job reads GET /v1/stats (views, likes, shares from TikTok and Instagram, refreshed hourly) and gives Grok the top posts so it learns what landed. See the agentic UGC pipeline.

Matching a trend to a video

The hard part of trend-jacking isn't posting, it's fit. A trend that has nothing to do with your product gets views and no sales, and can confuse the account's audience. Give Grok three things in the prompt: a one-line description of each finished video, the audience of each account, and a rule for when to skip ("if no video fits a trend well, schedule nothing and say why"). Ask it to return its reasoning in one sentence per post, and log it. When a trend post does well, that sentence tells you why it was picked.

Timing matters as much as fit. Trends on TikTok can peak within a day or two. Schedule the same evening, and spread the posts across accounts instead of putting all three on one. A campaign with spread: true does that in one request if you have more than a handful of videos; see campaigns.

Guardrails

  • Enum the accounts in the tool schema, as above, and check again in code.
  • Fix risky options in code. Privacy, AI label and drafts shouldn't be the model's call. If the creator chose privacy in your product, store it per account and apply it here.
  • Cap the volume. Limit posts per run and per account per day. TikTok and Instagram cap API posts per account; staying far below is better for reach too. See UGC posting cadence.
  • Trends move fast, reviews don't. If your brand needs approval, use TikTok drafts (options.tiktok.draft: true) so a person posts from the TikTok app.

Handling errors in the loop

Send each tool result back to the model as a tool message. If UGC API returns an error, it has a stable code and a readable message, for example media_unreachable when the video URL isn't public or insufficient_credits when the balance is out. Tell Grok in the system prompt to stop and report on any error rather than trying again with a different account. Retries belong in your code, with limits, and POST /v1/posts/:id/retry resends only failed results. See errors.

Interactive use: MCP-capable clients

If what you want is to chat with a model about trends and then schedule posts by hand, an MCP client is simpler than writing code. Claude, ChatGPT, Cursor and Gemini CLI can all add https://ugcapi.dev/mcp with an OAuth sign-in. You can do trend research in Grok, paste the angle into one of those, and schedule from there. See the agents overview.

What it costs

UGC API charges one credit per post per account: $10 per 1,000 posts, 50 free. Three videos a day to TikTok, Instagram and YouTube is about 270 posts a month, under $3. Grok tokens are billed by xAI.

FAQ

Can the Grok app post to TikTok?

Not by itself, and at the time of writing it doesn't accept custom MCP servers. Use the xAI API with tool calling and UGC API's REST endpoints.

Can Grok post to X with UGC API?

No. UGC API publishes to TikTok, Instagram, Facebook Pages and YouTube Shorts.

Which Grok model should I use?

Any Grok model that supports function calling. Pick by cost and speed; the tool definition stays the same.

Should I label AI-generated videos?

If the video is realistic AI-generated content, yes. Set options.tiktok.ai_generated to true; YouTube and Meta have their own disclosure rules too.

Related