# Postnero agent skill

Drive Postnero (TikTok short videos and photo carousels) from Cursor / Claude / Codex via MCP or REST.
Postnero does **not** host an LLM. Your agent writes captions and orchestrates; Postnero stores assets, carousels, renders, and schedules official TikTok publishes.

Postnero is self-service publishing software. Free includes MCP access, 10 scheduled
posts per calendar month, and one connected account. The visual editor is
included with Pro, which also removes the post and account quotas. See
`/pricing/` for current prices and the disclosed generated-media cleanup
periods.

## Auth

- Web UI: cookie session after login.
- Agents: Bearer API key (`ck_…`) from Settings → API keys.
- Header: `Authorization: Bearer ck_…`

## Connect from a prompt (no manual MCP configuration)

An agent with an HTTP client or code execution can use REST directly. A chat-only
agent cannot gain authenticated API tools from a prompt alone. Explain that
limitation instead of claiming a connection or asking the user to expose secrets.

1. Obtain the user's key through a secure credential input when available. Store
   it only with permission. Never log it, put it in a URL, or commit it.
2. Make `GET https://postnero.com/tiktok/accounts` with the bearer header. Send
   credentials only to `https://postnero.com`; do not forward them on redirects.
3. A 200 response has the shape `{ "accounts": [...] }`. Each account has `id`
   and `username` fields. Confirm successful access and list account names, not
   secrets. An empty list means the user must connect TikTok in Settings.
4. A 401 means the key is missing or invalid. A network failure does not prove
   authentication failed. Report the actual error and ask for the missing access.
5. Stop after this read-only check. Connection is not permission to post. Obtain
   explicit approval of content, account, audience, disclosure, and schedule
   before publishing or scheduling. Do not perform destructive actions at setup.

Use `GET /assets?limit=24` for paginated Library metadata. The response is
`{ "assets": [...], "nextCursor": "asset-id-or-null" }`. Pass `cursor` with the
next request only when more assets are needed. Do not download every image.

## Base URL

Same origin as the web app (e.g. `https://postnero.com`). MCP endpoint: `POST /mcp`.

## MCP tools

| Tool | Purpose |
|------|---------|
| `list_assets` | Library images |
| `list_carousels` / `get_carousel` / `create_carousel` / `update_carousel` | Carousel projects |
| `list_templates` / `get_template` / `save_template` / `delete_template` | Saved editor layouts |
| `design_carousel` / `get_carousel_design` / `update_carousel_design` | Create or patch editor slides (percent geometry) |
| `create_carousel_from_template` | New carousel from a saved layout + optional caption/background swaps |
| `create_app_store_showcase` | Five-slide built-in app template; imports four App Store icons, descriptions, and three screenshots per app |
| `list_renders` / `upload_render` | List or upload ordered final slide snapshots |
| `create_post` / `schedule_post` / `list_posts` / `cancel_post` / `retry_post` | Draft / schedule / cancel / retry |
| `list_tiktok_accounts` / `get_tiktok_account` / `get_tiktok_creator_info` | Connected accounts and live TikTok posting controls |
| `get_publish_status` | Post publish state |
| `get_analytics_overview` | Views, engagement, and tracking coverage by account |
| `list_post_performance` / `list_cover_performance` / `list_caption_performance` | Ranked post, first-slide, and full-caption signals |
| `list_hashtag_performance` / `list_timing_performance` | Ranked caption-tag and New York publish-time signals |
| `get_growth_insights` | Winners, underperformers, evidence-led next tests, and sample warnings |
| `refresh_tiktok_analytics` | Refresh official TikTok metrics for one or all accounts |

When scheduling via `create_post`, pass TikTok Direct Post fields from live creator info: `privacyLevel`, `disableComment`, `autoAddMusic`, `brandOrganicToggle`, `brandContentToggle`, and optional `title`. `autoAddMusic` lets TikTok choose recommended music; the API does not choose a named sound.

## Important workflow

1. Save a layout in the **Editor** (`File → Save as template`) or have an agent call `design_carousel`.
2. Agents fill new copy with `create_carousel_from_template` or `update_carousel_design`; for the built-in app layout, call `create_app_store_showcase` with exactly four App Store IDs or URLs. Coordinates are percents of the canvas (`x`/`y`/`width`/`height`, 0–100).
3. Open the returned `editorUrl` (`/editor?id=…`) to tweak and Export, or upload final images with `upload_render`, the Postnero Codex plugin's path-based importer, or `POST /carousels/:id/renders`.
4. Agent or UI schedules with `create_post` / `schedule_post` using `renderId` + `tiktokAccountId`.
5. Worker / cron runs `POST /internal/publish-due` to publish due posts.

The personal Postnero Codex plugin adds a local path-based bridge so image bytes travel directly from disk to Postnero instead of through chat context.

Analytics tools require TikTok's approved `video.list` scope and a fresh
authorization from each account. Missing permission is returned explicitly;
it is never represented as zero views. Cover and hashtag results describe
correlation across linked Postnero posts, not causation.
Refreshes use a five-minute per-account cooldown. Every analytics response
includes coverage counts and keeps last-known values when one account fails.

## REST highlights

- `GET/POST /templates` · `GET/PATCH/DELETE /templates/:id` · `POST /templates/:id/apply`
- `GET/POST /assets`: library upload
- `GET /tiktok/accounts`: multi-account list
- `DELETE /tiktok/accounts/:id`: disconnect one account
- `GET /api/analytics?accountId=&range=30d`: stored last-known account/post/cover/hashtag report
- `POST /api/analytics/refresh`: refresh official TikTok Display API metrics
- `POST /posts/:id/cancel` · `POST /posts/:id/retry`

## Multi-account

Pro users can connect multiple TikTok accounts in Settings. Free includes one.
Pass `tiktokAccountId` when creating or scheduling posts. When a Free quota is
reached, scheduling returns an upgrade-required error rather than silently
dropping the post.

## Docs

Agent setup guides: `/connect-agents`. In-app API reference: `/docs/api`.
Download this skill: `/skill.md`.


## Short video workflow

MP4 uploads and carousel-to-video conversion are included on Free and Pro.

1. To upload an MP4, use authenticated multipart `POST /videos/upload` with `file`, `title`, and a new UUID `requestId`. Limit: 100 MB, 3-180 seconds. Audio is preserved. Use a file stream; never place video bytes in the model context.
2. To convert rendered carousel slides, use `create_video_from_carousel` (or `POST /videos/from-carousel`) with `requestId`, `renderId`, `title`, and `secondsPerSlide` (integer 1-10, default 3). First create/upload the slide images through `create_carousel` and `upload_render` if needed. Design metadata alone is not a rendered image. The output is a separate, silent 1080x1920 video; the original carousel remains.
3. Poll `GET /videos/jobs/:id` or `list_video_jobs`. A ready receipt includes `renderId` and `editorUrl`. Reuse the identical request ID and inputs after an uncertain response. On a confirmed failed job, fix the reported problem and submit a new request ID. Uploaded input files are temporary.
4. Review the actual MP4 with the user. Query `get_tiktok_creator_info` for the current account duration, privacy and interaction restrictions. After explicit approval, call `create_post` with a UUID `requestId`, `renderId`, caption (maximum 2200 characters), `tiktokAccountId`, `scheduledAt`, `privacyLevel`, `disableComment`, explicit `disableDuet` and `disableStitch`, the correct brand flags, `videoConsent: true`, and `autoAddMusic: false`. Set `isAigc` for AI-generated content. Include music in the MP4 only when the user has the rights to it. A chat-only client cannot prepare or upload media without file or HTTP tools.
5. Prefer `list_posts_page` (default limit 20, maximum 50, optional status and cursor) to the legacy full-history tool. Use `get_publish_status` to confirm delivery. Scheduled, processing and published are different states. On a timeout, reconcile the receipt before retrying, and preserve the request ID for identical `create_post` calls.

Every account has 1 GB of generated media storage, up to 1,000 slide images and video previews, plus a 3 GB / 1,500-asset Library. Inspect generated usage with `GET /renders/usage`. With the user's deletion approval, remove an unused render with `DELETE /renders/:id`. Post references and in-progress conversions prevent deletion. Published media expires after the plan's retention period; the post record remains.
