PageSourceSearch

https://www.wonda.sh/assets/content-DKDtXaCo.js

js wonda.sh collected 2026-10-09 22:57:22 UTC 147,579 bytes, 2,765 lines download raw bytes

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.