1(function(){try{var e=typeof window<`u`?window:typeof global<`u`?global:typeof globalThis<`u`?globalThis:typeof self<`u`?self:{};e.SENTRY_RELEASE={id:`degaus-web@39f1dbbdc`}}catch{}})();try{(function(){var e=typeof window<`u`?window:typeof global<`u`?global:typeof globalThis<`u`?globalThis:typeof self<`u`?self:{},t=new e.Error().stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]=`0664f25a-8310-4ae0-baec-9643517c878b`,e._sentryDebugIdIdentifier=`sentry-dbid-0664f25a-8310-4ae0-baec-9643517c878b`)})()}catch{}import{n as e}from"./nav-akFC7jqe.js";var t=`--- 2title: Action Errors 3description: The error codes platform actions return, what each one means, and how a client should react. 4--- 5 6## Shape 7 8Failures return a structured error, not just an HTTP status: 9 10\`\`\`json 11{ 12 "error": { 13 "code": "limit_reached", 14 "message": "daily limit reached for linkedin/comment", 15 "deferUntil": "2026-07-28T00:00:00.000Z", 16 "reason": "limit_hit" 17 } 18} 19\`\`\` 20 21Branch on \`code\`. It is stable; \`message\` is for humans and may change. 22 23Two optional fields carry the detail a client needs to act without guessing: 24 25- \`deferUntil\` - an ISO timestamp for quota denials (\`throttled\`, 26 \`limit_reached\`, \`limit_exhausted\`). It is when the quota resets, so a client 27 can **re-arm at that time instead of polling**. 28- \`reason\` - the granular cause under the coarse code, such as 29 \`weekly_limit_hit\`, \`signal_cooldown\`, \`twin_paused\`, or \`relay_offline\`. 30 Branch on \`code\` first; read \`reason\` when you want the precise cause. 31 32## HTTP status 33 34The status tells you the shape before you parse: 35 36| Status | Meaning | 37| ------ | ---------------------------------------------------------------------------- | 38| 200 | Action completed; body has \`result\` | 39| 202 | Control session is warming; body has \`status\` and \`retryAfterMs\`, no \`error\` | 40| 400 | Unknown action or invalid payload | 41| 402 | Insufficient credits | 42| 403 | Cloud twin requires the Premium plan | 43| 404 | Twin not found | 44| 423 | Twin is paused, or blocked by a critical platform signal | 45| 429 | Action throttled | 46 47Only 200 and 202 carry a success body. Everything else carries \`error\`. Treat 48202 as a retry with \`retryAfterMs\`, not a failure - see 49[Running Platform Actions](/docs/platform-actions). 50 51## Codes 52 53| Code | Meaning | What a client should do | 54| --------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------- | 55| \`throttled\` | Pacing kicked in - the action was asked for too soon after the last one | Retry later; respect the cooldown rather than tightening the loop | 56| \`deferred\` | Deferred by the gate, OR the response was lost after dispatch | Safe to retry for reads; for writes, check state first (see below) | 57| \`limit_reached\` | A daily cap for this action was hit | Stop for the day; retrying will not help | 58| \`limit_exhausted\` | The account's write allowance is spent | Raise the allowance or wait for the next period | 59| \`needs_auth\` | The persona's session lapsed | Have a person sign in - see [Controlling the Browser](/docs/browser-control) | 60| \`sender_blocked\` | The platform blocked this account from the action | Do not retry; the account needs attention | 61| \`command_not_allowed\` | The action is not permitted for this persona or role | Check the persona's role and account policy | 62| \`unsupported_channel\` | No such platform/action pair | Fix the path; see the [Action Reference](/docs/action-reference) | 63| \`not_found\` | The persona does not exist, or your key cannot reach it | Check the slug and the key's access | 64| \`validation_error\` | A path parameter is missing (persona, platform, or action) | Fix the URL | 65 66Access denial does not come back as \`not_found\`: a persona your key has no 67operator grant on returns **403** with code \`forbidden\`, and so does a persona 68that does not exist, so the response cannot be used to discover which personas 69exist on other accounts. 70
71A malformed payload or an invalid \`via\` does NOT return \`validation_error\`: it 72returns \`command_not_allowed\` with \`reason: "invalid_payload"\`. Branching on 73\`reason\` is what separates "you sent the wrong fields" from "this persona may 74not run this action", since both share the code. 75 76Every code above except \`validation_error\` belongs to the twin taxonomy 77(\`TwinErrorCode\`). \`validation_error\` is the general request-level code, raised 78before the action is dispatched, so it never carries \`deferUntil\` or \`reason\`. 79 80## Retrying 81 82Retry \`throttled\`, \`limit_reached\`, and \`limit_exhausted\` **at \`deferUntil\`**, 83not before. 84 85\`deferred\` needs more care. It covers two situations: the gate declined to run 86the action now, and the action was dispatched but its terminal response was 87lost (\`reason\` is \`action_timeout\` or \`control_unavailable\`). Cancellation on 88timeout is best effort, so a **write** may already have completed. Retrying 89blindly can produce a duplicate post, comment, or message. For reads, retry 90freely; for writes, read the current state on the platform and confirm the 91action did not land before sending it again. That timestamp is why the field exists: the gate 92tells you when the quota resets so a client re-arms once rather than probing. 93 94Do not retry \`sender_blocked\`, \`command_not_allowed\`, \`unsupported_channel\`, 95\`not_found\`, or \`validation_error\`. The outcome will not change, and repeatedly 96hitting a blocked account makes its standing on the platform worse. 97 98If \`deferUntil\` is absent, back off rather than retrying immediately. Wonda 99already paces actions server-side; a client that retries tightly fights that 100pacing instead of benefiting from it. 101 102## Run history 103 104\`GET /twin/runs\` lists control and scheduled \`twin_run\` records. It is **not** 105an index of individual action executions: local relay actions create no 106\`twin_run\` at all, and cloud action correlation IDs are not represented, so it 107cannot confirm whether a specific timed-out write landed. Use it as an audit 108trail, not as confirmation: 109 110\`\`\`bash 111curl "https://api.wondercat.ai/api/v1/twin/runs?persona=natty&limit=20" \\ 112 -H "Authorization: Bearer $WONDA_API_KEY" 113\`\`\` 114 115Both query parameters are optional. When a run failed, its diagnostic artifacts 116are available as presigned download URLs: 117 118\`\`\`bash 119curl https://api.wondercat.ai/api/v1/twin/runs/{runId}/artifact \\ 120 -H "Authorization: Bearer $WONDA_API_KEY" 121\`\`\` 122 123## Dry runs 124 125Some writes accept \`"dryRun": true\`, intended to run every check - access, 126allowance, caps, account health - and report what would have happened without 127touching the platform. 128 129**Do not rely on it as a safety net on the hosted path.** Several actions 130accept the field but do not forward it to the underlying command, so the write 131is performed for real. \`linkedin/send-message\` and \`linkedin/comment\` both 132behave this way today; \`reddit/chat-send\` honours it. Until that is fixed, 133treat \`dryRun\` as best effort and test against an account you are willing to 134post from. 135 136The [Action Reference](/docs/action-reference) lists \`dryRun?\` in the payload 137of the actions that accept the field, which is not the same as the actions that 138honour it. 139 140## Related 141 142- [Running Platform Actions](/docs/platform-actions) 143- [Action Reference](/docs/action-reference) 144- [Error Codes](/docs/errors) - the general API error taxonomy 145`,n="---\ntitle: Action Reference\ndescription: Every platform action the relay can run, with its transport and payload fields.\n---\n\n<!-- GENERATED FILE - do not edit by hand.\n Source: packages/features/src/twins/action-registry.ts\n Regenerate: pnpm --filter @degaus/docs generate:action-reference -->\n\nEvery action below is an endpoint:\n\n```text\nPOST /twin/sessions/{persona}/actions/{platform}/{action}\n```\n\nSend the payload fields as a JSON object. Fields marked `?` are optional; an\nempty payload is `{}`. See [Running Platform Actions](/docs/platform-actions)\nfor the request and response shape, and [Routing](/docs/action-routing) for\nwhat `transport` means and when you can override it.\n\n**Kind** is `read` or `write`. Writes consume a write slot and are subject to\nyour account's allowance, daily caps, and cooldowns; reads are not.\n\nSome actions enforce cross-field rules the table cannot show. A row whose\nfields all read optional may still reject an otherwise reasonable payload, so\ncheck the 400 message. Known cases:\n\n| Action | Rule |\n| --- | --- |\n| `linkedin/activity`, `linkedin/enrich` | exactly one of `target` or `targets` |\n| `*/feed-engage` | exactly one of `authors` or `keywords` (Instagram requires `authors`) |\n| `reddit/submit` | exactly one of `text`, `url`, or `mediaRefs` |\n| `linkedin/salesnav-save-search` | keywords or a facet |\n\n## LinkedIn\n\n| Action | Kind | Transport | Payload |\n| --- | --- | --- | --- |\n| `activity` | read | `wab` | `target?`, `type?`, `count?`, `targets?` |\n| `analytics` | read | `cookies` | `target` |\n| `comment-reactors` | read | `cookies` | `commentUrn`, `count?`, `all?` |\n| `comment` | write | `wab` | `target`, `text`, `dryRun?` |\n| `comments` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `company` | read | `cookies` | `target` |\n| `connect` | write | `wab` | `target`, `message?` |\n| `connection-status` | read | `cookies` | `targets` |\n| `connections` | read | `cookies` | none |\n| `conversations` | read | `cookies` | none |\n| `delete-comment` | write | `wab` | `target` |\n| `delete-post` | write | `wab` | `target` |\n| `edit-comment` | write | `wab` | `target`, `commentId`, `text`, `dryRun?` |\n| `edit-post` | write | `wab` | `target`, `text` |\n| `engage-commenters` | write | `wab` | `post`, `actions?`, `replyText?`, `connectNote?`, `maxCommenters?`, `durationMs?`, `dryRun?` |\n| `enrich-engagers` | read | `cookies` | `activityId`, `reactions?`, `comments?`, `maxProfiles?`, `companyDetail?`, `profileSource?` |\n| `enrich` | read | `cookies` | `target?`, `via?`, `targets?` |\n| `feed-e
145ngage` | write | `wab` | `authors?`, `keywords?`, `subreddits?`, `reply?`, `replyStyle?`, `personaReply?`, `relevanceThreshold?`, `relevancePrompt?`, `maxReply?`, `perDayCap?`, `maxScan?`, `dryRun?`, `durationMs?`, `maxEngage`, `reactions?`, `expandPosts?`, `engageComments?`, `engageCommentsFrom?`, `maxCommentEngage?`, `navigate?`, `scrollMode?`, `scanIntervalMs?` |\n| `follow` | write | `wab` | `target` |\n| `inmail-credits` | read | `cookies` | none |\n| `inmail` | write | `wab` | `target`, `subject`, `message`, `yesConsumeCredit?`, `dryRun?` |\n| `invitations` | read | `cookies` | none |\n| `like` | write | `wab` | `target`, `reaction?`, `comment?` |\n| `me` | read | `cookies` | none |\n| `messages` | read | `cookies` | `target` |\n| `mute` | write | `wab` | `target` |\n| `notifications` | read | `cookies` | none |\n| `post-details` | read | `cookies` | `target` |\n| `post` | write | `wab` | `text`, `visibility?`, `mediaRefs?` |\n| `posts` | read | `cookies` | `target`, `count?`, `comments?` |\n| `profile` | read | `cookies` | `target` |\n| `react` | write | `wab` | `activityId`, `reactionType?` |\n| `reactions` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `recruiter-filters` | read | `cookies` | `filterType?`, `query?`, `searchUrl?`, `delayMs?`, `via?` |\n| `recruiter-open-saved-search` | read | `wab` | `reference`, `filter?`, `excludeFilter?`, `rangeFilter?`, `toggle?`, `filtersJson?`, `searchUrl?`, `count?`, `maxPages?`, `start?`, `delayMs?`, `all?`, `details?`, `maxProfiles?`, `noCache?`, `via?` |\n| `recruiter-profile` | read | `cookies` | `references`, `maxProfiles?`, `noCache?`, `delayMs?`, `via?` |\n| `recruiter-save-search` | write | `wab` | `name`, `keywords?`, `filter?`, `excludeFilter?`, `rangeFilter?`, `toggle?`, `filtersJson?`, `searchUrl?`, `recruiterProject?`, `newRecruiterProject?`, `alerts?`, `delayMs?`, `via?` |\n| `recruiter-saved-searches` | read | `cookies` | `delayMs?`, `via?` |\n| `recruiter-search` | read | `cookies` | `keywords?`, `filter?`, `excludeFilter?`, `rangeFilter?`, `toggle?`, `filtersJson?`, `searchUrl?`, `count?`, `maxPages?`, `start?`, `delayMs?`, `all?`, `details?`, `maxProfiles?`, `noCache?`, `via?` |\n| `reply-comment` | write | `wab` | `target`, `commentId`, `text`, `dryRun?` |\n| `salesnav-alerts` | read | `cookies` | none |\n| `salesnav-connect` | write | `wab` | `urn`, `expectName`, `note?`, `send?` |\n| `salesnav-create-list` | write | `wab` | `name`, `description?` |\n| `salesnav-delete-list` | write | `wab` | `id` |\n| `salesnav-delete-saved-search` | write | `wab` | `id` |\n| `salesnav-facets` | read | `cookies` | `type?`, `query?` |\n| `salesnav-insights` | read | `cookies` | `urn` |\n| `salesnav-list-add` | write | `wab` | `listId`, `urn` |\n| `salesnav-list-remove` | write | `wab` | `listId`, `urn` |\n| `salesnav-lists` | read | `wab` | none |\n| `salesnav-message` | write | `wab` | `urn`, `text`, `expectName`, `subject?`, `send?` |\n| `salesnav-notifications` | read | `cookies` | `count?` |\n| `salesnav-personas` | read | `cookies` | none |\n| `salesnav-profile` | read | `wab` | `urns` |\n| `salesnav-recent` | read | `cookies` | none |\n| `salesnav-recommended-companies` | read | `cookies` | `count?`, `all?`, `maxPages?`, `delayMs?` |\n| `salesnav-recommended-leads` | read | `cookies` | `count?`, `all?`, `maxPages?`, `delayMs?` |\n| `salesnav-save-lead` | write | `wab` | `urn`, `unsave?` |\n| `salesnav-save-search` | write | `wab` | `name`, `keywords?`, `seniority?`, `region?`, `industry?`, `company?`, `function?`, `connectionOf?`, `title?`, `pastTitle?`, `pastCompany?`, `school?`, `yearsOfExperience?` |\n| `salesnav-saved-searches` | read | `cookies` | none |\n| `salesnav-search` | read | `wab` | `keywords?`, `seniority?`, `region?`, `industry?`, `company?`, `function?`, `connectionOf?`, `title?`, `pastTitle?`, `pastCompany?`, `school?`, `yearsOfExperience?`, `count?`, `maxPages?`, `delayMs?` |\n| `salesnav-spotlights` | read | `cookies` | `list?`, `limit?`, `changedWithinDays?`, `postedWithinDays?` |\n| `salesnav-typeahead` | read | `cookies` | `query` |\n| `salesnav-warm-intro` | read | `cookies` | `urn`, `count?` |\n| `saves` | read | `cookies` | none |\n| `search-posts` | read | `wab` | `query`, `maxPosts?`, `minReactions?`, `excludeCompanyPages?`, `sort?`, `dateRange?`, `withAuthorProfile?` |\n| `search` | read | `cookies` | `query`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `send-message` | write | `wab` | `target`, `message`, `participantName?`, `dryRun?` |\n| `sent-invitations` | read | `cookies` | none |\n| `unlike` | write | `wab` | `target`, `reaction?`, `comment?` |\n| `visit` | write | `wab` | `target`, `dwellMs?`, `noScroll?` |\n\n## X\n\n| Action | Kind | Transport | Payload |\n| --- | --- | --- | --- |\n| `analytics` | read | `cookies` | `tweetId`, `count?`, `cursor?` |\n| `bookmark` | write | `wab` | `tweetId` |\n| `bookmarks` | read | `cookies` | none |\n| `delete` | write | `wab` | `tweetId` |\n| `dm-inbox` | read | `cookies` | `count?` |\n| `dm-read` | read | `cookies` | `conversationId`, `count?` |\n| `dm-requests` | read | `cookies` | `count?` |\n| `feed-e
145ngage` | write | `wab` | `authors?`, `keywords?`, `subreddits?`, `reply?`, `replyStyle?`, `personaReply?`, `relevanceThreshold?`, `relevancePrompt?`, `maxReply?`, `perDayCap?`, `maxScan?`, `dryRun?`, `durationMs?`, `maxEngage`, `reactions?`, `expandPosts?`, `engageComments?`, `engageCommentsFrom?`, `maxCommentEngage?`, `navigate?`, `scrollMode?`, `scanIntervalMs?` |\n| `follow` | write | `wab` | `handle` |\n| `followers` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `following` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `home` | read | `cookies` | `following?` |\n| `like` | write | `wab` | `tweetId` |\n| `likes` | read | `cookies` | `target?`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `list-timeline` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `lists` | read | `cookies` | `handle?`, `memberOf?` |\n| `mentions` | read | `cookies` | `count?` |\n| `news` | read | `cookies` | `tab?`, `count?` |\n| `quote` | write | `wab` | `tweetId`, `text`, `mediaRefs?` |\n| `read` | read | `cookies` | `tweetId`, `count?`, `cursor?` |\n| `replies` | read | `cookies` | `tweetId`, `count?`, `cursor?` |\n| `reply` | write | `wab` | `tweetId`, `text`, `mediaRefs?` |\n| `retweet` | write | `wab` | `tweetId` |\n| `search` | read | `cookies` | `query`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `thread` | read | `cookies` | `tweetId`, `count?`, `cursor?` |\n| `tweet` | write | `wab` | `text`, `mediaRefs?` |\n| `unbookmark` | write | `wab` | `tweetId` |\n| `unfollow` | write | `wab` | `handle` |\n| `unlike` | write | `wab` | `tweetId` |\n| `unretweet` | write | `wab` | `tweetId` |\n| `user-tweets` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `user` | read | `cookies` | `target` |\n\n## Reddit\n\n| Action | Kind | Transport | Payload |\n| --- | --- | --- | --- |\n| `analytics` | read | `cookies` | `target` |\n| `chat-accept-all` | write | `wab` | `delayMs?` |\n| `chat-accept` | write | `wab` | `conversationId` |\n| `chat-inbox` | read | `wab` | `count?` |\n| `chat-messages` | read | `wab` | `conversationId`, `count?` |\n| `chat-send` | write | `wab` | `conversationId`, `text`, `dryRun?` |\n| `chat-start` | write | `wab` | `username`, `text`, `dryRun?` |\n| `comment` | write | `wab` | `parentFullname`, `text`, `postId?`, `dryRun?` |\n| `comments` | read | `cookies` | `subreddit`, `count?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `delete` | write | `wab` | `fullname`, `postId?` |\n| `feed-engage` | write | `wab` | `authors?`, `keywords?`, `subreddits?`, `reply?`, `replyStyle?`, `personaReply?`, `relevanceThreshold?`, `relevancePrompt?`, `maxReply?`, `perDayCap?`, `maxScan?`, `dryRun?`, `durationMs?`, `maxEngage`, `reactions?`, `expandPosts?`, `engageComments?`, `engageCommentsFrom?`, `maxCommentEngage?`, `navigate?`, `scrollMode?`, `scanIntervalMs?` |\n| `feed` | read | `cookies` | `subreddit`, `count?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `home` | read | `cookies` | `target?`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `inbox` | read | `cookies` | `count?`, `after?`, `type?`, `unread?` |\n| `post` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `rules` | read | `cookies` | `target` |\n| `save` | write | `wab` | `fullname`, `postId?` |\n| `saved` | read | `cookies` | `target?`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `search` | read | `cookies` | `query`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `submit` | write | `wab` | `subreddit`, `title`, `text?`, `url?`, `mediaRefs?`, `flair?`, `dryRun?` |\n| `subreddit` | read | `cookies` | `target` |\n| `subscribe` | write | `wab` | `target` |\n| `trending` | read | `cookies` | `target?`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `unsave` | write | `wab` | `fullname`, `postId?` |\n| `user-comments` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `user-posts` | read | `cookies` | `target`, `count?`, `cursor?`, `after?`, `sort?`, `time?`, `all?`, `maxPages?`, `delayMs?` |\n| `user` | read | `cookies` | `target` |\n| `vote` | write | `wab` | `fullname`, `vote`, `postId?` |\n| `whoami` | read | `cookies` | none |\n\n## Instagram\n\n| Action | Kind | Transport | Payload |\n| --- | --- | --- | --- |\n| `comment` | write | `wab` | `media`, `text` |\n| `comments` | read | `cookies` | `target` |\n| `feed-e
145ngage` | write | `wab` | `authors?`, `keywords?`, `subreddits?`, `reply?`, `replyStyle?`, `personaReply?`, `relevanceThreshold?`, `relevancePrompt?`, `maxReply?`, `perDayCap?`, `maxScan?`, `dryRun?`, `durationMs?`, `maxEngage`, `reactions?`, `expandPosts?`, `engageComments?`, `engageCommentsFrom?`, `maxCommentEngage?`, `navigate?`, `scrollMode?`, `scanIntervalMs?` |\n| `saved` | read | `cookies` | none |\n\n## Actions that only run locally\n\nA few verbs are deliberately absent from the API because they cannot run on\nhosted infrastructure:\n\n| Action | Why |\n| --- | --- |\n| `x/dm-send` | WAB-only; may also need an encrypted XChat passcode |\n| `x/dm-accept` | WAB-only; may also need an encrypted XChat passcode |\n| `x/dm-start` | WAB-only; may also need an encrypted XChat passcode |\n\n### Nested verbs need `?engine=cloud` while your relay is online\n\nActions whose command nests a sub-verb - `x/dm-*`, `reddit/chat-*`, and\n`linkedin/salesnav-*` - are rejected by the local relay's argv check, which\nrequires the second command token to equal the action name.\n\nThere is **no automatic fallback** from that. The API only reroutes to the\nhosted twin when the relay is *lost*; a rejection is an error response, so the\ncall fails outright. With an online relay under the default `auto` policy,\nthese actions therefore require an explicit pin:\n\n```text\nPOST /twin/sessions/{persona}/actions/x/dm-inbox?engine=cloud\n```\n\nWithout the pin they fail while your machine is online and succeed while it is\noff, which is a confusing failure to debug. A relay carrying the argv fix\nremoves the need for the pin, but only once that build is installed.\n\nThese run through the local CLI or the local MCP server instead.\n\nThe passcode is set with `wonda x dm passcode set`, which is terminal-only by\ndesign - the secret never leaves your machine, so there is nothing for the API\nto forward. It is loaded only when X actually presents its encrypted-XChat\ngate, so an account without that gate can send DMs without one; the writes stay\nlocal because the transport is WAB, not because every account needs a\npasscode.\nThe DM **reads** (`x/dm-inbox`, `x/dm-read`, `x/dm-requests`) are available\nover the API like any other read.\n",r=`--- 146title: Routing - Your Machine or the Cloud 147description: How Wonda decides whether an action runs on your own computer or on the account's hosted browser, and how to pin it. 148--- 149 150## Two places an action can run 151 152The same API call can execute in one of two places: 153 154- **Your machine** - the Wonda desktop app is running, so the action runs in the 155 Wonda Automation Browser (WAB) on your computer, on your own IP, with the 156 account's cookies staying on your device. 157- **The cloud twin** - a hosted browser session for that persona, behind 158 dedicated mobile or residential IPs, which can run when your machine is off. 159 160You do not pick this per call. The backend routes each action, and an API client 161gets the same routing an MCP client would. 162 163## Engine policy 164 165Routing follows your account's engine policy: 166 167| Policy | Behaviour | 168| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 169| \`auto\` (default) | Prefer your machine when its relay is online; fall back to the cloud twin **if the persona is cloud-capable and the account has the Premium cloud-twin entitlement** | 170| \`my_machine\` | Only run on your machine; fail rather than fall back to the cloud | 171| \`cloud\` | Always run on the hosted twin, even when your machine is online | 172 173\`my_machine\` is the setting to choose when an account must never be touched from
174hosted infrastructure. 175 176\`auto\` does not guarantee the work continues when your laptop closes. Cloud 177fallback needs both a cloud-capable persona and Premium cloud-twin entitlement; 178without them a local persona returns \`relay_offline\` or \`paid_plan_required\` 179instead of moving to the cloud. 180 181## Transport: cookies or WAB 182 183Independently of _where_ an action runs, each action has a **transport** - how 184it talks to the platform: 185 186- \`cookies\` - a direct authenticated request using the persona's stored session. 187 Fast, cheap, and used for most reads. 188- \`wab\` - a real browser page driving the platform's UI. Slower, and required 189 for anything the platform does not expose to a plain request. 190 191Every action has a sensible default, listed in the 192[Action Reference](/docs/action-reference). Override it per call when the action 193supports both: 194 195\`\`\`bash 196curl -X POST \\ 197 "https://api.wondercat.ai/api/v1/twin/sessions/natty/actions/x/mentions?via=wab" \\ 198 -H "Authorization: Bearer $WONDA_API_KEY" \\ 199 -H "Content-Type: application/json" \\ 200 -d '{}' 201\`\`\` 202 203\`via\` accepts \`cookies\` or \`wab\`. Anything else is rejected with 204\`command_not_allowed\` and \`reason: "invalid_payload"\`. Forcing \`wab\` on a read is occasionally useful when the 205cookie path is being rate-limited by the platform; forcing \`cookies\` on an 206action that genuinely needs a browser will fail. 207 208## Pinning the cloud twin 209 210Add \`engine=cloud\` to run on the hosted twin regardless of the account policy: 211 212\`\`\`text 213POST /twin/sessions/{persona}/actions/{platform}/{action}?engine=cloud 214\`\`\` 215 216This exists so a caller that means "run this in the cloud" cannot be silently 217routed to a live local relay. 218 219## Related 220 221- [Running Platform Actions](/docs/platform-actions) 222- [Controlling the Browser](/docs/browser-control) - driving the WAB directly 223- [Action Errors](/docs/action-errors) 224`,i=`--- 225title: Alignment Timestamps 226description: Extract word-level timestamps by aligning a transcript to an audio file. 227--- 228 229\`POST /api/v1/alignment/extract-timestamps\` 230 231## Request Body 232 233| Parameter | Type | Required | Description | 234| ------------------ | -------- | -------- | ---------------------------- | 235| model | string | Yes | Model key (see models below) | 236| params | object | Yes | Model-specific parameters | 237| attachmentMediaIds | string[] | Yes | Audio file to align against | 238 239## Response 240 241\`\`\`json 242{ 243 "inferenceJobId": "ij_..." 244} 245\`\`\` 246 247## Example 248 249**POST /api/v1/alignment/extract-timestamps** 250 251\`\`\`json 252{ 253 "model": "elevenlabs-extract-timestamps", 254 "params": { 255 "text": "Welcome to Wonda, the AI-powered video editing platform." 256 }, 257 "attachmentMediaIds": ["media_abc123"] 258} 259\`\`\` 260 261--- 262 263## Models 264 265### elevenlabs-extract-timestamps 266 267Align a transcript to audio and extract word-level timestamps via ElevenLabs. 268 269| Parameter | Type | Required | Description | 270| --------- | ------ | -------- | ---------------------------------------------- | 271| text | string | Yes | The transcript text to align against the audio | 272 273**Attachments:** 1 required audio file (wav, mp3, mpeg, m4a). 274`,a=`--- 275title: Analytics 276description: Fetch account-level analytics for Instagram, TikTok, and Meta Ads from the public API. 277--- 278 279## Instagram analytics 280 281\`GET /api/v1/analytics/instagram\` 282 283| Parameter | Type | Required | Description | 284| ------------------ | ------------- | -------- | ----------------------------------------------------------------------------------------------- | 285| instagramAccountId | string (UUID) | No | Optional when exactly one Instagram account is connected; required when multiple are connected. | 286 287The response includes the connected account summary, recent media, and audience insights when available. 288 289**Response shape** 290 291\`\`\`json 292{ 293 "dataLevel": "full", 294 "account": { 295 "username": "wonda", 296 "followerCount": 12000, 297 "mediaCount": 84 298 }, 299 "accountMetrics": { 300 "reach": 54000, 301 "views": 92000, 302 "followsAndUnfollows": 126, 303 "period": "last_30d" 304 }, 305 "audienceInsights": { 306 "followerDemographics": {}, 307 "reachedAudienceDemographics": {}, 308 "onlineFollowers": {} 309 }, 310 "recentMedia": [] 311} 312\`\`\` 313 314\`accountMetrics\` and \`audienceInsights\` are nullable â they are \`null\` when the account has \`"dataLevel": "basic"\`. 315 316## TikTok analytics 317 318\`GET /api/v1/analytics/tiktok\` 319 320| Parameter | Type | Required | Description | 321| --------------- | ------------- | -------- | -------------------------------------------------------------------------------------------- | 322| tiktokAccountId | string (UUID) | No | Optional when exactly one TikTok account is connected; required when multiple are connected. | 323 324The response includes profile stats and a list of recent videos with view and engagement counts. 325 326**Response shape** 327 328\`\`\`json 329{ 330 "account": { 331 "displayName": "Wonda", 332 "followerCount": 12000, 333 "followingCount": 42, 334 "likesCount": 181000, 335 "videoCount": 84, 336 "bio": "Creative automation", 337 "isVerified": false 338 }, 339 "recentVideos": [] 340} 341\`\`\` 342 343## Meta Ads analytics 344 345\`GET /api/v1/analytics/meta-ads\` 346 347| Parameter | Type | Required | Description | 348| --------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | 349| metaAdAccountId | string (UUID) | No | Optional selector for one connected Meta ad account. If omitted, a single connected account is used directly or multiple accounts are aggregated. | 350| objectId | string | No | Overrides the target Ad Library object id. Defaults to the connected ad account when omitted. | 351| datePreset | string | No | One of the supported date presets. Defaults to last_7d. | 352| fields | string | No | Comma-separated Meta Insights fields. Defaults to the standard engagement and spend fields. | 353| breakdowns | string | No | Comma-separated breakdown values. Invalid combinations return a 400 response. | 354 355**Example** 356 357\`\`\`bash 358curl "https://api.wondercat.ai/api/v1/analytics/meta-ads?datePreset=last_7d" \\ 359 -H "Authorization: Bearer YOUR_API_KEY" 360\`\`\` 361 362When one ad account is connected, the endpoint returns a single account payload. When multiple accounts are connected, the response contains per-account rows plus an aggregate summary. 363 364**Single-account response** 365 366\`\`\`json 367{ 368 "accountName": "Wonda Ads", 369 "accountId": "act_123", 370 "datePreset": "last_7d", 371 "summary": { 372 "impressions": 12000, 373 "clicks": 340, 374 "spend": 92.13, 375 "reach": 8300, 376 "cpm": 7.67, 377 "cpc": 0.27, 378 "ctr": 2.83 379 }, 380 "actions": {}, 381 "rows": [], 382 "deltas": { 383 "spend": 12.5, 384 "impressions": -3.2, 385 "clicks": 8.1, 386 "ctr": 1.4, 387 "cpc": -2.0, 388 "cpm": 0.6 389 } 390} 391\`\`\` 392`,o=`--- 393title: Audio Dialogue 394description: Generate multi-speaker dialogue audio from a script. 395--- 396 397\`POST /api/v1/audio/dialogue\` 398 399## Request Body 400 401| Parameter | Type | Required | Description | 402| --------- | ------ | -------- | -------------------------------------------------- | 403| model | string | Yes | Model key (see models below) | 404| params | object | Yes | Model-specific parameters (speakers, script, etc.) | 405 406## Response 407 408\`\`\`json 409{ 410 "inferenceJobId": "ij_..." 411} 412\`\`\` 413 414## Example 415 416**POST /api/v1/audio/dialogue** 417 418\`\`\`json 419{ 420 "model": "elevenlabs-dialogue", 421 "params": { 422 "speakers": [ 423 { "label": "ALICE", "voiceId": "voice_alice123" }, 424 { "label": "BOB", "voiceId": "voice_bob456" } 425 ], 426 "script": "ALICE: Hey Bob, have you tried the new editor?\\nBOB: Yes! The AI features are incredible.\\nALICE: I know, right? It saves so much time.", 427 "stability": 0.5 428 } 429} 430\`\`\` 431 432--- 433 434## Models 435 436### elevenlabs-dialogue 437 438Multi-speaker dialogue generation via ElevenLabs. No prompt needed. 439 440| Parameter | Type | Required | Description | 441| --------- | ------ | -------- | ------------------------------------------------------------------------------------------- | 442| speakers | array | Yes | Array of { label: string, voiceId: string }. Each label must match a speaker in the script. | 443| script | string | Yes | Dialogue script. Format: SPEAKER_LABEL: text (one line per speaker turn). | 444| stability | number | No | Voice stability (0 to 1) | 445 446**Attachments:** None. 447 448#### Script Format 449 450\`\`\`text 451ALICE: Hey Bob, have you tried the new editor? 452BOB: Yes! The AI features are incredible. 453ALICE: I know, right? It saves so much time. 454\`\`\` 455 456Each line must begin with a speaker label that matches one of the entries in the \`speakers\` array, followed by a colon and the text to speak. 457`,s=`--- 458title: Audio Editing 459description: Trim audio locally with the Wonda CLI and route AI audio cleanup through direct audio endpoints. 460--- 461 462Audio editing is CLI-first. \`wonda edit audio\` runs local ffmpeg operations, uploads the result, and prints the output \`mediaId\`. 463
464The retired \`POST /api/v1/audio/edit\` endpoint returns \`410 Gone\` with a CLI migration hint. Move audio trim scripts to the CLI command below. 465 466## Setup 467 468\`\`\`bash 469npm i -g @degausai/wonda 470wonda auth login 471wonda doctor 472\`\`\` 473 474## Trim audio 475 476Use \`audioTrim\` with \`--audio-media\`. The value can be a Wonda media ID or a local file path. 477 478\`\`\`bash 479wonda edit audio --operation audioTrim \\ 480 --audio-media 019e1b73-32a4-8c9e-8bbf-3661a14a5716 \\ 481 --params '{"trimStartMs":1000,"trimEndMs":8000}' \\ 482 --wait -o ./trimmed.mp3 483\`\`\` 484 485Parameters: 486 487| Parameter | Type | Description | 488| ------------- | ---- | ---------------------------------------------------------------- | 489| \`trimStartMs\` | int | Start of the kept range, in milliseconds. | 490| \`trimEndMs\` | int | End of the kept range, in milliseconds. \`0\` means until the end. | 491 492Without \`--output\`, the CLI prints: 493 494\`\`\`json 495{ 496 "mediaId": "019e1b73-32a4-8c9e-8bbf-3661a14a5716", 497 "status": "succeeded" 498} 499\`\`\` 500 501## Audio AI operations 502 503Audio enhancement and voice extraction are direct inference workflows, not editor operations: 504 505| Need | API endpoint | CLI command | 506| --------------------------- | --------------------------- | -------------------------------------------- | 507| Denoise or enhance audio | \`POST /audio/enhance\` | \`wonda audio enhance <video-or-audio>\` | 508| Isolate vocals from a track | \`POST /audio/extract-voice\` | \`wonda audio extract-voice <video-or-audio>\` | 509 510Both API endpoints expect an audio media input. The CLI commands can accept a video or audio input and handle local audio extraction before calling the API. 511`,c=`--- 512title: Audio Speech 513description: Synthesize speech from text using AI voices. 514--- 515 516\`POST /api/v1/audio/speech\` 517 518## Request Body 519 520| Parameter | Type | Required | Description | 521| --------- | ------ | -------- | ------------------------------ | 522| model | string | Yes | Model key (see models below) | 523| prompt | string | Yes | Text to synthesize into speech | 524| params | object | No | Model-specific parameters | 525 526## Response 527 528\`\`\`json 529{ 530 "inferenceJobId": "ij_..." 531} 532\`\`\` 533 534## Example 535 536**POST /api/v1/audio/speech** 537 538\`\`\`json 539{ 540 "model": "elevenlabs-tts", 541 "prompt": "Welcome to Wonda, the AI-powered video editing platform.", 542 "params": { 543 "voiceId": "voice_abc123", 544 "stability": 0.5, 545 "similarityBoost": 0.75 546 } 547} 548\`\`\` 549 550--- 551 552## Models 553 554### elevenlabs-tts 555 556Text-to-speech via ElevenLabs. Prompt is the text to synthesize. 557 558| Parameter | Type | Required | Description | 559| --------------- | ------ | -------- | --------------------------- | 560| voiceId | string | Yes | ElevenLabs voice identifier | 561| stability | number | No | Voice stability (0 to 1) | 562| similarityBoost | number | No | Similarity boost (0 to 1) | 563 564**Attachments:** None. 565`,l=`--- 566title: Audio Transcription 567description: Transcribe audio files to text with AI speech recognition. 568--- 569 570\`POST /api/v1/audio/transcribe\` 571 572## Request Body 573 574| Parameter | Type | Required | Description | 575| ------------------ | -------- | -------- | ---------------------------- | 576| model | string | Yes | Model key (see models below) | 577| params | object | No | Model-specific parameters | 578| attachmentMediaIds | string[] | Yes | Audio file to transcribe | 579 580## Response 581 582\`\`\`json 583{ 584 "inferenceJobId": "ij_..." 585} 586\`\`\` 587 588## Example 589 590**POST /api/v1/audio/transcribe** 591 592\`\`\`json 593{ 594 "model": "elevenlabs-stt", 595 "params": { "languageCode": "en" }, 596 "attachmentMediaIds": ["media_abc123"] 597} 598\`\`\` 599 600--- 601 602## Models 603 604### elevenlabs-stt 605 606Speech-to-text via ElevenLabs. No prompt needed. 607 608| Parameter | Type | Required | Description | 609| ------------ | ------ | -------- | ----------------------------------------------------------------- |
610| languageCode | string | No | BCP-47 language code (e.g. en, es, fr). Auto-detected if omitted. | 611 612**Attachments:** 1 required audio file (wav, mp3, mpeg, m4a, ogg). 613`,u=`--- 614title: Authentication 615description: All API requests require a Bearer token in the Authorization header. 616--- 617 618## Authorization header 619 620Include your API key in the \`Authorization\` header using the Bearer scheme: 621 622**HTTP Header** 623 624\`\`\` 625Authorization: Bearer sk_your_api_key_here 626\`\`\` 627 628## Key format 629 630API keys use the prefix \`sk_\` followed by 64 hexadecimal characters. Example: 631 632\`\`\` 633sk_a1b2c3d4e5f6... (64 hex chars) 634\`\`\` 635 636## Managing your keys 637 638You can create, rotate, and revoke API keys from the [API Keys settings page](https://wonda.sh/api-keys). Keep your keys secret -- do not expose them in client-side code or public repositories. 639 640## Example request 641 642**cURL** 643 644\`\`\`bash 645curl https://api.wondercat.ai/api/v1/image/generate \\ 646 -H "Authorization: Bearer sk_your_api_key_here" \\ 647 -H "Content-Type: application/json" \\ 648 -d '{"prompt": "A sunset over the ocean", "model": "nano-banana-2"}' 649\`\`\` 650 651If the key is missing or invalid the API returns a \`401 Unauthorized\` response. 652`,d=`--- 653title: Controlling the Browser 654description: Show, hide, navigate, and screenshot the Wonda Automation Browser on your machine from the API. 655--- 656 657## What the WAB is 658 659The Wonda Automation Browser is a real, hardened Chrome window on your machine 660holding a persona's logged-in session. It launches on demand and runs offscreen 661by default. These endpoints let an API client surface it, point it somewhere, 662and see what it is showing - the same controls the MCP \`wab_*\` tools expose. 663 664These act on **your machine** and need the Wonda desktop app running. When it is 665offline they return a clear error; the cloud twin has its own login flow. 666 667## Commands 668 669\`\`\`text 670POST /twin/sessions/{persona}/wab/{command} 671\`\`\` 672 673| Command | Effect | 674| ------------ | ------------------------------------------------------------------- | 675| \`show\` | Bring the window on screen so a person can watch | 676| \`hide\` | Return it to running offscreen | 677| \`open\` | Navigate it to a URL (requires \`target\`) | 678| \`screenshot\` | Capture what it is currently displaying | 679| \`check\` | Report whether the session is still signed in (requires \`platform\`) | 680 681\`open\` takes a target: 682 683\`\`\`bash 684curl -X POST \\ 685 https://api.wondercat.ai/api/v1/twin/sessions/natty/wab/open \\ 686 -H "Authorization: Bearer $WONDA_API_KEY" \\ 687 -H "Content-Type: application/json" \\ 688 -d '{"target": "https://www.linkedin.com/feed/"}' 689\`\`\` 690 691\`open\` requires a non-empty \`target\`; a body with only \`platform\` is rejected 692with 400. \`platform\` is what the \`check\` command takes. The command set is 693fixed and the argv is built server-side, then re-validated on the relay - a 694client cannot smuggle an arbitrary command through. 695 696## Status across every persona 697 698Status is account-level, so it has its own endpoint rather than a per-persona 699one: 700 701\`\`\`bash 702curl -X POST https://api.wondercat.ai/api/v1/twin/wab/status \\ 703 -H "Authorization: Bearer $WONDA_API_KEY" 704\`\`\` 705 706It lists each persona and whether its browser is running. 707 708## Signing a persona in 709 710Sessions lapse. Recovering one is a human step by design: open the platform's 711login page in a **visible** window and let the person sign in themselves, 712including 2FA. 713 714\`\`\`bash 715# 1. surface the window 716curl -X POST https://api.wondercat.ai/api/v1/twin/sessions/natty/wab/show \\ 717 -H "Authorization: Bearer $WONDA_API_KEY" 718 719# 2. navigate it to the platform's login page 720curl -X POST https://api.wondercat.ai/api/v1/twin/sessions/natty/wab/open \\ 721 -H "Authorization: Bearer $WONDA_API_KEY" \\ 722 -H "Content-Type: application/json" \\ 723 -d '{"target": "https://x.com/login"}' 724 725# 3. after the person signs in, confirm (platform is required here) 726curl -X POST https://api.wondercat.ai/api/v1/twin/sessions/natty/wab/check \\ 727 -H "Authorization: Bearer $WONDA_API_KEY" \\ 728 -H "Content-Type: application/json" \\ 729 -d '{"platform": "x"}' 730\`\`\` 731 732This flow never handles credentials: the person types them into the browser 733themselves, and no WAB endpoint accepts a password. 734 735A separate credential API does exist - \`POST /credentials\` takes a \`password\`, 736\`PATCH /credentials/{id}\` can update it, and reads can return it decrypted - so 737do not tell users that platform passwords never cross the API boundary. Prefer 738this human-in-the-loop flow where you can: it keeps the secret off your 739integration entirely. 740 741## Related 742 743- [Personas and Sessions](/docs/personas-sessions) 744- [Routing](/docs/action-routing) - when work runs on your machine at all 745- [Action Errors](/docs/action-errors) - including the offline-machine case 746`,f=`--- 747title: Capabilities 748description: Live inventory of models and publish destinations exposed by the public API. 749--- 750 751\`GET /api/v1/capabilities\` 752 753## Overview 754 755This endpoint is the live source of truth for generation models and publish destinations available on the public API. Static documentation may lag behind, so consult this endpoint when choosing model keys, attachment requirements, publish operations, and params schemas. 756 757Editing operation discovery now lives in the CLI because current edits render locally. Use: 758 759\`\`\`bash 760wonda operations list 761wonda operations info <operation> 762\`\`\` 763 764The API response still includes an \`editing\` object for compatibility, but the \`video\`, \`image\`, and \`audio\` arrays are empty. 765 766## Response structure 767 768The response is organized into three top-level sections: \`generation\`, \`editing\`, and \`publish\`. 769 770### generation 771 772Grouped by media type. Each entry describes a model with its accepted attachments and params JSON Schema. 773 774\`\`\`json 775{ 776 "generation": { 777 "image": [ 778 { 779 "key": "nano-banana-2",
780 "label": "Nano Banana 2", 781 "description": "General-purpose image generation", 782 "attachments": ["reference_images"], 783 "params": { "type": "object", "properties": {} } 784 } 785 ], 786 "video": [], 787 "text": [] 788 } 789} 790\`\`\` 791 792### editing 793 794Current editing operations run in the CLI, not through the public API. 795 796\`\`\`json 797{ 798 "editing": { 799 "video": [], 800 "image": [], 801 "audio": [] 802 } 803} 804\`\`\` 805 806### publish 807 808Available publish destinations, the media they accept, and params JSON Schema. 809 810\`\`\`json 811{ 812 "publish": [ 813 { 814 "operation": "instagramPublish", 815 "label": "Instagram Publish", 816 "description": "Publish an image or video directly to Instagram.", 817 "accepts": { 818 "media": { 819 "kinds": ["image", "video"], 820 "min": 1, 821 "max": 1 822 }, 823 "text": { 824 "optional": true 825 } 826 }, 827 "params": { "type": "object", "properties": {} } 828 } 829 ] 830} 831\`\`\` 832`,p=`--- 833title: Connect Wonda to ChatGPT 834description: Add Wonda as a custom MCP server in ChatGPT so it can act through your social personas. 835--- 836 837## What you get 838 839ChatGPT gets Wonda's cloud twin: reading feeds, search results, profiles, 840analytics, and inboxes across LinkedIn, X, Reddit, and Instagram, plus approved 841writes such as posting, commenting, connecting, messaging, and running bounded 842campaigns. 843 844You do not need the Wonda CLI, a local browser, or an API key pasted into 845ChatGPT. 846 847## Turn on Developer mode first 848 849Open **Settings**, then **Security and login**, and enable **Developer mode**. 850 851Developer mode and full MCP support are a **Business and Enterprise/Edu** 852capability on ChatGPT web, enabled by a workspace admin (Enterprise/Edu can 853scope it per user). Consumer **Plus and Pro do not have it**, so if you are on 854one of those plans you cannot add a server here - use 855[Claude](/docs/connect-claude) or [Codex](/docs/connect-codex), or call the 856[API directly](/docs/platform-actions). 857 858Do this before anything else: the Plugins page has no way to add a server until 859Developer mode is on. 860 861## Add the server 862 863Go to [chatgpt.com/plugins](https://chatgpt.com/plugins) and: 864 8651. Click **+** and name it \`Wonda\`. 8662. Set **Connection** to \`Server URL\` and paste this into the URL field: 867 868 \`\`\`text 869 https://api.wondercat.ai/mcp 870 \`\`\` 871 8723. Leave **Authentication** on \`OAuth\`, tick **I understand and want to
873 continue**, and create it. 8744. ChatGPT asks you to sign in to Wonda and approve access. Done once, works 875 forever. 876 877Your Wonda API key stays inside Wonda and is never shown to ChatGPT. The grant 878is OAuth against the Wonda MCP resource at 879\`https://api.wondercat.ai/.well-known/oauth-protected-resource/mcp\`. 880 881## Verify 882 883Ask ChatGPT: 884 885\`\`\`text 886Use Wonda to tell me which personas I have. 887\`\`\` 888 889If it lists your personas, the connector works. If it reports none, connect a 890persona first - see [Personas and Sessions](/docs/personas-sessions). 891 892## Where actions run 893 894ChatGPT cannot load a local MCP server, so the connector itself is remote. That 895does **not** mean every action runs in the cloud: the remote server calls the 896same twin action endpoints as everything else, and those follow your account's 897engine policy. Under the default \`auto\`, an action runs in the Wonda Automation 898Browser on your machine whenever the Wonda app is online, and only falls back 899to the hosted twin otherwise. 900 901If you need a persona's writes to come from the hosted residential or mobile IP 902rather than your own connection, set the engine policy to \`cloud\` - see 903[Routing](/docs/action-routing). Assuming "remote connector" means "hosted IP" 904is exactly the mistake worth avoiding. 905 906## Approvals 907 908Read tools are labelled safe to allow broadly. Write tools request server-side 909write slots and should stay ask-first unless you want a hands-off loop. 910 911The approval setting in ChatGPT is a client-side prompt. Wonda still enforces 912the action gate, write-slot allowance, daily caps, cooldowns, account status, 913and safety checks server-side, so allowing a tool does not raise those limits. 914 915## Team and Enterprise 916 917An admin enables Developer mode and may need to approve the server before 918members can use it. Add Wonda once, complete the OAuth grant, and approve it for 919the workspace. 920 921The OAuth grant binds your Wonda **account**, not an organization: the consent 922screen has no organization chooser, and the connector does not send the 923\`X-Wonda-Org\` header that selects an organization seat, entitlement, or wallet. 924Actions therefore run against your personal context. Use the CLI or the web app 925when work must be billed to an organization. 926 927## Related 928 929- [Connect to Claude](/docs/connect-claude) 930- [Connect to Codex](/docs/connect-codex) 931- [Running Platform Actions](/docs/platform-actions) 932`,m=`--- 933title: Connect Wonda to Claude 934description: Add Wonda's cloud twin to Claude as a custom remote MCP connector with OAuth. 935--- 936 937## What you get 938 939The Wonda cloud twin lets Claude use your server-side social personas through Wonda tools. Claude can read search results, feeds, profiles, analytics, inboxes, and account health across LinkedIn, Reddit, X, and Instagram. It can also ask Wonda to take approved actions such as posting, replying, commenting, connecting, messaging, scheduling, and running bounded campaigns. 940 941This is the cloud connector path. You do not need the Wonda CLI, a local browser, or an API key field in Claude. 942 943## Connect on Claude.ai web or Cowork 944 945Add Wonda as a custom connector by URL: 946 947\`\`\`text 948https://api.wondercat.ai/mcp 949\`\`\` 950 951Existing connections made with the previous Cloud Run URL keep working; no reconnection is needed. 952 953In Claude, open **Customize**, then **Connectors** (or go straight to [claude.ai/customize/connectors](https://claude.ai/customize/connectors)). Click **+**, choose **Add custom connector**, name it \`Wonda\`, paste the URL, and continue. 954 955Claude opens Wonda's OAuth flow in the browser. Sign in with Wonda, choose the account or organization context you want Claude to use, review the consent screen, and approve access. Claude receives OAuth tokens for the Wonda MCP resource at \`https://api.wondercat.ai/.well-known/oauth-protected-resource/mcp\`. Your Wonda API key stays inside Wonda and is not shown to Claude or copied into the connector form. 956 957This custom connector path does not require a Connectors Directory listing or Anthropic review. The Directory path is optional and skipped by default. 958 959## Connect on Claude Desktop 960 961Claude Desktop can use the same remote connector when your Claude account has custom connector support. Add Wonda in Claude's connector settings, paste the same connector URL, and complete the OAuth grant in the browser. 962 963Technical users can also run Wonda locally: 964 965- Use the stdio MCP package with \`npx -y @degausai/wonda-mcp\` and your normal Wonda CLI authentication. 966- Use the local \`wonda.mcpb\` Desktop Extension on macOS when you want platform actions to run through your on-device Wonda Automation Browser and local cookie store. 967 968The local paths work in Claude Desktop, Claude Code, and Claude Cowork: the desktop app runs local MCP servers on your machine, outside the Cowork sandbox, so local mode works in Cowork sessions too. Claude web cannot load local servers and needs the remote connector. 969 970## Team and Enterprise 971 972For Claude Team and Enterprise workspaces, an organization owner or connector admin may need to add and approve Wonda before members can use it. Add Wonda once as a custom connector, complete the Wonda OAuth grant, and approve it for the workspace. 973 974In Wonda, paid organization seats use the organization's twin access and billing context when the OAuth grant is made from that organization. Members still act through their assigned Wonda permissions, spend limits, and platform account connections. 975 976## Consent and approvals 977
978Wonda labels read tools as safe for Claude's **Always allow** mode. Read tools have zero write slots and cover retrieval such as feeds, profiles, inboxes, analytics, job status, twin health, and action allowance. 979 980Write tools are labeled as needing approval. They request one or more server-side write slots depending on the action. Examples include comments, replies, direct messages, connection requests, follows, saves, votes, posts, schedules, and campaign runs. 981 982Claude's consent setting is a client-side prompt. Wonda still enforces the server-side action gate, write-slot allowance, daily caps, cooldowns, account status, billing, and safety checks before anything is sent to a platform. 983 984## Autopilot or supervised mode 985 986For supervised use, leave write tools in an ask-first mode. Claude will ask before it asks Wonda to act. 987 988For hands-off workflows, allow a bounded campaign or schedule tool instead of approving each small action. A campaign approval lets Wonda run the requested loop server-side within the configured caps, cooldowns, and relevance checks. 989 990Setting a write tool to **Always allow** does not mean unlimited action volume. Wonda still applies action allowances, spend limits, daily caps, cooldowns, paused-session checks, and platform health gates. 991 992## Onboard your platform accounts 993 994The connector can only act through platform accounts that are already connected to the selected Wonda twin. If a platform session expires, Wonda will ask you to refresh it through the streamed login view before read or write tools continue. 995 996## Troubleshooting 997 998- **Claude asks you to connect again**: complete the OAuth grant again from Claude's connector settings. 999- **A platform account needs auth**: open the Wonda streamed login view for that twin and platform, then sign in. 1000- **402 responses**: add credits or update billing. 1001- **423 responses**: resume the paused twin or clear the account safety state in Wonda. 1002- **429 responses**: wait for the action allowance, platform cooldown, or rate limit window to reset. 1003 1004## Connectors Directory 1005 1006The Connectors Directory is not required for this connector. Wonda ships as a custom connector by URL, so users can connect without a Directory listing and without Anthropic contact. 1007 1008If Wonda later chooses to request a Directory listing, that should be a separate go or hold decision after live connector verification has passed. The reviewer account must be owned by Wonda, must sit in a Team or Enterprise organization, and must have only Wonda-owned platform identities connected. Do not submit a Directory packet until the connector URL, OAuth metadata, redirect callbacks, read tools, write approvals, and reviewer credentials have all been verified. 1009`,h=`--- 1010title: Connect Wonda to Codex 1011description: Add Wonda to OpenAI Codex as an MCP server so it can act through your social personas. 1012--- 1013 1014## You may not need this 1015
1016Codex is the one assistant with a second way in: it runs in a terminal, so it 1017can drive Wonda by shelling out to the \`wonda\` binary directly, the way Claude 1018Code does. Sign in once: 1019 1020\`\`\`bash 1021wonda auth login 1022\`\`\` 1023 1024After that Codex can use Wonda with no connector at all. Adding the MCP server 1025below is still worth doing if you want Codex to drive Wonda on a **different 1026computer** than the one you are working on. 1027 1028## Add the server 1029 1030In Codex, open **Plugins**, then **MCPs**, and click **+ Add Server**. Name it 1031\`Wonda\`, set **Type** to \`Streamable HTTP\`, and paste this into **URL**, 1032leaving every other field empty: 1033 1034\`\`\`text 1035https://api.wondercat.ai/mcp 1036\`\`\` 1037 1038Save, then sign in to Wonda and approve access. Done once, works forever. 1039 1040## Prefer the terminal? 1041 1042Add this to \`~/.codex/config.toml\`: 1043 1044\`\`\`toml 1045[mcp_servers.wonda] 1046url = "https://api.wondercat.ai/mcp" 1047oauth_resource = "https://api.wondercat.ai/mcp" 1048\`\`\` 1049 1050Replace any existing \`[mcp_servers.wonda]\` block rather than pasting a second 1051copy - Codex rejects the whole file if the key appears twice. Then grant Codex 1052access to the server: 1053 1054\`\`\`bash 1055codex mcp login wonda 1056\`\`\` 1057 1058That is a different thing from \`wonda auth login\` above: \`wonda auth login\` 1059authenticates the CLI, while \`codex mcp login\` completes the OAuth grant for 1060the MCP server you just configured. 1061 1062## Verify 1063 1064Ask Codex: 1065 1066\`\`\`text 1067Use Wonda to tell me which personas I have. 1068\`\`\` 1069 1070If it lists your personas, the connection works. If it reports none, connect a 1071persona first - see [Personas and Sessions](/docs/personas-sessions). 1072 1073## Approvals 1074 1075Read tools are safe to allow broadly: they have zero write slots and only 1076retrieve data. Write tools request server-side write slots and should stay 1077ask-first unless you deliberately want a hands-off loop. 1078 1079Codex's approval setting is a client-side prompt. Wonda still enforces the 1080action gate, write-slot allowance, daily caps, cooldowns, account status, and 1081safety checks server-side, so allowing a tool in Codex does not raise those 1082limits. 1083 1084## Prefer plain HTTP? 1085 1086Codex can also call the Wonda API directly with an API key, without MCP. The 1087tools are a convenience wrapper over the same endpoints - see 1088[Running Platform Actions](/docs/platform-actions). 1089 1090## Related 1091 1092- [Connect to Claude](/docs/connect-claude) 1093- [Connect to ChatGPT](/docs/connect-chatgpt) 1094- [Running Platform Actions](/docs/platform-actions) 1095`,g=`--- 1096title: Distribution Accounts and History 1097description: List connected Instagram and TikTok accounts, then review publish history for each surface. 1098--- 1099 1100## What this surface covers 1101 1102This surface is separate from the direct publish endpoints. Use it to discover connected accounts and inspect publish history, especially when you need cursor-based pagination or need to filter previous Instagram and TikTok publishes. 1103 1104## Instagram accounts 1105 1106\`GET /api/v1/instagram/accounts\` 1107 1108Returns connected Instagram accounts that are currently active for the authenticated Wonda account. 1109 1110\`\`\`json 1111{ 1112 "accounts": [ 1113 { 1114 "instagramAccountId": "550e8400-e29b-41d4-a716-446655440000", 1115 "igUserId": "17841400000000000", 1116 "username": "wonda", 1117 "accountType": "BUSINESS", 1118 "status": "active", 1119 "scopes": ["instagram_basic", "instagram_content_publish"] 1120 } 1121 ] 1122} 1123\`\`\` 1124 1125## TikTok accounts 1126 1127\`GET /api/v1/tiktok/accounts\` 1128 1129Returns connected TikTok accounts that are currently active for the authenticated Wonda account. 1130 1131\`\`\`json 1132{ 1133 "accounts": [ 1134 { 1135 "tiktokAccountId": "550e8400-e29b-41d4-a716-446655440000", 1136 "tiktokUserId": "1234567890", 1137 "username": "wonda", 1138 "displayName": "Wonda Studio", 1139 "avatarUrl": "https://...", 1140 "status": "active", 1141 "grantedScopes": ["video.publish", "user.info.basic"] 1142 } 1143 ] 1144} 1145\`\`\` 1146 1147## Instagram publish history 1148 1149\`GET /api/v1/instagram/publishes\` 1150 1151| Parameter | Type | Required | Description | 1152| ------------------------ | -------------------------------------------- | -------- | -------------------------------------------------------------------------------- | 1153| limit | number | No | Maximum number of rows to return. Defaults to 10. | 1154| status | queued \\| in_progress \\| succeeded \\| failed | No | Filter by publish status. | 1155| product | IMAGE \\| REELS \\| STORIES \\| CAROUSEL | No | Filter by Instagram product type. | 1156| instagramAccountId | string (UUID) | No | Filter by a specific connected Instagram account. | 1157| cursorCreatedAt | string (datetime) | No | Cursor timestamp for pagination. Must be provided with cursorInstagramPublishId. | 1158| cursorInstagramPublishId | string (UUID) | No | Cursor publish ID for pagination. Must be provided with cursorCreatedAt. | 1159 1160The cursor pair must always travel together. The response returns a \`nextCursor\` object when more rows are available. 1161 1162\`\`\`json 1163{ 1164 "items": [ 1165 { 1166 "instagramPublishId": "b2d7e2ae-1d3d-4c88-8f01-0d2c8fb2d9b1", 1167 "instagramAccountId": "550e8400-e29b-41d4-a716-446655440000", 1168 "product": "CAROUSEL", 1169 "status": "succeeded", 1170 "sourceUrl": "https://...", 1171 "caption": "Spring launch", 1172 "altText": null, 1173 "containerId": "1789...", 1174 "igMediaId": "1789...", 1175 "permalink": "https://instagram.com/p/...", 1176 "createdAt": "2026-03-19T12:34:56.000Z", 1177 "publishedAt": "2026-03-19T12:35:45.000Z" 1178 } 1179 ], 1180 "nextCursor": { 1181 "createdAt": "2026-03-19T12:34:56.000Z", 1182 "instagramPublishId": "b2d7e2ae-1d3d-4c88-8f01-0d2c8fb2d9b1" 1183 } 1184} 1185\`\`\` 1186 1187## TikTok publish history 1188 1189\`GET /api/v1/tiktok/publishes\` 1190 1191| Parameter | Type | Required | Description | 1192| --------------------- | -------------------------------------------- | -------- | ----------------------------------------------------------------------------- | 1193| limit | number | No | Maximum number of rows to return. Defaults to 10. | 1194| status | queued \\| in_progress \\| succeeded \\| failed | No | Filter by publish status. | 1195| tiktokAccountId | string (UUID) | No | Filter by a specific connected TikTok account. | 1196| cursorCreatedAt | string (datetime) | No | Cursor timestamp for pagination. Must be provided with cursorTiktokPublishId. | 1197| cursorTiktokPublishId | string (UUID) | No | Cursor publish ID for pagination. Must be provided with cursorCreatedAt. | 1198 1199TikTok history uses the same cursor pattern as Instagram. The response includes \`nextCursor\` only when more rows are available. 1200 1201\`\`\`json 1202{ 1203 "items": [ 1204 { 1205 "tiktokPublishId": "c34a4b1f-b2ff-4f3f-a4fb-6cf2ca8f9e2c", 1206 "tiktokAccountId": "550e8400-e29b-41d4-a716-446655440000", 1207 "sourceUrl": "https://...", 1208 "caption": "Launch day", 1209 "privacyLevel": "SELF_ONLY", 1210 "status": "succeeded", 1211 "publishId": "v0...", 1212 "tiktokMediaId": "v0...", 1213 "isAigc": true, 1214 "errorCode": null, 1215 "errorMessage": null, 1216 "createdAt": "2026-03-19T12:34:56.000Z", 1217 "publishedAt": "2026-03-19T12:35:45.000Z" 1218 } 1219 ], 1220 "nextCursor": { 1221 "createdAt": "2026-03-19T12:34:56.000Z", 1222 "tiktokPublishId": "c34a4b1f-b2ff-4f3f-a4fb-6cf2ca8f9e2c" 1223 } 1224} 1225\`\`\` 1226`,_=`--- 1227title: Distribution Publishing 1228description: Publish carousel content and inspect distribution records. 1229--- 1230 1231Destination-specific publish docs cover single media and carousel publishing. Use this page when you need the carousel response shape, account lookup context, or publish history context. For connected accounts, start with [Distribution accounts](distribution-accounts). 1232 1233## Instagram carousel publishing 1234 1235\`POST /api/v1/publish/instagram/carousel\` 1236 1237| Parameter | Type | Required | Description | 1238| ------------------ | ------------- | -------- | ---------------------------------------------------------------- | 1239| mediaIds | string[] | Yes | 2 to 10 image media IDs. Instagram carousels only accept images. | 1240| instagramAccountId | string (UUID) | Yes | Connected Instagram account to publish to. | 1241| caption | string | No | Optional caption, up to 2200 characters. | 1242 1243This endpoint creates a publish record for a carousel post and returns the Instagram publish ID, IG media ID, permalink, and image count. 1244 1245\`\`\`json 1246{ 1247 "instagramPublishId": "b2d7e2ae-1d3d-4c88-8f01-0d2c8fb2d9b1", 1248 "igMediaId": "1789...", 1249 "permalink": "https://instagram.com/p/...", 1250 "imageCount": 4 1251} 1252\`\`\` 1253 1254Use this endpoint for carousel publishing. The direct Instagram publish endpoint handles a single image or video asset. 1255 1256## TikTok photo carousel publishing 1257 1258\`POST /api/v1/publish/tiktok/carousel\` 1259 1260| Parameter | Type | Required | Description | 1261| --------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | 1262| mediaIds | string[] | Yes | 2 to 35 media IDs. TikTok carousels only accept JPEG or WebP images. | 1263| tiktokAccountId | string (UUID) | Yes | Connected TikTok account to publish to. | 1264| caption | string | No | Optional caption, up to 90 characters. | 1265| privacyLevel | string | No | PUBLIC_TO_EVERYONE \\| MUTUAL_FOLLOW_FRIENDS \\| FOLLOWER_OF_CREATOR \\| SELF_ONLY. Defaults to SELF_ONLY and is ignored when postMode is inbox. | 1266| postMode | string | No | direct \\| inbox. Defaults to direct. | 1267| coverIndex | number | No | Index of the cover image to use. Defaults to 0. | 1268 1269TikTok carousel publishing also rejects S3-backed media. Use GCS-hosted images only, and keep the direct publish endpoint for single-video posts. 1270 1271\`\`\`json 1272{ 1273 "tiktokPublishId": "c34a4b1f-b2ff-4f3f-a4fb-6cf2ca8f9e2c", 1274 "publishId": "v0...", 1275 "tiktokMediaId": "v0...", 1276 "imageCount": 6 1277} 1278\`\`\` 1279`,v='---\ntitle: Errors\ndescription: Error response format and common HTTP status codes.\n---\n\n## Error response shape\n\nAll error responses follow a consistent JSON structure with a human-readable message and a machine-readable code.\n\n```json\n{\n "error": {\n "message": "Human-readable error message",\n "code": "machine_readable_code"\n }\n}\n```\n\n## HTTP status codes\n\n| HTTP status | Code | Meaning |\n| ----------- | ----------------------- | ------------------------------------------------------------------------------------------------ |\n| 400 | `validation_error` | Invalid request body or parameters. |\n| 400 | `bad_request` | Request was syntactically valid but cannot be processed. |\n| 400 | `unknown_project` | `X-Wonda-Project` names a project that does not exist in the active personal or org scope. |\n| 401 | `unauthorized` | Missing or invalid API key. |\n| 402 | `payment_required` | Payment required. |\n| 402 | `insufficient_credits` | Not enough credits to complete the request. |\n| 403 | `forbidden` | The account cannot access the resource or action. |\n| 403 | `feature_disabled` | A feature flag or account gate is disabled for this account. |\n| 404 | `not_found` | Resource not found or API not enabled for the account. |\n| 409 | `conflict` | Request conflicts with the current state of the resource. |\n| 409 | `project_exists` | A project with that normalized name already exists in the active scope. |\n| 410 | `gone` | Endpoint or operation has been retired. The response message may include a migration hint. |\n| 429 | `rate_limit_exceeded` | Too many requests. |\n| 429 | `throttled` | A safety or action gate blocked the request and may include retry metadata such as `deferUntil`. |\n| 500 | `internal_server_error` | Internal server error. |\n\nThe `code` field is always present in error responses. A 400 from request validation uses `validation_error`; other generic 400 errors use `bad_request`. A 402 uses `insufficient_credits` when the error message mentions insufficient credits, and `payment_required` otherwise.\n\n## Example\n\n```json\n{\n "error": {\n "message": "\'model\' is required",\n "code": "validation_error"\n }\n}\n```\n',y='---\ntitle: Image Editing\ndescription: Crop images and add local hyperframes text overlays with the Wonda CLI.\n---\n\nImage editing is CLI-first. `wonda edit image` handles exact pixel crops locally, then uploads the result and prints the output `mediaId`.\n\nThe retired `POST /api/v1/image/edit` endpoint returns `410 Gone` with a CLI migration hint. Move image editing scripts to the commands below.\n\n## Setup\n\n```bash\nnpm i -g @degausai/wonda\nwonda auth login\nwonda doctor\n```\n\n## Crop an image\n\nUse `imageCrop` for exact pixel rectangles.\n\n```bash\nwonda edit image --operation imageCrop \\\n --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --params \'{"cropPixelX":100,"cropPixelY":50,"cropPixelWidth":500,"cropPixelHeight":500}\' \\\n --wait -o ./cropped.png\n```\n\nParameters:\n\n| Parameter | Type | Description |\n| ----------------- | ---- | ------------------------------------------- |\n| `cropPixelX` | int | Left edge of the crop rectangle, in pixels. |\n| `cropPixelY` | int | Top edge of the crop rectangle, in pixels. |\n| `cropPixelWidth` | int | Crop rectangle width, in pixels. |\n| `cropPixelHeight` | int | Crop rectangle height, in pixels. |\n\nWithout `--output`, the CLI prints:\n\n```json\n{\n "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db",\n "status": "succeeded"\n}\n```\n\n## Add text to an image\n\n`textOverlay` is a local hyperframes operation. Invoke it through `wonda edit video` even when the input media is an image.\n\n```bash\nwonda edit video --operation textOverlay \\\n --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --prompt-text "New drop" \\\n --p
1279arams \'{"fontFamily":"TikTok Sans SemiCondensed","position":"center","sizePercent":66,"fontSizeScale":0.5,"strokeWidth":4.5}\' \\\n --wait -o ./with-text.png\n```\n\nCommon styling params include `fontFamily`, `position`, `sizePercent`, `fontSizeScale`, `textColor`, `strokeColor`, `strokeWidth`, `highlightColor`, and `showShadow`. Run `wonda operations info textOverlay` for the current shape.\n\n## Related image workflows\n\nAI image editing, background removal, and vectorization are direct generation workflows. Use `POST /image/generate` with the appropriate model and attachments, or use the matching CLI generation commands.\n',b=`--- 1280title: Image Generation 1281description: Generate images, remove backgrounds, and vectorize with AI models. 1282--- 1283 1284\`POST /api/v1/image/generate\` 1285 1286## Request Body 1287 1288| Parameter | Type | Required | Description | 1289| ------------------ | -------- | -------- | -------------------------------------- | 1290| model | string | Yes | Model key (see models below) | 1291| prompt | string | No | Text prompt (required for most models) | 1292| params | object | No | Model-specific parameters | 1293| attachmentMediaIds | string[] | No | Positional media attachment IDs | 1294 1295## Response 1296 1297\`\`\`json 1298{ 1299 "inferenceJobId": "ij_..." 1300} 1301\`\`\` 1302 1303## Example 1304 1305**POST /api/v1/image/generate** 1306 1307\`\`\`json 1308{ 1309 "model": "nano-banana-2", 1310 "prompt": "A polished product shot of a ceramic mug on travertine", 1311 "params": { "aspectRatio": "1:1", "resolution": "1K" } 1312} 1313\`\`\` 1314 1315--- 1316 1317## Models 1318 1319### nano-banana-2 1320 1321General-purpose image generation. Prompt required. 1322 1323| Parameter | Type | Required | Description | 1324| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- | 1325| aspectRatio | string | No | 9:16, 16:9, 1:1, 4:5, 4:3, 3:4, 3:2, 2:3, 21:9, 8:1, 1:8, 4:1, 1:4, auto (default 9:16) | 1326| resolution | string | No | 1K, 2K, 4K (default 1K) | 1327| styleId | string | No | Optional style UUID to apply | 1328 1329**Attachments:** Up to 14 optional reference images. 1330 1331### nano-banana-pro 1332 1333Pro-tier image generation. Prompt required. 1334 1335| Parameter | Type | Required | Description | 1336| ----------- | ------ | -------- | ------------------------------------------------------------------- | 1337| aspectRatio | string | No | 9:16, 16:9, 1:1, 4:5, 4:3, 3:4, 3:2, 2:3, 21:9, auto (default 9:16) | 1338| resolution | string | No | 1K, 2K, 4K (default 1K) | 1339| styleId | string | No | Optional style UUID to apply | 1340 1341**Attachments:** Up to 14 optional reference images. 1342 1343### seedream-4-5 1344 1345High-quality image generation. Prompt required. 1346 1347| Parameter | Type | Required | Description | 1348| ----------- | ------ | -------- | -------------------------------------------------------- | 1349| aspectRatio | string | No | 1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, 21:9 (default 16:9) | 1350| resolution | string | No | 2K, 4K (default 2K) | 1351 1352**Attachments:** Up to 14 optional reference images. 1353 1354### z-image 1355 1356Fast image generation. Prompt required. 1357 1358| Parameter | Type | Required | Description | 1359| ----------- | ------ | -------- | -------------------------------------------------------------- | 1360| aspectRatio | string | No | 1:1, 21:9, 16:9, 4:3, 3:2, 2:3, 3:4, 9:16, 9:21 (default 9:16) | 1361 1362**Attachments:** None. 1363 1364### gpt-image-1-5 1365 1366OpenAI image generation. Prompt required. 1367 1368| Parameter | Type | Required | Description | 1369| ----------- | ------ | -------- | ---------------------------------------- | 1370| aspectRatio | string | No | 1:1, 16:9, 9:16 (default 9:16) |
1371| quality | string | No | auto, high, medium, low (default auto) | 1372| background | string | No | auto, transparent, opaque (default auto) | 1373 1374**Attachments:** Up to 16 optional reference images. 1375 1376### grok-imagine 1377 1378Fast image generation and editing by xAI. Prompt required. 1379 1380| Parameter | Type | Required | Description | 1381| ----------- | ------ | -------- | ------------------------------------------------------------------ | 1382| aspectRatio | string | No | 9:16, 16:9, 1:1, 4:3, 3:4, 3:2, 2:3, 2:1, 1:2, auto (default 9:16) | 1383| resolution | string | No | 1k, 2k (default 1k) | 1384 1385**Attachments:** 1 optional reference image for editing. 1386 1387### grok-imagine-pro 1388 1389High-quality image generation and editing by xAI. Prompt required. 1390 1391| Parameter | Type | Required | Description | 1392| ----------- | ------ | -------- | ------------------------------------------------------------------ | 1393| aspectRatio | string | No | 9:16, 16:9, 1:1, 4:3, 3:4, 3:2, 2:3, 2:1, 1:2, auto (default 9:16) | 1394| resolution | string | No | 1k, 2k (default 1k) | 1395 1396**Attachments:** 1 optional reference image for editing. 1397 1398### birefnet-bg-removal 1399 1400Background removal. No prompt needed. 1401 1402| Parameter | Type | Required | Description | 1403| -------------- | ------ | -------- | -------------------------------------------------------------- | 1404| bgRemovalModel | string | No | portrait, general-fast, general-premium (default general-fast) | 1405| quality | string | No | low, high (default low) | 1406 1407**Attachments:** 1 required image (input_image). 1408 1409### runware-vectorize 1410 1411Image vectorization. No prompt needed. 1412 1413| Parameter | Type | Required | Description | 1414| -------------- | ------ | -------- | ---------------------------------------------- | 1415| vectorizeModel | string | No | recraft:1@1, picsart:1@1 (default recraft:1@1) | 1416 1417**Attachments:** 1 required image (input_image). 1418`,x=`--- 1419title: Job Polling 1420description: Direct generation and publishing operations follow a create-then-poll pattern. 1421--- 1422 1423## How it works 1424 14251. **Submit** a request, such as \`POST /image/generate\` or \`POST /publish/instagram\`. 14262. **Poll** \`GET /jobs/inference/{inferenceJobId}\` or \`GET /jobs/publish/{outputJobId}\` until the job reaches a terminal status. 14273. **Read** output media or publish details from the completed job response. 1428 1429\`GET /api/v1/jobs/inference/{inferenceJobId}\` 1430 1431\`GET /api/v1/jobs/publish/{outputJobId}\` 1432 1433Local CLI editing does not create a public API job. The \`wonda edit\` commands render locally and return a \`mediaId\` or downloaded file path when the render completes. 1434 1435## Status values 1436 1437| Status | Terminal | Description | 1438| ------------- | -------- | ----------------------------------- | 1439| \`idle\` | No | Job is queued and waiting to start. | 1440| \`locked\` | No | Job has been claimed by a worker. | 1441| \`in_progress\` | No | Job is actively running. | 1442| \`queued\` | No | Publish job is waiting in queue. | 1443| \`succeeded\` | Yes | Job completed successfully. | 1444| \`failed\` | Yes | Job encountered an error. | 1445| \`canceled\` | Yes | Inference job was canceled. | 1446 1447## Polling strategy 1448 1449Start polling at 1-second intervals. For long-running jobs such as video generation, increase the interval up to 5 seconds to reduce unnecessary requests. 1450 1451## Chaining pattern 1452 1453A typical workflow chains async API work with local CLI editing: 1454 1455\`\`\` 1456upload -> generate -> poll -> take output mediaId -> edit locally with wonda CLI -> publish -> poll 1457\`\`\` 1458 1459## Full flow example 1460 1461\`\`\`javascript 1462const BASE = "https://api.wondercat.ai/api/v1"; 1463const HEADERS = { 1464 Authorization: "Bearer sk_your_api_key_here", 1465 "Content-Type": "application/json", 1466}; 1467 1468async function pollJob(type, id) { 1469 let delay = 1000; 1470 while (true) { 1471 const job = await fetch(\`\${BASE}/jobs/\${type}/\${id}\`, { 1472 headers: { Authorization: HEADERS.Authorization }, 1473 }).then((response) => response.json()); 1474 1475 if (job.status === "succeeded") return job; 1476 if (job.status === "failed") { 1477 throw new Error(job.errorMessage ?? "Job failed"); 1478 } 1479 if (job.status === "canceled") { 1480 throw new Error("Job was canceled"); 1481 } 1482 1483 await new Promise((resolve) => setTimeout(resolve, delay));
1484 delay = Math.min(delay * 1.5, 5000); 1485 } 1486} 1487 1488const generation = await fetch(\`\${BASE}/image/generate\`, { 1489 method: "POST", 1490 headers: HEADERS, 1491 body: JSON.stringify({ 1492 model: "nano-banana-2", 1493 prompt: "A sunset over the ocean", 1494 params: { resolution: "2K" }, 1495 }), 1496}).then((response) => response.json()); 1497 1498const generationResult = await pollJob("inference", generation.inferenceJobId); 1499const generated = generationResult.outputs.find( 1500 (output) => output.media, 1501)?.media; 1502if (!generated?.mediaId) { 1503 throw new Error("No generated media found"); 1504} 1505 1506const publish = await fetch(\`\${BASE}/publish/instagram\`, { 1507 method: "POST", 1508 headers: HEADERS, 1509 body: JSON.stringify({ 1510 mediaId: generated.mediaId, 1511 instagramAccountId: "550e8400-e29b-41d4-a716-446655440000", 1512 caption: "Made with Wonda", 1513 product: "IMAGE", 1514 }), 1515}).then((response) => response.json()); 1516 1517const publishResult = await pollJob("publish", publish.outputJobId); 1518(() => {})("Publish status:", publishResult.status); 1519\`\`\` 1520`,S=`--- 1521title: Media Upload 1522description: Upload images, videos, and audio files to use in generation and editing workflows. 1523--- 1524 1525\`POST /api/v1/media/upload\` 1526 1527## Content-Type 1528 1529Requests must use \`multipart/form-data\`. For a single file, use the field name \`file\`. For multiple files, use any field name per file. 1530 1531## Supported Formats 1532 1533| Category | MIME Types | 1534| -------- | ----------------------------------- | 1535| Images | jpeg, png, gif, webp, svg+xml | 1536| Videos | mp4, webm, quicktime, x-msvideo | 1537| Audio | mpeg, mp3, wav, ogg, webm, aac, m4a | 1538 1539## Single-File Response 1540 1541\`\`\`json 1542{ 1543 "mediaId": "uuid", 1544 "url": "https://...", 1545 "mimeType": "video/mp4", 1546 "uploads": { 1547 "file": { "mediaId": "uuid", "url": "...", "mimeType": "..." } 1548 } 1549} 1550\`\`\` 1551 1552## Multi-File Response 1553 1554When uploading multiple files, the response includes an \`uploads\` map keyed by field name, plus an \`errors\` map for any files that failed. Partial success is possible -- some files may upload successfully while others fail. 1555 1556\`\`\`json 1557{ 1558 "uploads": { 1559 "background": { "mediaId": "...", "url": "...", "mimeType": "..." }, 1560 "overlay": { "mediaId": "...", "url": "...", "mimeType": "..." } 1561 }, 1562 "errors": { 1563 "badfile": "Unsupported MIME type" 1564 } 1565} 1566\`\`\` 1567 1568## Example 1569 1570**cURL -- single file upload** 1571 1572\`\`\`bash 1573curl https://api.wondercat.ai/api/v1/media/upload \\ 1574 -H "Authorization: Bearer sk_your_api_key_here" \\ 1575 -F "file=@/path/to/video.mp4" 1576\`\`\` 1577 1578**cURL -- multi-file upload** 1579 1580\`\`\`bash 1581curl https://api.wondercat.ai/api/v1/media/upload \\ 1582 -H "Authorization: Bearer sk_your_api_key_here" \\ 1583 -F "background=@/path/to/bg.png" \\ 1584 -F "overlay=@/path/to/overlay.png" 1585\`\`\` 1586 1587## Request Fields 1588 1589| Parameter | Type | Required | Description | 1590| --------- | ------ | -------- | ------------------------------------------------------------------------------------------------- | 1591| file | binary | Yes | The file to upload. Use field name "file" for single uploads, or any name for multi-file uploads. | 1592`,C=`--- 1593title: Music Generation 1594description: Generate original music tracks with AI. 1595--- 1596 1597\`POST /api/v1/music/generate\` 1598 1599## Request Body 1600 1601| Parameter | Type | Required | Description | 1602| --------- | ------ | -------- | ---------------------------------------- | 1603| model | string | Yes | Model key (see models below) | 1604| prompt | string | Yes | Text prompt describing the desired music | 1605| params | object | No | Model-specific parameters | 1606 1607## Response 1608 1609\`\`\`json 1610{ 1611 "inferenceJobId": "ij_..." 1612} 1613\`\`\` 1614 1615## Example 1616 1617**POST /api/v1/music/generate** 1618 1619\`\`\`json 1620{ 1621 "model": "suno-music", 1622 "prompt": "Upbeat electronic track with a driving bassline", 1623 "params": { "instrumental": true } 1624} 1625\`\`\` 1626 1627--- 1628 1629## Models 1630 1631### suno-music 1632 1633AI music generation via Suno. Prompt required. 1634 1635| Parameter | Type | Required | Description | 1636| ------------ | ------- | -------- | ----------------------------------------------- | 1637| instrumental | boolean | No | Generate instrumental-only track (default true) | 1638
1639**Attachments:** None. 1640`,w=`--- 1641title: Overview 1642description: Programmatic access to Wonda generation, publishing, media, and local CLI editing workflows. 1643--- 1644 1645## What the API does 1646 1647The Wonda API lets you generate images, videos, text, music, and speech; transcribe or analyze media; upload files; inspect jobs; estimate costs; and publish finished media to connected social accounts. 1648 1649Use REST endpoints for generation, media, pricing, publishing, analytics, scraping, and account-connected workflows. Use the Wonda CLI for editing operations such as trim, crop, merge, overlays, captions, audio mixing, and silence removal. CLI editing runs locally with ffmpeg or hyperframes, then uploads the result back to your media library. 1650 1651## Base URL 1652 1653\`\`\` 1654https://api.wondercat.ai/api/v1 1655\`\`\` 1656 1657All endpoints are served under this base URL. The current API version is **v1**. 1658 1659## Request and response format 1660 1661- All JSON request bodies must include \`Content-Type: application/json\`. 1662- All responses are JSON. 1663- Dates are ISO 8601 strings. 1664- IDs in path parameters are UUIDs unless the endpoint states otherwise. 1665 1666## Async pattern 1667 1668Generation and publishing operations are asynchronous. When you submit work, the API returns a job ID immediately. Poll the matching job endpoint until the job reaches a terminal status. 1669 16701. Submit a request, such as \`POST /image/generate\` or \`POST /publish/instagram\`. 16712. Poll \`GET /jobs/inference/{inferenceJobId}\` or \`GET /jobs/publish/{outputJobId}\` until \`status\` is \`"succeeded"\` or \`"failed"\`. 16723. Read output media or publish details from the completed job response. 1673 1674Local CLI editing is different: \`wonda edit video\`, \`wonda edit image\`, and \`wonda edit audio\` render on your machine and return the uploaded \`mediaId\` directly. The REST editing endpoints are retired and return \`410 Gone\` with CLI migration hints. 1675 1676## Main surfaces 1677 1678| Surface | Behavior | Use case | 1679| --------------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | 1680| Direct generation endpoints | Submit a prompt and params, then poll an inference job. Prompts are used as provided. | Automated image, video, text, music, speech, transcription, and analysis workflows. | 1681| Publishing endpoints | Queue a publish job for connected Instagram or TikTok accounts, then poll the publish job. | Single-asset publishing and social distribution automation. | 1682| Wonda CLI editing | Render locally with ffmpeg or hyperframes, then upload the output media. | Deterministic media transforms, captions, overlays, merges, audio edits, and local post-production. | 1683 1684## Connect to Claude 1685 1686Use the [Connect Wonda to Claude](/docs/connect-claude) guide to add the cloud twin as a custom remote MCP connector. Paste the Wonda connector URL in Claude, grant OAuth in the browser, and use Wonda tools without a local CLI or API key field. 1687`,T=`--- 1688title: Personas and Sessions 1689description: How Wonda models a social account you control, and how to address one from the API. 1690--- 1691 1692## What a persona is 1693 1694A **persona** is one social account Wonda can act as - a LinkedIn profile, an X 1695handle, a Reddit user, an Instagram account. Every action you run through the 1696API names the persona it should run as. 1697 1698Personas are addressed by a short slug you choose when connecting the account: 1699 1700\`\`\`text 1701POST /twin/sessions/{persona}/actions/{platform}/{action} 1702\`\`\` 1703 1704A persona holds the logged-in session for that account. You never send platform 1705credentials to the API - you sign in once through Wonda, and the session lives 1706either on your own machine or on the account's hosted browser. See 1707[Routing](/docs/action-routing) for which one runs a given call. 1708 1709## Listing your personas 1710 1711\`\`\`bash 1712curl https://api.wondercat.ai/api/v1/twin/sessions \\ 1713 -H "Authorization: Bearer $WONDA_API_KEY" 1714\`\`\` 1715 1716The response lists each persona with the platform it belongs to and whether its 1717session is currently usable. 1718 1719## Session health 1720 1721A persona's session can lapse - a platform signs you out, requires a 1722re-verification, or flags the account. Actions against a lapsed
1722session fail 1723with \`needs_auth\` rather than silently doing nothing. 1724 1725To check health without running an action, read it: 1726 1727\`\`\`bash 1728curl https://api.wondercat.ai/api/v1/twin/sessions/natty/health \\ 1729 -H "Authorization: Bearer $WONDA_API_KEY" 1730\`\`\` 1731 1732That returns the twin's lifecycle status and its ban-signal health. 1733 1734Do **not** use \`POST /twin/needs-auth\` as a probe. Despite the name it is a 1735write: it _flags_ the twin as needing re-authentication and pauses its 1736schedules. Call it when you have established a session is dead, never to ask 1737whether it is. 1738 1739Re-authenticating is deliberately a human step: it happens in a visible browser 1740where the person signs in themselves, including any 2FA. There is no API for 1741submitting a platform password, and there will not be one. See 1742[Controlling the Browser](/docs/browser-control) for opening that window. 1743 1744## Access and roles 1745 1746An API key acts for the account that owns it. Personas belonging to an 1747organization are reachable when your key's account has an **operator** role on 1748that persona. Without one - including a read-only grant, or a persona that does 1749not exist - the call fails with **403** and code \`forbidden\`. 1750 1751## Related 1752 1753- [Running Platform Actions](/docs/platform-actions) - the request and response shape 1754- [Action Reference](/docs/action-reference) - every action, its transport, and its payload 1755- [Routing](/docs/action-routing) - my machine versus the cloud 1756`,E=`--- 1757title: Running Platform Actions 1758description: Drive LinkedIn, X, Reddit, and Instagram from the API with your API key - the same actions the MCP tools use. 1759--- 1760 1761## One endpoint per action 1762 1763Everything Wonda can do on a social platform is an endpoint: 1764 1765\`\`\`text 1766POST /twin/sessions/{persona}/actions/{platform}/{action} 1767\`\`\` 1768 1769\`platform\` is \`linkedin\`, \`x\`, \`reddit\`, or \`instagram\`. \`action\` is a verb such 1770as \`search\`, \`comment\`, or \`feed-engage\`. The full list, with payload fields for 1771each, is in the [Action Reference](/docs/action-reference). 1772 1773This is the same surface the Wonda MCP server uses. An MCP client and a plain 1774HTTP client have the same capabilities - MCP is a thin wrapper over these 1775endpoints, not a privileged path. 1776 1777## A read 1778 1779\`\`\`bash 1780curl -X POST \\ 1781 https://api.wondercat.ai/api/v1/twin/sessions/natty/actions/x/mentions \\ 1782 -H "Authorization: Bearer $WONDA_API_KEY" \\ 1783 -H "Content-Type: application/json" \\ 1784 -d '{"count": 20}' 1785\`\`\` 1786 1787The payload is a JSON object whose fields come from the action's row in the 1788[Action Reference](/docs/action-reference). An action that takes no arguments 1789still wants a body - send \`{}\`. 1790 1791## A write 1792 1793\`\`\`bash 1794curl -X POST \\ 1795 https://api.wondercat.ai/api/v1/twin/sessions/natty/actions/linkedin/comment \\ 1796 -H "Authorization: Bearer $WONDA_API_KEY" \\ 1797 -H "Content-Type: application/json" \\ 1798 -d '{ 1799 "target": "urn:li:activity:7123456789", 1800 "text": "The second point matches what we measured." 1801 }' 1802\`\`\` 1803 1804Writes consume a **write slot**. Reads do not. Slots are what the daily caps, 1805cooldowns, and spend limits are counted against, so a read-heavy client is not 1806rate-limited by write policy. 1807 1808Some writes accept \`"dryRun": true\`, intended to run every check and report 1809what would have happened without touching the platform. Support is per-action, 1810and some actions accept the field without honouring it, so it is not a 1811guaranteed safety net - see [Dry runs](/docs/action-errors). 1812 1813## Response shape 1814 1815A successful call returns the action's result: 1816 1817\`\`\`json 1818{ 1819 "result": { "...": "action-specific" }, 1820 "actionRunId": "run_01J...", 1821 "notices": [{ "code": "relay_update_available", "message": "..." }] 1822} 1823\`\`\` 1824 1825\`actionRunId\` identifies the run for audit. \`notices\` carries soft out-of-band 1826hints riding a successful result; render each \`message\` and ignore codes you do 1827not recognise rather than failing. 1828 1829### 202: the session is warming 1830 1831A control session that is not hot yet answers **202**, not 200: 1832 1833\`\`\`json 1834{ "status": "warming", "retryAfterMs": 2000 } 1835\`\`\` 1836 1837This is not an error and there is no \`error\` object. A client that treats any 1838non-200 as failure will drop actions that would have succeeded, so branch on 1839the status code before looking for \`error\`. 1840 1841For a **read**, wait \`retryAfterMs\` and send the same request again. 1842 1843For a **write**, do not retry blind. A 202 is also returned when the control 1844session goes stale _after_ the action was dispatched, and the spawned action is 1845not cancelled, so the write may still complete. Confirm the current state 1846before re-sending, exactly as with \`deferred\` - see 1847[Action Errors](/docs/action-errors). 1848 1849A failure returns a structured error rather than an HTTP-only signal: 1850 1851\`\`\`json 1852{ 1853 "error": { 1854 "message": "session needs re-authentication", 1855 "code": "needs_auth" 1856 } 1857} 1858\`\`\` 1859 1860The \`code\` is a stable, machine-readable value - branch on it, not on the 1861message. See [Action Errors](/docs/action-errors) for the full taxonomy and what 1862to do about each one. 1863 1864## Discovering actions at runtime 1865 1866The OpenAPI document describes every action endpoint with its typed request 1867body: 1868 1869\`\`\`bash 1870curl https://api.wondercat.ai/api/v1/openapi.json 1871\`\`\` 1872 1873Each action is a distinct operation, so generated clients get real parameter 1874types rather than an opaque blob. 1875 1876## Related 1877 1878- [Action Reference](/docs/action-reference) - all actions and payloads 1879- [Routing](/docs/action-routing) - where an action actually executes 1880- [Action Errors](/docs/action-errors) - the error taxonomy 1881- [Personas and Sessions](/docs/personas-sessions) - what \`{persona}\` refers to 1882`,D=`--- 1883title: Pricing Estimate 1884description: Get a cost estimate for a generation request before running it. 1885--- 1886 1887\`POST /api/v1/pricing/estimate\` 1888 1889## Request Body 1890 1891| Parameter | Type | Required | Description | 1892| --------- | ------ | -------- | -------------------------------------------------------------------------- | 1893| model | string | Yes | Model key to estimate cost for | 1894| prompt | string | No | Text prompt (used for token-based cost estimation) | 1895| params | object | No | Model-specific parameters that affect pricing (e.g., resolution, duration) | 1896 1897## Response 1898 1899\`\`\`json 1900{ 1901 "model": "nano-banana-2", 1902 "estimatedCostMicrodollars": 1234, 1903 "estimatedCostUsd": "$0.001234", 1904 "estimatedCredits": 1234 1905} 1906\`\`\` 1907 1908## Example 1909 1910**cURL** 1911 1912\`\`\`bash 1913curl https://api.wondercat.ai/api/v1/pricing/estimate \\ 1914 -H "Authorization: Bearer sk_your_api_key_here" \\ 1915 -H "Content-Type: application/json" \\ 1916 -d '{ 1917 "model": "nano-banana-2", 1918 "params": { "resolution": "2K", "aspectRatio": "16:9" } 1919 }' 1920\`\`\` 1921`,O=`--- 1922title: Pricing 1923description: Retrieve current pricing for generation models and legacy render pricing fields. 1924--- 1925 1926\`GET /api/v1/pricing\` 1927 1928## Overview 1929 1930Returns the current pricing schedule with two sections: \`models\` and \`editor\`. All monetary values include microdollars, USD, and credit equivalents. 1931 1932Current \`wonda edit\` operations render locally in the CLI and do not create server render credit holds. The \`editor\` field remains in the response for compatibility with older clients and legacy render accounting. 1933 1934### models 1935 1936Per-model pricing. Each model has a \`pricing\` array with one entry per variant, such as resolution or quality tier. 1937 1938**Unit values:** \`per_second\`, \`per_image\`, \`per_character\`, \`per_render\`, \`per_generation\`, \`per_million_input_tokens\`, \`variable\` 1939 1940\`\`\`json 1941{ 1942 "models": [ 1943 { 1944 "key": "nano-banana-2",
1945 "label": "Nano Banana 2", 1946 "description": "General-purpose image generation.", 1947 "stepType": "image", 1948 "pricing": [ 1949 { 1950 "unit": "per_image", 1951 "variant": "1K", 1952 "unitPriceMicrodollars": 4000, 1953 "unitPriceUsd": "$0.004000", 1954 "credits": 4 1955 } 1956 ] 1957 } 1958 ] 1959} 1960\`\`\` 1961 1962### editor 1963 1964Legacy editor pricing entry retained in the API response. 1965 1966\`\`\`json 1967{ 1968 "editor": { 1969 "type": "editor_render", 1970 "label": "Video/Image/Audio Editor Render", 1971 "pricing": { 1972 "unit": "per_render", 1973 "unitPriceMicrodollars": 50000, 1974 "unitPriceUsd": "$0.050000", 1975 "credits": 50 1976 } 1977 } 1978} 1979\`\`\` 1980`,k=`--- 1981title: Publish to Instagram 1982description: Publish single images, reels, stories, and carousels to a connected Instagram account. 1983--- 1984 1985## Single media publish 1986 1987\`POST /api/v1/publish/instagram\` 1988 1989| Parameter | Type | Required | Description | 1990| -------------------- | ------------- | -------- | --------------------------------------------------------------------------------------- | 1991| \`mediaId\` | string | Yes | Media ID to publish. | 1992| \`instagramAccountId\` | string (UUID) | Yes | Connected Instagram account ID from \`GET /instagram/accounts\`. | 1993| \`caption\` | string | No | Post caption. | 1994| \`altText\` | string | No | Alt text for accessibility. | 1995| \`product\` | string | No | \`"IMAGE"\`, \`"REELS"\`, or \`"STORIES"\`. Images default to IMAGE, videos default to REELS. | 1996| \`shareToFeed\` | boolean | No | Share a Reel to the main feed as well. | 1997 1998The operation is asynchronous. The initial response returns an \`outputJobId\` and a \`status\`. Poll \`GET /jobs/publish/{outputJobId}\` until the status reaches \`succeeded\` or \`failed\`. 1999 2000\`\`\`json 2001{ 2002 "outputJobId": "019e1b76-74d7-8c7e-a927-6bd34bfaa114", 2003 "status": "queued" 2004} 2005\`\`\` 2006 2007## Example 2008 2009\`\`\`json 2010{ 2011 "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db", 2012 "instagramAccountId": "550e8400-e29b-41d4-a716-446655440000", 2013 "caption": "Check out this new video!", 2014 "product": "REELS", 2015 "shareToFeed": true 2016} 2017\`\`\` 2018 2019## Instagram carousel 2020 2021\`POST /api/v1/publish/instagram/carousel\` 2022 2023| Parameter | Type | Required | Description | 2024| -------------------- | ------------- | -------- | ---------------------------------------------------------------- | 2025| \`mediaIds\` | string[] | Yes | 2 to 10 image media IDs. Instagram carousels only accept images. | 2026| \`instagramAccountId\` | string (UUID) | Yes | Connected Instagram account ID from \`GET /instagram/accounts\`. | 2027| \`caption\` | string | No | Optional caption, up to 2200 characters. | 2028 2029\`\`\`json 2030{ 2031 "mediaIds": [ 2032 "019e1b70-6f9e-80fd-8c49-690bcbdaf8db", 2033 "019e1b72-0742-8bae-bb93-b569036d05af" 2034 ], 2035 "instagramAccountId": "550e8400-e29b-41d4-a716-446655440000", 2036 "caption": "New carousel" 2037} 2038\`\`\` 2039 2040\`\`\`json 2041{ 2042 "instagramPublishId": "b2d7e2ae-1d3d-4c88-8f01-0d2c8fb2d9b1", 2043 "igMediaId": "1789...", 2044 "permalink": "https://instagram.com/p/...", 2045 "imageCount": 2 2046} 2047\`\`\` 2048`,A='---\ntitle: Publish to TikTok\ndescription: Publish single videos and photo carousels to a connected TikTok account.\n---\n\n## Single video publish\n\n`POST /api/v1/publish/tiktok`\n\n| Parameter | Type | Required | Description |\n| -------------------- | ------------- | -------- | ------------------------------------------------------------------------------------- |\n| `mediaId` | string | Yes | Video media ID to publish. |\n| `tiktokAccountId` | string (UUID) | Yes | Connected TikTok account ID from `GET /tiktok/accounts`. |\n| `caption` | string | No | Post caption. |\n| `privacyLevel` | string | No | `PUBLIC_TO_EVERYONE`, `MUTUAL_FOLLOW_FRIENDS`, `FOLLOWER_OF_CREATOR`, or `SELF_ONLY`. |\n| `isAigc` | boolean | No | Flag content as AI-generated. |\n| `postMode` | string | No | `"direct"` or `"inbox"`. |\n| `disableComment` | boolean | No | Disable comments. |\n| `disableDuet` | boolean | No | Disable duet. |\n| `disableStitch` | boolean | No | Disable stitch. |\n| `discloseCommercial` | boolean | No | Disclose commercial content. |\n| `brandOrganic` | boolean | No | Mark as brand organic content. |\n| `brandedContent` | boolean | No | Mark as branded content. |\n\nThe operation is asynchronous. The initial response returns an `outputJobId` and a `status`. Poll `GET /jobs/publish/{outputJobId}` until the status reaches `succeeded` or `failed`.\n\n```json\n{\n "outputJobId": "019e1b76-74d7-8c7e-a927-6bd34bfaa114",\n "status": "queued"\n}\n```\n\n## Example\n\n```json\n{\n "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db",\n "tiktokAccountId": "550e8400-e29b-41d4-a716-446655440000",\n "caption": "Made with AI #wonda",\n "privacyLevel": "SELF_ONLY",\n "isAigc": true,\n "postMode": "direct"\n}\n```\n\n## TikTok photo carousel\n\n`POST /api/v1/publish/tiktok/carousel`\n\n| Parameter | Type | Required | Description |\n| -------------------- | ------------- | -------- | --------------------------------------------------------------------- |\n| `mediaIds` | string[] | Yes | 2 to 35 media IDs. TikTok carousels only accept JPEG and WebP images. |\n| `tiktokAccountId` | string (UUID) | Yes | Connected TikTok account ID from `GET /tiktok/accounts`. |\n| `caption` | string | No | Optional caption, up to 90 characters. |\n| `privacyLevel` | string | No | Defaults to `SELF_ONLY`. |\n| `postMode` | string | No | `direct` or `inbox`. Defaults to `direct`. |\n| `coverIndex` | number | No | Index of the cover image to use. Defaults to `0`. |\n| `isAigc` | boolean | No | Defaults to `false`. |\n| `disableComment` | boolean | No | Disable comments. |\n| `disableDuet` | boolean | No | Disable duet. |\n| `disableStitch` | boolean | No | Disable stitch. |\n| `discloseCommercial` | boolean | No | Defaults to `false`. |\n| `brandOrganic` | boolean | No | Defaults to `false`. |\n| `brandedContent` | boolean | No | Defaults to `false`. |\n\nTikTok carousel publishing rejects S3-backed media. Use GCS-hosted JPEG or WebP images.\n\n```json\n{\n "mediaIds": [\n "019e1b70-6f9e-80fd-8c49-690bcbdaf8db",\n "019e1b72-0742-8bae-bb93-b569036d05af"\n ],\n "tiktokAccountId": "550e8400-e29b-41d4-a716-446655440000",\n "caption": "New carousel",\n "privacyLevel": "SELF_ONLY",\n "postMode": "direct",\n "coverIndex": 0\n}\n```\n\n```json\n{\n "tiktokPublishId": "c34a4b1f-b2ff-4f3f-a4fb-6cf2ca8f9e2c",\n "publishId": "v0...",\n "tiktokMediaId": "v0...",\n "permalink": "https://www.tiktok.com/@example/video/...",\n "imageCount": 2\n}\n```\n',j=`--- 2049title: Quick Start 2050description: Get up and running with API-key auth, generation, job polling, and publishing. 2051--- 2052 2053## 1. Authenticate 2054 2055Every API request uses a bearer token. 2056 2057\`\`\`bash 2058export WONDA_API_KEY="sk_your_api_key_here" 2059export WONDA_API_BASE="https://api.wondercat.ai/api/v1" 2060\`\`\` 2061 2062If you are using the CLI for local editing or scripting, install it and sign in: 2063 2064\`\`\`bash 2065npm i -g @degausai/wonda 2066wonda auth login 2067wonda auth check 2068\`\`\` 2069 2070## 2. Generate an image 2071 2072Submit a direct generation request. The response contains an \`inferenceJobId\`. 2073 2074\`\`\`bash 2075curl -X POST "$WONDA_API_BASE/image/generate" \\ 2076 -H "Authorization: Bearer $WONDA_API_KEY" \\ 2077 -H "Content-Type: application/json" \\ 2078 -d '{ 2079 "model": "nano-banana-2", 2080 "prompt": "A polished product shot of a ceramic mug on travertine", 2081 "params": { 2082 "aspectRatio": "1:1", 2083 "resolution": "1K" 2084 } 2085 }' 2086\`\`\` 2087 2088\`\`\`json 2089{ 2090 "inferenceJobId": "019e1b6c-e954-89d3-bcef-6608093508e5" 2091} 2092\`\`\` 2093 2094## 3. Poll the inference job 2095 2096Poll until the status is \`succeeded\` or \`failed\`. A succeeded image job includes output media records. 2097 2098\`\`\`bash 2099curl "$WONDA_API_BASE/jobs/inference/019e1b6c-e954-89d3-bcef-6608093508e5" \\ 2100 -H "Authorization: Bearer $WONDA_API_KEY" 2101\`\`\` 2102 2103\`\`\`json 2104{ 2105 "inferenceJobId": "019e1b6c-e954-89d3-bcef-6608093508e5", 2106 "model": "nano-banana-2", 2107 "provider": "runware", 2108 "type": "image", 2109 "prompt": "A polished product shot of a ceramic mug on travertine", 2110 "status": "succeeded", 2111 "params": { 2112 "aspectRatio": "1:1", 2113 "resolution": "1K" 2114 }, 2115 "errorCode": null, 2116 "errorMessage": null, 2117 "infoMessage": null, 2118 "createdAt": "2026-06-12T12:00:00.000Z", 2119 "finishedAt": "2026-06-12T12:00:12.000Z", 2120 "outputs": [ 2121 { 2122 "inferenceJobOutputId": "019e1b6f-5e8d-88c2-a0f3-159684318a10", 2123 "outputKey": "image", 2124 "outputValue": null, 2125 "createdAt": "2026-06-12T12:00:12.000Z", 2126 "media": { 2127 "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db", 2128 "url": "https://storage.googleapis.com/...", 2129 "mimeType": "image/png", 2130 "width": 1024, 2131 "height": 1024, 2132 "durationMs": null, 2133 "fps": null 2134 } 2135 } 2136 ], 2137 "attachments": [] 2138} 2139\`\`\` 2140 2141Use the output \`media.mediaId\` as the input to publishing or local CLI editing. 2142 2143## 4. Publish to Instagram 2144 2145Get an \`instagramAccountId\` from \`GET /instagram/accounts\`, then create a publish job. 2146 2147\`\`\`bash 2148curl -X POST "$WONDA_API_BASE/publish/instagram" \\ 2149 -H "Authorization: Bearer $WONDA_API_KEY" \\ 2150 -H "Content-Type: application/json" \\ 2151 -d '{ 2152 "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db", 2153 "instagramAccountId": "550e8400-e29b-41d4-a716-446655440000", 2154 "caption": "Made with Wonda", 2155 "product": "IMAGE" 2156 }' 2157\`\`\` 2158 2159\`\`\`json 2160{ 2161 "outputJobId": "019e1b76-74d7-8c7e-a927-6bd34bfaa114", 2162 "status": "queued" 2163} 2164\`\`\` 2165 2166Poll the publish job until it reaches a terminal status. 2167 2168\`\`\`bash 2169curl "$WONDA_API_BASE/jobs/publish/019e1b76-74d7-8c7e-a927-6bd34bfaa114" \\ 2170 -H "Authorization: Bearer $WONDA_API_KEY" 2171\`\`\` 2172 2173## Next steps 2174 2175- Learn how prompts are handled in [Creative vs Verbatim mode](verbatim-mode). 2176- Explore [Image Generation](image-generation), [Video Generation](video-generation), and [Pricing Estimate](pricing-estimate). 2177- Set up production-safe polling with [Job Polling](job-polling). 2178- Use [Publish to Instagram](publish-instagram) or [Publish to TikTok](publish-tiktok) for destination-specific options.
2179- Use [Video Editing](video-editing), [Image Editing](image-editing), and [Audio Editing](audio-editing) for local CLI editing. 2180`,M=`--- 2181title: Rate Limits 2182description: Request-rate limiting and concurrent task admission rules for the public API. 2183--- 2184 2185## Request-rate limiting 2186 2187The public API applies per-IP request-rate limits enforced at the edge via Google Cloud Armor. The current buckets are: 2188 2189| Bucket | Limit | Applies to | 2190| ---------------- | ---------------- | ---------------------- | 2191| General | 300 requests/min | Most API requests | 2192| Upload | 300 requests/min | \`POST /media/upload\` | 2193| Account creation | 15 requests/hour | \`POST /auth/temporary\` | 2194 2195When the rate limit is exceeded, the API returns a 429 Too Many Requests response. 2196 2197## Concurrent task admission 2198 2199Some heavy routes do not use request-per-minute limiting. Instead, they are admitted through a separate per-account concurrency and queue policy. This controls direct generation, analysis, and other queued worker workloads. 2200 2201| Plan | Concurrent limit | Queue limit | 2202| -------- | ---------------- | ----------- | 2203| Free | 2 | 25 | 2204| Basic | 5 | 150 | 2205| Wonda | 25 | 100 | 2206| Pro | 15 | 500 | 2207| Absolute | 50 | 2000 | 2208 2209When the queue limit is exceeded, the API rejects the request with a concurrency error that includes the active and queued counts. When the queue still has space, the request may be accepted and started later rather than running immediately. 2210 2211## What this means in practice 2212 2213- Simple request bursts are governed by the request-rate buckets. 2214- Long-running generation and analysis workloads are governed by the concurrency policy instead. 2215- Local CLI editing runs on your machine, so it is not admitted through the server render queue. 2216- The two systems are separate. A route can be exempt from request-rate limiting and still be subject to concurrency limits. 2217`,N=`---
2218title: Scraping 2219description: Scrape public social profiles and Meta Ads Library for competitive intelligence. 2220--- 2221 2222## Social Scraping 2223 2224Scrape public profile data and recent media from Instagram or TikTok accounts. Tasks are async -- create a task, then poll for results. 2225 2226\`POST /api/v1/scrape/social\` 2227 2228### Request Body 2229 2230| Parameter | Type | Required | Description | 2231| ----------- | --------------------------- | -------- | ----------------------------------- | 2232| handle | string | Yes | Public username to scrape | 2233| platform | \`"instagram"\` \\| \`"tiktok"\` | Yes | Target platform | 2234| callbackUrl | string | No | Webhook URL to notify on completion | 2235 2236### Example 2237 2238**Create scrape task** 2239 2240\`\`\`bash 2241curl -X POST https://api.wondercat.ai/api/v1/scrape/social \\ 2242 -H "Authorization: Bearer YOUR_API_KEY" \\ 2243 -H "Content-Type: application/json" \\ 2244 -d '{"handle": "natgeo", "platform": "instagram"}' 2245\`\`\` 2246 2247**Response (201)** 2248 2249\`\`\`json 2250{ 2251 "scrapeTaskId": "st_...", 2252 "handle": "natgeo", 2253 "platform": "instagram", 2254 "status": "pending" 2255} 2256\`\`\` 2257 2258\`GET /api/v1/scrape/social/{taskId}\` 2259 2260### Response (completed) 2261 2262Once complete, the task includes the profile and an array of recent media with engagement metrics. 2263 2264\`\`\`json 2265{ 2266 "scrapeTaskId": "st_...", 2267 "status": "completed", 2268 "profile": { 2269 "username": "natgeo", 2270 "name": "National Geographic", 2271 "bio": "Experience the world through the eyes of National Geographic photographers.", 2272 "followerCount": 284000000, 2273 "profilePicUrl": "https://..." 2274 }, 2275 "media": [ 2276 { 2277 "originalUrl": "https://...", 2278 "postUrl": "https://instagram.com/p/...", 2279 "caption": "...", 2280 "likesCount": 120000, 2281 "commentsCount": 3400, 2282 "postTimestamp": "2026-03-20T12:00:00Z" 2283 } 2284 ] 2285} 2286\`\`\` 2287 2288--- 2289 2290## Meta Ads Library 2291 2292Search the Meta Ad Library for competitor creatives. 2293 2294\`POST /api/v1/scrape/meta-ads\` 2295 2296### Request Body 2297 2298| Parameter | Type | Required | Description | 2299| ------------------ | --------------------------------------------------------- | -------- | ---------------------------------------------------- | 2300| query | string | Yes | Search query (brand name, keyword, etc.) | 2301| countryCode | string | Yes | ISO country code (e.g. US, GB, FR) | 2302| searchType | \`"page"\` \\| \`"keyword"\` | No | Search mode. Defaults to "keyword". | 2303| activeStatus | \`"all"\` \\| \`"active"\` \\| \`"inactive"\` | No | Filter by active/inactive ads. Defaults to "active". | 2304| sortBy | \`"impressions_desc"\` \\| \`"most_recent"\` | No | Sort order for returned ads. | 2305| period | \`"last24h"\` \\| \`"last7d"\` \\| \`"last14d"\` \\| \`"last30d"\` | No | Time window for the search results. | 2306| contentLanguages | string[] | No | Optional language filters. | 2307| publisherPlatforms | string[] | No | Optional publisher platform filters. | 2308| mediaType | \`"all"\` \\| \`"image"\` \\| \`"video"\` \\| \`"meme"\` \\| \`"none"\` | No | Filter by media type. | 2309| maxResults | number | No | Max ads to return | 2310 2311\`GET /api/v1/scrape/meta-ads/{taskId}\` 2312 2313### Response (completed) 2314 2315\`\`\`json 2316{ 2317 "scrapeTaskId": "st_...", 2318 "status": "completed", 2319 "ads": [ 2320 { 2321 "title": "Spring Sale", 2322 "bodyText": "50% off all items...", 2323 "imageUrl": "https://...", 2324 "videoUrl": null, 2325 "isActive": true, 2326 "startDate": "2026-03-01", 2327 "endDate": null 2328 } 2329 ] 2330} 2331\`\`\` 2332 2333--- 2334 2335## Download a Reel or TikTok 2336 2337\`POST /api/v1/scrape/reel\` 2338 2339Download a single Instagram Reel or TikTok video by URL. 2340 2341### Request Body 2342 2343| Parameter | Type | Required | Description | 2344| --------- | ------ | -------- | ----------------------------------- | 2345| url | string | Yes | URL of the Instagram Reel or TikTok | 2346 2347### Example 2348 2349\`\`\`bash 2350curl -X POST https://api.wondercat.ai/api/v1/scrape/reel \\ 2351 -H "Authorization: Bearer YOUR_API_KEY" \\ 2352 -H "Content-Type: application/json" \\ 2353 -d '{"url": "https://www.instagram.com/reel/ABC123"}' 2354\`\`\` 2355 2356### Response 2357 2358Returns a scrape task ID and platform. Poll \`GET /scrape/social/{scrapeTaskId}\` until status is \`completed\`. The downloaded video appears in the media array of the scrape result. 2359 2360Instagram downloads start in \`"pending"\` status; TikTok downloads start in \`"processing"\` (sent directly to the video worker). 2361 2362\`\`\`json 2363{ 2364 "scrapeTaskId": "st_...", 2365 "platform": "instagram", 2366 "status": "pending" 2367} 2368\`\`\` 2369`,P=`--- 2370title: List Styles 2371description: Retrieve brand and featured styles available to your account. 2372--- 2373 2374\`GET /api/v1/styles\` 2375 2376## Behavior 2377 2378Returns all styles accessible to the authenticated account. Brand styles (account-specific) are listed first, followed by up to 50 platform-curated featured styles. 2379 2380## Response Fields 2381 2382| Parameter | Type | Required | Description | 2383| ------------- | ------------------------- | -------- | ------------------------------------------------------------------------------------ | 2384| styleId | string | Yes | UUID of the style | 2385| name | string | Yes | Display name | 2386| description | string \\| null | No | Short description of the style (nullable) | 2387| coverImageUrl | string \\| null | No | Preview image URL (nullable) | 2388| type | \`"brand"\` \\| \`"featured"\` | Yes | Whether this is an account-specific brand style or a platform-curated featured style | 2389 2390## Response 2391 2392\`\`\`json 2393{ 2394 "styles": [ 2395 { 2396 "styleId": "a1b2c3d4-...", 2397 "name": "Brand Cinematic",
2398 "description": "Warm cinematic tones with film grain", 2399 "coverImageUrl": "https://storage.example.com/styles/brand-cinematic.webp", 2400 "type": "brand" 2401 }, 2402 { 2403 "styleId": "e5f6a7b8-...", 2404 "name": "Neon Pop", 2405 "description": null, 2406 "coverImageUrl": null, 2407 "type": "featured" 2408 } 2409 ] 2410} 2411\`\`\` 2412`,F=`--- 2413title: Text Generation 2414description: Generate text completions and extract brand styles with AI models. 2415--- 2416 2417\`POST /api/v1/text/generate\` 2418 2419## Request Body 2420 2421| Parameter | Type | Required | Description | 2422| ------------------ | -------- | -------- | ------------------------------------------------ | 2423| model | string | Yes | Model key (see models below) | 2424| prompt | string | No | Text prompt (required for openrouter-completion) | 2425| params | object | No | Model-specific parameters | 2426| attachmentMediaIds | string[] | No | Positional media attachment IDs | 2427 2428## Response 2429 2430\`\`\`json 2431{ 2432 "inferenceJobId": "ij_..." 2433} 2434\`\`\` 2435 2436## Example 2437 2438**POST /api/v1/text/generate** 2439 2440\`\`\`json 2441{ 2442 "model": "openrouter-completion", 2443 "prompt": "Write a tagline for a sustainable fashion brand", 2444 "params": { 2445 "llm": "anthropic/claude-sonnet-4.6", 2446 "systemPrompt": "You are a creative copywriter specializing in fashion.", 2447 "reasoningEnabled": true, 2448 "reasoningEffort": "medium", 2449 "maxOutputTokens": 4096 2450 } 2451} 2452\`\`\` 2453 2454--- 2455 2456## Models 2457 2458### openrouter-completion 2459 2460LLM text completion via OpenRouter. Prompt required. 2461 2462| Parameter | Type | Required | Description | 2463| ------------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 2464| llm | string | No | openai/gpt-5.2, openai/gpt-5.1, openai/gpt-5-chat, google/gemini-3-pro-preview, google/gemini-3-flash-preview, anthropic/claude-opus-4.5, anthropic/claude-sonnet-4.5, anthropic/claude-sonnet-4.6, x-ai/grok-4, x-ai/grok-4.3 (default x-ai/grok-4.3) | 2465| systemPrompt | string | No | System prompt to set the LLM persona and behavior | 2466| reasoningEnabled | boolean | No | Enable reasoning/chain-of-thought mode | 2467| reasoningEffort | string | No | minimal, low, medium, high, xhigh | 2468| reasoningMaxTokens | number | No | 1024 to 32000 | 2469| maxOutputTokens | number | No | 1024 to 128000 | 2470 2471**Attachments:** Up to 4 optional media attachments. 2472 2473#### Available LLMs 2474 2475| Provider | Model | 2476| --------- | ------------------------------- | 2477| OpenAI | \`openai/gpt-5.2\` | 2478| OpenAI | \`openai/gpt-5.1\` | 2479| OpenAI | \`openai/gpt-5-chat\` | 2480| Google | \`google/gemini-3-pro-preview\` | 2481| Google | \`google/gemini-3-flash-preview\` | 2482| Anthropic | \`anthropic/claude-opus-4.5\` | 2483| Anthropic | \`anthropic/claude-sonnet-4.5\` | 2484| Anthropic | \`anthropic/claude-sonnet-4.6\` | 2485| xAI | \`x-ai/grok-4\` | 2486| xAI | \`x-ai/grok-4.3\` | 2487 2488### extract-brand-style 2489 2490Extract brand style attributes from images. Prompt is hardcoded internally. 2491 2492**Params:** None. 2493 2494**Attachments:** 1 to 8 brand images (first is required). 2495`,I=`--- 2496title: Creative vs Verbatim Mode 2497description: Understand how Wonda handles prompts on the current public API surface. 2498--- 2499 2500## The two modes 2501 2502| Mode | Prompt handling | Best for | 2503| -------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------ | 2504| Creative | Wonda may enhance, rewrite, or expand a prompt before it reaches a model. | Exploration, brainstorming, and end-user prompts that need improvement. | 2505| Verbatim | Your prompt is sent to the model exactly as provided. | Deterministic pipelines, tests, and prompts produced by your own system. | 2506 2507## Current public API behavior 2508 2509Direct generation endpoints are verbatim. When you call endpoints such as \`POST /image/generate\`, \`POST /video/generate\`, \`POST /text/generate\`, \`POST /music/generate\`, or \`POST /audio/speech\`, the \`prompt\` field is used as provided. 2510 2511No request flag is required to enable verbatim mode on direct endpoints. 2512 2513| Surface | Default mode | How to switch | 2514| --------------------------- | ------------------------------------------------------ | ----------------- | 2515| Direct generation endpoints | Verbatim | No switch needed. | 2516| CLI generation commands | Verbatim for the prompt passed to the direct endpoint. | No switch needed. | 2517 2518## Recommendation for API consumers 2519 2520If you are building an automated pipeline where prompts are pre-crafted or generated by your own system, use direct generation endpoints. This keeps outputs predictable and makes request logs easier to audit. 2521 2522Use creative prompt rewriting only in product surfaces where you explicitly control that behavior before calling the API. 2523 2524## Example: direct image generation 2525 2526\`\`\`bash 2527curl -X POST https://api.wondercat.ai/api/v1/image/generate \\ 2528 -H "Authorization: Bearer sk_your_api_key_here" \\ 2529 -H "Content-Type: application/json" \\ 2530 -d '{ 2531 "model": "nano-banana-2", 2532 "prompt": "16:9 image of a golden retriever on a beach, 35mm photo, late afternoon light", 2533 "params": { 2534 "aspectRatio": "16:9" 2535 } 2536 }' 2537\`\`\` 2538 2539The model receives the prompt string in the request body.
2540`,L='---\ntitle: Video Editing\ndescription: Apply local video edits with the Wonda CLI: trim, crop, merge, overlay, captions, audio mixing, and more.\n---\n\nVideo editing is CLI-first. `wonda edit video` downloads inputs when needed, renders locally with ffmpeg or hyperframes, uploads the output media, and prints the resulting `mediaId`. There is no server-side editor job for current video edits.\n\nThe retired `POST /api/v1/video/edit` endpoint returns `410 Gone` with a migration hint for known operations. Move scripts to the CLI commands below.\n\n## Setup\n\n```bash\nnpm i -g @degausai/wonda\nwonda auth login\nwonda doctor\n```\n\n`wonda doctor` checks local prerequisites such as ffmpeg. Hyperframes operations such as `textOverlay` and `animatedCaptions` also need the bundled Chromium renderer.\n\n## Usage\n\n```bash\nwonda edit video --operation <operation> \\\n --media <media-id-or-local-file> \\\n --params \'{...}\' \\\n --wait -o ./out.mp4\n```\n\nCommon flags:\n\n| Flag | Description |\n| -------------------- | ------------------------------------------------------------------------------------------------------------------- |\n| `--operation` | Required operation name. Run `wonda operations list` to see the local registry. |\n| `--media` | Media IDs or local file paths. Pass multiple inputs as a comma-separated value, such as `--media <base>,<overlay>`. |\n| `--params` | Raw JSON object for operation-specific params. Run `wonda operations info <operation>` for the shape. |\n| `--preset` | Featured preset name scoped to `--operation`. Explicit `--params` values override preset params. |\n| `--audio-media` | Audio media ID or local audio file for `editAudio`. |\n| `--prompt-text` | Required text for `textOverlay`. |\n| `--caption-segments` | Raw JSON array for `animatedCaptions`. Produce timing data with `wonda alignment extract-timestamps`. |\n| `--wait` | Accepted for compatibility. Local renders finish before output is printed. |\n| `-o`, `--output` | Download the rendered output to a local file path. Implies `--wait`. |\n\nVideo-only shortcut flags:\n\n| Flag | Applies to | Description |\n| ------------------------ | -------------- | ---------------------------------------------------------------------------------------- |\n| `--threshold` | `splitScenes` | Scene-change sensitivity from `0.01` to `0.9`. |\n| `--min-clip-duration` | `splitScenes` | Minimum scene duration in seconds. |\n| `--mode` | `splitScenes` | `split` for separate scene files or `omit` to remove one scene and concatenate the rest. |\n| `--output-selection` | `splitScenes` | `first`, `last`, or a 1-indexed scene number. |\n| `--duration-ms` | `imageToVideo` | Hold a still image for this many milliseconds, from `500` to `60000`. |\n| `--silence-threshold-db` | `skipSilence` | Silence detection noise floor in dB. |\n| `--min-silence-duration` | `skipSilence` | Shortest gap that counts as silence, in seconds. |\n| `--max-silence-duration` | `skipSilence` | Silence beyond this gets cut; remaining silence is bounded to this value. |\n\n## Output\n\nWithout `--output`, a successful local render prints:\n\n```json\n{\n "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db",\n "status": "succeeded"\n}\n```\n\nWith `--output`, the CLI downloads the result and prints the local path plus `mediaId`:\n\n```json\n{\n "path": "./trimmed.mp4",\n "mediaId": "019e1b70-6f9e-80fd-8c49-690bcbdaf8db"\n}\n```\n\n`splitScenes` in split mode prints a `scenes` array because it can produce multiple media outputs.\n\n## Operations\n\n| Operation | Renderer | Inputs | Key params |\n| ------------------ | ----------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |\n| `trim` | ffmpeg | One video | `trimStartMs`, `trimEndMs` |\n| `crop` | ffmpeg | One video | `aspectRatio`, `customWidth`, `customHeight`, `cropPercent`, `cropAxis`, `position`, `paddingTop` |\n| `merge` | ffmpeg | Multiple videos | Input order
2540comes from `--media <id1>,<id2>,...` |\n| `overlay` | ffmpeg | Base video plus overlay video | `position`, `resizePercent`, `resizeAxis`, `baseVideoVolume`, `overlayVideoVolume`, `overlayStartMs`, `overlayDurationMs` |\n| `splitScreen` | ffmpeg | Two videos | `targetAspectRatio` |\n| `speed` | ffmpeg | One video | `speed`, `preservePitch` |\n| `volume` | ffmpeg | One video | `volume`, `muted` |\n| `reverseVideo` | ffmpeg | One video | None |\n| `extractFrame` | ffmpeg | One video | `timestampMs` or `timestampPercent` |\n| `extractAudio` | ffmpeg | One video | None |\n| `editAudio` | ffmpeg | One video plus one audio input | `videoVolume`, `audioVolume`, `audioStartMs`, `audioEndMs`, `audioOffsetMs` |\n| `imageToVideo` | ffmpeg | One image | `durationMs`, or the `--duration-ms` shortcut |\n| `skipSilence` | ffmpeg | One video with audio | `silenceThresholdDb`, `minSilenceDuration`, `maxSilenceDuration` |\n| `splitScenes` | ffmpeg | One video | `mode`, `outputSelection`, `threshold`, `minCl
2540ipDuration` |\n| `textOverlay` | hyperframes | One video or image plus `--prompt-text` | Styling params such as `fontFamily`, `position`, `sizePercent`, `fontSizeScale`, `strokeWidth` |\n| `animatedCaptions` | hyperframes | One video plus `--caption-segments` | Caption styling params such as `fontFamily`, `position`, `sizePercent`, `fontSizeScale`, `strokeWidth`, `highlightColor` |\n\nFor exact parameter defaults and ranges, run:\n\n```bash\nwonda operations info trim\nwonda operations info textOverlay\n```\n\n## Examples\n\nTrim a video:\n\n```bash\nwonda edit video --operation trim --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --params \'{"trimStartMs":3000,"trimEndMs":10000}\' \\\n --wait -o ./trimmed.mp4\n```\n\nMerge videos locally:\n\n```bash\nwonda edit video --operation merge \\\n --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db,019e1b72-0742-8bae-bb93-b569036d05af \\\n --wait -o ./merged.mp4\n```\n\nAdd a static text overlay:\n\n```bash\nwonda edit video --operation textOverlay --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --prompt-text "Launch day" \\\n --params \'{"fontFamily":"TikTok Sans SemiCondensed","position":"top-center","sizePercent":66,"fontSizeScale":0.5,"strokeWidth":4.5}\' \\\n --wait -o ./with-text.mp4\n```\n\nRender animated captions:\n\n```bash\nwonda edit video --operation animatedCaptions --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --caption-segments \'[{"text":"Launch","startS":0},{"text":"day","startS":0.4}]\' \\\n --params \'{"fontFamily":"TikTok Sans SemiCondensed","position":"bottom-center","sizePercent":80}\' \\\n --wait -o ./captioned.mp4\n```\n\nReplace or mix audio:\n\n```bash\nwonda edit video --operation editAudio \\\n --media 019e1b70-6f9e-80fd-8c49-690bcbdaf8db \\\n --audio-media 019e1b73-32a4-8c9e-8bbf-3661a14a5716 \\\n --params \'{"videoVolume":30,"audioVolume":80,"audioOffsetMs":2000}\' \\\n --wait -o ./with-audio.mp4\n```\n',R=`--- 2541title: Video Generation 2542description: Generate, transform, upscale, and process videos with AI models. 2543--- 2544 2545\`POST /api/v1/video/generate\` 2546 2547## Request Body 2548 2549| Parameter | Type | Required | Description | 2550| ------------------ | -------- | -------- | -------------------------------------- | 2551| model | string | Yes | Model key (see models below) | 2552| prompt | string | No | Text prompt (required for most models) | 2553| params | object | No | Model-specific parameters | 2554| attachmentMediaIds | string[] | No | Positional media attachment IDs | 2555 2556## Response 2557 2558\`\`\`json 2559{ 2560 "inferenceJobId": "ij_..." 2561} 2562\`\`\` 2563 2564## Example 2565 2566**POST /api/v1/video/generate** 2567 2568\`\`\`json 2569{ 2570 "model": "sora2", 2571 "prompt": "A drone shot flying over a misty forest at sunrise", 2572 "params": { "aspectRatio": "16:9", "duration": "8" } 2573} 2574\`\`\` 2575 2576--- 2577 2578## Models 2579 2580### sora2 2581 2582Text-to-video generation. Prompt required. 2583 2584| Parameter | Type | Required | Description | 2585| -------------- | ------- | -------- | --------------------------------------------------- | 2586| aspectRatio | string | No | 16:9, 9:16 | 2587| resolution | string | No | 720p only | 2588| duration | string | No | "4", "8", "12", "16", or "20" seconds (default "8") | 2589| omitFirstScene | boolean | No | Omit the first scene from the output | 2590 2591**Attachments:** 1 optional image. 2592 2593### sora2pro 2594 2595Pro-tier text-to-video. Prompt required. 2596 2597| Parameter | Type | Required | Description | 2598| -------------- | ------- | -------- | --------------------------------------------------- | 2599| aspectRatio | string | No | 16:9, 9:16 | 2600| resolution | string | No | 720p, 1024p, 1080p (default 720p) | 2601| duration | string | No | "4", "8", "12", "16", or "20" seconds (default "8") | 2602| omitFirstScene | boolean | No | Omit the first scene from the output | 2603 2604**Attachments:** 1 optional image. 2605 2606### veo3_1-fast 2607 2608Fast video generation with fixed 8-second duration. Prompt required. 2609 2610| Parameter | Type | Required | Description | 2611| ----------- | ------ | -------- | ----------- | 2612| aspectRatio | string | No | 16:9, 9:16 | 2613| resolution | string | No | 720p, 1080p | 2614 2615**Duration:** Fixed at 8 seconds. 2616 2617**Attachments:** Up to 2 images (first_frame, last_frame). last_frame requires first_frame to be provided. 2618 2619### kling2_5-pro 2620 2621Kling 2.5 Pro video generation. Prompt required. 2622 2623| Parameter | Type | Required | Description | 2624| ----------- | ------ | -------- | --------------- | 2625| aspectRatio | string | No | 16:9, 9:16, 1:1 | 2626| duration | number | No | 5 or 10 seconds | 2627
2628**Attachments:** Up to 2 optional images. 2629 2630### kling_2_6_pro 2631 2632Kling 2.6 Pro with automatic image-to-video. Prompt required. 2633 2634| Parameter | Type | Required | Description | 2635| ----------- | ------ | -------- | --------------- | 2636| aspectRatio | string | No | 16:9, 9:16, 1:1 | 2637| duration | number | No | 5 or 10 seconds | 2638 2639**Attachments:** 1 optional image (auto image-to-video when provided). 2640 2641### kling_2_6_motion_control 2642 2643Motion-controlled video from a reference image and video. Prompt required. 2644 2645| Parameter | Type | Required | Description | 2646| -------------------- | ------- | -------- | ------------------------------------------------ | 2647| characterOrientation | string | No | image, video | 2648| keepOriginalSound | boolean | No | Keep the original audio from the reference video | 2649 2650**Attachments:** 2 required -- reference_image + reference_video. 2651 2652### kling_3_pro 2653 2654Text-to-video and image-to-video with fine-grained controls. Prompt required. 2655 2656| Parameter | Type | Required | Description | 2657| -------------- | ------- | -------- | --------------------------------------------- | 2658| aspectRatio | string | No | Aspect ratio of the output video | 2659| duration | number | No | 3 to 15 seconds | 2660| generateAudio | boolean | No | Generate audio for the video | 2661| multiPrompt | boolean | No | Enable multi-prompt mode | 2662| negativePrompt | string | No | Negative prompt to guide generation away from | 2663| cfgScale | number | No | Classifier-free guidance scale (0 to 1) | 2664 2665**Attachments:** Optional start_image, end_image, and up to 2 element slots. 2666 2667### sync-lipsync-v2-pro 2668 2669Lip-sync a video to an audio track. No prompt needed. 2670 2671| Parameter | Type | Required | Description | 2672| -------------------- | ------ | -------- | ------------------------------------- | 2673| syncMode | string | No | cut_off, loop, bounce, silence, remap | 2674| videoDurationSeconds | number | No | 1 to 600 seconds | 2675 2676**Attachments:** 2 required -- video + audio. 2677 2678### bria-video-background-removal 2679 2680Remove background from video. No prompt or params needed. 2681 2682**Params:** None. 2683 2684**Attachments:** 1 required video. 2685 2686### veed-video-background-removal 2687 2688VEED-powered video background removal. No prompt needed. 2689 2690| Parameter | Type | Required | Description | 2691| --------------- | ------- | -------- | --------------------------------------------------- | 2692| subjectIsPerson | boolean | No | Whether the subject is a person (optimizes removal) | 2693 2694**Attachments:** 1 required video. 2695 2696### veed-video-background-removal-fast 2697 2698Fast variant of VEED video background removal. No prompt needed. 2699 2700| Parameter | Type | Required | Description | 2701| --------------- | ------- | -------- | --------------------------------------------------- | 2702| subjectIsPerson | boolean | No | Whether the subject is a person (optimizes removal) | 2703 2704**Attachments:** 1 required video. 2705 2706### seedance-2 2707 2708Text-to-video and image-to-video generation. Routes automatically based on image attachment. 2709 2710| Parameter | Type | Required | Description | 2711| ----------- | ------ | -------- | -------------------------------- | 2712| aspectRatio | string | No | 16:9, 9:16, 4:3, 3:4 | 2713| duration | string | No | "5", "10", or "15" (default "5") | 2714| quality | string | No | high (standard), basic (fast) | 2715 2716**Attachments:** 1 optional image (triggers image-to-video mode). 2717 2718### seedance-2-omni 2719 2720Reference-based video generation. Use @image1, @audio1 in prompt. 2721 2722| Parameter | Type | Required | Description | 2723| ----------- | ------ | -------- | --------------------------------- | 2724| aspectRatio | string | No | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 | 2725| duration | string | No | "4" to "15" seconds (default "5") | 2726
2727**Attachments:** Up to 3 images and 1 audio clip (all optional). 2728 2729### seedance-2-video-edit 2730 2731Edit an existing video using text prompts. 2732 2733| Parameter | Type | Required | Description | 2734| ----------- | ------ | -------- | --------------------------- | 2735| aspectRatio | string | No | 16:9, 9:16, 4:3, 3:4 | 2736| quality | string | No | basic, high (default basic) | 2737 2738**Attachments:** 1 required video. 2739 2740### grok-imagine-video 2741 2742Video generation by xAI. Text-to-video and image-to-video. Prompt required. 2743 2744| Parameter | Type | Required | Description | 2745| ----------- | ------ | -------- | -------------------------------------------------- | 2746| aspectRatio | string | No | 9:16, 16:9, 1:1, 4:3, 3:4, 3:2, 2:3 (default 9:16) | 2747| duration | string | No | 5, 8, 10, or 15 seconds (default 8) | 2748| resolution | string | No | 480p, 720p (default 720p) | 2749 2750**Attachments:** 1 optional start image for image-to-video. 2751 2752### topaz-video-upscale 2753 2754Upscale video resolution with Topaz. No prompt needed. 2755 2756| Parameter | Type | Required | Description | 2757| ------------- | ---------------- | -------- | ---------------------- | 2758| upscaleFactor | number | No | 1 to 4 | 2759| targetFps | string \\| number | No | "original" or 16 to 60 | 2760| codec | string | No | h265, h264 | 2761 2762**Attachments:** 1 required video. 2763`,z=/^---\n([\s\S]*?)\n---\n/;function B(e){let t=z.exec(e);if(!t)return{data:{},content:e};let n={};for(let e of(t[1]??``).split(` 2764`)){let t=e.indexOf(`:`);t!==-1&&(n[e.slice(0,t).trim()]=e.slice(t+1).trim())}return{data:n,content:e.slice(t[0].length)}}var V=Object.assign({"../../packages/docs/content/action-errors.md":t,"../../packages/docs/content/action-reference.md":n,"../../packages/docs/content/action-routing.md":r,"../../packages/docs/content/alignment-timestamps.md":i,"../../packages/docs/content/analytics.md":a,"../../packages/docs/content/audio-dialogue.md":o,"../../packages/docs/content/audio-editing.md":s,"../../packages/docs/content/audio-speech.md":c,"../../packages/docs/content/audio-transcription.md":l,"../../packages/docs/content/authentication.md":u,"../../packages/docs/content/browser-control.md":d,"../../packages/docs/content/capabilities.md":f,"../../packages/docs/content/connect-chatgpt.md":p,"../../packages/docs/content/connect-claude.md":m,"../../packages/docs/content/connect-codex.md":h,"../../packages/docs/content/distribution-accounts.md":g,"../../packages/docs/content/distribution-publishing.md":_,"../../packages/docs/content/errors.md":v,"../../packages/docs/content/image-editing.md":y,"../../packages/docs/content/image-generation.md":b,"../../packages/docs/content/job-polling.md":x,"../../packages/docs/content/media-upload.md":S,"../../packages/docs/content/music-generation.md":C,"../../packages/docs/content/overview.md":w,"../../packages/docs/content/personas-sessions.md":T,"../../packages/docs/content/platform-actions.md":E,"../../packages/docs/content/pricing-estimate.md":D,"../../packages/docs/content/pricing.md":O,"../../packages/docs/content/publish-instagram.md":k,"../../packages/docs/content/publish-tiktok.md":A,"../../packages/docs/content/quick-start.md":j,"../../packages/docs/content/rate-limits.md":M,"../../packages/docs/content/scraping.md":N,"../../packages/docs/content/styles-list.md":P,"../../packages/docs/content/text-generation.md":F,"../../packages/docs/content/verbatim-mode.md":I,"../../packages/docs/content/video-editing.md":L,"../../packages/docs/content/video-generation.md":R});function H(e){return/\/([^/]+)\.md$/.exec(e)?.[1]??``}var U=new Map;for(let[e,t]of Object.entries(V))U.set(H(e),t);function W(t){let n=U.get(t);if(!n)return null;let{data:r,content:i}=B(n);return{content:i,title:r.title??e[t]??t,description:r.description}}export{W as t}; 2765//# sourceMappingURL=content-DKDtXaCo.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.