Developers

MCP server: drive Pamba from Claude Code, Codex or any MCP client

Connect an MCP client to your workspace, pick the toolsets you need, and learn how calls, credits, waits, approvals and hand-offs behave before you automate anything.

Pamba's MCP server exposes every tool the in-app assistant has, over the Model Context Protocol, at one endpoint: https://api.pamba.app/mcp. Your client's model gets the same product knowledge the assistant runs on, so it can chain the tools into whole workflows (research a format, build the avatar, create the projects, generate, schedule) without you translating screens into API calls. This guide covers what the reference cannot: how the surface is cut, how a call behaves, what waits, what costs credits, and the ordering rules that trip people up. The exact tool list, with every parameter, is the MCP tool reference.

Connect

  • Endpoint: https://api.pamba.app/mcp, Streamable HTTP, one JSON-RPC message per POST.
  • Credential: an X-API-Key header with a workspace API key. Create one in workspace settings (open the workspace switcher, then Settings, then API keys); the secret is shown once. A key belongs to exactly one workspace and every call runs there; sending an X-Workspace-Id header that names a different workspace is refused. To work in another workspace, connect with that workspace's key. Three tools act on the person behind the key rather than the connected workspace, because that is what they do in the app too: delete_workspace accepts any workspace the person administers, and list_api_keys and revoke_api_key cover their keys in every workspace. The instructions tell the model to confirm with the person before the destructive two. An Authorization: Bearer <JWT> plus X-Workspace-Id header works too, the same way it does on the REST API.

Claude Code:

claude mcp add --transport http pamba https://api.pamba.app/mcp --header "X-API-Key: <your workspace API key>"

Codex (~/.codex/config.toml or the project's .codex/config.toml):

[mcp_servers.pamba]
url = "https://api.pamba.app/mcp"
http_headers = { "X-API-Key" = "<your workspace API key>" }

Any client that takes a JSON server list:

{
  "mcpServers": {
    "pamba": {
      "type": "http",
      "url": "https://api.pamba.app/mcp",
      "headers": { "X-API-Key": "<your workspace API key>" }
    }
  }
}

Once connected, ask the model "What can you do with Pamba?": the answer comes from the product map the server sends at connection, not from guesses.

Choose how much of the surface to load

The full surface is about three hundred tools. Most clients work best with fewer in context, and a script that only reads analytics has no reason to see the tools that spend money. Three switches on the endpoint URL shape a connection: two cut the surface, one caps spend.

  • ?toolsets=videos,avatars loads only the named toolsets. The names: videos (create, generate, replicate, drafts, scheduling, campaigns, the avatar wizard, and list_avatars, because every project starts from an avatar id), editing (the editor: concepts, takes, renders, text hooks, captions, model switches), avatars (appearance, voices, scene libraries, image editing), accounts (the account fleet, seats and billing, profile edits, warming, health, individual scheduled posts), ideas (the ideas library and tracked inspiration accounts), discover (the viral corpus, niche feed, trends, the source picker), content (script batches, the review desk, knowledge base, writer engine, learning loop), automation (campaign strategy and content plans), workspace (settings, members, onboarding, billing and credits, the media library, API keys, help, support).
  • ?readonly=true loads only read-only tools. A tool outside the connection's scope is unknown to it, so this is a guard, not a hint: a read-only connection cannot be talked into a write.
  • ?max_credits=500 refuses any single credit-spending call whose up-front estimate is above five hundred credits, or that cannot be estimated, with status: spend_limit_exceeded and nothing charged. It is a gate on the estimate, not a meter on the charge: the estimate is what the tool would charge on its first attempt, and a tool's own retries and model fallbacks follow its usual accounting once it runs. The in-app assistant's per-turn spend tripwire does not apply over MCP, so an autonomous client without a ceiling has only the workspace's balance as a brake.

Combine them: https://api.pamba.app/mcp?toolsets=accounts,videos&readonly=true. A toolset name the server does not know is refused at connection time with the list of known names, and so is a toolsets value that names nothing, so a typo or an empty computed list shows up in your client's connection error rather than as a silently widened surface.

Every tool is annotated. readOnlyHint is true on reads; everything else carries destructiveHint, which is what clients such as Claude Code use to decide when to ask you before a call. The description of every tool that spends credits ends with its cost basis.

What else the client receives

  • Instructions. The initialize response carries the transport rules below, the connected workspace's name, niche and website, and the assistant's full product map. Clients inject this into the model's context, which is why the model knows the order of operations without you explaining it.
  • Prompts. Four golden-path workflows, listed as prompts (Claude Code shows them as slash commands): first_video, replicate_tiktok, new_avatar, performance_review. Each is the tool chain the assistant runs for that goal, with the waits and the spend points named. A connection only lists the prompts whose every tool is inside its scope, so a read-only or narrowed connection is not offered a workflow it cannot run.
  • Resources. Every help-center article, including this one and the tool reference, as pamba://help/<slug> in markdown. The model can read them on demand, and clients that let you attach resources let you drop an article into the conversation.

How a call behaves

  • Nothing waits for your approval on Pamba's side. In the app, the assistant parks writes and credit spends on a confirmation card, and a turn that accumulates about eight hundred credits of estimated spend parks too. Over MCP there is no card and no per-turn tripwire: a write or credit-spending tool runs the moment the client sends it. Your client's own permission prompt is the safety net, so keep it on for anything that is not read-only, connect with readonly=true for exploration, and set max_credits on a connection an autonomous agent drives. Two server-side refusals remain: affordability, where a spend the workspace cannot cover is refused before anything runs with status: insufficient_credits, the credits required and the credits remaining; and the connection's ceiling, where a call estimated above max_credits is refused with status: spend_limit_exceeded. Neither charges anything.
  • Results are JSON objects, in both the text content and structuredContent. A status field carries the outcome. Success reads ok, created, updated, saved, deleted, scheduled and similar. not_found means no such object in this workspace. invalid_id means an id was not a UUID from the matching list tool. Other invalid_* statuses name a rejected field, and message says why. insufficient_credits, payment_required (a paid plan is required), forbidden (the caller's workspace role is too low, for example a member trying an admins-only setting, or an operator-only tool), busy, queue_full, work_in_flight and automation_running (work in flight, wait for it) and error (the operation failed unexpectedly) are refusals. message is written to be relayed to a person. A next field, when present, names the follow-up call.
  • Refusals are results, not protocol errors. Only status: error sets MCP's isError flag. A JSON-RPC error comes back for protocol problems only: an unknown tool or one outside the scope, arguments that do not fit the input schema, an unknown method, malformed JSON.
  • Never retry a failed or lost call blindly. A tool may have completed part of its work (a charge, a scheduled row) before it failed, which is why status: error carries a generic line rather than the internal cause. A call your client abandons or times out is not cancelled either: it runs to completion on the server and its answer is simply lost. The assistant is told to report and stop; give your own automation the same rule, read the matching status tool after a lost answer, and retry only once the cause named in message is fixed.
  • Arguments. Omit an optional argument to leave it unset; do not send an empty string in its place unless the tool says an empty string clears the field (the company profile fields do). Every argument is checked against the tool's input schema before anything runs, and every refusal names the argument: a name the tool does not declare is refused with the accepted names, a missing or null required argument is refused, a whole-number parameter takes a JSON integer or an integral numeric string and refuses a fraction, a boolean takes true or false, a string must be a JSON string, and a parameter with listed choices refuses a value outside them. A typo therefore never runs the tool with a default in place of your value. Ids are UUIDs; take them from the matching list tool and pass them back verbatim. An avatar is addressed by its avatar project id: list_avatars returns both id and avatar_project_id, and almost every other tool wants the latter. Dates are YYYY-MM-DD. Scheduling tools take a precise ISO-8601 time in UTC (2026-12-25T14:00:00Z) or a date-only value that auto-picks a time in the posting window. The workspace timezone (update_workspace_settings) is the clock for posting windows and campaign schedules.
  • Lists are truncated, not paged. Most list tools return the full count alongside a fixed-size slice and no cursor: list_projects forty (archived excluded unless include_archived=true), list_scheduled_posts and list_accounts two hundred, list_workspaces twenty, list_scene_frames one hundred, list_video_generations forty clips with ten takes each, or twenty-five takes when asked for one clip, list_creative_concepts twenty versions. Narrow with the tool's filters rather than expecting a next page. The exceptions that do page or take a limit: list_ideas and search_tracked_videos (page, twenty-five per page), the Discover tools (page, twenty per page), browse_picker_videos (page, twenty-four per page), list_assets (limit and offset), get_studio_overview (limit up to two hundred).
  • Result size. get_project returns the complete editor state and get_content_batch the whole batch. Read the narrower tools (list_projects, get_render_job, list_video_generations) when you only need a status.
  • URLs you pass in are fetched from Pamba's servers. Public http(s) only; anything resolving to a private or loopback address is refused, and redirects are re-checked.
  • Conversation id. get_conversation_info returns mcp as the conversation id because there is no chat transcript over this transport. The workspace id it returns is what support needs.

Waiting for work

Most tools that produce media are asynchronous: the tool returns at once with a status, and the work finishes in the background over minutes. Poll the matching read tool about once a minute, and do not re-trigger the same work while a status reads pending, queued, generating, building, rendering or applying; a second call either reuses the live job or is refused.

  • Clips and videos: get_project and list_video_generations. A failed clip generation retries itself up to three times, including an AI reword of the script after a content refusal, and falls back to the more permissive Grok Imagine model when the chosen model's safety filter still blocks it (the clip's video_model_fallback_from records the blocked model, and the clip's model preference then follows the fallback). So a clip can sit in generating for several minutes before it completes or fails for good. A project stays "generating" through the editing pass, captions, render and text hook, not just until the first clip lands.
  • Drafts and replications: get_replication_status (build step, failure kind, whether a retry applies). A review-queue item with building: true is a draft still writing its concept, frames and script; do not generate or edit it until that clears.
  • Renders: get_render_job, and render_state on the project (none, current, dirty, rendering, failed). Renders are never cancelled: an in-flight one settles and the next render supersedes stale output.
  • Avatars: get_avatar_wizard for the wizard, get_avatar_generation and list_avatar_generations for redesigns, voices and scene jobs.
  • Accounts: list_accounts shows a purchased seat's setup progress until the account is ready and get_seat_billing each seat's state; list_account_profile_edits tracks profile edits and get_account_link_status a link. These run on Pamba-managed phones; a profile edit takes about two minutes and a creation longer.
  • Onboarding jobs: get_onboarding_state (media_capture_status, the presenter match, the avatar job).

A few tools block instead, for up to minutes, and return the finished result: create_avatar, update_wizard_appearance, generate_wizard_scenes, generate_avatar_voices, redesign_avatar, render_project, and update_account_profile when it edits a TikTok profile. Give them a generous client timeout.

Credits, plans and money

  • Metered operations consume credits: video generation per second at the clip model's rate (roughly sixteen credits a second on Grok Imagine, twenty-two on Gemini Omni, fifty-three on Seedance, rounded up per clip; get_credit_pricing is the live list), avatar photos, scenes and variations at fifteen credits an image, replication frames at about eighteen (generation plus a realism pass), premium voice clones at one thousand five hundred, clip transcription for captions at about two credits per minute of video (repeat calls served from cache), content-engine script runs, and Ideas script generation by tokens. Basic voices are free. get_credit_balance is the balance, and reads unlimited rather than a number for internal accounts.
  • Charging is reserve-then-charge. Credits are reserved when work starts, the charge commits only on success, and a failed generation is never charged. A reservation holds for up to two hours and reduces the reported balance meanwhile, so a balance can look low while work is in flight.
  • The affordability refusal is skipped for a project that already has live video work, so a repeat "generate it" reads the tool's own in-flight answer instead of a false shortfall.
  • A new workspace starts with a signup grant of three hundred credits and its first avatar is free (photo, scenes, basic voice). Three hundred is below a typical first video (a twenty-five to thirty-five second concept runs about four to five hundred credits), so a first generate_video without a plan or top-up usually answers insufficient_credits. A workspace you add with create_workspace starts at zero.
  • Top-ups come in units of one thousand credits, one to twenty units per purchase, and are available to subscribed workspaces only; create_topup_checkout_session returns the Stripe link. Plans: get_credit_plans (yearly plans grant twelve times the monthly credits up front), then create_checkout_session with the plan's price_id; for a workspace that already subscribes, the link is Stripe's confirm page showing the prorated amount, and confirming changes the plan in place. Downgrading a yearly plan is refused and goes through support. create_billing_portal_session opens subscription management; a cancellation there takes effect at the period end, and access lasts until then. Every one of these returns a URL a person completes in a browser; the purchase lands on the workspace when the payment settles, so re-read get_credit_balance or get_seat_billing afterwards.
  • Purchases need the caller to be a billing admin of the workspace; other members get forbidden.
  • A paid-plan gate returns payment_required: inspiration accounts, ideas and Discover details require an active subscription (a credit plan or account seats), and enabling or firing a campaign requires an active subscription on the workspace owner. Discover shows free workspaces the first rows and blurs the rest; create_video_project with an idea_description has no such gate.
  • Booking a call with the Pamba team at pamba.app/book-a-call earns twenty dollars of credits, added by the team after the call.

What needs a browser or a phone

  • Checkout. Every purchase is a Stripe URL the person opens.
  • Files. Tools take public http(s) URLs, never an upload body. upload_asset stores a URL in the media library (png, jpeg, webp, gif, mp4, quicktime, webm, mp3); avatar and scene tools take image URLs. The library holds up to thirty image and video files (audio does not count) and answers library_full until one is deleted. Asset URLs the tools return are signed and expire within twelve hours: never store one in editor state.
  • Visual judgment. Watching generated footage and comparing scene images is the person's call. Hand over the URLs the tools return.
  • Accounts. TikTok, Instagram and Facebook accounts are created, edited and posted from on Pamba-managed iPhones by background device jobs. The client never touches a phone; it schedules the job and polls.

Ordering and nuance, by area

These are the rules the assistant follows and the ones people most often get wrong when driving the tools directly.

Projects and generation
  • Two ways to start a project with an avatar: create_video_project with script (spoken verbatim) or with idea_description (a fresh script is written on every call, so fanning one idea across avatars gives each a distinct script; never copy one generated script to several avatars). Passing both or neither is invalid_request; a script run that fails is generation_failed, and rephrasing the idea usually fixes it. promotional=false writes a non-promotional script with no brand weaving. Creation costs nothing; generate_video is the spend.
  • The project returns before its concept exists. A background job writes the script split, the default scene and the title within a minute or so; while it runs, review-queue items show building: true and get_project reports the concept as none. A failed build marks the project failed rather than shipping an empty draft.
  • The clip split is automatic, on natural speech boundaries, with durations the project's video model allows. Non-automated creations also pick a default scene automatically from the avatar's labeled library scenes, at random among those that fit the script, so two creates from the same script can differ; when nothing fits, a random face-visible library scene stands in. Override frames only when a specific look is wanted. preview_script_clips shows a split without saving anything.
  • Authoring and generating are separate steps. Changing frames, scenes, script, concept or timeline is complete when saved; rendering or generating is a further, explicit request. The assistant is told never to queue a spend to "finish" an edit, and a script that drives the tools should not either.
  • A project can exist without an avatar: create_draft_project with no avatar plus set_edited_video turns a ready-made video into a postable project. The avatar stays unassigned forever; it cannot be added later.
  • Video models: grok-imagine-1.5, seedance, gemini-omni. The default resolves in this order: the project's explicit model, the campaign's per-member model, the avatar's default_video_model, the workspace routing rules, then Gemini Omni. set_video_model switches drafts and projects in bulk and re-splits the stored script under the new model's limits (skipped when every duration is already legal, because a re-split mints new clip rows). Gemini Omni authors clips of four to ten seconds, the extended models four to fifteen; every model shares the four-second floor, and a concept save with a clip outside its model's range is refused whole.
  • get_project uses sentinel strings: concept and editor_state_json read none until they exist, final_video_duration_seconds reads unknown until the file is probed, and generated_at stays empty until every clip has a generated video. Prefer the measured duration over summing clip durations, which are the plan. promotional reads true, false or not_applicable (verbatim scripts decide nothing).
  • update_project changes only the fields passed: name, notes, user_review_state (not_reviewed or approved), posted_state, user_visibility. Archiving also cancels the project's pending posts. list_projects with posted_only means the project actually went live, which posted_state alone does not tell you (a cross-post downgrades a live project to scheduled, and cancelling a pending post resets it to approved).
  • Approving or scheduling is refused with a conflict while the video is still generating, with one exception: clips in their final 60fps upscaling pass (the take is already playable: active_generation_status is null while preview_video_url is set) do not block; approve or schedule, and the automatic render waits for the upscaled files before anything posts.
  • generate_clips takes optional zero-based clip_indices; on a clip in that upscaling pass it replaces the take: a fresh take starts, the superseded pass finishes and parks in the clip's take history (billed like any completed take, revertable with select_clip_video). A clip still producing its take keeps that generation. keep_raw_voice=true keeps the model's own audio and skips the avatar voice dub and the speech trim.
  • Refusals from the clip-starting tools: insufficient_credits, automation_active (a pipeline owns the project), queue_full (try again in a few minutes), work_in_flight (a draft still building, or clips, an edit or a render from a previous generate still running). A pipeline stamp older than two hours is treated as dead, so a crashed run cannot lock a project out forever.
  • duplicate_project clones a shell (concept and frames, no script, clips or videos); duplicate_project_full clones an exact independent copy, nothing re-billed. Neither carries scheduled posts, approval state or in-flight generations.
Editing
  • edit_video is the entry point for timeline edits: pass the intent in natural language and a dedicated editing agent, which sees the full timeline, the concept and the media library, applies validated operations and reports applied or no_changes with what it rejected and why. edit_clip_videos is different: it changes a clip's pixels via video-to-video on Gemini Omni whatever model made the clip, on clips that already have a video and are three to ten seconds long; for a longer clip, pass in_point and out_point to edit a window, one clip at a time, billed for the window at the Omni rate. Each edit lands as a new take, auto-selected, with the prior take still available. A failed edit leaves the working take untouched and reports on latest_edit_status.
  • set_editor_state replaces the whole editor state object. Always read it from get_project, modify, and write it back; a partial object deletes what it omits. When changing one field of an existing item, copy the item verbatim: an item with the same id inherits its earlier placement and style for fields you leave null, but explicit values always win.
  • Editor item shapes: text items place with x, y, w normalized zero to one (x 0.5 centered, y the vertical center: a top hook sits near 0.12 to 0.2, a bottom one near 0.8), and style.font_size is pixels on a 1080 by 1920 reference (default sixty-four, readable minimum twenty-four). Always set x and y or the text renders center-frame. Text wraps only at its own line breaks unless text_wrap is true, which makes w the box width. Prefer style_preset ids from list_text_style_presets over hand-built styles. Media items need a durable public URL (a signed asset URL expires; re-host through the project first) and take w as a width fraction (1.0 fullscreen, about 0.6 for a picture-in-picture, about 0.4 for a logo flash); video items also take speed 0.5 to 2 and volume, which you set to zero so a demo clip never talks over the presenter.
  • Clip ids are re-minted on every concept save. An id held across a save answers "Clips not found in the selected concept"; re-read the project. Changing a clip's starting frame also drops that clip's generated video, which comes back only by reverting to the prior concept version (list_creative_concepts, then revert_creative_concept, which restores script, clips and editor state together and is refused while automation runs).
  • select_clip_video needs a completed take of the same project; re-render afterwards to bake the change in. A main-track entry with use_original_voice: true keeps the clip's pre-dub audio in renders, and the flag is dropped when the clip re-points to a new generation.
  • Captions come from transcribe_clips. Word timings arrive in spoken order and must not be re-sorted.
  • Renders are automatic when saved edits are newer than the last render: approving, scheduling and leaving the editor re-render, scheduled posts wait briefly for an in-flight render rather than posting stale video, and a sweeper renders recently active projects once they have been quiet a few minutes. render_state: failed means the last attempt for the saved edits failed and only the next edit or commit point retries it. A video supplied directly (set_edited_video, or a video_url on schedule_post) is recorded as the current render and is never re-rendered over.
  • set_clip_voice_effects adjusts the acoustic environment baked into generated clips' audio: free, seconds per clip, frames untouched.
Replication and drafts
  • replicate_project takes exactly one source: a tiktok_url, a source_video_url from the workspace, or a source_project_id of one of the workspace's own projects (its rendered video is the reference, so it needs a finished video). draft_only=true builds a reviewable draft and stops before clip generation, so video credits are spent only when the draft is generated. max_duration_seconds is a target, not a cap: it shortens or lengthens the replica, and every replica is capped at one hundred sixty seconds whichever model generates it. variation_instructions cap at four thousand characters. A workspace runs ten replication jobs at once; requests past that queue automatically.
  • Replicating from a TikTok URL also captures the source into the ideas library, deduplicated on the video URL. Replication plans media from the workspace asset library on its own: an app demo the original cut to becomes a media scene, partial cards and logo flashes become timed overlays on a Media track. A non-promotional replica does not use the brand media library.
  • A hub video judged hard to replicate returns low_feasibility_warning until the call repeats with acknowledge_low_feasibility=true. A video that needs the brand's own digital files returns missing_brand_assets naming what to upload (upload_asset) rather than starting; the same acknowledgement proceeds anyway and the replica drops those beats. Physical products are never a requirement.
  • get_replication_status reports build_step (source, analyze, concept, scenes, frames, assemble, done) and, on failure, failure_kind (transient, timeout, safety, quality, content, unknown), retriable and a next hint. retry_draft_build resumes from the last completed checkpoint, so finished stages are never re-paid; prefer it for transient and timeout failures and request_draft_edits for safety or content failures, because a blocked look keeps getting blocked. A failed request-edits revision restores the draft intact and reports failed_revision with the preserved feedback.
  • An ungenerated replication draft's editor is read-only: direct set_editor_state is refused. Its edit surface is the draft itself, through the edit ladder: words only, on one scene, edit_scene_script (free); the whole read, edit_draft_script; one scene should look or play differently, edit_scene (image credits); the whole video's look, regenerate_look_canon; restructure, duration, add or remove scenes, request_draft_edits, which edit_scene refuses and which cannot serve script drafts. Scene edits of different scenes run in parallel; same-scene and whole-script edits serialize. Every completed edit_scene is undoable with revert_scene_edit, per scene, free.
  • A draft can complete with some scene frames failed; regenerate_scene_frame retries them, and generate_replication_draft is gated until every scene has a frame.
  • generate_replication_draft approves the reviewed draft into clip generation plus the final editing pass and render, honoring editor changes present on the draft as deliberate overrides. generate_video on a draft instead runs the standard automation pipeline and does not carry draft edits as overrides.
Scheduling and posting
  • schedule_post posts a project's video to TikTok (tiktok_username), to the avatar's Instagram (also_post_to_instagram), or both in one atomic schedule: if either platform has no slot (device busy, no slot left that day), nothing is scheduled and the whole request is rejected. schedule_instagram_post schedules a standalone Reel, and its share_to_facebook is the only Facebook path. update_scheduled_post, cancel_scheduled_post and retry_scheduled_post manage the queue; list_scheduled_posts and get_scheduled_post read it.
  • A project with an avatar may only post to a TikTok account linked to that avatar; check get_avatar. A project with no avatar can post to any account on the workspace's fleet, linked or unassigned; posting to an avatar's account attributes the analytics to that avatar, posting to an unassigned account attributes them to none.
  • Posting a video you already have (nothing generated, rendered or credit-metered): create_draft_project makes an empty project with no avatar, so it can post to any account on the fleet; set_edited_video attaches the file from a publicly reachable video url and records it as the project's completed render; then schedule_post or schedule_instagram_post posts it. There is no upload body over MCP: a file on the client's machine is staged with the REST upload (POST /uploads/videos, multipart, the same API key) and its returned url passed to set_edited_video. To attribute an uploaded video's analytics to an avatar, create the project in the app's Upload button or with the REST create call and its avatar field, then attach and schedule from here; the avatar choice is permanent. set_edited_video is refused while automation runs on the project or a replication draft is locked, and a scheduled post for the project picks up the new video.
  • A post goes out only if its project is approved at its slot. Scheduling through schedule_post approves the project; update_project with user_review_state=approved approves without scheduling. Automated pipelines (campaigns, content pushes) generate, render and schedule but never approve on their own, so a scheduled post whose project nobody approved fails at its slot with the message "Project not approved at scheduled time". That is the review step working, not an outage.
  • Captions: generate_project_description writes a hook line plus exactly five hashtags from the script and company profile, but only returns the text; pass it as the caption yourself. TikTok captions may not contain the commercial-disclosure hashtags #ad, #ads, #sponsored, #partnership or #paidpartnership: TikTok's own disclosure gate blocks the post, so the caption validator refuses them up front.
  • When the avatar has no account on a platform yet, schedule_post with await_new_account=true (TikTok) or await_new_instagram_account=true, or schedule_instagram_post with await_new_account=true, persists the post as waiting; purchase_account_seats with link_avatar_project_id then buys the account, and once it is created the waiting post books a real slot and goes out with no further action, independently per platform.
  • If a schedule is rejected, read the reason and offer the valid accounts or another time; do not retry blind.
Avatars and voices
  • The wizard, in order: create_avatar (blocks until the candidate scenes exist and charges seventy-five credits: one appearance plus four scenes), then any of discard_wizard_scene, generate_wizard_scenes (fifteen credits a scene) and update_wizard_appearance (regenerates the look) before accept_avatar_appearance locks the appearance, then select_avatar_voice, which finishes the wizard. get_avatar_wizard polls and already lists the free basic voice_options; reroll_preset_voices swaps in three other free picks (direction accepts only deeper or higher). generate_avatar_voices (premium clones, one to three, one thousand five hundred credits each) only when a premium voice is wanted. Completion auto-starts pose and angle variations for every kept scene, free on the workspace's first avatar and charged per image after, so do not also call generate_scene_variations on a fresh avatar. The first kept scene becomes the profile image.
  • Voices come in exactly two kinds: free basic voices (called "preset" in tool names for historical reasons) and paid premium clones (generate_premium_voice, cloned from a generated speaking clip on Seedance by default). get_preset_voices then apply_preset_voice changes an existing avatar's basic voice; browsing and rerolling is free.
  • update_avatar_settings replaces whole sets: tiktok_usernames, tags and warming_search_terms are overwritten with what you pass (an empty list clears, and warming then falls back to niche terms), and the TikTok accounts must already exist on a workspace device. default_video_model takes default to clear back to the workspace routing rules.
  • Scene library: every scene and library frame carries vision-derived content_labels from a fixed vocabulary plus a scene_description; match those against a clip's needs rather than picking by name. generate_scene_frames (one to ten, default three) lands frames inactive; activating one with update_scene_frame auto-generates six pose variations (ninety credits) when it has none, and upload_scene_frame is stored active and does the same. delete_scene_frames also deletes a scene's variations, and the profile frame cannot be deleted; set another first. Replication-generated scenes stay out of the avatar's active library on purpose.
  • edit_image edits any Pamba-hosted image with a text instruction (fifteen credits) and returns a new URL; on a registered frame the result is itself usable as a starting frame. save_scene_variation keeps that result as a variation (original untouched), replace_scene_image points the frame at it instead, losing the original. promote_scene_variation swaps a variation with the scene's reference, so promoting it back undoes the swap.
  • Camera styles are selfie, tripod, tripod_full_body_visible and podcast on the avatar tools; generate_starting_frames spells the full-body style tripod_full_body, and the other spelling falls through to selfie there.
  • import_avatar creates an avatar from a photo URL with gender MALE or FEMALE and a free basic voice; redesign_avatar applies free-form appearance or voice changes and blocks until they land. track_external_tiktok_account attaches an account you post to from your own phone, for analytics only: posting and warming stay unavailable for it.
  • Operator-only tools exist on the surface because the in-app assistant has them; for a customer workspace they answer forbidden: the reference-frame tools, create_social_account, get_account_creation_status, resume_account_creation, generate_image, and the writer-engine controls (run_content_engine, control_stage_run, update_engine_prompt, set_autonomy_dial, set_batch_share_page).
Accounts, seats and devices
  • list_accounts is the inventory of every TikTok, Instagram and Facebook account on the workspace's fleet, including accounts assigned to no avatar (their avatar fields are null). Status is posting, track_only or archived; health flags include SHADOWBAN_RISK (after the account's first three weeks of tracking), NOT_RECOMMENDED and SUSPENDED.
  • Managed account seats cost one hundred dollars a month each, every three include a dedicated phone, and every TikTok plus Instagram pair across the subscription prices its second account at fifty dollars, re-priced when seats are added or cancelled. Any quantity up to a thousand accounts per checkout can be bought; the seats the phones cannot back yet stay being set up until the team adds phones. Facebook has no seat of its own; it rides Instagram cross-posting. purchase_account_seats returns a checkout URL; an already subscribed workspace gets Stripe's confirm page raising the quantity with proration.
  • A purchase never adopts a spare account already sitting on the workspace's phones. Check for spares first: an unassigned spare links to an avatar free, TikTok through update_avatar_settings (tiktok_usernames), Instagram through link_social_account without a password.
  • A bought seat waits for its username before creation starts. suggest_account_usernames returns a checked, currently free idea per waiting seat, check_account_username verifies a pick (availability is a hint, not a reservation), set_account_username saves it and starts that seat's creation, or use_default_name=true creates with a platform default. Instagram gets the typed name at signup; TikTok assigns its own handle and applies the pick as a rename right after, which spends TikTok's one username change per thirty days. A name that fails when applied falls back to close variations, then keeps the platform handle. Progress shows per account on list_accounts until the account is ready.
  • cancel_account_seat keeps the account posting until the paid period ends, then stops posting and billing, no refund; reinstate_account_seat undoes it before that date at no cost. get_seat_billing shows the next renewal's total per seat.
  • A workspace that only buys accounts and posts its own videos runs this order, and nothing in it spends credits: list_accounts to rule out a spare, purchase_account_seats (pass link_avatar_project_id when the account is for an avatar) and the person pays at the checkout URL, suggest_account_usernames then set_account_username per seat (creation starts only once a seat has a name), list_accounts until the account reads posting, then create_draft_project, set_edited_video and schedule_post with the new username (see Scheduling and posting). To queue the post before the account exists, the project needs the avatar the purchase links to, and schedule_post takes await_new_account=true in place of a username.
  • update_account_profile edits display name, handle, picture and bio on the hosting phone. Bios are capped at one hundred sixty characters on TikTok and one hundred fifty on Instagram; a URL typed into a bio is plain text, the link field is separate and untouched. list_accounts reports each account's current bio, whichever is newer of the one Pamba last set and the one last read off the phone; every linked account's bio is read once a day, so an in-app change shows within a day. Only the fields an edit asked for count as outcomes: a bio-only edit reports one operation, not three.
  • Pamba-created TikTok accounts block AI comments automatically once linked to an avatar: an account linked at creation gets the filter after its first post is live, one linked later gets it queued at link time, and an unassigned account is never filtered. disable_ai_comments turns it off per account. get_avatar reports the state per account as applied, queued, scheduled, failed or off, and null when the account is not on one of the workspace's phones.
  • enable_instagram_ai_creator is enable-only and idempotent: once on, the label locks on, and disabling is rejected.
  • Warming (human-like feed browsing) is always on for every device-hosted account and cannot be turned off from the tools. Exactly one config governs an account: an avatar-assigned account warms through its avatar's config (get_warming_config, terms via update_avatar_settings), an unassigned one through its own (get_account_warming_config, set_account_warming_search_terms); assigning an avatar moves ownership and cancels pending account-level sessions. Terms cap at twenty-five of eighty characters; without explicit terms, sessions fall back to terms generated from the workspace niche. cancel_warming_session works only on pending sessions.
  • Every device-held linked TikTok account gets one account-health check a day. Findings open incidents (ACCOUNT_WARNING, VIDEO_REMOVED, VIDEO_NOT_RECOMMENDED), shown as health flags and cards, emailed to the workspace and surfaced on Home; these kinds never pause the account. get_tiktok_account_health returns the latest screenshots and open issues; request_tiktok_appeal records the decision to appeal a removed or restricted video, after which the Pamba team files it from the phone by hand, one appeal per issue. Outcomes are inferred, never read from TikTok directly: a removed video reappearing closes its issue, warnings close after two clean daily checks. close_account_incident dismisses an issue for good.
  • Accounts suspended by Meta open a SUSPENDED incident that pauses posting and warming and rejects scheduling until a session runs clean or the incident is closed with close_account_incident, only after the account is verified restored. reconcile_tiktok_rename repairs an account renamed on TikTok itself, moving the avatar's active account and all forward-looking drafts, plan and scheduling to the new handle; old posts stay under the old handle.
Ideas, discover and research
  • list_ideas and get_idea read the library (twenty-five per page, sortable by date, views and engagement ratios); every hub video carries a replication feasibility_verdict (pass, fail, unjudged) with the judge's reason, and exclude_low_feasibility=true hides failed ones while unjudged stay visible. get_idea lists required_brand_assets with in_library per kind, which tells you before replicating whether an upload is needed. A workspace holds up to one hundred ideas.
  • Research needs an active subscription, a credit plan or account seats; free workspaces browse but every addition (create_idea, branch_idea, add_tracked_accounts, generate_script_from_idea) answers payment_required. Saving a video that is already analyzed is allowed on every plan. The inspiration-account cap scales with the plan tier. Tracking an account feeds its breakout videos into the create page's For You blend once the feasibility judge passes them; remove_tracked_account cannot remove an account linked to one of the workspace's avatars.
  • search_tracked_videos searches the workspace's own avatar accounts by default; pass include_research_accounts=true for the inspiration accounts. Ground recommendations there rather than in memory. generate_script_from_idea writes a fresh thirty to forty-five second script and does not save it; save_idea_script or create_video_project does.
  • Discover: get_trending_videos (by default only avatar-replicable content, screened for promotion carriage; include_unproducible=true reveals everything), get_niche_feed (returns niche_status pending or no_niche for an empty feed), search_viral_videos (paid only; falls through to a live TikTok search when the corpus is thin, with a daily budget reported as live_searches_remaining_today), get_breakout_creators. To act: use_discover_video puts a video on the Ideas board (idempotent), bookmark_discover_video saves it, track_video_author adds the creator as an inspiration account. browse_picker_videos is the create page's shelf; a row whose video_url is null is an un-enriched Discover row, so prepare it with use_discover_video first.
Content review, knowledge and automation
  • Campaigns are autonomous cycles that plan, write, generate and queue posts for their member avatar and account bindings on a schedule, gated by review windows unless auto-approve is on. Schedules run in the workspace timezone and plans are ready for review by nine in the morning local time by default. Every workspace has a Default campaign that owns unassigned members and cannot be deleted; create_campaign copies its schedule and starts disabled with no members; assign_avatar_to_campaign is a complete move. enable_campaign spends credits on every future cycle until disable_campaign, and both need an active subscription on the workspace owner. run_campaign_now plans the gap days up to the next scheduled cycle without stealing that cycle's window.
  • preview_content_plan is a dry run that creates nothing; plan_content_batch plans (or re-plans an unapproved batch via batch_id); get_content_plan explains, per avatar, why each got its slots; edit_plan_slots moves, removes, swaps, adds or pauses. approve_content_plan or approve_all_content_plans is where credit spend starts, and approval is refused while the plan has error-severity violations. set_mix_targets replaces all targets, so read get_content_strategy first. delete_plan only removes a planning or brief-pending batch and never touches projects.
  • push_content_batch is safe by default: without push_now=true or a preflight_id it only runs the preflight. With push_now, each pushed approved script becomes a fully automated project that generates and schedules, and spends video credits. decide_content_script with a batch_id and no script_id approves every undecided script; require_green=true skips scripts with failing checks. send_writer_chat_message answers asynchronously: read the thread with get_content_script (view=writer_chat), then apply_script_revision.
  • Knowledge base: patterns (a pattern's category is its canonical format; lipsync patterns are classification-only, the planner never allocates them), principles, playbooks and term lists (tiered pools of real terms the writer draws from: proven, testing and exploratory tiers are writer-eligible, candidate and risk_flagged terms are not). The writer's references are chosen automatically at claim time from pattern links; curate them with manage_pattern_link and preview with get_pattern_references.
  • get_studio_overview is the one read for the Drafts and Videos tabs. Always pass statuses: drafts is the Drafts population (concept-stage items awaiting generation), the others (queue, failed, approved, scheduled, posted, archived) are the Videos tab's filter, and posted history and archived projects are reachable only here. Omitting statuses returns the classic queue capped at fifty with drafts sorted below everything else, which hides them on a busy workspace. sort (newest, oldest, posttime) decides which items make the window and requires statuses; a typo in either errors rather than defaulting. view=home also returns the getting-live setup, where ready_to_post (not account_connected) says whether posting would actually work.
Analytics
  • get_analytics_summary (days one to three hundred sixty-five, default thirty; platform tiktok, instagram or facebook, default TikTok; optional avatar) gives views and followers per platform, broken down by up to twenty avatars. search_tracked_videos is per-video TikTok performance, list_social_videos per-video Instagram and Facebook performance, get_tracked_account_metrics an account's lifetime totals and cadence.
  • The numbers are snapshots and the surfaces bucket differently, so do not expect them to reconcile to the view. The summary tool buckets days in UTC; the app's dashboard uses the workspace timezone and includes the current partial day. The dashboard sums daily deltas, while per-account metrics sum lifetime view counts. Views a video earns before its first snapshot (about an hour after posting, when TikTok front-loads) never land in a daily bucket. Accounts assigned to a deactivated avatar keep posting and accruing views but do not appear in avatar-scoped dashboards. A TikTok rename starts a new account row, and each era's videos stay on their era's row. Instagram's headline views are the play count the app shows, and the first observation of a reel attributes its whole lifetime to one day.
Workspace, members, onboarding and support
  • update_workspace_settings is admins only; setting website_url re-scrapes the site and replaces the stored company profile (and the niche, unless it was hand-written). update_company_profile edits the brief field by field and leaves the others alone; an empty string clears a field. Name, niche and profile feed the model's own context, from the next connection onward. list_workspaces returns at most twenty workspaces and list_workspace_members one hundred.
  • create_workspace with website_url sets a workspace up like an onboarded one in one call (brief, name, media library, niche feed, three matched avatars; the site read takes about thirty seconds); pass niche_description and name instead when there is no site. A new workspace has its own plan and starts with zero credits, and the connection stays bound to the workspace of its key. If setup fails after creation the error carries the workspace_id: finish or delete it, never create a second. delete_workspace is a soft delete and cannot remove the user's default workspace.
  • Onboarding state (get_onboarding_state) runs website, brand, media, first video, avatar, plan, device; the light flow of an added workspace ends after set_onboarding_brand and complete_onboarding. set_onboarding_website is best-effort (an unreachable site still records the URL and advances) and kicks a background media capture into the asset library (media_capture_status). list_onboarding_presenter_options returns an empty list while the niche match is still running, so poll again rather than treating it as no avatars. select_onboarding_presenter picks a matched starter avatar for free; start_onboarding_avatar generates one and spends image credits. create_onboarding_concept_projects is free and idempotent. The device half must be resolved (purchased or skipped) before complete_onboarding, which refuses otherwise. set_onboarding_referral accepts only its listed sources, with free text in detail under other. A user with no credits and no avatars right after signing up has a torn bootstrap; heal_signup_bootstrap re-runs the missing grants idempotently.
  • contact_support emails the Pamba team and allows three messages per workspace and five per user in twenty-four hours, so send one complete message of up to five thousand characters. list_api_keys, create_api_key and revoke_api_key manage keys; a revoked key's MCP connection fails at its next call. create_api_key returns the new secret in its result, which over a hosted client lands in a transcript, so create the key for an MCP connection in the app and keep the tool for keys the agent itself will hand to a system.
  • Content rules: Pamba's Acceptable Use Policy is the public page https://pamba.app/acceptable-use-policy; point people there for what is allowed, why a generation was refused by safety filters, and what happens to accounts that break the rules.

Security model

  • A key or token resolves to one user in one workspace, and every tool runs with that identity. Ownership checks are the same the app enforces: an id from another workspace answers not_found, never data. Admins-only settings answer forbidden for members. Operator endpoints behind Pamba's admin key are not reachable through this server at all; the admin key is not a credential here.
  • Rotate a key by creating a new one and revoking the old; connections are stateless, so the next call after revocation is the one that fails.

Protocol details

  • Streamable HTTP, stateless: every POST is independent and carries its own credential, there is no session id, and no server-to-client stream (GET and DELETE answer 405). A deploy between two calls is invisible to the client.
  • One JSON-RPC message per POST, at most one megabyte (enough for a full editor state; media never travels in a message) and at most sixty-four levels of nesting; a larger body is answered with HTTP 413 and a deeper one with HTTP 400, each with a JSON-RPC error. Batches are refused. Responses are application/json; the server never opens an event stream. Sixteen tool bodies run at once across every connection and four per workspace: a call past the workspace's share answers status: busy at once, and one past the overall bound waits up to thirty seconds for a slot before answering the same, in both cases with nothing run, so a saturated server never hangs a client and one workspace's fan-out never starves another's. Protocol versions 2025-06-18 and 2025-11-25 are accepted; anything else, including 2025-03-26 (whose transport requires batches), negotiates to 2025-06-18.
  • Capabilities: tools, prompts and resources, none with change notifications; the listing changes only with a deploy. Regenerate the reference in your own docs from tools/list if you mirror it.
  • JSON-RPC errors: -32700 malformed JSON, -32600 invalid request or batch, -32601 unknown method, -32602 unknown tool, tool outside the scope, bad arguments, unknown prompt or a missing uri, -32002 resource not found (the data names the uri), -32603 internal error. Auth failures are HTTP 401 before any message is read; a bad toolsets, readonly or max_credits value on the URL is HTTP 400 with a JSON-RPC error body.
Was this helpful?