Developer documentation
Build with the Neurodance API and MCP server.
Use the REST API for deterministic integrations or connect the remote MCP server to let compatible AI clients operate Neurodance with user approval. Both surfaces share the same workspace, scopes, rate limits and capability model.
Reviewed by Neurodance ·
REST API foundations
The OpenAPI 3.1 contract exposes 104 operations across 86 paths. Authenticate server-side requests with a workspace-scoped nd_live_ or nd_test_ API key in the Authorization Bearer header.
Every mutation requires a stable Idempotency-Key. Long-running template, generation, variation and distribution operations return a job handle; poll the linked job endpoint using poll_after_seconds instead of creating a duplicate operation.
- Production base URL: https://api-public.neurodance.ai
- OpenAPI contract: https://api-public.neurodance.ai/v1/openapi.json
- Scopes: read, generate and distribute
Complete REST operation index (104)
The interactive documentation includes searchable parameters, request fields, response codes, scope, rate tier, async-job and idempotency metadata for every operation.
- GET /v1/account — Get account status [read]
- GET /v1/templates — List templates [read]
- GET /v1/templates/{id} — Get a template [read]
- POST /v1/templates/build — Build a template (async) [generate]
- POST /v1/templates/{id}/variations — Create a variation (synchronous) [generate]
- GET /v1/assets — List asset library [read]
- GET /v1/generations — List generations [read]
- POST /v1/generations — Create a generation (async) [generate]
- GET /v1/generations/{id} — Get generation status [read]
- GET /v1/distributions — List distributions [read]
- POST /v1/distributions — Distribute a generation (async) [distribute]
- GET /v1/distributions/{id} — Get distribution status [read]
- DELETE /v1/distributions/{id} — Delete an Instagram post or remove a local YouTube distribution record [distribute]
- POST /v1/distributions/{job_id}/activate — Activate a paused Ads distribution [distribute]
- POST /v1/distributions/{job_id}/dismiss — Dismiss a Meta Ads distribution [distribute]
- POST /v1/distributions/{job_id}/cancel — Cancel a Meta Ads distribution [distribute]
- POST /v1/distributions/{job_id}/sync — Sync one distribution [distribute]
- POST /v1/distributions/sync-all — Sync distributions [distribute]
- GET /v1/metrics — List performance metrics [read]
- GET /v1/metrics/diagnostics — Diagnose metrics polling [read]
- GET /v1/metrics/{platform_post_id} — Get post metrics time series [read]
- POST /v1/performance-briefs — Compose a performance brief [generate]
- GET /v1/performance-briefs/{platform_post_id} — List performance briefs [read]
- GET /v1/jobs/{job_id} — Get any job's status [read]
- POST /v1/uploads/reference — Upload a reference image [generate]
- GET /v1/keys — List API keys [read]
- POST /v1/keys — Create an API key [read]
- DELETE /v1/keys — Revoke an API key [read]
- GET /v1/shared/{token} — View a share link [read]
- POST /v1/shared/{token}/feedback — Leave a guest note on a shared creative or file [generate]
- POST /v1/shared/{token}/upload-url — Get a presigned upload URL for a guest contribution [generate]
- POST /v1/shared/{token}/confirm-upload — Confirm a guest upload completed [generate]
- GET /v1/capabilities — Search the typed capability catalog [read]
- GET /v1/search — Search workspace [read]
- GET /v1/campaigns/{campaign_id}/memory — List campaign memory [read]
- POST /v1/campaigns/{campaign_id}/memory — Record campaign memory [generate]
- GET /v1/notes — List workspace notes [read]
- POST /v1/notes — Add workspace note [generate]
- DELETE /v1/notes/{note_id} — Delete workspace note [generate]
- GET /v1/generations/{generation_id}/review-thread — List review thread [read]
- POST /v1/review-entries/{source}/{entry_id}/resolution — Resolve review entry [generate]
- PATCH /v1/campaign-memory/{entry_id} — Update campaign memory lifecycle [generate]
- GET /v1/memory-ledger — List workspace decision ledger [read]
- GET /v1/campaigns/{campaign_id}/related-learnings — List related campaign learnings [read]
- GET /v1/assets/library — List asset library [read]
- PATCH /v1/assets/{asset_id}/library — Rename, file, or tag asset [generate]
- GET /v1/archive/generations — List generations [read]
- GET /v1/trash — List trash [read]
- DELETE /v1/archive/{entity_type}/{entity_id} — Move object to trash [generate]
- POST /v1/archive/{entity_type}/{entity_id}/restore — Restore object from trash [generate]
- PATCH /v1/templates/{template_id}/name — Rename template [generate]
- GET /v1/campaigns/{campaign_id}/asset-folders — List campaign asset folders [read]
- POST /v1/campaigns/{campaign_id}/asset-folders — Create campaign asset folder [generate]
- PATCH /v1/asset-folders/{folder_id} — Rename campaign asset folder [generate]
- DELETE /v1/asset-folders/{folder_id} — Delete campaign asset folder [generate]
- POST /v1/generations/{generation_id}/cancel — Cancel active generation [generate]
- POST /v1/generations/{generation_id}/review — Record generation QC verdict [generate]
- PATCH /v1/generations/{generation_id}/library — Rename or tag creative [generate]
- GET /v1/generation-workflow-status — Get batch, carousel, or reusable generation status [read]
- DELETE /v1/carousels/{carousel_id} — Delete carousel group [generate]
- GET /v1/flyer-suite — Load Flyer Suite workspace [read]
- GET /v1/flyer-suite/series — List flyer series [read]
- POST /v1/flyer-suite/series — Create flyer series [generate]
- POST /v1/flyer-suite/series/{series_id}/files — File renders into a series [generate]
- POST /v1/flyer-suite/renders — Render flyer formats [generate]
- GET /v1/shares/targets — List share targets [read]
- GET /v1/shares — List object shares [read]
- POST /v1/shares — Create object share [generate]
- DELETE /v1/shares/{share_id} — Revoke object share [generate]
- GET /v1/shares/teammates — List workspace teammates [read]
- POST /v1/shares/teammates — Send creative or file to teammates [generate]
- GET /v1/shares/incoming — List shares received [read]
- GET /v1/generations/{generation_id}/lineage — Get generation lineage [read]
- GET /v1/assets/{asset_id}/review-thread — List file review thread [read]
- GET /v1/assets/{asset_id}/model-annotations — List 3D point comments [read]
- POST /v1/assets/{asset_id}/model-annotations — Add 3D point comment [generate]
- DELETE /v1/assets/{asset_id}/model-annotations/{annotation_id} — Delete 3D point comment [generate]
- GET /v1/distribution-planning — Load distribution planning workspace [read]
- POST /v1/distribution-planning/campaigns — Create distribution campaign [generate]
- POST /v1/distribution-planning/narratives — Create distribution narrative [generate]
- PATCH /v1/distribution-planning/campaigns/{campaign_id} — Update distribution campaign [generate]
- DELETE /v1/distribution-planning/campaigns/{campaign_id} — Delete distribution campaign [generate]
- POST /v1/distribution-planning/campaigns/{campaign_id}/archive — Archive distribution campaign [generate]
- POST /v1/distribution-planning/campaigns/{campaign_id}/restore — Restore distribution campaign [generate]
- PATCH /v1/distribution-planning/narratives/{narrative_id} — Update distribution narrative [generate]
- DELETE /v1/distribution-planning/narratives/{narrative_id} — Delete distribution narrative [generate]
- POST /v1/distribution-planning/assignments — Organize distribution assignment [generate]
- DELETE /v1/distribution-planning/assignments/{assignment_id}/narrative — Unassign creative from narrative [generate]
- GET /v1/distribution-planning/generation-assignments/{generation_id} — List generation assignments [read]
- GET /v1/performance/workspace — Load performance workspace [read]
- GET /v1/performance/attributes — List performance attributes [read]
- POST /v1/performance/attributes — Add performance attribute [generate]
- DELETE /v1/performance/attributes/{attribute_id} — Delete performance attribute [generate]
- GET /v1/performance/attributes/analysis — Analyze performance cohorts [read]
- GET /v1/performance/audience-balance — Assess audience balance [read]
- GET /v1/editor/media — List editor media [read]
- GET /v1/editor/projects — Load editor project [read]
- POST /v1/editor/projects — Save editor project [generate]
- POST /v1/editor/sources/resolve — Resolve editor sources [read]
- PATCH /v1/editor/asset-names — Set editor asset name [generate]
- DELETE /v1/editor/asset-names — Delete editor asset name [generate]
- POST /v1/editor/uploads — Begin editor media upload [generate]
- POST /v1/editor/uploads/confirm — Confirm editor media upload [generate]
- GET /v1/editor/exports/{export_id} — Get editor export [read]
Connect the MCP server
The Neurodance MCP v2.3.0 server uses Streamable HTTP at https://mcp.neurodance.ai/mcp. Compatible clients discover OAuth automatically, open Neurodance sign-in and request read, generate or distribute scopes. No API key is pasted into the client.
The server supports direct tools, embedded MCP Apps workflow views and a typed capability bridge. A client may show fewer tools if it does not support MCP Apps or applies its own connector curation.
- Claude.ai and Claude Desktop: Settings → Connectors → Add custom connector
- ChatGPT: Settings → Apps → Developer Mode → Create App, then choose OAuth
- Other clients: configure the remote Streamable HTTP endpoint and follow OAuth protected-resource discovery
Complete MCP tool index (86)
These are the non-legacy tools advertised by the server. Expand the interactive reference for complete descriptions, inputs, workflow, scope and safety annotations.
- upload_attachment — Save a file the host has already delivered to this tool call — an image, a reference video clip, or a reference/voiceover audio file — directly to the user's asset library. No picker, no widget. Returns media_id immediately; pass that media_id straight into reference_images on create_generation, generate_image, or create_image_carousel. Do not call list_assets afterward — the id this tool returns is already the stable one. IN CHATGPT: when the user attached a file to this message, do not describe it in `label` — the host populates the `file` argument automatically, and this tool fetches and saves it; no other input needed. IN CLAUDE.AI: there is no host-populated attachment channel and this tool cannot ingest a file already attached to the chat — do not attempt to transcribe or base64-encode a chat attachment yourself, that will not work and will stall. Call open_upload_picker instead; the user re-selects the same file in the widget, which reads it directly in the browser. media_url/media_base64 are for a caller that already possesses real file bytes or a fetchable URL outside the chat (a public HTTPS link, or an MCP client with actual local file access) — not for describing a chat attachment. Fails with code storage_limit_exceeded (error.details has used/limit bytes) when the file would exceed the workspace's plan storage limit; tell the user to free space or upgrade rather than retrying. Requires: generate scope. [generate; direct_tool]
- open_upload_picker — Open the Neurodance upload widget so the user can pick a product/style image, a reference video clip, or a reference/voiceover audio file and save it to their asset library. The widget reads the file directly in the browser, so this is the only reliable path when the file is not already usable server-side. IN CHATGPT: use this only for a local/device file the user has not yet attached, or to pick an additional/different file — if the user already attached a file to this message, call upload_attachment instead, which ingests it in one call with no picker. IN CLAUDE.AI: always use this, even for a file the user just attached to the chat — Claude.ai has no host-populated attachment channel, so upload_attachment cannot ingest it. Tell the user to select the same file again in the widget; that is the only way to get its bytes out. Requires: generate scope. [generate; direct_tool]
- list_templates — List the video ad templates available in your Neurodance account. Returns template names, IDs, and metadata. Use template IDs with create_generation. Optional filters: campaign / narrative (name or id — only templates used in that bucket) and search (matches name, description, and scene prompt text). Requires: read scope. [read; direct_tool]
- list_campaigns — List the user's Campaigns workspace hierarchy. A campaign is the top-level commercial initiative or testing bucket, with an optional optimization goal and notes. Narratives sit inside a campaign and represent audience/angle lanes; each can carry a target audience and notes. Templates, generations, and variants are assigned into this hierarchy. Call this when the user references an existing campaign or narrative by name, then pass campaign/narrative on write_template_json, rewrite_template_canvas, or create_generation to sort new work as it is created. Requires: read scope. [read; direct_tool]
- create_campaign — Create a Campaigns workspace campaign. In Neurodance, campaigns are top-level commercial/testing buckets such as a launch, product line, funnel, or experiment. They contain narratives, and narratives contain the templates/generations/variants. Use this when the user explicitly asks to create or set up a campaign. If the campaign already exists by name, this returns the existing campaign instead of duplicating it. Requires: generate scope. [generate; direct_tool]
- create_narrative — Create a narrative inside a Campaigns workspace campaign. In Neurodance, a narrative is an angle/audience lane within one campaign, for example 'Founder pain', 'Cost objection', or 'Enterprise proof'. Narratives can carry a target audience and notes, and templates, generations, and variants are sorted under them. Use this when the user explicitly asks to create a narrative or define campaign lanes. If the narrative already exists in the campaign by name, this returns the existing narrative instead of duplicating it. Requires: generate scope. [generate; direct_tool]
- get_template — Get details of a specific template by ID. Requires: read scope. [read; direct_tool]
- list_cuts — List cuts: templates that host several other templates combined into one final assembled video. A cut's host_template_id is a normal template you can pass to get_template_canvas, editor.media.list, create_generation, etc. — a cut only changes which generations the editor offers, not how the host template itself is generated. Requires: read scope. [read; direct_tool]
- get_cut — Get one cut's member templates in running order, with the starred (winning) one flagged. Requires: read scope. [read; direct_tool]
- list_brands — List the brands in your workspace, each with its identity color and color palette. Read a brand's kit with get_brand_kit before generating so the ad matches its identity. Requires: read scope. [read; direct_tool]
- get_brand_kit — Get one brand's full kit: palette, named characters, and every kit asset (logo, style_reference, character, product_shot, font, audio) with a signed, fetchable url. Read this before generating for a brand so references, colors, and characters stay consistent with its identity. Editing the kit is not supported here. Requires: read scope. [read; direct_tool]
- get_template_canvas — Load the editable canvas for a template, including node ids, prompts, narrative roles, stored variation counts, and testable nodes. The node summaries include reference_images; ['product'] means the node should use generation-level product references. Start here before editing the canvas, creating canvas variations, previewing test plans, or generating from an edited template. Some older canvases may show generic roles such as Scene; that is valid canvas state. For variations, pass the node_id and variation_axis to create_canvas_variation and let the backend resolve the node's effective role from canvas context. Recommended workflow: get_template_canvas → rewrite_template_canvas (bulk edit the full manifest for an existing template) → get_template_canvas again to verify → create_generation or run_test_plan. Requires: read scope. [read; direct_tool]
- write_template_json — Create a NEW video ad template instantly from a complete video-manifest-v1 payload that YOU, the MCP agent, have already generated as JSON. This tool directly inserts the caller's template row; it does not call any queued builder. For a user's request to make a new template, use this tool once with no template_id. Do NOT use list_templates to find an existing template unless the user explicitly asked to edit an existing template. For bulk edits to an existing template, use rewrite_template_canvas instead; it requires template_id and preserves builder-owned metadata and stored variants for stable node ids. Manifest shape: { templateName, segments: [{ id: 'video1', promptText, duration (1-15), usesProductReference?, nodes: [{ id, promptText, duration (1-15), narrativeRole }] }] }. Every node narrativeRole must be one of the app component names: Hook, Problem, Demo, Proof, Social proof, Transformation, Objection, CTA. The server stores node labels as those canonical component names; do not invent custom component names. Set segments[].usesProductReference=true on every segment that should use the product image supplied to create_generation. Do not replace product details with {{product_name}} or {{cta_url}} placeholders; use literal creative prompts and blueprintSummary for narrative metadata. Include blueprintSummary (product, audience, whyCare, cta, duration) when you want the app's Narrative/Goal/CTA panel populated. Node durations must sum to a 15s multiple (15-120). DURATION EQUATIONS (server-enforced): for every segment, segment.duration MUST equal the sum of that segment's nodes[].duration; totalDurationSeconds MUST equal the sum of all segments[].duration. Example: three 5s nodes require one segment with duration: 15, never duration: 5. A mismatch is rejected and must never be sent to create_generation. SEGMENTATION: a segment is ONE Seedance provider call of up to 15 seconds, and its nodes are the internal cuts of that call. Group beats into 15-second segments — a 15s ad is ONE segment with 2-4 nodes; a 30s ad is TWO 15s segments. Never emit one short segment per beat (eight 4s segments instead of two 15s ones): each segment generates as a separate clip conditioned on the first, which degrades quality. The server packs over-segmented manifests automatically, but authoring correct 15s segments is strongly preferred. PROMPTTEXT CONTRACT (server-enforced by a deterministic realism lint; violations return a 400 with per-finding remediations — fix and retry): every promptText must OPEN with a physical capture anchor — what camera and where it physically is (e.g. 'Vertical phone video filmed by a friend across the counter', 'Handheld documentary footage on the rig deck', 'Locked-off studio macro shot'). Name ONE practical light source ('grey overcast daylight', 'warm tungsten practicals') and never style words — banned vocabulary includes: cinematic, photorealistic, dramatic lighting, stunning, 8K, vibrant colors, golden glow. Stage any subject — fantastical ones included — as the closest shot a real crew could film: reframe the camera, never drop the idea. Keep faces mid-distance or partially occluded unless the capture anchor is phone/UGC. Specify the soundscape in every prompt (one ambient bed grounded in the scene, plus the exact spoken line with speaker or explicitly 'no speech'). Do NOT request any on-screen text, captions, titles, subtitles, or overlays — rendered text never looks right; deliver messaging through voiceover instead. Restate persistent state in every cut (product color/variant, wardrobe, worn props). For product/UGC ads: keep the product in the real scene, held or used (never floating/rotating on a plain, seamless, gradient, or blurred backdrop, and no display-only beat); keep its real container and form (a rigid box does not tear open like a packet); keep any device off/dim/out-of-focus (screen content renders as gibberish); keep the brand only on the hero product; and for UGC keep eyelines and dialogue to who is actually in frame (one or more presenters both fine). Avoid beauty/skin tells (flawless/glowing skin, ring light) — write real skin under flat light. Soft findings are returned as realism_warnings on success. Requires: generate scope. [generate; direct_tool]
- rewrite_template_canvas — Bulk edit an existing template by replacing its canvas with a complete video-manifest-v1 manifest. This is the preferred MCP editing path after a template has been created by start_template/write_template_json: call get_template_canvas first, keep stable node ids where you want stored variants and scene metadata preserved, include blueprintSummary to update the app's Narrative/Goal/CTA panel, then call get_template_canvas again to verify. The MCP agent must provide the full edited manifest JSON directly; this tool does not call a queued builder. Every node narrativeRole must be a canonical app component name: Hook, Problem, Demo, Proof, Social proof, Transformation, Objection, CTA. When the user asks to add/use product references on nodes, set segments[].usesProductReference=true for each product-visible segment so the rebuilt canvas has reference_images ['product']; do not invent template variables like {{product_name}} or {{cta_url}}. Unlike write_template_json, this requires template_id and preserves builder-owned fields such as agent instructions/model, activation state, examples, guide, and stored variants for node ids that still exist. It prunes scene-block metadata for deleted node ids. Use create_canvas_variation for single-node test variants instead of rewriting the whole template. Keep segments at 15 seconds with beats as internal nodes (a 30s ad is two 15s segments, not eight thin ones); the server packs over-segmented manifests but correct segmentation is preferred. PROMPTTEXT CONTRACT: any promptText you add or modify must follow the same server-enforced realism lint as write_template_json — open with a physical capture anchor (what camera, where it physically is), one named practical light source, no banned style vocabulary (cinematic, photorealistic, dramatic lighting, 8K, vibrant colors, golden glow, ...), a specified soundscape (ambient bed + exact spoken line or 'no speech'), NO on-screen text/captions/overlays of any kind, and persistent state (product color, wardrobe, props) restated per cut. For product/UGC: product stays in the real scene held or used (never isolated on a plain/blurred backdrop, no display-only beat), keeps its real form, devices off/out-of-focus, brand on the hero product only, UGC eyelines/dialogue matched to who is in frame, and no beauty/skin tells (flawless/glowing skin, ring light). Violations return a 400 with per-finding remediations — fix and retry. Prompts you pass through UNCHANGED from get_template_canvas are grandfathered and reported as non-blocking realism_warnings instead. Requires: generate scope. [generate; direct_tool]
- rebuild_segment — Regenerate one template segment's execution prompt into a single coherent Seedance scene, without redoing the rest of the template. Use this after editing a segment's node-level beats (e.g. with refine_node_prompt_detail) when you want the server's builder AI to recompose them into one filmable instruction, rather than authoring segments[].promptText yourself with rewrite_template_canvas. Preserves every other segment/node id, duration, and prompt exactly. Free — no token cost. Requires: generate scope. [generate; direct_tool]
- get_template_history — List a template's canvas snapshots, newest first. A snapshot is taken automatically whenever an AI regeneration replaces the canvas — including rewrite_template_canvas and rebuild_segment — so you can see what changed and restore an earlier one with restore_template_version. Requires: read scope. [read; direct_tool]
- restore_template_version — Put an earlier canvas snapshot back as the template's current canvas. The canvas being replaced is snapshotted first, so a restore can always be undone with another restore. Call get_template_history first to find the version_id. Requires: generate scope. [generate; direct_tool]
- start_template — Start a new template by asking the user the five blueprint questions yourself (product, main benefit, call-to-action, ad format, duration), then generate a complete video-manifest-v1 payload and call write_template_json with no template_id to save it. Requires: generate scope. [generate; direct_tool]
- create_generation — Submit a new video ad generation job. Provide a template, product name, and product description. Optionally attach reference media (product photos, style references, or a completed generation to reuse) — pass whatever id the source tool returned as media_id; Neurodance resolves it to a fresh URL server-side. Use this only after the canvas is already ready and verified. If you manually changed nodes or edges, call get_template_canvas again before generating so you confirm the final canvas state. If you want to test node-level variations, create them on the canvas first and use preview_test_plan/run_test_plan. Do not use this tool to invent variations after the fact. See the video_model and video_resolution field descriptions for per-model tier, pricing, and reference/first-frame requirements. Product/style reference_images are prompt context and do not count as Kling's required first frame. Returns a job_id immediately. Use wait_for_job to wait for completion (takes 2–10 minutes for video). Check get_account first to confirm you have enough tokens. PREFER A REFERENCE IMAGE: if the user has not already provided or uploaded one, ask whether they want to attach a product/style reference and, if so, call upload_attachment (ChatGPT: a file already attached to this message) or open_upload_picker (a local/device file, and the only working path on Claude.ai even for an already-attached file) and wait for the upload to complete BEFORE submitting this job. Only submit without a reference when the user explicitly confirms they don't want one. This advice does not apply to minimax-h3-max, which accept no reference media at all — submit those without one. Requires: generate scope. [generate; direct_tool]
- edit_generation — Whole-clip edit: cut a window out of a COMPLETED video generation's actual rendered footage and send that footage — not a from-scratch composition — to the provider's edit route with a change instruction. Use this to iterate on a finished ad (e.g. 'make the lighting warmer in the first 5 seconds') without regenerating the whole clip. Only Seedance 2.5 (the control generation's own video model) supports this. Pass the window you want edited as crop_start_seconds/crop_end_seconds measured from the start of the control's output; the server derives the actual padded provider window at execution time — pass your best estimate of the intended range, not a pre-padded one. The window must lie inside the control's rendered length: the server measures that length before queueing and rejects a range past the end with an error stating it. The edit renders at the control's own resolution and is billed on the replaced window (its source and result seconds) at that resolution's edit rate. Returns a job_id immediately. Use wait_for_job to wait for completion. Requires: generate scope. [generate; direct_tool]
- list_assets — Browse the product images, reference videos, and reference/voiceover audio saved in the user's asset library — the same files shown on the Assets page in the app. Use this only to discover a pre-existing file the user refers to without an id, or to browse their library; it is never required after upload_attachment, open_upload_picker, or a completed generation, all of which already return an id that plugs directly into reference_images[].media_id. Filter with campaign (one campaign's asset library) or scope=general (references not filed into any campaign). Requires: read scope. [read; direct_tool]
- list_generations — List the user's past generations, newest first. Returns id, product_name, status, job_id, has_media/media_kind (no URLs — call get_generation on one id to actually see it), ad_format, template_id, video_model, created_at, and tokens_used. Use this to find a previous generation to distribute, re-run, reference, or anchor a later run_test_plan variation. Never ask the user to paste IDs; inspect this list and choose the matching generation yourself, asking a plain-language clarification only if ambiguous. Requires: read scope. [read; direct_tool]
- generate_image — Submit an AI image generation job and return the job_id immediately. Unlike create_generation (which makes a video ad), this produces a still image. For image carousels that need previous-slide visual continuity, call this sequentially: wait for slide N, then pass its job_id as reference_images[].media_id for slide N+1. For batch carousels whose references are already known, prefer create_image_carousel. After calling this tool, ALWAYS call wait_for_job with the returned job_id — wait_for_job will return the image inline in the chat window once it's ready. Do NOT call generate_image again while waiting — that wastes tokens by creating duplicate jobs. Provide your product name, a description of what to generate, and optional reference media (product photos, style refs, or a prior generation to reuse). PREFER A REFERENCE IMAGE: if the user has not already provided or uploaded one, ask whether they want to attach a product/style reference and, if so, call upload_attachment (ChatGPT: a file already attached to this message) or open_upload_picker (a local/device file, and the only working path on Claude.ai even for an already-attached file) and wait for the upload to complete BEFORE submitting this job; only submit without one on explicit confirmation. Costs 0.5 tokens per image. Check get_account first to confirm you have enough tokens. Requires: generate scope. [generate; direct_tool]
- create_image_carousel — Create an ordered image carousel by submitting 2-10 still-image generation jobs as one group. Use this when the user asks for a carousel, swipe-through ad, multi-card image concept, or Meta/Instagram carousel creative and the card prompts/references are already known. The agent must write the individual image prompt for every card in product_features; the backend does not infer a story arc or know that 'slide 3' should say anything specific. Each card becomes an ordinary image generation with shared carousel_group_id metadata; after every returned job_id is complete, publish with create_distribution using post_type=carousel, generation_id set to the first card, and carousel_generation_ids set to the completed generation ids in order. Instagram carousel publishing requires 2-10 completed image generations. Meta Ads can also use the same ordered ids for a carousel creative, alongside its normal campaign/ad set/targeting/copy fields. If slide-to-slide visual consistency depends on the previous generated slide, create the cards sequentially with generate_image instead: wait for each slide, then pass its job_id as reference_images[].media_id for the next slide. Call wait_for_jobs with every returned job_id and do not create duplicate carousel jobs while waiting. Each card is one image generation costing 0.5 tokens, so a carousel costs 0.5 tokens per card. Requires: generate scope. [generate; direct_tool]
- upload_reference_image — App-internal upload transport used by the open_upload_picker widget — not for a model to call directly. A model-facing caller should use upload_attachment for a file already attached to the chat, or open_upload_picker for a local/device file. Saves an image, reference video clip, or reference/voiceover audio file permanently to the user's asset library and returns its media_id immediately. HOW TO PROVIDE THE FILE — choose one path: • media_url: public HTTPS URLs, fetched server-side. • media_base64: raw file bytes, for files up to ~5 MB raw. Accepted image formats: JPEG, PNG, WebP, GIF (max 20 MB via media_url). Accepted video formats: MP4, MOV, WebM (max 500 MB via media_url). Accepted audio formats: MP3, M4A, AAC, WAV, OGG (max 100 MB via media_url). Readable images must be at least 300x300px. Requires: generate scope. [generate; direct_tool]
- create_canvas_variation — Create a pre-generation variation on a specific canvas node inside a template. This is the correct workflow for testing hooks/tones/CTAs: load the canvas, pick a node_id, choose a variation_axis, create one or more variations, preview the test plan, then run the test plan. You normally do not need to pass narrative_role; the backend resolves the effective role from the canvas, scene-block metadata, prompt, and node position, so older generic Scene roles do not block variation testing. By default the variant is saved onto the template's scene-block state for later testing. Costs 0.05 tokens per call, charged whether or not you keep the variant. Requires: generate scope. [generate; direct_tool]
- enhance_node_prompt — Expand a rough one-line idea into a production-ready generation prompt for a single canvas node, with a suggested narrative role and (for video) duration. Free, stateless — does not read or write a template. Use this to draft a node's prompt before calling write_template_json or rewrite_template_canvas; it does not save anything itself. Requires: generate scope. [generate; direct_tool]
- rewrite_node_prompt — Free mode: weave a dragged/attached reference's usage into one canvas node's EXISTING prompt in concrete visual terms, preserving everything else — this is what makes attaching a reference actually change the generated result instead of being cosmetic. Stateless — does not read or write a template; write the returned prompt onto the node yourself with rewrite_template_canvas. For any other targeted edit not driven by a reference (e.g. 'make the lighting warmer'), use refine_node_prompt_detail instead. Requires: generate scope. [generate; direct_tool]
- refine_node_prompt_detail — Paid mode: surgically rewrite one canvas node's EXISTING prompt to apply a specific requested change, preserving everything the change does not touch. Costs 0.05 tokens per call. Stateless — does not read or write a template; write the returned prompt onto the node yourself with rewrite_template_canvas. For incorporating a dragged/attached reference specifically, use the free rewrite_node_prompt instead. Requires: generate scope. [generate; direct_tool]
- preview_test_plan — Preview the pre-generation test plan for a template from stored canvas variations. Returns a control plus one version per saved node variation, including the node_overrides that would be sent to generation. Use this before run_test_plan. Requires: read scope. [read; direct_tool]
- run_test_plan — Run one or more pre-generation canvas test versions for a template. This is the preferred way to test variations: upload references first if needed, preview the test plan, select version ids, then run. The tool creates one generation job per selected version and returns all job_ids together — call wait_for_jobs with all of them rather than polling one at a time. When the user asks for a variation of an ad that already exists, do not ask them for IDs: use control_strategy='auto' and either let this tool find the latest matching control generation or pass control_job_id/control_generation_id from list_generations or a previous run_test_plan result. video_model and video_resolution have the same Seedance/Kling constraints and token multipliers as create_generation. Billing: the control is a full generation, while each variant bills only the seconds it actually regenerates — the scenes its node_overrides touch — at the model's per-second rate. On Seedance 2.5 a variant also bills the control-reference seconds it sends as continuity context. Requires: generate scope. [generate; direct_tool]
- create_distribution — Distribute a completed ad generation to Instagram organic, YouTube Shorts, Meta Ads, X Organic/Ads, or TikTok Organic/Ads. The generation must have status=complete. Instagram supports captions, Reel, Story, Carousel, user/location tags, alt text, paid partnership labels, and trial Reels. YouTube supports title, description, tags, privacy, and made-for-kids. Meta Ads supports video, single image, or carousel creatives and requires explicit campaign, ad set, targeting, destination URL, primary text, and CTA fields; it will not infer creative copy or targeting. For carousel publishing, first use create_image_carousel or completed image generations, then pass post_type=carousel, generation_id as the first image, and carousel_generation_ids as the 2-10 completed image ids in display order. For Instagram or YouTube, use get_account once if you need account ids, then call create_distribution directly. For Meta Ads, ask the user for any missing campaign/ad set/budget/targeting/copy fields before calling so the trace stays clean. Returns a job_id immediately; use wait_for_job/get_job_status to track progress. Requires: distribute scope. [distribute; direct_tool]
- list_distributions — List distribution history across Instagram organic, YouTube Shorts, Meta Ads, X, and TikTok. Returns stable job_id values such as dist:ig:<id>, dist:yt:<id>, dist:meta:<id>, dist:xorg:<id>, and dist:ttads:<id>, plus raw id values for compatibility, platform ids/permalinks, generation/template metadata, publishing fields, and metrics polling error state where relevant. Requires: read scope. [read; direct_tool]
- activate_distribution — Activate a paused Meta Ads, X Ads, or TikTok Ads distribution. Pass the job_id from create_distribution or list_distributions, e.g. dist:meta:<id>, dist:xads:<id>, or dist:ttads:<id>. The provider state is re-read before the worker enables delivery. Unsupported for organic posts. Requires: distribute scope. [distribute; direct_tool]
- dismiss_distribution — Dismiss or cancel a non-active Meta Ads distribution job from public API/MCP. Pass the job_id from create_distribution or list_distributions, e.g. dist:meta:<id>. Unsupported for organic posts. Requires: distribute scope. [distribute; direct_tool]
- delete_distribution — Delete an Instagram organic post or remove a local Neurodance record for a YouTube Short. Removing a YouTube record does not delete the video from YouTube. Delete an X organic post that was created by Neurodance. Pass the job_id from list_distributions, e.g. dist:ig:<id>, dist:yt:<id>, or dist:xorg:<id>. Meta Ads deletion is intentionally not exposed here; use dismiss_distribution before activation or manage active campaigns in Meta. Requires: distribute scope. [distribute; direct_tool]
- sync_distribution — Sync one distribution against its platform to verify the remote object still exists. Supports Meta Ads, Instagram organic, and YouTube Shorts. Pass the job_id from list_distributions, e.g. dist:meta:<id>, dist:ig:<id>, or dist:yt:<id>. Requires: distribute scope. [distribute; direct_tool]
- sync_all_distributions — Sync distributions against their remote platforms and report how many were checked and how many appear missing. Supports all platforms together or one of Meta Ads, Instagram organic, and YouTube Shorts. This mirrors the app's distribution maintenance action. Returns at most one page: if next_cursor is non-null, call again with the same platform and that cursor. rate_limited=true means a provider quota stopped the page early. Requires: distribute scope. [distribute; direct_tool]
- get_metrics — Retrieve post performance metrics snapshots. By default returns the latest snapshot per post; set latest_only=false for raw paginated snapshots. Supports platform, generation_id, platform_post_id, since, and until filters. Requires: read scope. [read; direct_tool]
- get_metric_timeseries — Return the full oldest-first metrics time series for one platform post id. Use this for trend charts, debugging hourly polling, or before composing a brief. Requires: read scope. [read; direct_tool]
- compose_performance_brief — Compose and persist an AI performance brief from the latest metrics for a published post. Returns the same structured brief used by the app to re-brief the next generation, including generationRequirementsPrompt. Requires: generate scope. [generate; direct_tool]
- list_performance_briefs — List previously composed performance briefs for one platform post, newest first. Use this to retrieve re-brief history and generationRequirementsPrompt values. Requires: read scope. [read; direct_tool]
- get_job_status — Get the current status of any async job by its job_id. Works for generation, template build, variation, and distribution jobs. Status values: pending | running | complete | failed. When complete, output_url is set for generations and published organic distribution jobs. Requires: read scope. [read; direct_tool]
- get_generation_media — Fetch a completed generation's output as base64 bytes so a widget can render it inline (Claude.ai iframes block loading media from external URLs). Called automatically by the generation-result widget via tools/call; do not call this manually — for an agent, the output_url from get_job_status is what you want. Returns { media_base64, media_type, too_large } — too_large=true (no bytes) when the file exceeds the inline limit. Requires: read scope. [read; direct_tool]
- wait_for_job — Wait briefly for an async job to complete and return the final result. Each call polls every 8 seconds for about 20 seconds, then returns status=still_running if the job is not done yet. Call wait_for_job again with the same job_id until complete; never submit a duplicate generation/image/distribution while waiting. Use this after create_generation, generate_image, run_test_plan, or create_distribution to get the final result without manual polling. Requires: read scope. [read; direct_tool]
- wait_for_jobs — Wait briefly for a set of async jobs together — a carousel's cards, a test plan's variants, or any other parallel batch — instead of calling wait_for_job once per job_id. Polls every 8 seconds for about 20 seconds, then returns status=still_running for any job not done yet. Call wait_for_jobs again with the same job_ids until every job is complete or failed; never submit duplicate jobs while waiting. Requires: read scope. [read; direct_tool]
- get_account — Get your account status: token balance and every connected publishing account — Instagram Organic, YouTube Shorts, Meta Ads, X Organic, X Ads, TikTok Organic, and TikTok Ads. Check token_balance before creating generations — video jobs cost tokens based on duration, model, and resolution. If a platform is missing, open your Neurodance Settings → Connections to connect it. The accounts arrays carry the ids create_distribution needs: ig_account_id, yt_account_id, meta_account_id, and the exact connection_id for X/TikTok (plus advertiser_account_id from social_advertiser_accounts for x_ads and tiktok_ads). An X/TikTok connection whose token_status is no longer 'valid' is still listed under accounts but reports false in connected_platforms — tell the user to reconnect it rather than publishing to it. Platforms named in unavailable_platforms could not be read just now — retry get_account instead of telling the user to reconnect them. Requires: read scope. [read; direct_tool]
- get_upload_url — Generate a presigned upload URL so the browser widget can PUT a file directly to Neurodance storage in MCP hosts that allow widget network PUTs, such as ChatGPT. Claude.ai blocks external widget PUT/fetch calls; there the upload widget uses host-forwarded tools/call instead (and is limited to small files as a result — this is the only path that supports full-size video/audio uploads). Called automatically by compatible upload widgets; agents should not call this manually. Returns upload_url (PUT target) and a storage_path scoped to the resolved media kind. Refused with code storage_limit_exceeded (error.details carries used/limit bytes) when size_bytes would take the workspace past its plan's storage limit. Requires: generate scope. [generate; direct_tool]
- confirm_upload — Record an uploaded file in the user's asset library after the browser widget has PUT the file to the presigned URL from get_upload_url. Called automatically by the upload widget via tools/call; do not call this manually. Refused with code storage_limit_exceeded, and the uploaded object removed, when its real size would take the workspace past its plan's storage limit. Requires: generate scope. [generate; direct_tool]
- search_capabilities — Look up a typed Neurodance capability that is not part of the curated dedicated-tool set. mode='search' (default) returns up to 10 lightweight matches ({id, title, one_line, workflow}, no schemas) for a query and/or workflow id; if nothing matches, returns the list of real workflow ids instead of an empty result. mode='describe' takes an exact capability_id from a search result and returns its full input/output schema, scope, rate tier, and idempotency requirement. Run the chosen capability with run_capability. Requires: read scope. [read; capability_bridge]
- open_library_workspace — Open the user's generations and files as a visual grid of their actual creatives, product photos, references, and clips, with search and type filters. They can open any item and pick it as the reference for the next generation, see what is filed to a campaign, and reach what they moved to trash. Use when the user asks what they have, wants to find or reuse something, needs to choose a product reference, or is looking for something they deleted. Requires: read scope. [read; workflow_app]
- run_capability — Run one typed capability returned by search_capabilities (mode: 'describe'). Dispatch re-checks the selected capability's own required scope and rate tier, and requires a stable idempotency_key for any mutation. Not an HTTP proxy — arguments must match the capability's input_schema. [read; capability_bridge]
- workspace_search — Searches templates, generations, campaigns, and assets in the current workspace. Requires: read scope. [read; direct_tool]
- campaign_memory_list — Returns the campaign memory timeline with evidence and lifecycle state. Requires: read scope. [read; direct_tool]
- notes_list — Lists internal team notes for one tenant-owned template, asset, campaign, or generation. Requires: read scope. [read; direct_tool]
- notes_add — Adds an internal team note to one tenant-owned template, asset, campaign, or generation. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- reviews_thread_list — Returns the merged guest-feedback and internal-note review thread for one creative (generation_id) or file (asset_id). Exactly one id, never both. Requires: read scope. [read; direct_tool]
- reviews_thread_resolve — Resolves or reopens one guest-feedback or internal-note review entry. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- campaign_memory_create — Atomically records a campaign observation, insight, hypothesis, decision, outcome, or learning with evidence. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- assets_library_list — Lists tenant assets across general, campaign, folder, and media-type scopes with short-lived signed media URLs. Requires: read scope. [read; direct_tool]
- assets_library_update — Renames an asset, moves it into General, a campaign library, or a validated campaign folder, and tags what it IS as reference material (product, style, character, logo, other) or clears the tag for a plain asset. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- archive_generations_list — Lists the Generations page: terminal creatives with search, status, filing (sorted = filed to a campaign, unsorted = not), cursor paging, and performance rollups. status 'all' is what the page shows — complete, cancelled, and rejected; failed jobs are queue diagnostics and are returned only on request. Requires: read scope. [read; direct_tool]
- trash_list — Lists soft-deleted generations, assets, and templates in the current workspace. Requires: read scope. [read; direct_tool]
- archive_restore — Restores one soft-deleted asset, template, or generation in the current workspace. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- assets_folders_list — Lists the folder hierarchy for one tenant-owned campaign asset library. Requires: read scope. [read; direct_tool]
- generation_review_qc — Records a human review verdict on one tenant generation. By default the verdict is all it writes. Pass move_to_trash=true with qc_status=rejected to also move the creative to trash, which is what the app's Reject does — the verdict clears it from the review queue and the soft delete clears it from Generations, restorable from Trash. Archiving its distribution assignment only hides the output from Distribute. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- generation_workflow_status — Returns one generation batch, carousel group, or latest reusable control for a template. Requires: read scope. [read; direct_tool]
- flyer_workspace — Loads series, optional series date folders, base assets, and recent still-image generations. Requires: read scope. [read; direct_tool]
- flyer_series_create — Creates a named flyer series (a run of event dates) in the current workspace. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- flyer_series_list — Lists flyer series with their date folders. Requires: read scope. [read; direct_tool]
- flyer_series_files_create — Files completed render outputs into a series date folder — all-or-nothing, idempotent per operation. Each filed copy counts toward workspace storage; refused with 402 storage_limit_exceeded when the copies would exceed the limit. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- flyer_renders_create — Renders a flat-image master flyer into delivery formats — one paused render job per event row × format, polled via /v1/jobs. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- sharing_list — Lists live workspace and public-link shares for one tenant-owned entity. Requires: read scope. [read; direct_tool]
- sharing_create — Creates a member-workspace share or public view link with optional password, expiry, download, and upload controls. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- generation_lineage_get — Returns ancestry, descendants, campaign filing, posts, performance rollup, and creative-loop briefs. Requires: read scope. [read; direct_tool]
- distribution_planning_workspace — Loads campaigns, narratives, assignments, templates, and assigned generations for planning. Requires: read scope. [read; direct_tool]
- distribution_assignment_upsert — Atomically creates or updates a tenant creative assignment within a campaign or narrative. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- performance_workspace — Loads generation rollups, recent metric snapshots, and distribution status for analysis. Requires: read scope. [read; direct_tool]
- performance_attributes_list — Lists workspace-defined creative attribute cohorts. Requires: read scope. [read; direct_tool]
- performance_attributes_add — Adds a phrase used to compare a creative cohort with the workspace baseline. Pass a stable idempotency_key; reuse it after a lost response. Requires: generate scope. [generate; direct_tool]
- performance_attributes_analyze — Compares median completion and engagement for every saved attribute against the workspace baseline. Requires: read scope. [read; direct_tool]
- performance_audience_balance — Computes an observational Instagram audience-balance diagnostic without claiming randomization or significance. Requires: read scope. [read; direct_tool]
- editor_media_list — Lists editor uploads, paged completed generation sources, node clips, and shared custom names. Requires: read scope. [read; direct_tool]
- editor_project_load — Loads a tenant project and its current immutable timeline revision. Requires: read scope. [read; direct_tool]
- get_media_preview — Fetch inline bytes for up to 12 tenant-owned generations or assets so a workspace app can render real thumbnails and video inside the chat client (host iframes block loading media from storage URLs). Called by the workspace apps via tools/call — an agent that wants to see one generation should call get_generation instead, which returns a real image the model can read. Each item returns media_base64 + media_type, or skipped (too_large / batch_full / unavailable / video) when it wasn't inlined. Requires: read scope. [read; direct_tool]
- get_generation — See one generation: returns a real inline image the model can look at (a ~512px preview, not the full-resolution original), plus its status, product name, and a link to the full-resolution output. For a video generation the image is a poster frame — the response also includes a resource_link to the video itself, which this tool never inlines. Use this after list_generations to actually judge a specific result rather than just reading its status. Requires: read scope. [read; direct_tool]
Rate limits and errors
Current per-credential, per-workspace limits are 120 reads per minute, 60 creative writes per minute, 10 external writes per minute and 10 credential writes per minute. Follow Retry-After after a 429 and use exponential backoff with jitter for transient failures.
Errors provide a stable machine-readable type, human message, remediation when available, documentation URL and request ID. Integrations should branch on the error type rather than message text.
