# Seed UGC across many accounts with Mastra

Source: https://developers.tokportal.com/agents/mastra/ugc-seeding/
Markdown: https://developers.tokportal.com/agents/mastra/ugc-seeding.md

UGC seeding from Mastra means taking a batch of creator-style videos and getting them posted from many ordinary-looking accounts in the target market, so the campaign reads as organic rather than as one brand handle. TokPortal does the account side: `create_bundles_bulk` opens N accounts in one country, `configure_bundle_video` places each creative on its slot with `disclose_as_ads` when required, `publish_bundle` hands each account to a human manager, and `export_analytics_videos` gives you a per-account, per-video report. Each account is human-created and human-operated, which is what keeps a seeding wave from being flagged as coordinated automation.

## Connect TokPortal to Mastra

Mastra is an agent framework (code): TypeScript agent framework; `MCPClient` from `@mastra/mcp` connects HTTP or stdio MCP servers and hands their tools to an `Agent`.

```bash
npm i @mastra/core @mastra/mcp
```

```ts
import { Agent } from '@mastra/core/agent';
import { MCPClient } from '@mastra/mcp';

const mcp = new MCPClient({
  servers: {
    tokportal: {
      url: new URL('https://app.tokportal.com/api/ext/mcp'),
      requestInit: {
        headers: { 'X-API-Key': process.env.TOKPORTAL_API_KEY! },
      },
    },
  },
  timeout: 30000,
});

export const socialOps = new Agent({
  id: 'social-ops',
  name: 'Social ops',
  instructions: 'You operate TikTok and Instagram accounts through TokPortal tools. Quote credit costs before creating bundles.',
  model: 'anthropic/claude-sonnet-4-5',
  tools: await mcp.listTools(),
});
```

Tools are namespaced `tokportal_tokportal_*` (server name + tool name). Use `mcp.listToolsets()` to pass tools per request instead of at construction, and `mcp.disconnect()` on shutdown.

Snippet status: **verified** against Mastra's documentation ([source](https://mastra.ai/en/reference/tools/mcp-client)).

Once connected, sanity-check the setup with a read-only call: "What is my TokPortal credit balance?" should trigger `tokportal_get_credit_balance`. GET requests and dry-run writes do not spend credits.

## Try the workflow without spending

For this trial, use the remote MCP endpoint `https://app.tokportal.com/api/ext/mcp`, local `tokportal-mcp` **1.15.1 or later**, or the REST API. Upgrade and restart an older local server first. Version 1.15.0 does not forward the dry-run header; do not use its write tools for a simulation. If you cannot verify the installed local version, use the remote endpoint or REST.

Use the [sandbox](https://developers.tokportal.com/sandbox) for the first attempt. MCP write tools accept `dry_run: true` as a top-level argument, beside `body`; REST writes accept the `X-TokPortal-Dry-Run: true` header. Keep your usual authentication and scopes. Each simulated write validates the request and returns `credits_would_charge` with `credits_charged: 0`. Nothing is created or published.

Simulated IDs start with `00000000-0000-4000-8000-`. Use them only in later dry-run writes. GET requests read real data, so skip publish-readiness checks and polling for synthetic IDs. Simulations have no cross-call memory and upload URLs are placeholders: do not upload files to them.

To run for real, review the returned price and confirm **before the first live write**. Bundle creation charges credits immediately; publishing hands the order to a manager. Repeat creation without dry-run mode and use the new real IDs for configuration and publishing. A synthetic ID cannot be reused in a live request.

## How it works

A seeding plan is a matrix: creatives × accounts × dates. The agent starts with the accounts. `create_bundles_bulk` with `platforms: ["tiktok"]` (or `["tiktok","instagram"]` to seed both), `country`, `accounts_count` (≤100 per call) and `videos_per_account` returns one bundle id per account. Each account gets its own `configure_bundle_account` — vary handles, bios and profile pictures (upload with `upload_image_from_url`) so the accounts look like different people, and consider `advanced_warming_terms` in the product's niche so the accounts have a history when the seeding starts.

Then the creatives. Upload each once (`upload_video` → `public_url`) and reuse the URL across bundles; TokPortal's duplicate-post guard is per account, so the same file on ten different accounts is fine. Fill slots with `configure_bundle_video` or `batch_configure_bundle_videos`, staggering `target_publish_date` across days and accounts (max 3 per day per bundle) so the wave looks natural. Set `disclose_as_ads: true` where the content is paid promotion — the manager enables branded-content disclosure or adds #ad — and add `tiktok_sound_url` if the campaign runs on a sound. `publish_bundle` per bundle (or loop). If a client asks for the Spark/Partner code to boost a post, `create_video_ad_code_request` returns it after finalization (7 credits).

Reporting is where Mastra shines: `export_analytics_videos` (CSV, filter by `country`, `platform`, `from`/`to`) plus `get_comment_pulse` for what people say, aggregated by the agent into a campaign summary.

## Run it from Mastra

With Mastra the sequence is driven by your code: give the agent the tools from the TokPortal MCP server and the prompt below as the user message (or split it into tasks). Log every `tokportal_*` call and its arguments in development — the tool list is large (91 tools), so consider filtering to the ones this job needs.

**Tool sequence**

1. `tokportal_get_credit_costs` — N accounts × (32 + 2 × videos) — quote before creating.
2. `tokportal_create_bundles_bulk` — `platforms`, `country`, `accounts_count`, `videos_per_account`, optional `advanced_warming_terms_count`.
3. `tokportal_configure_bundle_account` — Different persona per bundle: handle, name, bio, `profile_picture_url`.
4. `tokportal_upload_video` — Upload each creative once; reuse `public_url` across bundles.
5. `tokportal_configure_bundle_video` — Place creative on slot: `description`, `target_publish_date`, `video_url`, `disclose_as_ads`, `tiktok_sound_url`.
6. `tokportal_publish_bundle` — One call per bundle.
7. `tokportal_create_video_ad_code_request` — Spark Code / Partner Code for paid boosting after finalization (7 credits).
8. `tokportal_export_analytics_videos` — Per-video CSV across all accounts for the campaign report.
9. `tokportal_get_comment_pulse` — Sentiment / themes across the seeded posts.

**Prompt to paste**

```text
Evaluate this workflow in the TokPortal sandbox only.
Use the remote MCP endpoint https://app.tokportal.com/api/ext/mcp or local tokportal-mcp 1.15.1 or later for write tools.
Verify the installed local version before using its write tools. Version 1.15.0 is unsafe for simulations.
If the local version is older or unknown, use the remote endpoint or authenticated REST
requests with X-TokPortal-Dry-Run: true instead.
For every non-GET MCP tool call, set dry_run: true as a top-level boolean beside body.
For every REST write in a workflow, send the X-TokPortal-Dry-Run: true header.
Use normal read tools for existing real objects. Do not GET or poll synthetic IDs,
and do not upload files to simulated upload URLs. Simulated objects have no cross-call memory.
Show credits_would_charge and verify credits_charged is 0 for each simulated write.
Do not execute any live write. Ask for my explicit GO before the first real write,
including bundle creation, which charges immediately. After GO, repeat creation
without dry_run and use the new real IDs; never reuse synthetic IDs in live requests.

Use the TokPortal MCP tools. Campaign: 12 UGC creatives, seed in Mexico on TikTok across 12 accounts,
one creative per account, dates spread over 2026-09-08 → 2026-09-12, all disclosed as ads.
Quote with get_credit_costs, call create_bundles_bulk (12 accounts, 1 video each, external_ref "mx-wave1"),
then show me the per-bundle configure_bundle_account and configure_bundle_video payloads before running them.
```

Run with `mastra dev` and test in the playground, or call `agent.generate()` from your server code.

**REST equivalent** (write requests below are simulations; GET requests read existing real data)

```bash
# 15 seeding accounts in Brazil, 4 videos each, both platforms
curl -X POST -H "X-TokPortal-Dry-Run: true" https://app.tokportal.com/api/ext/bundles/bulk \
  -H "X-API-Key: sk_..." -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"platforms":["tiktok","instagram"],"country":"BR","accounts_count":15,"videos_per_account":4,"external_ref":"seed-sept-br"}'

# Same creative on bundle A and bundle B, disclosed as ad
for B in BUNDLE_A BUNDLE_B; do
curl -X PUT -H "X-TokPortal-Dry-Run: true" https://app.tokportal.com/api/ext/bundles/$B/videos/1 \
  -H "X-API-Key: sk_..." -H "Content-Type: application/json" \
  -d '{"video_type":"video","description":"testei por 7 dias 👀 #publi","target_publish_date":"2026-09-05","video_url":"https://.../creative-1.mp4","disclose_as_ads":true}'
done

# Campaign export
curl "https://app.tokportal.com/api/ext/analytics/export/videos?country=BR&from=2026-09-01&to=2026-09-30" -H "X-API-Key: sk_..."
```

## Key parameters

| Parameter                | Values                              | Notes                                                 |
| ------------------------ | ----------------------------------- | ----------------------------------------------------- |
| `accounts_count`         | 1–100 per bulk call                 | One bundle/account each; repeat calls for more.       |
| `platforms`              | \["tiktok"] · \["instagram"] · both | Bulk creates accounts on each listed platform.        |
| `disclose_as_ads`        | boolean (free)                      | Branded-content disclosure or                         |
| `target_publish_date`    | YYYY-MM-DD                          | Stagger across accounts; 3/day/bundle max.            |
| `external_ref`           | ≤200 chars                          | Campaign tag copied to every bundle of the bulk call. |
| `instagram_content_type` | reel · post                         | For Instagram slots; carousels via carousel\_images.  |

Full schemas: [OpenAPI reference](https://developers.tokportal.com/api-reference) · [openapi.json](https://developers.tokportal.com/openapi.json).

## Example configurations

**Bulk seeding fleet**

```json
{"platforms":["tiktok"],"country":"MX","accounts_count":25,"videos_per_account":3,
 "wants_advanced_warming":true,"advanced_warming_terms_count":3,"external_ref":"launch-mx-wave1"}
```

**Slot with disclosure and sound**

```json
{"video_type":"video","description":"lo probé y… #ad #skincare","target_publish_date":"2026-09-06",
 "video_url":"https://pub-xxx.r2.dev/videos/creative-2.mp4","disclose_as_ads":true,
 "tiktok_sound_url":"https://www.tiktok.com/music/original-sound-7300000000000000000"}
```

**Ad code request (POST /videos/{id}/ad-code-request)**

```json
{"note":"Boost for MX wave 1"}
```

## Credits

25 accounts × (32 + 3 × 2) = 950 credits for a 25-account, 3-post wave at standard rates, plus warming targets (5 each) and 7 credits per ad code. Quote live with `get_credit_costs`; see [Credits & Pricing](https://developers.tokportal.com/credits).

## Why not the official API

The official APIs are built for a brand posting on its own audited app to accounts users authorized one by one; seeding across dozens of fresh accounts would need dozens of OAuth grants, an audit, and would still be capped per token (6 requests/minute) and per user per day. TokPortal's model — distinct human-operated accounts, dated slots, disclosure flags — is the shape seeding actually needs.

As of August 2026 the first-party routes look like this. TikTok's Content Posting API (Direct Post) requires each account owner to authorize your app with the `video.publish` scope, limits every user access token to 6 requests per minute, keeps all posts from unaudited apps in private viewing mode until TikTok audits the app, and enforces an unpublished daily post cap per user (`spam_risk_too_many_posts`) that integrators commonly report at roughly 15–25 posts per account per day. Meta's Instagram Content Publishing API allows 100 API-published posts per professional account in a 24-hour moving window and only for accounts you own and connect via OAuth. Neither creates accounts, warms them, or reports third-party bans. TokPortal is human-operated infrastructure: accounts created and run by managers in the target country, one `X-API-Key` for all of them, dated slots (max 3 per day per bundle) instead of per-account tokens.

Sources: [TikTok Content Posting API – Direct Post](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post), [TikTok Content Posting API – Get started](https://developers.tiktok.com/doc/content-posting-api-get-started), [Instagram Platform – Content Publishing](https://developers.facebook.com/docs/instagram-platform/content-publishing).

## FAQ

### Do the seeded accounts look related?

Only if you make them: use distinct handles, bios and pictures per `configure_bundle_account`, different warming terms, and staggered dates. Each account has its own manager, device and network.

### Can I reuse the accounts for the next campaign?

Yes — `list_accounts` then `videos_only` bundles with `account_id`. Accounts remain managed and warm between waves.

### How do I handle

Set `disclose_as_ads: true` on paid content; the manager enables the platform's branded-content toggle or adds #ad. Combine with `create_video_ad_code_request` if you plan to boost.

### How do I report per creative rather than per account?

Put the creative id in each slot's `external_ref` (or `name`), then join `export_analytics_videos` on it in the agent.

## Related

- [UGC distribution at scale](https://developers.tokportal.com/use-cases/industry/ugc-distribution-at-scale)
- [TikTok Shop product seeding](https://developers.tokportal.com/use-cases/industry/tiktok-shop-product-seeding)
- [Create bulk](https://developers.tokportal.com/create-bulk)
- [Ad code request](https://developers.tokportal.com/ad-code-request)
- [MCP server](https://developers.tokportal.com/mcp)

## Also works with

- [Seed UGC across many accounts with Make](https://developers.tokportal.com/agents/make/ugc-seeding)
- [Seed UGC across many accounts with Zapier](https://developers.tokportal.com/agents/zapier/ugc-seeding)
- [Seed UGC across many accounts with Pipedream](https://developers.tokportal.com/agents/pipedream/ugc-seeding)
- [Seed UGC across many accounts with Dify](https://developers.tokportal.com/agents/dify/ugc-seeding)
- [Seed UGC across many accounts with Flowise](https://developers.tokportal.com/agents/flowise/ugc-seeding)
- [Seed UGC across many accounts with Langflow](https://developers.tokportal.com/agents/langflow/ugc-seeding)

[All 25 agents for "Seed UGC across many accounts"](https://developers.tokportal.com/agents/for/ugc-seeding)

## Other jobs with Mastra

- [Create TikTok accounts with Mastra](https://developers.tokportal.com/agents/mastra/create-tiktok-accounts)
- [Post 100 TikTok videos a day with Mastra](https://developers.tokportal.com/agents/mastra/post-100-videos-a-day)
- [Run US TikTok accounts from abroad with Mastra](https://developers.tokportal.com/agents/mastra/us-tiktok-accounts-from-abroad)
- [Warm TikTok & Instagram accounts with Mastra](https://developers.tokportal.com/agents/mastra/warm-accounts)
- [Run a faceless TikTok channel with Mastra](https://developers.tokportal.com/agents/mastra/faceless-channel)
- [Seed a music sound on TikTok with Mastra](https://developers.tokportal.com/agents/mastra/music-sound-seeding)
- [Launch an app with persona accounts with Mastra](https://developers.tokportal.com/agents/mastra/app-persona-launch)
- [Run multi-client agency operations with Mastra](https://developers.tokportal.com/agents/mastra/agency-multi-client)
- [Get ban alerts via webhooks with Mastra](https://developers.tokportal.com/agents/mastra/ban-webhooks)
- [Pull analytics across all accounts with Mastra](https://developers.tokportal.com/agents/mastra/analytics-multi-account)
- [Create Instagram accounts with Mastra](https://developers.tokportal.com/agents/mastra/create-instagram-accounts)
